@vtex/faststore-plugin-buyer-portal 1.1.116 → 1.2.1
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/package.json +1 -1
- package/src/features/org-units/components/OrgUnitBreadcrumb/OrgUnitBreadcrumbLink.tsx +0 -1
- package/src/features/shared/components/index.ts +0 -1
- package/src/features/shared/components/withErrorBoundary/withErrorBoundary.tsx +7 -7
- package/src/features/shared/hooks/index.ts +0 -1
- package/src/features/shared/types/AuthRouteProps.ts +2 -3
- package/src/features/shared/utils/withAuth.tsx +7 -45
- package/src/features/shared/utils/withAuthLoader.ts +1 -29
- package/src/features/shared/utils/withAuthProvider.tsx +8 -59
- package/src/features/shared/utils/withLoaderErrorBoundary.ts +71 -79
- package/src/themes/index.scss +0 -1
- package/src/features/shared/components/PageLoader/PageLoader.tsx +0 -22
- package/src/features/shared/components/PageLoader/index.ts +0 -1
- package/src/features/shared/components/PageLoader/page-loader.scss +0 -22
- package/src/features/shared/hooks/useCookieMonitor.ts +0 -73
package/package.json
CHANGED
|
@@ -76,4 +76,3 @@ export { ErrorBoundary } from "./ErrorBoundary/ErrorBoundary";
|
|
|
76
76
|
export { withErrorBoundary } from "./withErrorBoundary/withErrorBoundary";
|
|
77
77
|
export { default as Error } from "./Error/Error";
|
|
78
78
|
export { IconBookmarked } from "./IconBookmarked/IconBookmarked";
|
|
79
|
-
export { PageLoader } from "./PageLoader";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import React from "react";
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
import { ErrorBoundary } from "../ErrorBoundary/ErrorBoundary";
|
|
6
6
|
|
|
7
7
|
type WithErrorBoundaryOptions = {
|
|
8
8
|
fallback?: React.ReactNode;
|
|
@@ -15,16 +15,16 @@ type WithErrorBoundaryOptions = {
|
|
|
15
15
|
|
|
16
16
|
export function withErrorBoundary<P extends Record<string, unknown>>(
|
|
17
17
|
WrappedComponent: React.ComponentType<P>,
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
|
|
19
|
+
options: WithErrorBoundaryOptions = {}
|
|
20
20
|
) {
|
|
21
|
-
|
|
21
|
+
const { onError, tags } = options;
|
|
22
22
|
|
|
23
23
|
const ComponentWithErrorBoundary = (props: P) => {
|
|
24
24
|
return (
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
<ErrorBoundary onError={onError} tags={tags}>
|
|
26
|
+
<WrappedComponent {...props} />
|
|
27
|
+
</ErrorBoundary>
|
|
28
28
|
);
|
|
29
29
|
};
|
|
30
30
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { ClientContext } from "../utils";
|
|
2
2
|
|
|
3
3
|
export type AuthRouteProps<T> =
|
|
4
|
-
| { authorized: true; data: T; clientContext: ClientContext
|
|
5
|
-
| { authorized: false
|
|
6
|
-
| { authorized: false; loading: true };
|
|
4
|
+
| { authorized: true; data: T; clientContext: ClientContext }
|
|
5
|
+
| { authorized: false };
|
|
@@ -1,65 +1,27 @@
|
|
|
1
|
-
import { useEffect,
|
|
1
|
+
import { useEffect, type ComponentType } from "react";
|
|
2
2
|
|
|
3
3
|
import { useRouter } from "next/router";
|
|
4
4
|
|
|
5
|
-
import { PageLoader } from "../components";
|
|
6
|
-
import { useCookieMonitor } from "../hooks/useCookieMonitor";
|
|
7
|
-
|
|
8
5
|
import type { AuthRouteProps } from "../types";
|
|
9
6
|
|
|
10
7
|
/**
|
|
11
|
-
* HOC that checks only for authorization
|
|
12
|
-
* Now handles loading state for pre-fetch scenarios.
|
|
8
|
+
* HOC that checks only for authorization
|
|
13
9
|
*/
|
|
14
10
|
export const withAuth = <T extends Record<string, unknown>>(
|
|
15
11
|
Component: ComponentType<T>
|
|
16
12
|
) => {
|
|
17
13
|
return function AuthenticatedComponent(props: AuthRouteProps<T>) {
|
|
18
14
|
const router = useRouter();
|
|
19
|
-
const hasCookie = useCookieMonitor();
|
|
20
|
-
const reloadAttemptedRef = useRef(false);
|
|
21
|
-
|
|
22
|
-
// Debug logging
|
|
23
|
-
useEffect(() => {
|
|
24
|
-
console.log("[withAuth] Props state:", {
|
|
25
|
-
authorized: props?.authorized,
|
|
26
|
-
loading: props?.loading,
|
|
27
|
-
hasCookie,
|
|
28
|
-
reloadAttempted: reloadAttemptedRef.current,
|
|
29
|
-
});
|
|
30
|
-
}, [props?.authorized, props?.loading, hasCookie]);
|
|
31
15
|
|
|
32
16
|
useEffect(() => {
|
|
33
|
-
// If not authorized
|
|
34
|
-
if (
|
|
35
|
-
|
|
36
|
-
!props?.loading &&
|
|
37
|
-
!reloadAttemptedRef.current
|
|
38
|
-
) {
|
|
39
|
-
console.log("[withAuth] Reloading: not authorized and not loading");
|
|
40
|
-
reloadAttemptedRef.current = true;
|
|
41
|
-
// Use replace to bypass Next.js data cache
|
|
42
|
-
router.replace(router.asPath);
|
|
17
|
+
// If not authorized, reload the page
|
|
18
|
+
if (!props?.authorized) {
|
|
19
|
+
router.reload();
|
|
43
20
|
}
|
|
44
|
-
}, [props?.authorized,
|
|
45
|
-
|
|
46
|
-
useEffect(() => {
|
|
47
|
-
if (props?.loading && hasCookie && !reloadAttemptedRef.current) {
|
|
48
|
-
console.log(
|
|
49
|
-
"[withAuth] Cookie available, performing hard reload to bypass cache"
|
|
50
|
-
);
|
|
51
|
-
reloadAttemptedRef.current = true;
|
|
52
|
-
// Hard reload to completely bypass Next.js cache
|
|
53
|
-
if (typeof window !== "undefined") {
|
|
54
|
-
window.location.href = router.asPath;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}, [props?.loading, hasCookie, router]);
|
|
21
|
+
}, [props?.authorized, router]);
|
|
58
22
|
|
|
23
|
+
// If not authorized, render nothing
|
|
59
24
|
if (!props?.authorized) {
|
|
60
|
-
if (props?.loading) {
|
|
61
|
-
return <PageLoader />;
|
|
62
|
-
}
|
|
63
25
|
return null;
|
|
64
26
|
}
|
|
65
27
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { validateAccessService } from "../services";
|
|
2
2
|
|
|
3
|
-
import { getAuthCookie } from "./cookie";
|
|
4
3
|
import { ClientContext, getClientContext } from "./getClientContext";
|
|
5
4
|
|
|
6
5
|
import type { AuthRouteProps } from "../types";
|
|
@@ -9,67 +8,40 @@ import type { LoaderData } from "../types";
|
|
|
9
8
|
/**
|
|
10
9
|
* Utility function to encapsulate access validation in loaders.
|
|
11
10
|
* Similar to withAuthProvider but for server-side usage.
|
|
12
|
-
*
|
|
13
|
-
* Now supports a loading state for when cookies are not yet available during pre-fetch.
|
|
14
11
|
*/
|
|
15
12
|
export const withAuthLoader = async <T>(
|
|
16
13
|
data: LoaderData,
|
|
17
14
|
dataLoader: (clientContext: ClientContext) => Promise<T>
|
|
18
15
|
): Promise<AuthRouteProps<T>> => {
|
|
19
16
|
try {
|
|
20
|
-
// Check if auth cookie exists before proceeding
|
|
21
|
-
const authCookie = getAuthCookie(data);
|
|
22
|
-
|
|
23
|
-
console.log("[withAuthLoader] Cookie check:", {
|
|
24
|
-
hasCookie: !!authCookie,
|
|
25
|
-
cookieLength: authCookie?.length,
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
if (!authCookie || authCookie === "") {
|
|
29
|
-
console.log("[withAuthLoader] Returning loading state (no cookie)");
|
|
30
|
-
return {
|
|
31
|
-
authorized: false,
|
|
32
|
-
loading: true,
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
36
17
|
const { cookie, userId, ...clientContext } = await getClientContext(data);
|
|
37
18
|
|
|
38
19
|
const hasAccess = await validateAccessService({ cookie });
|
|
39
20
|
|
|
40
|
-
console.log("[withAuthLoader] Access validation result:", hasAccess);
|
|
41
|
-
|
|
42
21
|
if (!hasAccess) {
|
|
43
|
-
console.log("[withAuthLoader] Access denied, redirecting to /");
|
|
44
22
|
data.res?.writeHead(302, { Location: "/" });
|
|
45
23
|
data.res?.end();
|
|
46
24
|
|
|
47
25
|
return {
|
|
48
26
|
authorized: false,
|
|
49
|
-
loading: false,
|
|
50
27
|
};
|
|
51
28
|
}
|
|
52
29
|
|
|
53
30
|
const pageData = await dataLoader({ cookie, userId, ...clientContext });
|
|
54
31
|
|
|
55
|
-
console.log(
|
|
56
|
-
"[withAuthLoader] Successfully loaded data, returning authorized"
|
|
57
|
-
);
|
|
58
32
|
return {
|
|
59
33
|
authorized: true,
|
|
60
34
|
data: pageData,
|
|
61
35
|
clientContext: { cookie, userId, ...clientContext },
|
|
62
|
-
loading: false,
|
|
63
36
|
};
|
|
64
37
|
} catch (error) {
|
|
65
|
-
console.error("
|
|
38
|
+
console.error("Auth validation failed:", error);
|
|
66
39
|
|
|
67
40
|
data.res?.writeHead(302, { Location: "/" });
|
|
68
41
|
data.res?.end();
|
|
69
42
|
|
|
70
43
|
return {
|
|
71
44
|
authorized: false,
|
|
72
|
-
loading: false,
|
|
73
45
|
};
|
|
74
46
|
}
|
|
75
47
|
};
|
|
@@ -1,81 +1,30 @@
|
|
|
1
|
-
import { useEffect,
|
|
1
|
+
import { useEffect, type ComponentType } from "react";
|
|
2
2
|
|
|
3
3
|
import { useRouter } from "next/router";
|
|
4
4
|
|
|
5
|
-
import { BuyerPortalProvider
|
|
6
|
-
import { useCookieMonitor } from "../hooks/useCookieMonitor";
|
|
5
|
+
import { BuyerPortalProvider } from "../components";
|
|
7
6
|
|
|
8
7
|
import type { AuthRouteProps } from "../types";
|
|
9
8
|
import type { ClientContext } from "./getClientContext";
|
|
10
9
|
|
|
11
10
|
/**
|
|
12
|
-
* HOC que encapsula lógica de autenticação e provider
|
|
13
|
-
* Now handles loading state for pre-fetch scenarios.
|
|
14
|
-
* Monitors cookie availability and reloads when cookie becomes available.
|
|
11
|
+
* HOC que encapsula lógica de autenticação e provider
|
|
15
12
|
*/
|
|
16
13
|
export const withAuthProvider = <T,>(
|
|
17
14
|
Component: ComponentType<T & { clientContext: ClientContext }>
|
|
18
15
|
) => {
|
|
19
16
|
return function WrappedPage(props: AuthRouteProps<T>) {
|
|
20
17
|
const router = useRouter();
|
|
21
|
-
const hasCookie = useCookieMonitor();
|
|
22
|
-
const reloadAttemptedRef = useRef(false);
|
|
23
|
-
const isProduction = process.env.NODE_ENV === "production";
|
|
24
18
|
|
|
25
|
-
// Debug logging (only in development or when needed)
|
|
26
19
|
useEffect(() => {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
loading: props?.loading,
|
|
31
|
-
hasCookie,
|
|
32
|
-
reloadAttempted: reloadAttemptedRef.current,
|
|
33
|
-
routerPath: router.asPath,
|
|
34
|
-
});
|
|
20
|
+
// Se não está autorizado, recarrega a página
|
|
21
|
+
if (!props?.authorized) {
|
|
22
|
+
router.reload();
|
|
35
23
|
}
|
|
36
|
-
}, [
|
|
37
|
-
props?.authorized,
|
|
38
|
-
props?.loading,
|
|
39
|
-
hasCookie,
|
|
40
|
-
router.asPath,
|
|
41
|
-
isProduction,
|
|
42
|
-
]);
|
|
43
|
-
|
|
44
|
-
useEffect(() => {
|
|
45
|
-
// Se não está autorizado e não está carregando, recarrega a página
|
|
46
|
-
if (
|
|
47
|
-
!props?.authorized &&
|
|
48
|
-
!props?.loading &&
|
|
49
|
-
!reloadAttemptedRef.current
|
|
50
|
-
) {
|
|
51
|
-
console.log(
|
|
52
|
-
"[withAuthProvider] Reloading: not authorized and not loading"
|
|
53
|
-
);
|
|
54
|
-
reloadAttemptedRef.current = true;
|
|
55
|
-
// Use replace to bypass Next.js data cache
|
|
56
|
-
router.replace(router.asPath);
|
|
57
|
-
}
|
|
58
|
-
}, [props?.authorized, props?.loading, router]);
|
|
59
|
-
|
|
60
|
-
useEffect(() => {
|
|
61
|
-
// If we're in loading state and cookie becomes available, do hard reload
|
|
62
|
-
if (props?.loading && hasCookie && !reloadAttemptedRef.current) {
|
|
63
|
-
console.log(
|
|
64
|
-
"[withAuthProvider] Cookie available, performing hard reload to bypass cache"
|
|
65
|
-
);
|
|
66
|
-
reloadAttemptedRef.current = true;
|
|
67
|
-
// Hard reload to completely bypass Next.js cache
|
|
68
|
-
if (typeof window !== "undefined") {
|
|
69
|
-
window.location.href = router.asPath;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}, [props?.loading, hasCookie, router]);
|
|
24
|
+
}, [props?.authorized, router]);
|
|
73
25
|
|
|
26
|
+
// Se não está autorizado, não renderiza nada
|
|
74
27
|
if (!props?.authorized) {
|
|
75
|
-
if (props?.loading) {
|
|
76
|
-
console.log("[withAuthProvider] Loading state");
|
|
77
|
-
return <PageLoader />;
|
|
78
|
-
}
|
|
79
28
|
return null;
|
|
80
29
|
}
|
|
81
30
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import { getClientContext } from "./getClientContext";
|
|
2
2
|
import { serializeLoaderData } from "./serializeLoaderData";
|
|
3
3
|
|
|
4
4
|
import type { LoaderData } from "../types";
|
|
@@ -11,85 +11,77 @@ interface WithLoaderErrorBoundaryOptions {
|
|
|
11
11
|
|
|
12
12
|
export function withLoaderErrorBoundary<TQuery, TReturn>(
|
|
13
13
|
loaderFn: (data: LoaderData<TQuery>) => Promise<TReturn>,
|
|
14
|
-
|
|
15
|
-
_options: WithLoaderErrorBoundaryOptions = {}
|
|
14
|
+
options: WithLoaderErrorBoundaryOptions = {}
|
|
16
15
|
) {
|
|
17
|
-
|
|
16
|
+
const { componentName, onError, redirectToError = true } = options;
|
|
17
|
+
|
|
18
18
|
return async (data: LoaderData<TQuery>): Promise<TReturn> => {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
try {
|
|
20
|
+
const result = await loaderFn(data);
|
|
21
|
+
return serializeLoaderData(result);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.error(`[${componentName || "Loader"}] Error:`, {
|
|
24
|
+
message: (error as Error).message,
|
|
25
|
+
query: data.query,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
if (onError) {
|
|
29
|
+
onError(error as Error, data.query);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (redirectToError) {
|
|
33
|
+
let clientContext;
|
|
34
|
+
try {
|
|
35
|
+
clientContext = await getClientContext(data);
|
|
36
|
+
} catch (contextError) {
|
|
37
|
+
console.error(
|
|
38
|
+
`[${componentName || "Loader"}] Failed to get client context:`,
|
|
39
|
+
contextError
|
|
40
|
+
);
|
|
41
|
+
clientContext = {
|
|
42
|
+
cookie: "",
|
|
43
|
+
customerId: "",
|
|
44
|
+
userId: "",
|
|
45
|
+
vtexIdclientAutCookie: "",
|
|
46
|
+
};
|
|
47
|
+
}
|
|
22
48
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
//
|
|
62
|
-
// const errorResponse = {
|
|
63
|
-
// error: {
|
|
64
|
-
// error: {
|
|
65
|
-
// message: (error as Error).message,
|
|
66
|
-
// name: (error as Error).name,
|
|
67
|
-
// stack: (error as Error).stack || null,
|
|
68
|
-
// query: serializedQuery,
|
|
69
|
-
// },
|
|
70
|
-
// tags: {
|
|
71
|
-
// component: componentName || "Unknown",
|
|
72
|
-
// errorType: "loader_error",
|
|
73
|
-
// },
|
|
74
|
-
// extra: {
|
|
75
|
-
// query: serializedQuery,
|
|
76
|
-
// },
|
|
77
|
-
// },
|
|
78
|
-
// hasError: true,
|
|
79
|
-
// context: {
|
|
80
|
-
// clientContext,
|
|
81
|
-
// currentOrgUnit: null,
|
|
82
|
-
// currentContract: null,
|
|
83
|
-
// currentUser: null,
|
|
84
|
-
// },
|
|
85
|
-
// data: null,
|
|
86
|
-
// };
|
|
87
|
-
//
|
|
88
|
-
// // Ensure error response is also JSON-serializable
|
|
89
|
-
// return serializeLoaderData(errorResponse) as TReturn;
|
|
90
|
-
// }
|
|
91
|
-
//
|
|
92
|
-
// throw error;
|
|
93
|
-
// }
|
|
94
|
-
// };
|
|
49
|
+
// Serialize query to ensure it's JSON-safe (use null instead of undefined)
|
|
50
|
+
const serializedQuery = data.query
|
|
51
|
+
? JSON.parse(JSON.stringify(data.query))
|
|
52
|
+
: null;
|
|
53
|
+
|
|
54
|
+
const errorResponse = {
|
|
55
|
+
error: {
|
|
56
|
+
error: {
|
|
57
|
+
message: (error as Error).message,
|
|
58
|
+
name: (error as Error).name,
|
|
59
|
+
stack: (error as Error).stack || null,
|
|
60
|
+
query: serializedQuery,
|
|
61
|
+
},
|
|
62
|
+
tags: {
|
|
63
|
+
component: componentName || "Unknown",
|
|
64
|
+
errorType: "loader_error",
|
|
65
|
+
},
|
|
66
|
+
extra: {
|
|
67
|
+
query: serializedQuery,
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
hasError: true,
|
|
71
|
+
context: {
|
|
72
|
+
clientContext,
|
|
73
|
+
currentOrgUnit: null,
|
|
74
|
+
currentContract: null,
|
|
75
|
+
currentUser: null,
|
|
76
|
+
},
|
|
77
|
+
data: null,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// Ensure error response is also JSON-serializable
|
|
81
|
+
return serializeLoaderData(errorResponse) as TReturn;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
};
|
|
95
87
|
}
|
package/src/themes/index.scss
CHANGED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { Skeleton } from "@faststore/ui";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* PageLoader component displays skeleton loaders while page data is being fetched.
|
|
5
|
-
* Used when cookies are not yet available during pre-fetch scenarios.
|
|
6
|
-
*/
|
|
7
|
-
export const PageLoader = () => {
|
|
8
|
-
return (
|
|
9
|
-
<div data-fs-bp-page-loader>
|
|
10
|
-
<div data-fs-bp-page-loader-header>
|
|
11
|
-
<Skeleton size={{ width: "12rem", height: "2rem" }} />
|
|
12
|
-
<Skeleton size={{ width: "8rem", height: "1.5rem" }} />
|
|
13
|
-
</div>
|
|
14
|
-
|
|
15
|
-
<div data-fs-bp-page-loader-content>
|
|
16
|
-
<Skeleton size={{ width: "100%", height: "4rem" }} />
|
|
17
|
-
<Skeleton size={{ width: "100%", height: "8rem" }} />
|
|
18
|
-
<Skeleton size={{ width: "100%", height: "8rem" }} />
|
|
19
|
-
</div>
|
|
20
|
-
</div>
|
|
21
|
-
);
|
|
22
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { PageLoader } from "./PageLoader";
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
@import "@faststore/ui/src/components/atoms/Skeleton/styles.scss";
|
|
2
|
-
|
|
3
|
-
[data-fs-bp-page-loader] {
|
|
4
|
-
padding: var(--fs-spacing-3);
|
|
5
|
-
width: 100%;
|
|
6
|
-
min-height: 100vh;
|
|
7
|
-
display: flex;
|
|
8
|
-
flex-direction: column;
|
|
9
|
-
gap: var(--fs-spacing-4);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
[data-fs-bp-page-loader-header] {
|
|
13
|
-
display: flex;
|
|
14
|
-
flex-direction: column;
|
|
15
|
-
gap: var(--fs-spacing-2);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
[data-fs-bp-page-loader-content] {
|
|
19
|
-
display: flex;
|
|
20
|
-
flex-direction: column;
|
|
21
|
-
gap: var(--fs-spacing-3);
|
|
22
|
-
}
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from "react";
|
|
2
|
-
|
|
3
|
-
import storeConfig from "discovery.config";
|
|
4
|
-
|
|
5
|
-
import { AUT_COOKIE_KEY } from "../utils/constants";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Hook to monitor when authentication cookie becomes available.
|
|
9
|
-
* Used to detect when cookies load after pre-fetch scenarios.
|
|
10
|
-
*
|
|
11
|
-
* @returns boolean indicating if auth cookie is present
|
|
12
|
-
*/
|
|
13
|
-
export const useCookieMonitor = () => {
|
|
14
|
-
const [hasCookie, setHasCookie] = useState(false);
|
|
15
|
-
|
|
16
|
-
useEffect(() => {
|
|
17
|
-
const checkCookie = () => {
|
|
18
|
-
if (typeof document === "undefined") return false;
|
|
19
|
-
|
|
20
|
-
const cookieName = `${AUT_COOKIE_KEY}_${storeConfig?.api.storeId}`;
|
|
21
|
-
const cookies = document.cookie.split(";");
|
|
22
|
-
|
|
23
|
-
const authCookie = cookies.find((cookie) =>
|
|
24
|
-
cookie.trim().startsWith(`${cookieName}=`)
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
const hasCookieValue =
|
|
28
|
-
!!authCookie && authCookie.split("=")[1]?.trim() !== "";
|
|
29
|
-
|
|
30
|
-
console.log("[useCookieMonitor] Checking cookie:", {
|
|
31
|
-
cookieName,
|
|
32
|
-
hasCookie: hasCookieValue,
|
|
33
|
-
cookieValue: authCookie
|
|
34
|
-
? authCookie.split("=")[1]?.substring(0, 10) + "..."
|
|
35
|
-
: "none",
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
return hasCookieValue;
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
// Check immediately
|
|
42
|
-
const initialCheck = checkCookie();
|
|
43
|
-
console.log("[useCookieMonitor] Initial check:", initialCheck);
|
|
44
|
-
setHasCookie(initialCheck);
|
|
45
|
-
|
|
46
|
-
// If no cookie yet, poll for it
|
|
47
|
-
if (!initialCheck) {
|
|
48
|
-
console.log("[useCookieMonitor] Starting cookie polling...");
|
|
49
|
-
const interval = setInterval(() => {
|
|
50
|
-
const hasAuthCookie = checkCookie();
|
|
51
|
-
|
|
52
|
-
if (hasAuthCookie) {
|
|
53
|
-
console.log("[useCookieMonitor] Cookie found! Stopping poll.");
|
|
54
|
-
setHasCookie(true);
|
|
55
|
-
clearInterval(interval);
|
|
56
|
-
}
|
|
57
|
-
}, 100); // Check every 100ms
|
|
58
|
-
|
|
59
|
-
// Cleanup after 5 seconds max
|
|
60
|
-
const timeout = setTimeout(() => {
|
|
61
|
-
console.log("[useCookieMonitor] Polling timeout reached (5s)");
|
|
62
|
-
clearInterval(interval);
|
|
63
|
-
}, 5000);
|
|
64
|
-
|
|
65
|
-
return () => {
|
|
66
|
-
clearInterval(interval);
|
|
67
|
-
clearTimeout(timeout);
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
}, []);
|
|
71
|
-
|
|
72
|
-
return hasCookie;
|
|
73
|
-
};
|