@greatapps/common 1.1.689 → 1.1.691
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/modules/auth/actions/validate-session.action.mjs +13 -6
- package/dist/modules/auth/actions/validate-session.action.mjs.map +1 -1
- package/dist/modules/auth/hooks/useUserQuery.mjs +6 -4
- package/dist/modules/auth/hooks/useUserQuery.mjs.map +1 -1
- package/dist/providers/auth.provider.mjs +2 -2
- package/dist/providers/auth.provider.mjs.map +1 -1
- package/package.json +1 -1
- package/src/modules/auth/actions/validate-session.action.ts +19 -6
- package/src/modules/auth/hooks/useUserQuery.ts +16 -4
- package/src/providers/auth.provider.tsx +7 -2
|
@@ -3,7 +3,7 @@ import { redirect } from "next/navigation";
|
|
|
3
3
|
import { cookies, headers } from "next/headers";
|
|
4
4
|
import { authService } from "../services/auth.service";
|
|
5
5
|
import { getClientInfoFromRequest } from "../../../infra/utils/client-info";
|
|
6
|
-
async function redirectToLogin() {
|
|
6
|
+
async function redirectToLogin(publicRoutes = []) {
|
|
7
7
|
const h = await headers();
|
|
8
8
|
const referer = h.get("referer");
|
|
9
9
|
if (!referer) {
|
|
@@ -11,19 +11,26 @@ async function redirectToLogin() {
|
|
|
11
11
|
return;
|
|
12
12
|
}
|
|
13
13
|
const url = new URL(referer);
|
|
14
|
-
|
|
14
|
+
const isPublic = publicRoutes.some((pattern) => {
|
|
15
|
+
try {
|
|
16
|
+
return new RegExp(pattern).test(url.pathname);
|
|
17
|
+
} catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
if (["/login", "/register", "/forgot-password"].includes(url.pathname) || isPublic) {
|
|
15
22
|
return;
|
|
16
23
|
}
|
|
17
24
|
const loginUrl = new URL("/login", url.origin);
|
|
18
25
|
loginUrl.searchParams.set("redirect", url.pathname + url.search);
|
|
19
26
|
redirect(loginUrl.toString());
|
|
20
27
|
}
|
|
21
|
-
async function validateSessionAction() {
|
|
28
|
+
async function validateSessionAction(publicRoutes = []) {
|
|
22
29
|
if (process.env.DUMMY_AUTH_TOKEN) return true;
|
|
23
30
|
const cookieStore = await cookies();
|
|
24
31
|
const cookie = cookieStore.get("greatapps")?.value;
|
|
25
32
|
if (!cookie) {
|
|
26
|
-
await redirectToLogin();
|
|
33
|
+
await redirectToLogin(publicRoutes);
|
|
27
34
|
return false;
|
|
28
35
|
}
|
|
29
36
|
try {
|
|
@@ -31,14 +38,14 @@ async function validateSessionAction() {
|
|
|
31
38
|
const isValid = await authService.validateSession(clientInfo);
|
|
32
39
|
if (!isValid) {
|
|
33
40
|
await authService.removeAuthCookie();
|
|
34
|
-
await redirectToLogin();
|
|
41
|
+
await redirectToLogin(publicRoutes);
|
|
35
42
|
return false;
|
|
36
43
|
}
|
|
37
44
|
return true;
|
|
38
45
|
} catch (error) {
|
|
39
46
|
console.error("[validateSessionAction] Error:", error);
|
|
40
47
|
await authService.removeAuthCookie();
|
|
41
|
-
await redirectToLogin();
|
|
48
|
+
await redirectToLogin(publicRoutes);
|
|
42
49
|
return false;
|
|
43
50
|
}
|
|
44
51
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/modules/auth/actions/validate-session.action.ts"],"sourcesContent":["'use server';\n\nimport { redirect } from 'next/navigation';\nimport { cookies, headers } from 'next/headers';\nimport { authService } from '../services/auth.service';\nimport { getClientInfoFromRequest } from '../../../infra/utils/client-info';\n\nasync function redirectToLogin() {\n const h = await headers();\n const referer = h.get('referer');\n\n if (!referer) {\n redirect('/login');\n return;\n }\n\n const url = new URL(referer);\n\n if (['/login', '/register', '/forgot-password'].includes(url.pathname)) {\n return;\n }\n\n const loginUrl = new URL('/login', url.origin);\n loginUrl.searchParams.set('redirect', url.pathname + url.search);\n redirect(loginUrl.toString());\n}\n\nexport async function validateSessionAction(): Promise<boolean> {\n if (process.env.DUMMY_AUTH_TOKEN) return true;\n\n const cookieStore = await cookies();\n const cookie = cookieStore.get('greatapps')?.value;\n\n if (!cookie) {\n await redirectToLogin();\n return false;\n }\n\n try {\n const clientInfo = await getClientInfoFromRequest();\n const isValid = await authService.validateSession(clientInfo);\n\n if (!isValid) {\n await authService.removeAuthCookie();\n await redirectToLogin();\n return false;\n }\n\n return true;\n } catch (error) {\n console.error('[validateSessionAction] Error:', error);\n await authService.removeAuthCookie();\n await redirectToLogin();\n return false;\n }\n}\n"],"mappings":";AAEA,SAAS,gBAAgB;AACzB,SAAS,SAAS,eAAe;AACjC,SAAS,mBAAmB;AAC5B,SAAS,gCAAgC;
|
|
1
|
+
{"version":3,"sources":["../../../../src/modules/auth/actions/validate-session.action.ts"],"sourcesContent":["'use server';\n\nimport { redirect } from 'next/navigation';\nimport { cookies, headers } from 'next/headers';\nimport { authService } from '../services/auth.service';\nimport { getClientInfoFromRequest } from '../../../infra/utils/client-info';\n\n/**\n * `publicRoutes` é informado pelo CONSUMER app (ex.: via prop do AuthProvider) — a lib\n * não conhece rotas específicas de cada app. Cada item é um source de RegExp testado\n * contra o pathname do referer.\n */\nasync function redirectToLogin(publicRoutes: string[] = []) {\n const h = await headers();\n const referer = h.get('referer');\n\n if (!referer) {\n redirect('/login');\n return;\n }\n\n const url = new URL(referer);\n\n const isPublic = publicRoutes.some((pattern) => {\n try {\n return new RegExp(pattern).test(url.pathname);\n } catch {\n return false;\n }\n });\n\n if (['/login', '/register', '/forgot-password'].includes(url.pathname) || isPublic) {\n return;\n }\n\n const loginUrl = new URL('/login', url.origin);\n loginUrl.searchParams.set('redirect', url.pathname + url.search);\n redirect(loginUrl.toString());\n}\n\nexport async function validateSessionAction(publicRoutes: string[] = []): Promise<boolean> {\n if (process.env.DUMMY_AUTH_TOKEN) return true;\n\n const cookieStore = await cookies();\n const cookie = cookieStore.get('greatapps')?.value;\n\n if (!cookie) {\n await redirectToLogin(publicRoutes);\n return false;\n }\n\n try {\n const clientInfo = await getClientInfoFromRequest();\n const isValid = await authService.validateSession(clientInfo);\n\n if (!isValid) {\n await authService.removeAuthCookie();\n await redirectToLogin(publicRoutes);\n return false;\n }\n\n return true;\n } catch (error) {\n console.error('[validateSessionAction] Error:', error);\n await authService.removeAuthCookie();\n await redirectToLogin(publicRoutes);\n return false;\n }\n}\n"],"mappings":";AAEA,SAAS,gBAAgB;AACzB,SAAS,SAAS,eAAe;AACjC,SAAS,mBAAmB;AAC5B,SAAS,gCAAgC;AAOzC,eAAe,gBAAgB,eAAyB,CAAC,GAAG;AAC1D,QAAM,IAAI,MAAM,QAAQ;AACxB,QAAM,UAAU,EAAE,IAAI,SAAS;AAE/B,MAAI,CAAC,SAAS;AACZ,aAAS,QAAQ;AACjB;AAAA,EACF;AAEA,QAAM,MAAM,IAAI,IAAI,OAAO;AAE3B,QAAM,WAAW,aAAa,KAAK,CAAC,YAAY;AAC9C,QAAI;AACF,aAAO,IAAI,OAAO,OAAO,EAAE,KAAK,IAAI,QAAQ;AAAA,IAC9C,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF,CAAC;AAED,MAAI,CAAC,UAAU,aAAa,kBAAkB,EAAE,SAAS,IAAI,QAAQ,KAAK,UAAU;AAClF;AAAA,EACF;AAEA,QAAM,WAAW,IAAI,IAAI,UAAU,IAAI,MAAM;AAC7C,WAAS,aAAa,IAAI,YAAY,IAAI,WAAW,IAAI,MAAM;AAC/D,WAAS,SAAS,SAAS,CAAC;AAC9B;AAEA,eAAsB,sBAAsB,eAAyB,CAAC,GAAqB;AACzF,MAAI,QAAQ,IAAI,iBAAkB,QAAO;AAEzC,QAAM,cAAc,MAAM,QAAQ;AAClC,QAAM,SAAS,YAAY,IAAI,WAAW,GAAG;AAE7C,MAAI,CAAC,QAAQ;AACX,UAAM,gBAAgB,YAAY;AAClC,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,aAAa,MAAM,yBAAyB;AAClD,UAAM,UAAU,MAAM,YAAY,gBAAgB,UAAU;AAE5D,QAAI,CAAC,SAAS;AACZ,YAAM,YAAY,iBAAiB;AACnC,YAAM,gBAAgB,YAAY;AAClC,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT,SAAS,OAAO;AACd,YAAQ,MAAM,kCAAkC,KAAK;AACrD,UAAM,YAAY,iBAAiB;AACnC,UAAM,gBAAgB,YAAY;AAClC,WAAO;AAAA,EACT;AACF;","names":[]}
|
|
@@ -9,9 +9,9 @@ async function fetchUser() {
|
|
|
9
9
|
const result = await getUserDataAction();
|
|
10
10
|
return result.success && result.data ? result.data : null;
|
|
11
11
|
}
|
|
12
|
-
async function validateUserSession() {
|
|
12
|
+
async function validateUserSession(publicRoutes = []) {
|
|
13
13
|
const { validateSessionAction } = await import("../actions/validate-session.action");
|
|
14
|
-
return await validateSessionAction();
|
|
14
|
+
return await validateSessionAction(publicRoutes);
|
|
15
15
|
}
|
|
16
16
|
function useUserQuery() {
|
|
17
17
|
const queryKey = useWlQueryKey([...USER_QUERY_KEY]);
|
|
@@ -23,11 +23,13 @@ function useUserQuery() {
|
|
|
23
23
|
retry: false
|
|
24
24
|
});
|
|
25
25
|
}
|
|
26
|
-
function useUserValidateSession(
|
|
26
|
+
function useUserValidateSession(publicRoutesOrOptions = [], maybeOptions) {
|
|
27
|
+
const publicRoutes = Array.isArray(publicRoutesOrOptions) ? publicRoutesOrOptions : [];
|
|
28
|
+
const options = Array.isArray(publicRoutesOrOptions) ? maybeOptions : publicRoutesOrOptions;
|
|
27
29
|
const queryKey = useWlQueryKey([...USER_VALIDATE_SESSION_KEY]);
|
|
28
30
|
return useQuery({
|
|
29
31
|
queryKey,
|
|
30
|
-
queryFn: validateUserSession,
|
|
32
|
+
queryFn: () => validateUserSession(publicRoutes),
|
|
31
33
|
retry: false,
|
|
32
34
|
staleTime: 5 * 60 * 1e3,
|
|
33
35
|
...options,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/modules/auth/hooks/useUserQuery.ts"],"sourcesContent":["'use client';\n\nimport { useMutation, useQuery, useQueryClient, UseQueryOptions } from '@tanstack/react-query';\nimport { User } from '../../users/schema';\nimport { withAction } from '../../../utils/withAction';\nimport { useWlQueryKey } from '../../../hooks/useAuthQueryKey';\n\nexport const USER_QUERY_KEY = ['user'] as const;\nexport const USER_VALIDATE_SESSION_KEY = ['user-validate-session'] as const;\n\nasync function fetchUser(): Promise<User | null> {\n const { findUserById: getUserDataAction } = await import('../../users/action/find-user-by-id.action');\n const result = await getUserDataAction();\n return result.success && result.data ? result.data : null;\n}\n\nasync function validateUserSession(): Promise<boolean> {\n const { validateSessionAction } = await import('../actions/validate-session.action');\n return await validateSessionAction();\n}\n\nexport function useUserQuery() {\n const queryKey = useWlQueryKey([...USER_QUERY_KEY]);\n\n return useQuery({\n queryKey,\n queryFn: fetchUser,\n staleTime: 60 * 1000,\n gcTime: 10 * 60 * 1000,\n retry: false,\n });\n}\n\nexport function useUserValidateSession(options?: UseQueryOptions) {\n const queryKey = useWlQueryKey([...USER_VALIDATE_SESSION_KEY]);\n\n return useQuery({\n queryKey,\n queryFn: validateUserSession,\n retry: false,\n staleTime: 5 * 60 * 1000,\n ...options,\n refetchOnMount: 'always',\n refetchOnWindowFocus: true,\n });\n}\n\nexport function useTwoFactorVerify() {\n const queryClient = useQueryClient();\n const userKey = useWlQueryKey([...USER_QUERY_KEY]);\n const twoFactorKey = useWlQueryKey(['two-factor-pending']);\n\n return useMutation({\n mutationFn: async ({\n cookie,\n code,\n window,\n setCookie,\n }: {\n cookie: string;\n code: string;\n window?: number;\n /**\n * Quando `false`, o verify não grava o cookie de sessão e devolve o\n * `accessToken` no resultado. Usado em fluxos como SSO em que o token\n * vai pra outro destino (callback de app) e não pode derrubar a\n * sessão atual do Great no navegador.\n */\n setCookie?: boolean;\n }) => {\n const { verifyTwoFactorAction } = await import('../actions/verify-two-factor.action');\n return withAction(() => verifyTwoFactorAction(cookie, code, { window, setCookie }))();\n },\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: userKey });\n queryClient.invalidateQueries({ queryKey: twoFactorKey });\n },\n });\n}\n\nexport function useInvalidateUser() {\n const queryClient = useQueryClient();\n const userKey = useWlQueryKey([...USER_QUERY_KEY]);\n return () => queryClient.invalidateQueries({ queryKey: userKey });\n}\n\nexport function useSetUserData() {\n const queryClient = useQueryClient();\n const userKey = useWlQueryKey([...USER_QUERY_KEY]);\n return (user: User | null) => queryClient.setQueryData(userKey, user);\n}\n"],"mappings":";AAEA,SAAS,aAAa,UAAU,sBAAuC;AAEvE,SAAS,kBAAkB;AAC3B,SAAS,qBAAqB;AAEvB,MAAM,iBAAiB,CAAC,MAAM;AAC9B,MAAM,4BAA4B,CAAC,uBAAuB;AAEjE,eAAe,YAAkC;AAC/C,QAAM,EAAE,cAAc,kBAAkB,IAAI,MAAM,OAAO,2CAA2C;AACpG,QAAM,SAAS,MAAM,kBAAkB;AACvC,SAAO,OAAO,WAAW,OAAO,OAAO,OAAO,OAAO;AACvD;AAEA,eAAe,
|
|
1
|
+
{"version":3,"sources":["../../../../src/modules/auth/hooks/useUserQuery.ts"],"sourcesContent":["'use client';\n\nimport { useMutation, useQuery, useQueryClient, UseQueryOptions } from '@tanstack/react-query';\nimport { User } from '../../users/schema';\nimport { withAction } from '../../../utils/withAction';\nimport { useWlQueryKey } from '../../../hooks/useAuthQueryKey';\n\nexport const USER_QUERY_KEY = ['user'] as const;\nexport const USER_VALIDATE_SESSION_KEY = ['user-validate-session'] as const;\n\nasync function fetchUser(): Promise<User | null> {\n const { findUserById: getUserDataAction } = await import('../../users/action/find-user-by-id.action');\n const result = await getUserDataAction();\n return result.success && result.data ? result.data : null;\n}\n\nasync function validateUserSession(publicRoutes: string[] = []): Promise<boolean> {\n const { validateSessionAction } = await import('../actions/validate-session.action');\n return await validateSessionAction(publicRoutes);\n}\n\nexport function useUserQuery() {\n const queryKey = useWlQueryKey([...USER_QUERY_KEY]);\n\n return useQuery({\n queryKey,\n queryFn: fetchUser,\n staleTime: 60 * 1000,\n gcTime: 10 * 60 * 1000,\n retry: false,\n });\n}\n\n// Overloads preservam o contrato antigo `useUserValidateSession(options?)` enquanto\n// adicionam a forma nova `useUserValidateSession(publicRoutes, options?)`.\nexport function useUserValidateSession(options?: UseQueryOptions): ReturnType<typeof useQuery>;\nexport function useUserValidateSession(\n publicRoutes: string[],\n options?: UseQueryOptions,\n): ReturnType<typeof useQuery>;\nexport function useUserValidateSession(\n publicRoutesOrOptions: string[] | UseQueryOptions = [],\n maybeOptions?: UseQueryOptions,\n) {\n const publicRoutes = Array.isArray(publicRoutesOrOptions) ? publicRoutesOrOptions : [];\n const options = Array.isArray(publicRoutesOrOptions) ? maybeOptions : publicRoutesOrOptions;\n const queryKey = useWlQueryKey([...USER_VALIDATE_SESSION_KEY]);\n\n return useQuery({\n queryKey,\n queryFn: () => validateUserSession(publicRoutes),\n retry: false,\n staleTime: 5 * 60 * 1000,\n ...options,\n refetchOnMount: 'always',\n refetchOnWindowFocus: true,\n });\n}\n\nexport function useTwoFactorVerify() {\n const queryClient = useQueryClient();\n const userKey = useWlQueryKey([...USER_QUERY_KEY]);\n const twoFactorKey = useWlQueryKey(['two-factor-pending']);\n\n return useMutation({\n mutationFn: async ({\n cookie,\n code,\n window,\n setCookie,\n }: {\n cookie: string;\n code: string;\n window?: number;\n /**\n * Quando `false`, o verify não grava o cookie de sessão e devolve o\n * `accessToken` no resultado. Usado em fluxos como SSO em que o token\n * vai pra outro destino (callback de app) e não pode derrubar a\n * sessão atual do Great no navegador.\n */\n setCookie?: boolean;\n }) => {\n const { verifyTwoFactorAction } = await import('../actions/verify-two-factor.action');\n return withAction(() => verifyTwoFactorAction(cookie, code, { window, setCookie }))();\n },\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: userKey });\n queryClient.invalidateQueries({ queryKey: twoFactorKey });\n },\n });\n}\n\nexport function useInvalidateUser() {\n const queryClient = useQueryClient();\n const userKey = useWlQueryKey([...USER_QUERY_KEY]);\n return () => queryClient.invalidateQueries({ queryKey: userKey });\n}\n\nexport function useSetUserData() {\n const queryClient = useQueryClient();\n const userKey = useWlQueryKey([...USER_QUERY_KEY]);\n return (user: User | null) => queryClient.setQueryData(userKey, user);\n}\n"],"mappings":";AAEA,SAAS,aAAa,UAAU,sBAAuC;AAEvE,SAAS,kBAAkB;AAC3B,SAAS,qBAAqB;AAEvB,MAAM,iBAAiB,CAAC,MAAM;AAC9B,MAAM,4BAA4B,CAAC,uBAAuB;AAEjE,eAAe,YAAkC;AAC/C,QAAM,EAAE,cAAc,kBAAkB,IAAI,MAAM,OAAO,2CAA2C;AACpG,QAAM,SAAS,MAAM,kBAAkB;AACvC,SAAO,OAAO,WAAW,OAAO,OAAO,OAAO,OAAO;AACvD;AAEA,eAAe,oBAAoB,eAAyB,CAAC,GAAqB;AAChF,QAAM,EAAE,sBAAsB,IAAI,MAAM,OAAO,oCAAoC;AACnF,SAAO,MAAM,sBAAsB,YAAY;AACjD;AAEO,SAAS,eAAe;AAC7B,QAAM,WAAW,cAAc,CAAC,GAAG,cAAc,CAAC;AAElD,SAAO,SAAS;AAAA,IACd;AAAA,IACA,SAAS;AAAA,IACT,WAAW,KAAK;AAAA,IAChB,QAAQ,KAAK,KAAK;AAAA,IAClB,OAAO;AAAA,EACT,CAAC;AACH;AASO,SAAS,uBACd,wBAAoD,CAAC,GACrD,cACA;AACA,QAAM,eAAe,MAAM,QAAQ,qBAAqB,IAAI,wBAAwB,CAAC;AACrF,QAAM,UAAU,MAAM,QAAQ,qBAAqB,IAAI,eAAe;AACtE,QAAM,WAAW,cAAc,CAAC,GAAG,yBAAyB,CAAC;AAE7D,SAAO,SAAS;AAAA,IACd;AAAA,IACA,SAAS,MAAM,oBAAoB,YAAY;AAAA,IAC/C,OAAO;AAAA,IACP,WAAW,IAAI,KAAK;AAAA,IACpB,GAAG;AAAA,IACH,gBAAgB;AAAA,IAChB,sBAAsB;AAAA,EACxB,CAAC;AACH;AAEO,SAAS,qBAAqB;AACnC,QAAM,cAAc,eAAe;AACnC,QAAM,UAAU,cAAc,CAAC,GAAG,cAAc,CAAC;AACjD,QAAM,eAAe,cAAc,CAAC,oBAAoB,CAAC;AAEzD,SAAO,YAAY;AAAA,IACjB,YAAY,OAAO;AAAA,MACjB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,MAWM;AACJ,YAAM,EAAE,sBAAsB,IAAI,MAAM,OAAO,qCAAqC;AACpF,aAAO,WAAW,MAAM,sBAAsB,QAAQ,MAAM,EAAE,QAAQ,UAAU,CAAC,CAAC,EAAE;AAAA,IACtF;AAAA,IACA,WAAW,MAAM;AACf,kBAAY,kBAAkB,EAAE,UAAU,QAAQ,CAAC;AACnD,kBAAY,kBAAkB,EAAE,UAAU,aAAa,CAAC;AAAA,IAC1D;AAAA,EACF,CAAC;AACH;AAEO,SAAS,oBAAoB;AAClC,QAAM,cAAc,eAAe;AACnC,QAAM,UAAU,cAAc,CAAC,GAAG,cAAc,CAAC;AACjD,SAAO,MAAM,YAAY,kBAAkB,EAAE,UAAU,QAAQ,CAAC;AAClE;AAEO,SAAS,iBAAiB;AAC/B,QAAM,cAAc,eAAe;AACnC,QAAM,UAAU,cAAc,CAAC,GAAG,cAAc,CAAC;AACjD,SAAO,CAAC,SAAsB,YAAY,aAAa,SAAS,IAAI;AACtE;","names":[]}
|
|
@@ -29,10 +29,10 @@ import { setLocaleCookie } from "../utils/intl/locale-cookie";
|
|
|
29
29
|
const AuthContext = createContext(
|
|
30
30
|
void 0
|
|
31
31
|
);
|
|
32
|
-
function AuthProvider({ children }) {
|
|
32
|
+
function AuthProvider({ children, publicRoutes = [] }) {
|
|
33
33
|
const { data: user, isLoading: isQueryLoading } = useUserQuery();
|
|
34
34
|
const { data: account, isLoading: isAccountLoading } = useCurrentAccount();
|
|
35
|
-
const { isLoading: isSessionLoading } = useUserValidateSession();
|
|
35
|
+
const { isLoading: isSessionLoading } = useUserValidateSession(publicRoutes);
|
|
36
36
|
const queryClient = useQueryClient();
|
|
37
37
|
const setUserData = useSetUserData();
|
|
38
38
|
const { accountsUrl, pagesUrl } = useWhitelabelUrls();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/providers/auth.provider.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n createContext,\n ReactNode,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n} from \"react\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport {\n useUserQuery,\n useSetUserData,\n useUserValidateSession,\n} from \"../modules/auth/hooks/useUserQuery\";\nimport { useLogin } from \"../modules/auth/hooks/login.hook\";\nimport { useRegister } from \"../modules/auth/hooks/register.hook\";\nimport { useLogout } from \"../modules/auth/hooks/logout.hook\";\nimport { useSocialGoogleLogin } from \"../modules/auth/hooks/social-google-login.hook\";\nimport { useSocialGoogleOnboarding } from \"../modules/auth/hooks/social-google-onboarding.hook\";\nimport {\n AuthState,\n LoginRequest,\n RegisterRequest,\n SocialGooglePartial,\n SocialOnboardingRequest,\n} from \"../modules/auth/schema\";\n\nexport type LoginResult =\n | { result: \"success\" }\n | { result: \"two_factor_required\"; cookie: string; twoFactorMode: \"verify\" | \"setup\" }\n | { result: \"error\"; message: string };\n\nexport type GoogleLoginResult =\n | { result: \"success\" }\n | { result: \"two_factor_required\"; cookie: string; twoFactorMode: \"verify\" | \"setup\" }\n | { result: \"needs_onboarding\"; onboardingToken: string; partial: SocialGooglePartial }\n | { result: \"link_requires_password\"; message: string }\n | { result: \"error\"; message: string };\nimport {\n useCurrentAccount,\n ACCOUNT_QUERY_KEY,\n} from \"../modules/accounts/hooks/current-account.hook\";\nimport { useWhitelabelUrls, useWhitelabel } from \"./whitelabel.provider\";\nimport { useWlQueryKey } from \"../hooks/useAuthQueryKey\";\nimport { normalizeLocale } from \"../i18n/normalize\";\nimport { setLocaleCookie } from \"../utils/intl/locale-cookie\";\n\ninterface AuthContextProps extends AuthState {\n login: (credentials: LoginRequest) => Promise<LoginResult>;\n register: (data: RegisterRequest) => Promise<void>;\n logout: () => Promise<void>;\n loginWithGoogle: (code: string) => Promise<GoogleLoginResult>;\n completeGoogleOnboarding: (data: SocialOnboardingRequest) => Promise<void>;\n}\n\nexport const AuthContext = createContext<AuthContextProps | undefined>(\n undefined,\n);\n\ninterface AuthProviderProps {\n children: ReactNode;\n}\n\nexport function AuthProvider({ children }: AuthProviderProps) {\n const { data: user, isLoading: isQueryLoading } = useUserQuery();\n const { data: account, isLoading: isAccountLoading } = useCurrentAccount();\n const { isLoading: isSessionLoading } = useUserValidateSession();\n\n const queryClient = useQueryClient();\n const setUserData = useSetUserData();\n const { accountsUrl, pagesUrl } = useWhitelabelUrls();\n const { whitelabel } = useWhitelabel();\n const accountKey = useWlQueryKey([...ACCOUNT_QUERY_KEY]);\n\n // Mantém o cookie NEXT_LOCALE alinhado à preferência da conta (login, sessão existente,\n // atualização). Compartilhado entre subdomínios via domínio do whitelabel. A próxima\n // navegação/requisição passa a resolver o locale pela preferência do usuário.\n useEffect(() => {\n const locale = normalizeLocale(user?.language);\n if (locale) setLocaleCookie(locale, whitelabel?.domain);\n }, [user?.language, whitelabel?.domain]);\n\n const { mutateAsync: loginMutate, isPending: isLogging } = useLogin();\n const { mutateAsync: registerMutate, isPending: isRegistering } =\n useRegister();\n const { mutateAsync: logoutMutate, isPending: isLoggingOut } = useLogout();\n const { mutateAsync: googleLoginMutate, isPending: isGoogleLogging } =\n useSocialGoogleLogin();\n const { mutateAsync: googleOnboardingMutate, isPending: isGoogleOnboarding } =\n useSocialGoogleOnboarding();\n\n const isAuthenticated = !!user;\n const isLoading =\n isLogging ||\n isRegistering ||\n isLoggingOut ||\n isGoogleLogging ||\n isGoogleOnboarding ||\n isQueryLoading ||\n isAccountLoading ||\n isSessionLoading;\n\n const login = useCallback(\n async (credentials: LoginRequest): Promise<LoginResult> => {\n try {\n const data = await loginMutate(credentials);\n\n if (data.result === \"two_factor_required\") {\n return { result: \"two_factor_required\", cookie: data.cookie, twoFactorMode: data.twoFactorMode };\n }\n\n queryClient.clear();\n setUserData(data.user);\n queryClient.setQueryData(accountKey, data.account);\n\n return { result: \"success\" };\n } catch (error) {\n const message =\n error instanceof Error\n ? error.message\n : \"Ocorreu um erro ao fazer login. Tente novamente.\";\n return { result: \"error\", message };\n }\n },\n [queryClient, setUserData, accountKey],\n );\n\n const register = useCallback(\n async (data: RegisterRequest): Promise<void> => {\n await registerMutate(data, {\n onSuccess: (data) => {\n queryClient.clear();\n setUserData(data.user);\n queryClient.setQueryData(accountKey, data.account);\n },\n });\n },\n [queryClient, setUserData, accountKey],\n );\n\n const loginWithGoogle = useCallback(\n async (code: string): Promise<GoogleLoginResult> => {\n try {\n const data = await googleLoginMutate(code);\n\n if (data.result === \"two_factor_required\") {\n return {\n result: \"two_factor_required\",\n cookie: data.cookie,\n twoFactorMode: data.twoFactorMode,\n };\n }\n\n if (data.result === \"needs_onboarding\") {\n return {\n result: \"needs_onboarding\",\n onboardingToken: data.onboardingToken,\n partial: data.partial,\n };\n }\n\n if (data.result === \"link_requires_password\") {\n return { result: \"link_requires_password\", message: data.message };\n }\n\n queryClient.clear();\n setUserData(data.user);\n queryClient.setQueryData(accountKey, data.account);\n\n return { result: \"success\" };\n } catch (error) {\n const message =\n error instanceof Error\n ? error.message\n : \"Ocorreu um erro ao fazer login com Google. Tente novamente.\";\n return { result: \"error\", message };\n }\n },\n [googleLoginMutate, queryClient, setUserData, accountKey],\n );\n\n const completeGoogleOnboarding = useCallback(\n async (data: SocialOnboardingRequest): Promise<void> => {\n await googleOnboardingMutate(data, {\n onSuccess: (data) => {\n queryClient.clear();\n setUserData(data.user);\n queryClient.setQueryData(accountKey, data.account);\n },\n });\n },\n [googleOnboardingMutate, queryClient, setUserData, accountKey],\n );\n\n const resolveLogoutRedirect = useCallback(() => {\n try {\n const currentOrigin = window.location.origin;\n const pagesOrigin = pagesUrl ? new URL(pagesUrl).origin : \"\";\n\n if (pagesOrigin && currentOrigin === pagesOrigin) {\n return `${accountsUrl}/login?redirect=${encodeURIComponent(pagesUrl)}`;\n }\n } catch {\n // fallback below\n }\n\n return `${accountsUrl}/login?redirect=${encodeURIComponent(pagesUrl || \"/\")}`;\n }, [accountsUrl, pagesUrl]);\n\n const logout = useCallback(async (): Promise<void> => {\n try {\n await logoutMutate(undefined);\n } catch {\n // cookie já removido no servidor mesmo se a API falhou\n } finally {\n queryClient.clear();\n window.location.assign(resolveLogoutRedirect());\n }\n }, [queryClient, logoutMutate, resolveLogoutRedirect]);\n\n const value: AuthContextProps = useMemo(\n () => ({\n user: user ?? null,\n account: account ?? null,\n isAuthenticated,\n isLoading,\n login,\n register,\n logout,\n loginWithGoogle,\n completeGoogleOnboarding,\n }),\n [\n user,\n account,\n isAuthenticated,\n isLoading,\n login,\n register,\n logout,\n loginWithGoogle,\n completeGoogleOnboarding,\n ],\n );\n\n return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;\n}\n\nexport function useAuth(): AuthContextProps {\n const context = useContext(AuthContext);\n\n if (context === undefined) {\n throw new Error(\"useAuth deve ser usado dentro de um AuthProvider\");\n }\n\n return context;\n}\n"],"mappings":"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","names":["data"]}
|
|
1
|
+
{"version":3,"sources":["../../src/providers/auth.provider.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n createContext,\n ReactNode,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n} from \"react\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport {\n useUserQuery,\n useSetUserData,\n useUserValidateSession,\n} from \"../modules/auth/hooks/useUserQuery\";\nimport { useLogin } from \"../modules/auth/hooks/login.hook\";\nimport { useRegister } from \"../modules/auth/hooks/register.hook\";\nimport { useLogout } from \"../modules/auth/hooks/logout.hook\";\nimport { useSocialGoogleLogin } from \"../modules/auth/hooks/social-google-login.hook\";\nimport { useSocialGoogleOnboarding } from \"../modules/auth/hooks/social-google-onboarding.hook\";\nimport {\n AuthState,\n LoginRequest,\n RegisterRequest,\n SocialGooglePartial,\n SocialOnboardingRequest,\n} from \"../modules/auth/schema\";\n\nexport type LoginResult =\n | { result: \"success\" }\n | { result: \"two_factor_required\"; cookie: string; twoFactorMode: \"verify\" | \"setup\" }\n | { result: \"error\"; message: string };\n\nexport type GoogleLoginResult =\n | { result: \"success\" }\n | { result: \"two_factor_required\"; cookie: string; twoFactorMode: \"verify\" | \"setup\" }\n | { result: \"needs_onboarding\"; onboardingToken: string; partial: SocialGooglePartial }\n | { result: \"link_requires_password\"; message: string }\n | { result: \"error\"; message: string };\nimport {\n useCurrentAccount,\n ACCOUNT_QUERY_KEY,\n} from \"../modules/accounts/hooks/current-account.hook\";\nimport { useWhitelabelUrls, useWhitelabel } from \"./whitelabel.provider\";\nimport { useWlQueryKey } from \"../hooks/useAuthQueryKey\";\nimport { normalizeLocale } from \"../i18n/normalize\";\nimport { setLocaleCookie } from \"../utils/intl/locale-cookie\";\n\ninterface AuthContextProps extends AuthState {\n login: (credentials: LoginRequest) => Promise<LoginResult>;\n register: (data: RegisterRequest) => Promise<void>;\n logout: () => Promise<void>;\n loginWithGoogle: (code: string) => Promise<GoogleLoginResult>;\n completeGoogleOnboarding: (data: SocialOnboardingRequest) => Promise<void>;\n}\n\nexport const AuthContext = createContext<AuthContextProps | undefined>(\n undefined,\n);\n\ninterface AuthProviderProps {\n children: ReactNode;\n /**\n * Rotas públicas (sources de RegExp) que NÃO devem redirecionar para o login mesmo\n * sem sessão. Informadas pelo consumer app — a lib não conhece rotas específicas.\n */\n publicRoutes?: string[];\n}\n\nexport function AuthProvider({ children, publicRoutes = [] }: AuthProviderProps) {\n const { data: user, isLoading: isQueryLoading } = useUserQuery();\n const { data: account, isLoading: isAccountLoading } = useCurrentAccount();\n const { isLoading: isSessionLoading } = useUserValidateSession(publicRoutes);\n\n const queryClient = useQueryClient();\n const setUserData = useSetUserData();\n const { accountsUrl, pagesUrl } = useWhitelabelUrls();\n const { whitelabel } = useWhitelabel();\n const accountKey = useWlQueryKey([...ACCOUNT_QUERY_KEY]);\n\n // Mantém o cookie NEXT_LOCALE alinhado à preferência da conta (login, sessão existente,\n // atualização). Compartilhado entre subdomínios via domínio do whitelabel. A próxima\n // navegação/requisição passa a resolver o locale pela preferência do usuário.\n useEffect(() => {\n const locale = normalizeLocale(user?.language);\n if (locale) setLocaleCookie(locale, whitelabel?.domain);\n }, [user?.language, whitelabel?.domain]);\n\n const { mutateAsync: loginMutate, isPending: isLogging } = useLogin();\n const { mutateAsync: registerMutate, isPending: isRegistering } =\n useRegister();\n const { mutateAsync: logoutMutate, isPending: isLoggingOut } = useLogout();\n const { mutateAsync: googleLoginMutate, isPending: isGoogleLogging } =\n useSocialGoogleLogin();\n const { mutateAsync: googleOnboardingMutate, isPending: isGoogleOnboarding } =\n useSocialGoogleOnboarding();\n\n const isAuthenticated = !!user;\n const isLoading =\n isLogging ||\n isRegistering ||\n isLoggingOut ||\n isGoogleLogging ||\n isGoogleOnboarding ||\n isQueryLoading ||\n isAccountLoading ||\n isSessionLoading;\n\n const login = useCallback(\n async (credentials: LoginRequest): Promise<LoginResult> => {\n try {\n const data = await loginMutate(credentials);\n\n if (data.result === \"two_factor_required\") {\n return { result: \"two_factor_required\", cookie: data.cookie, twoFactorMode: data.twoFactorMode };\n }\n\n queryClient.clear();\n setUserData(data.user);\n queryClient.setQueryData(accountKey, data.account);\n\n return { result: \"success\" };\n } catch (error) {\n const message =\n error instanceof Error\n ? error.message\n : \"Ocorreu um erro ao fazer login. Tente novamente.\";\n return { result: \"error\", message };\n }\n },\n [queryClient, setUserData, accountKey],\n );\n\n const register = useCallback(\n async (data: RegisterRequest): Promise<void> => {\n await registerMutate(data, {\n onSuccess: (data) => {\n queryClient.clear();\n setUserData(data.user);\n queryClient.setQueryData(accountKey, data.account);\n },\n });\n },\n [queryClient, setUserData, accountKey],\n );\n\n const loginWithGoogle = useCallback(\n async (code: string): Promise<GoogleLoginResult> => {\n try {\n const data = await googleLoginMutate(code);\n\n if (data.result === \"two_factor_required\") {\n return {\n result: \"two_factor_required\",\n cookie: data.cookie,\n twoFactorMode: data.twoFactorMode,\n };\n }\n\n if (data.result === \"needs_onboarding\") {\n return {\n result: \"needs_onboarding\",\n onboardingToken: data.onboardingToken,\n partial: data.partial,\n };\n }\n\n if (data.result === \"link_requires_password\") {\n return { result: \"link_requires_password\", message: data.message };\n }\n\n queryClient.clear();\n setUserData(data.user);\n queryClient.setQueryData(accountKey, data.account);\n\n return { result: \"success\" };\n } catch (error) {\n const message =\n error instanceof Error\n ? error.message\n : \"Ocorreu um erro ao fazer login com Google. Tente novamente.\";\n return { result: \"error\", message };\n }\n },\n [googleLoginMutate, queryClient, setUserData, accountKey],\n );\n\n const completeGoogleOnboarding = useCallback(\n async (data: SocialOnboardingRequest): Promise<void> => {\n await googleOnboardingMutate(data, {\n onSuccess: (data) => {\n queryClient.clear();\n setUserData(data.user);\n queryClient.setQueryData(accountKey, data.account);\n },\n });\n },\n [googleOnboardingMutate, queryClient, setUserData, accountKey],\n );\n\n const resolveLogoutRedirect = useCallback(() => {\n try {\n const currentOrigin = window.location.origin;\n const pagesOrigin = pagesUrl ? new URL(pagesUrl).origin : \"\";\n\n if (pagesOrigin && currentOrigin === pagesOrigin) {\n return `${accountsUrl}/login?redirect=${encodeURIComponent(pagesUrl)}`;\n }\n } catch {\n // fallback below\n }\n\n return `${accountsUrl}/login?redirect=${encodeURIComponent(pagesUrl || \"/\")}`;\n }, [accountsUrl, pagesUrl]);\n\n const logout = useCallback(async (): Promise<void> => {\n try {\n await logoutMutate(undefined);\n } catch {\n // cookie já removido no servidor mesmo se a API falhou\n } finally {\n queryClient.clear();\n window.location.assign(resolveLogoutRedirect());\n }\n }, [queryClient, logoutMutate, resolveLogoutRedirect]);\n\n const value: AuthContextProps = useMemo(\n () => ({\n user: user ?? null,\n account: account ?? null,\n isAuthenticated,\n isLoading,\n login,\n register,\n logout,\n loginWithGoogle,\n completeGoogleOnboarding,\n }),\n [\n user,\n account,\n isAuthenticated,\n isLoading,\n login,\n register,\n logout,\n loginWithGoogle,\n completeGoogleOnboarding,\n ],\n );\n\n return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;\n}\n\nexport function useAuth(): AuthContextProps {\n const context = useContext(AuthContext);\n\n if (context === undefined) {\n throw new Error(\"useAuth deve ser usado dentro de um AuthProvider\");\n }\n\n return context;\n}\n"],"mappings":"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","names":["data"]}
|
package/package.json
CHANGED
|
@@ -5,7 +5,12 @@ import { cookies, headers } from 'next/headers';
|
|
|
5
5
|
import { authService } from '../services/auth.service';
|
|
6
6
|
import { getClientInfoFromRequest } from '../../../infra/utils/client-info';
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
/**
|
|
9
|
+
* `publicRoutes` é informado pelo CONSUMER app (ex.: via prop do AuthProvider) — a lib
|
|
10
|
+
* não conhece rotas específicas de cada app. Cada item é um source de RegExp testado
|
|
11
|
+
* contra o pathname do referer.
|
|
12
|
+
*/
|
|
13
|
+
async function redirectToLogin(publicRoutes: string[] = []) {
|
|
9
14
|
const h = await headers();
|
|
10
15
|
const referer = h.get('referer');
|
|
11
16
|
|
|
@@ -16,7 +21,15 @@ async function redirectToLogin() {
|
|
|
16
21
|
|
|
17
22
|
const url = new URL(referer);
|
|
18
23
|
|
|
19
|
-
|
|
24
|
+
const isPublic = publicRoutes.some((pattern) => {
|
|
25
|
+
try {
|
|
26
|
+
return new RegExp(pattern).test(url.pathname);
|
|
27
|
+
} catch {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
if (['/login', '/register', '/forgot-password'].includes(url.pathname) || isPublic) {
|
|
20
33
|
return;
|
|
21
34
|
}
|
|
22
35
|
|
|
@@ -25,14 +38,14 @@ async function redirectToLogin() {
|
|
|
25
38
|
redirect(loginUrl.toString());
|
|
26
39
|
}
|
|
27
40
|
|
|
28
|
-
export async function validateSessionAction(): Promise<boolean> {
|
|
41
|
+
export async function validateSessionAction(publicRoutes: string[] = []): Promise<boolean> {
|
|
29
42
|
if (process.env.DUMMY_AUTH_TOKEN) return true;
|
|
30
43
|
|
|
31
44
|
const cookieStore = await cookies();
|
|
32
45
|
const cookie = cookieStore.get('greatapps')?.value;
|
|
33
46
|
|
|
34
47
|
if (!cookie) {
|
|
35
|
-
await redirectToLogin();
|
|
48
|
+
await redirectToLogin(publicRoutes);
|
|
36
49
|
return false;
|
|
37
50
|
}
|
|
38
51
|
|
|
@@ -42,7 +55,7 @@ export async function validateSessionAction(): Promise<boolean> {
|
|
|
42
55
|
|
|
43
56
|
if (!isValid) {
|
|
44
57
|
await authService.removeAuthCookie();
|
|
45
|
-
await redirectToLogin();
|
|
58
|
+
await redirectToLogin(publicRoutes);
|
|
46
59
|
return false;
|
|
47
60
|
}
|
|
48
61
|
|
|
@@ -50,7 +63,7 @@ export async function validateSessionAction(): Promise<boolean> {
|
|
|
50
63
|
} catch (error) {
|
|
51
64
|
console.error('[validateSessionAction] Error:', error);
|
|
52
65
|
await authService.removeAuthCookie();
|
|
53
|
-
await redirectToLogin();
|
|
66
|
+
await redirectToLogin(publicRoutes);
|
|
54
67
|
return false;
|
|
55
68
|
}
|
|
56
69
|
}
|
|
@@ -14,9 +14,9 @@ async function fetchUser(): Promise<User | null> {
|
|
|
14
14
|
return result.success && result.data ? result.data : null;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
async function validateUserSession(): Promise<boolean> {
|
|
17
|
+
async function validateUserSession(publicRoutes: string[] = []): Promise<boolean> {
|
|
18
18
|
const { validateSessionAction } = await import('../actions/validate-session.action');
|
|
19
|
-
return await validateSessionAction();
|
|
19
|
+
return await validateSessionAction(publicRoutes);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
export function useUserQuery() {
|
|
@@ -31,12 +31,24 @@ export function useUserQuery() {
|
|
|
31
31
|
});
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
// Overloads preservam o contrato antigo `useUserValidateSession(options?)` enquanto
|
|
35
|
+
// adicionam a forma nova `useUserValidateSession(publicRoutes, options?)`.
|
|
36
|
+
export function useUserValidateSession(options?: UseQueryOptions): ReturnType<typeof useQuery>;
|
|
37
|
+
export function useUserValidateSession(
|
|
38
|
+
publicRoutes: string[],
|
|
39
|
+
options?: UseQueryOptions,
|
|
40
|
+
): ReturnType<typeof useQuery>;
|
|
41
|
+
export function useUserValidateSession(
|
|
42
|
+
publicRoutesOrOptions: string[] | UseQueryOptions = [],
|
|
43
|
+
maybeOptions?: UseQueryOptions,
|
|
44
|
+
) {
|
|
45
|
+
const publicRoutes = Array.isArray(publicRoutesOrOptions) ? publicRoutesOrOptions : [];
|
|
46
|
+
const options = Array.isArray(publicRoutesOrOptions) ? maybeOptions : publicRoutesOrOptions;
|
|
35
47
|
const queryKey = useWlQueryKey([...USER_VALIDATE_SESSION_KEY]);
|
|
36
48
|
|
|
37
49
|
return useQuery({
|
|
38
50
|
queryKey,
|
|
39
|
-
queryFn: validateUserSession,
|
|
51
|
+
queryFn: () => validateUserSession(publicRoutes),
|
|
40
52
|
retry: false,
|
|
41
53
|
staleTime: 5 * 60 * 1000,
|
|
42
54
|
...options,
|
|
@@ -61,12 +61,17 @@ export const AuthContext = createContext<AuthContextProps | undefined>(
|
|
|
61
61
|
|
|
62
62
|
interface AuthProviderProps {
|
|
63
63
|
children: ReactNode;
|
|
64
|
+
/**
|
|
65
|
+
* Rotas públicas (sources de RegExp) que NÃO devem redirecionar para o login mesmo
|
|
66
|
+
* sem sessão. Informadas pelo consumer app — a lib não conhece rotas específicas.
|
|
67
|
+
*/
|
|
68
|
+
publicRoutes?: string[];
|
|
64
69
|
}
|
|
65
70
|
|
|
66
|
-
export function AuthProvider({ children }: AuthProviderProps) {
|
|
71
|
+
export function AuthProvider({ children, publicRoutes = [] }: AuthProviderProps) {
|
|
67
72
|
const { data: user, isLoading: isQueryLoading } = useUserQuery();
|
|
68
73
|
const { data: account, isLoading: isAccountLoading } = useCurrentAccount();
|
|
69
|
-
const { isLoading: isSessionLoading } = useUserValidateSession();
|
|
74
|
+
const { isLoading: isSessionLoading } = useUserValidateSession(publicRoutes);
|
|
70
75
|
|
|
71
76
|
const queryClient = useQueryClient();
|
|
72
77
|
const setUserData = useSetUserData();
|