117 lines
2.5 KiB
TypeScript
117 lines
2.5 KiB
TypeScript
import React, { useMemo, useState, useEffect } from 'react';
|
|
import { useApolloClient } from '@apollo/client';
|
|
import { isFunction } from 'lodash';
|
|
import { context as Context } from './context';
|
|
import { AuthContext, User } from './types';
|
|
import TokenStorage from '../tokenstorage/TokenStorage';
|
|
import { QUERY_ME } from './queries';
|
|
import { MUTATION_SIGN_IN } from './mutations';
|
|
|
|
export interface AuthProviderProps {
|
|
tokenStorage?: TokenStorage;
|
|
children?: React.ReactNode;
|
|
}
|
|
|
|
type MeQueryResult = {
|
|
me: User | null;
|
|
};
|
|
|
|
type SignInMutationResult = {
|
|
token: string;
|
|
user: User;
|
|
};
|
|
|
|
type SignInMutationVariables = {
|
|
email: string;
|
|
staySignedIn: boolean;
|
|
password: string;
|
|
};
|
|
|
|
export function AuthProvider(props: AuthProviderProps) {
|
|
const client = useApolloClient();
|
|
const [user, setUser] = useState<AuthContext['user']>(null);
|
|
const [loading, setLoading] = useState<boolean>(true);
|
|
const tokenStorage = useMemo(() => {
|
|
if (props.tokenStorage) {
|
|
return props.tokenStorage;
|
|
}
|
|
return new TokenStorage();
|
|
}, [props.tokenStorage]);
|
|
|
|
useEffect(() => {
|
|
loadUser();
|
|
}, []);
|
|
|
|
const loadUser = async () => {
|
|
if (tokenStorage.token) {
|
|
try {
|
|
const result = await client.query<MeQueryResult>({
|
|
query: QUERY_ME,
|
|
fetchPolicy: 'network-only',
|
|
});
|
|
if (result.data.me) {
|
|
setUser(result.data.me);
|
|
}
|
|
} catch (e) {}
|
|
}
|
|
setLoading(false);
|
|
};
|
|
|
|
const signIn: AuthContext['signIn'] = async (
|
|
email: string,
|
|
password: string,
|
|
staySignedIn: boolean,
|
|
validate?: (user: User) => boolean
|
|
) => {
|
|
const result = await client.mutate<
|
|
SignInMutationResult,
|
|
SignInMutationVariables
|
|
>({
|
|
mutation: MUTATION_SIGN_IN,
|
|
variables: {
|
|
email,
|
|
password,
|
|
staySignedIn,
|
|
},
|
|
});
|
|
|
|
if (result.data?.user) {
|
|
if (isFunction(validate) && !validate(result.data?.user)) {
|
|
return null;
|
|
}
|
|
tokenStorage.setToken(result.data.token);
|
|
setUser(result.data.user);
|
|
client.writeQuery<MeQueryResult>({
|
|
query: QUERY_ME,
|
|
data: {
|
|
me: result.data.user,
|
|
},
|
|
});
|
|
return result.data.user;
|
|
}
|
|
|
|
return null;
|
|
};
|
|
|
|
const signOut = () => {
|
|
return client.clearStore().then(() => {
|
|
tokenStorage.setToken('');
|
|
setUser(null);
|
|
});
|
|
};
|
|
|
|
return (
|
|
<Context.Provider
|
|
value={{
|
|
user,
|
|
tokenStorage,
|
|
signIn,
|
|
signOut,
|
|
loading,
|
|
}}
|
|
>
|
|
{props.children}
|
|
</Context.Provider>
|
|
);
|
|
}
|