import * as React from 'react'; import { createContext } from 'react'; import { useClientContext } from '../hooks/useClientContext'; import { StorageService } from '../service/Storage'; import { AuthProviderInfo } from 'pocketbase'; export type RegisterWithEmailType = (email: string, password: string) => Promise; export type SignInWithEmailType = (email: string, password: string) => Promise; export type SignInWithProviderType = (provider: string) => Promise; export type SubmitProviderResultType = (url: string) => Promise; export type SignOutType = () => void; export type SendPasswordResetEmailType = (email: string) => Promise; export type SendEmailVerificationType = (email: string) => Promise; export type UpdateProfileType = (id: string, record: {}) => Promise; export type UpdateEmailType = (email: string) => Promise; export type DeleteUserType = (id: string) => Promise; export interface AuthActions { registerWithEmail: RegisterWithEmailType; signInWithEmail: SignInWithEmailType; signInWithProvider: SignInWithProviderType; submitProviderResult: SubmitProviderResultType; signOut: SignOutType; sendPasswordResetEmail: SendPasswordResetEmailType; sendEmailVerification: SendEmailVerificationType; updateProfile: UpdateProfileType; updateEmail: UpdateEmailType; deleteUser: DeleteUserType; } export const AuthContext = createContext({} as AuthActions); export type AuthProviderProps = { children: React.ReactNode; webRedirectUrl: string; mobileRedirectUrl: string; openURL: (url: string) => Promise; }; export const AuthProvider = (props: AuthProviderProps) => { const client = useClientContext(); const [authProviders, setAuthProviders] = React.useState(); const actions: AuthActions = { registerWithEmail: async (email, password) => { await client?.collection('users').create({ email: email, password: password, passwordConfirm: password, }); }, signInWithEmail: async (email: string, password: string) => { await client?.collection('users').authWithPassword(email, password); }, signInWithProvider: async (provider: string) => { const authProvider = authProviders?.find((p) => p.name === provider); const redirectURL = typeof document !== 'undefined' ? props.webRedirectUrl : props.mobileRedirectUrl; const url = authProvider?.authURL + redirectURL; await StorageService.set('provider', JSON.stringify(authProviders)); await props.openURL(url); }, submitProviderResult: async (url: string) => { const params = new URLSearchParams(url.split('?')[1]); const code = params.get('code'); const state = params.get('state'); const providersString = await StorageService.get('provider'); if (providersString) { const providers = JSON.parse(providersString) as AuthProviderInfo[]; const authProvider = providers?.find((p) => p.state === state); if (authProvider && code) { await client ?.collection('users') .authWithOAuth2Code( authProvider.name, code, authProvider.codeVerifier, typeof document !== 'undefined' ? props.webRedirectUrl : props.mobileRedirectUrl ); } } }, signOut: () => { client?.authStore.clear(); }, sendPasswordResetEmail: async (email: string) => { await client?.collection('users').requestPasswordReset(email); }, sendEmailVerification: async (email: string) => { await client?.collection('users').requestVerification(email); }, updateProfile: async (id: string, record: {}) => { await client?.collection('profiles').update(id, record); }, updateEmail: async (email: string) => { await client?.collection('users').requestEmailChange(email); }, deleteUser: async (id: string) => { await client?.collection('users').delete(id); }, }; React.useEffect(() => { (async () => { const methods = await client?.collection('users').listAuthMethods(); setAuthProviders(methods?.oauth2?.providers ?? []); })(); }, [props.webRedirectUrl, props.mobileRedirectUrl]); return {props.children}; };