saleor-dashboard/src/auth/AuthProvider.tsx

174 lines
4.7 KiB
TypeScript
Raw Normal View History

2019-08-09 10:26:22 +00:00
import React from "react";
2019-06-19 14:40:52 +00:00
2019-09-06 15:30:33 +00:00
import {
isSupported as isCredentialsManagementAPISupported,
login as loginWithCredentialsManagementAPI,
saveCredentials
} from "@saleor/utils/credentialsManagement";
2019-09-03 13:42:15 +00:00
import { MutationFunction, MutationResult } from "react-apollo";
import { UserContext } from "./";
2019-06-19 14:40:52 +00:00
import { TypedTokenAuthMutation, TypedVerifyTokenMutation } from "./mutations";
import { TokenAuth, TokenAuthVariables } from "./types/TokenAuth";
import { User } from "./types/User";
import { VerifyToken, VerifyTokenVariables } from "./types/VerifyToken";
2019-09-03 13:42:15 +00:00
import { getAuthToken, removeAuthToken, setAuthToken } from "./utils";
2019-06-19 14:40:52 +00:00
interface AuthProviderOperationsProps {
2019-09-02 19:23:37 +00:00
children: (props: {
hasToken: boolean;
isAuthenticated: boolean;
tokenAuthLoading: boolean;
tokenVerifyLoading: boolean;
user: User;
}) => React.ReactNode;
2019-06-19 14:40:52 +00:00
}
const AuthProviderOperations: React.FC<AuthProviderOperationsProps> = ({
children
}) => {
2019-06-19 14:40:52 +00:00
return (
<TypedTokenAuthMutation>
{(...tokenAuth) => (
<TypedVerifyTokenMutation>
{(...tokenVerify) => (
2019-09-03 13:42:15 +00:00
<AuthProvider tokenAuth={tokenAuth} tokenVerify={tokenVerify}>
2019-06-19 14:40:52 +00:00
{children}
</AuthProvider>
)}
</TypedVerifyTokenMutation>
)}
</TypedTokenAuthMutation>
);
};
interface AuthProviderProps {
2019-09-02 19:23:37 +00:00
children: (props: {
hasToken: boolean;
isAuthenticated: boolean;
tokenAuthLoading: boolean;
tokenVerifyLoading: boolean;
user: User;
}) => React.ReactNode;
2019-09-03 13:42:15 +00:00
tokenAuth: [
MutationFunction<TokenAuth, TokenAuthVariables>,
MutationResult<TokenAuth>
];
tokenVerify: [
MutationFunction<VerifyToken, VerifyTokenVariables>,
MutationResult<VerifyToken>
];
2019-06-19 14:40:52 +00:00
}
interface AuthProviderState {
user: User;
persistToken: boolean;
}
class AuthProvider extends React.Component<
AuthProviderProps,
AuthProviderState
> {
constructor(props) {
super(props);
this.state = { user: undefined, persistToken: false };
}
componentWillReceiveProps(props: AuthProviderProps) {
const { tokenAuth, tokenVerify } = props;
2019-09-03 13:42:15 +00:00
const tokenAuthOpts = tokenAuth[1];
const tokenVerifyOpts = tokenVerify[1];
if (tokenAuthOpts.error || tokenVerifyOpts.error) {
2019-06-19 14:40:52 +00:00
this.logout();
}
2019-09-03 13:42:15 +00:00
if (tokenAuthOpts.data) {
const user = tokenAuthOpts.data.tokenCreate.user;
2019-06-19 14:40:52 +00:00
// FIXME: Now we set state also when auth fails and returned user is
// `null`, because the LoginView uses this `null` to display error.
this.setState({ user });
if (user) {
setAuthToken(
2019-09-03 13:42:15 +00:00
tokenAuthOpts.data.tokenCreate.token,
2019-06-19 14:40:52 +00:00
this.state.persistToken
);
}
} else {
2019-09-03 13:42:15 +00:00
if (tokenVerifyOpts.data && tokenVerifyOpts.data.tokenVerify.user) {
const user = tokenVerifyOpts.data.tokenVerify.user;
2019-06-19 14:40:52 +00:00
this.setState({ user });
}
}
}
componentDidMount() {
const { user } = this.state;
const token = getAuthToken();
if (!!token && !user) {
2019-09-03 13:42:15 +00:00
this.verifyToken(token);
} else {
2019-09-11 14:04:41 +00:00
loginWithCredentialsManagementAPI(this.login);
2019-06-19 14:40:52 +00:00
}
}
login = async (email: string, password: string) => {
2019-06-19 14:40:52 +00:00
const { tokenAuth } = this.props;
2019-09-03 13:42:15 +00:00
const [tokenAuthFn] = tokenAuth;
tokenAuthFn({ variables: { email, password } }).then(result => {
if (result && !result.data.tokenCreate.errors.length) {
2019-09-11 14:04:41 +00:00
saveCredentials(result.data.tokenCreate.user, password);
}
});
2019-09-03 13:42:15 +00:00
};
loginByToken = (token: string, user: User) => {
this.setState({ user });
setAuthToken(token, this.state.persistToken);
2019-06-19 14:40:52 +00:00
};
logout = () => {
this.setState({ user: undefined });
2019-09-06 15:30:33 +00:00
if (isCredentialsManagementAPISupported) {
navigator.credentials.preventSilentAccess();
}
2019-06-19 14:40:52 +00:00
removeAuthToken();
};
2019-09-03 13:42:15 +00:00
verifyToken = (token: string) => {
const { tokenVerify } = this.props;
const [tokenVerifyFn] = tokenVerify;
return tokenVerifyFn({ variables: { token } });
};
2019-06-19 14:40:52 +00:00
render() {
const { children, tokenAuth, tokenVerify } = this.props;
2019-09-03 13:42:15 +00:00
const tokenAuthOpts = tokenAuth[1];
const tokenVerifyOpts = tokenVerify[1];
2019-06-19 14:40:52 +00:00
const { user } = this.state;
const isAuthenticated = !!user;
2019-09-02 19:23:37 +00:00
2019-06-19 14:40:52 +00:00
return (
<UserContext.Provider
2019-09-02 19:23:37 +00:00
value={{
login: this.login,
2019-09-03 13:42:15 +00:00
loginByToken: this.loginByToken,
2019-09-02 19:23:37 +00:00
logout: this.logout,
2019-09-03 13:42:15 +00:00
tokenAuthLoading: tokenAuthOpts.loading,
tokenVerifyLoading: tokenVerifyOpts.loading,
2019-09-02 19:23:37 +00:00
user
}}
2019-06-19 14:40:52 +00:00
>
{children({
hasToken: !!getAuthToken(),
isAuthenticated,
2019-09-03 13:42:15 +00:00
tokenAuthLoading: tokenAuthOpts.loading,
tokenVerifyLoading: tokenVerifyOpts.loading,
2019-06-19 14:40:52 +00:00
user
})}
</UserContext.Provider>
);
}
}
export default AuthProviderOperations;