saleor-dashboard/src/auth/hooks/useAuthProvider.ts

211 lines
5.4 KiB
TypeScript
Raw Normal View History

Use graphql-codegen (#1874) * Use generated hooks in apps * Remove unused files * Use proper types in apps * Use generated hooks in attributes * Use generated hooks in auth module * Use generated hooks in categories * Use generated hooks in channels * Use generated types in collections * Remove legacy types from background tasks * Use generated hooks in customers * Use generated hooks in discounts * Use generated hook in file upload * Use generated types in gift cards * Use generated types in home * Use generated hooks in navigation * Use generated hooks in orders * Use generated hooks in pages * Use generated hooks in page types * Use generated hooks in permission groups * Use generated hooks in plugins * Use generated hooks in products * Use fragment to mark product variants * Improve code a bit * Use generated hooks in page types * Use generated types in searches * Use generated hooks in shipping * Use generated hooks in site settings * Use generated hooks in staff members * Use generated hooks in taxes * Place all gql generated files in one directory * Use generated hooks in translations * Use global types from new generated module * Use generated hooks in warehouses * Use generated hooks in webhooks * Use generated fragment types * Unclutter types * Remove hoc components * Split hooks and types * Fetch introspection file * Delete obsolete schema file * Fix rebase artifacts * Fix autoreplace * Fix auth provider tests * Fix urls * Remove leftover types * Fix rebase artifacts
2022-03-09 08:56:55 +00:00
import { ApolloClient } from "@apollo/client";
2021-01-26 22:04:54 +00:00
import { IMessageContext } from "@saleor/components/messages";
import { APP_DEFAULT_URI, APP_MOUNT_URI, DEMO_MODE } from "@saleor/config";
Use graphql-codegen (#1874) * Use generated hooks in apps * Remove unused files * Use proper types in apps * Use generated hooks in attributes * Use generated hooks in auth module * Use generated hooks in categories * Use generated hooks in channels * Use generated types in collections * Remove legacy types from background tasks * Use generated hooks in customers * Use generated hooks in discounts * Use generated hook in file upload * Use generated types in gift cards * Use generated types in home * Use generated hooks in navigation * Use generated hooks in orders * Use generated hooks in pages * Use generated hooks in page types * Use generated hooks in permission groups * Use generated hooks in plugins * Use generated hooks in products * Use fragment to mark product variants * Improve code a bit * Use generated hooks in page types * Use generated types in searches * Use generated hooks in shipping * Use generated hooks in site settings * Use generated hooks in staff members * Use generated hooks in taxes * Place all gql generated files in one directory * Use generated hooks in translations * Use global types from new generated module * Use generated hooks in warehouses * Use generated hooks in webhooks * Use generated fragment types * Unclutter types * Remove hoc components * Split hooks and types * Fetch introspection file * Delete obsolete schema file * Fix rebase artifacts * Fix autoreplace * Fix auth provider tests * Fix urls * Remove leftover types * Fix rebase artifacts
2022-03-09 08:56:55 +00:00
import { useUserDetailsQuery } from "@saleor/graphql";
2022-02-01 10:23:48 +00:00
import useLocalStorage from "@saleor/hooks/useLocalStorage";
import useNavigator from "@saleor/hooks/useNavigator";
import { commonMessages } from "@saleor/intl";
import {
GetExternalAccessTokenData,
LoginData,
useAuth,
useAuthState
} from "@saleor/sdk";
import {
isSupported as isCredentialsManagementAPISupported,
login as loginWithCredentialsManagementAPI,
saveCredentials
} from "@saleor/utils/credentialsManagement";
import { useEffect, useRef, useState } from "react";
2021-01-26 22:04:54 +00:00
import { IntlShape } from "react-intl";
import urlJoin from "url-join";
2021-01-26 22:04:54 +00:00
import {
ExternalLoginInput,
RequestExternalLoginInput,
RequestExternalLogoutInput,
UserContext,
UserContextError
} from "../types";
import { displayDemoMessage } from "../utils";
2021-01-26 22:04:54 +00:00
export interface UseAuthProviderOpts {
intl: IntlShape;
notify: IMessageContext;
apolloClient: ApolloClient<any>;
}
export function useAuthProvider({
intl,
notify,
apolloClient
}: UseAuthProviderOpts): UserContext {
const {
login,
getExternalAuthUrl,
getExternalAccessToken,
logout
} = useAuth();
const navigate = useNavigator();
const { authenticated, authenticating, user } = useAuthState();
2022-02-01 10:23:48 +00:00
const [requestedExternalPluginId] = useLocalStorage(
"requestedExternalPluginId",
null
);
const [error, setError] = useState<UserContextError>();
const permitCredentialsAPI = useRef(true);
2021-01-26 22:04:54 +00:00
useEffect(() => {
if (authenticating && error) {
setError(undefined);
}
}, [authenticating]);
useEffect(() => {
if (authenticated) {
permitCredentialsAPI.current = true;
}
}, [authenticated]);
useEffect(() => {
2022-02-01 10:23:48 +00:00
if (
!authenticated &&
!authenticating &&
!requestedExternalPluginId &&
permitCredentialsAPI.current
) {
permitCredentialsAPI.current = false;
loginWithCredentialsManagementAPI(handleLogin);
}
}, [authenticated, authenticating]);
2021-01-26 22:04:54 +00:00
Use graphql-codegen (#1874) * Use generated hooks in apps * Remove unused files * Use proper types in apps * Use generated hooks in attributes * Use generated hooks in auth module * Use generated hooks in categories * Use generated hooks in channels * Use generated types in collections * Remove legacy types from background tasks * Use generated hooks in customers * Use generated hooks in discounts * Use generated hook in file upload * Use generated types in gift cards * Use generated types in home * Use generated hooks in navigation * Use generated hooks in orders * Use generated hooks in pages * Use generated hooks in page types * Use generated hooks in permission groups * Use generated hooks in plugins * Use generated hooks in products * Use fragment to mark product variants * Improve code a bit * Use generated hooks in page types * Use generated types in searches * Use generated hooks in shipping * Use generated hooks in site settings * Use generated hooks in staff members * Use generated hooks in taxes * Place all gql generated files in one directory * Use generated hooks in translations * Use global types from new generated module * Use generated hooks in warehouses * Use generated hooks in webhooks * Use generated fragment types * Unclutter types * Remove hoc components * Split hooks and types * Fetch introspection file * Delete obsolete schema file * Fix rebase artifacts * Fix autoreplace * Fix auth provider tests * Fix urls * Remove leftover types * Fix rebase artifacts
2022-03-09 08:56:55 +00:00
const userDetails = useUserDetailsQuery({
client: apolloClient,
skip: !authenticated,
// Don't change this to 'network-only' - update of intl provider's
// state will cause an error
fetchPolicy: "cache-and-network"
2021-01-26 22:04:54 +00:00
});
const handleLogout = async () => {
const path = APP_MOUNT_URI === APP_DEFAULT_URI ? "" : APP_MOUNT_URI;
const returnTo = urlJoin(window.location.origin, path);
const result = await logout({
input: JSON.stringify({
returnTo
} as RequestExternalLogoutInput)
});
if (isCredentialsManagementAPISupported) {
navigator.credentials.preventSilentAccess();
}
// Forget last logged in user data.
// On next login, user details query will be refetched due to cache-and-network fetch policy.
apolloClient.clearStore();
const errors = result?.errors || [];
const externalLogoutUrl = result
? JSON.parse(result.data?.externalLogout?.logoutData || null)?.logoutUrl
: "";
if (!errors.length) {
if (externalLogoutUrl) {
window.location.href = externalLogoutUrl;
} else {
navigate("/");
}
}
return;
};
const handleLogin = async (email: string, password: string) => {
try {
const result = await login({
email,
password
});
if (result && !result.data.tokenCreate.errors.length) {
if (DEMO_MODE) {
displayDemoMessage(intl, notify);
}
saveCredentials(result.data.tokenCreate.user, password);
} else {
setError("loginError");
}
await logoutNonStaffUser(result.data.tokenCreate);
return result.data.tokenCreate;
} catch (error) {
setError("serverError");
}
};
const handleRequestExternalLogin = async (
pluginId: string,
input: RequestExternalLoginInput
) => {
const result = await getExternalAuthUrl({
pluginId,
input: JSON.stringify(input)
});
return result?.data?.externalAuthenticationUrl;
};
const handleExternalLogin = async (
pluginId: string,
input: ExternalLoginInput
) => {
try {
const result = await getExternalAccessToken({
pluginId,
input: JSON.stringify(input)
});
if (result && !result.data?.externalObtainAccessTokens.errors.length) {
if (DEMO_MODE) {
displayDemoMessage(intl, notify);
}
} else {
setError("externalLoginError");
}
await logoutNonStaffUser(result.data.externalObtainAccessTokens);
return result?.data?.externalObtainAccessTokens;
} catch (error) {
setError("serverError");
}
2021-01-26 22:04:54 +00:00
};
const logoutNonStaffUser = async (
data: LoginData | GetExternalAccessTokenData
) => {
if (data.user && !data.user.isStaff) {
notify({
status: "error",
text: intl.formatMessage(commonMessages.unauthorizedDashboardAccess),
title: intl.formatMessage(commonMessages.insufficientPermissions)
});
await handleLogout();
}
};
2021-01-26 22:04:54 +00:00
return {
login: handleLogin,
requestLoginByExternalPlugin: handleRequestExternalLogin,
loginByExternalPlugin: handleExternalLogin,
logout: handleLogout,
authenticating: authenticating && !error,
authenticated: authenticated && user?.isStaff,
user: userDetails.data?.me,
error
2021-01-26 22:04:54 +00:00
};
}