@vtex/faststore-plugin-buyer-portal 1.1.115 → 1.1.116-poc-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.
Files changed (32) hide show
  1. package/package.json +42 -42
  2. package/src/features/addresses/layouts/AddressDetailsLayout/AddressDetailsLayout.tsx +1 -0
  3. package/src/features/addresses/layouts/AddressesLayout/AddressesLayout.tsx +1 -0
  4. package/src/features/budgets/layouts/BudgetsDetailsLayout/BudgetsDetailsLayout.tsx +1 -0
  5. package/src/features/collections/layouts/CollectionsLayout/CollectionsLayout.tsx +1 -0
  6. package/src/features/contracts/hooks/index.ts +2 -0
  7. package/src/features/contracts/hooks/useContractDetails.ts +22 -0
  8. package/src/features/contracts/hooks/useContractsByOrgUnitId.ts +20 -0
  9. package/src/features/credit-cards/layouts/CreditCardsLayout/CreditCardLayout.tsx +1 -0
  10. package/src/features/custom-fields/layouts/CustomFieldsLayout/CustomFieldsLayout.tsx +1 -0
  11. package/src/features/org-units/hooks/index.ts +1 -0
  12. package/src/features/org-units/hooks/useOrgUnitBasicData.ts +20 -0
  13. package/src/features/org-units/layouts/OrgUnitDetailsLayout/OrgUnitDetailsLayout.tsx +31 -28
  14. package/src/features/payment-methods/layouts/PaymentMethodsLayout/PaymentMethodsLayout.tsx +1 -0
  15. package/src/features/profile/layouts/ProfileLayout/ProfileLayout.tsx +33 -16
  16. package/src/features/shared/components/Error/Error.tsx +12 -13
  17. package/src/features/shared/components/PageLoader/PageLoader.tsx +36 -11
  18. package/src/features/shared/components/withErrorBoundary/withErrorBoundary.tsx +6 -7
  19. package/src/features/shared/hooks/index.ts +1 -0
  20. package/src/features/shared/hooks/useAuth.ts +54 -0
  21. package/src/features/shared/hooks/useCookieMonitor.ts +2 -6
  22. package/src/features/shared/layouts/ContractTabsLayout/ContractTabsLayout.tsx +6 -4
  23. package/src/features/shared/layouts/ErrorTabsLayout/ErrorTabsLayout.tsx +1 -0
  24. package/src/features/shared/layouts/LoadingTabsLayout/LoadingTabsLayout.tsx +2 -27
  25. package/src/features/shared/types/AuthRouteProps.ts +2 -8
  26. package/src/features/shared/utils/withAuth.tsx +10 -62
  27. package/src/features/shared/utils/withAuthLoader.ts +0 -28
  28. package/src/features/shared/utils/withAuthProvider.tsx +11 -81
  29. package/src/features/shared/utils/withLoaderErrorBoundary.ts +71 -79
  30. package/src/features/shared/utils/withProviders.tsx +1 -2
  31. package/src/pages/org-unit-details.tsx +32 -58
  32. package/src/pages/profile.tsx +46 -64
@@ -0,0 +1,54 @@
1
+ import { useEffect, useState } from "react";
2
+
3
+ import { useRouter } from "next/router";
4
+
5
+ import { authClient } from "../clients/Auth";
6
+
7
+ import { useBuyerPortal } from "./useBuyerPortal";
8
+
9
+ export type UseAuthResult = {
10
+ isAuthenticated: boolean | null;
11
+ isLoading: boolean;
12
+ };
13
+
14
+ /**
15
+ * Client-side hook to validate user authentication.
16
+ * Checks access with the server and redirects to home if unauthorized.
17
+ *
18
+ * @returns Object containing authentication status and loading state
19
+ */
20
+ export const useAuth = (): UseAuthResult => {
21
+ const { clientContext } = useBuyerPortal();
22
+ const [isAuthenticated, setIsAuthenticated] = useState<boolean | null>(null);
23
+ const [isLoading, setIsLoading] = useState(true);
24
+ const router = useRouter();
25
+
26
+ useEffect(() => {
27
+ const validateAccess = async () => {
28
+ setIsLoading(true);
29
+
30
+ try {
31
+ const hasAccess = await authClient.validateAccess(clientContext);
32
+
33
+ if (!hasAccess) {
34
+ router.push("/");
35
+ setIsAuthenticated(false);
36
+ } else {
37
+ setIsAuthenticated(true);
38
+ }
39
+ } catch {
40
+ router.push("/");
41
+ setIsAuthenticated(false);
42
+ } finally {
43
+ setIsLoading(false);
44
+ }
45
+ };
46
+
47
+ validateAccess();
48
+ }, [router]);
49
+
50
+ return {
51
+ isAuthenticated,
52
+ isLoading,
53
+ };
54
+ };
@@ -12,7 +12,6 @@ import { AUT_COOKIE_KEY } from "../utils/constants";
12
12
  */
13
13
  export const useCookieMonitor = () => {
14
14
  const [hasCookie, setHasCookie] = useState(false);
15
- const [timedOut, setTimedOut] = useState(false);
16
15
 
17
16
  useEffect(() => {
18
17
  const checkCookie = () => {
@@ -59,10 +58,7 @@ export const useCookieMonitor = () => {
59
58
 
60
59
  // Cleanup after 5 seconds max
61
60
  const timeout = setTimeout(() => {
62
- console.log(
63
- "[useCookieMonitor] Polling timeout reached (5s) - cookie never appeared"
64
- );
65
- setTimedOut(true);
61
+ console.log("[useCookieMonitor] Polling timeout reached (5s)");
66
62
  clearInterval(interval);
67
63
  }, 5000);
68
64
 
@@ -73,5 +69,5 @@ export const useCookieMonitor = () => {
73
69
  }
74
70
  }, []);
75
71
 
76
- return { hasCookie, timedOut };
72
+ return hasCookie;
77
73
  };
@@ -18,6 +18,7 @@ export type ContractTabsLayoutProps = {
18
18
  image?: ReactNode;
19
19
  name: string;
20
20
  role?: string;
21
+ id: string;
21
22
  };
22
23
  loading?: boolean;
23
24
  children?: ReactNode;
@@ -29,8 +30,9 @@ export const ContractTabsLayout = ({
29
30
  children,
30
31
  orgUnitId,
31
32
  contractId,
33
+ person,
32
34
  }: ContractTabsLayoutProps) => {
33
- const { currentOrgUnit, currentUser, currentContract } = useBuyerPortal();
35
+ const { currentOrgUnit, currentContract } = useBuyerPortal();
34
36
 
35
37
  const verticalLinks = getContractSettingsLinks({
36
38
  contractId: currentContract?.id ?? contractId ?? "",
@@ -43,9 +45,9 @@ export const ContractTabsLayout = ({
43
45
  orgUnit={currentOrgUnit}
44
46
  pageName={pageName}
45
47
  person={{
46
- name: currentUser?.name ?? "",
47
- role: currentUser?.role ?? "",
48
- id: currentUser?.id ?? "",
48
+ name: person.name,
49
+ role: person.role,
50
+ id: person.id,
49
51
  }}
50
52
  loading={loading}
51
53
  />
@@ -82,6 +82,7 @@ export const ErrorTabsLayout = ({ children, error }: ErrorTabsLayoutProps) => {
82
82
  image: undefined,
83
83
  name: user?.name ?? "",
84
84
  role: user?.role ?? "",
85
+ id: user?.id ?? "",
85
86
  }}
86
87
  >
87
88
  <ErrorTabsLayoutContent title={pageTitle} error={error} />
@@ -78,6 +78,7 @@ export const LoadingTabsLayout = ({ children }: LoadingTabsLayoutProps) => {
78
78
  image: undefined,
79
79
  name: "",
80
80
  role: "",
81
+ id: "",
81
82
  }}
82
83
  loading={true}
83
84
  >
@@ -100,33 +101,7 @@ export const LoadingTabsLayout = ({ children }: LoadingTabsLayoutProps) => {
100
101
  );
101
102
 
102
103
  case "OrgUnitDetailsLayout":
103
- return (
104
- <OrgUnitsDetailsLayout
105
- loading={true}
106
- data={{
107
- contracts: [],
108
- orgUnit: {
109
- contractMode: "Single",
110
- customerGroup: { customerIds: [] },
111
- id: routeParams.orgUnitId,
112
- name: "",
113
- path: {
114
- ids: "",
115
- names: "",
116
- },
117
- },
118
- user: {
119
- name: "",
120
- roles: [],
121
- id: "",
122
- orgUnit: {
123
- id: routeParams.orgUnitId,
124
- name: "",
125
- },
126
- },
127
- }}
128
- />
129
- );
104
+ return <OrgUnitsDetailsLayout loading={true} orgUnitId="" userId="" />;
130
105
 
131
106
  default:
132
107
  return <LoadingTabsLayoutContent />;
@@ -1,11 +1,5 @@
1
1
  import { ClientContext } from "../utils";
2
2
 
3
3
  export type AuthRouteProps<T> =
4
- | { authorized: true; data: T; clientContext: ClientContext; loading: false }
5
- | { authorized: false; loading: false }
6
- | {
7
- authorized: false;
8
- loading: true;
9
- data?: Partial<T>;
10
- clientContext?: ClientContext;
11
- };
4
+ | { authorized: true; data: T; clientContext: ClientContext }
5
+ | { authorized: false };
@@ -1,83 +1,31 @@
1
- import { useEffect, useRef, type ComponentType } from "react";
1
+ import { useEffect, type ComponentType } from "react";
2
2
 
3
3
  import { useRouter } from "next/router";
4
4
 
5
- import { useCookieMonitor } from "../hooks/useCookieMonitor";
6
-
7
5
  import type { AuthRouteProps } from "../types";
8
6
 
9
7
  /**
10
- * HOC that checks only for authorization.
11
- * Now handles loading state for pre-fetch scenarios.
8
+ * HOC that checks only for authorization
12
9
  */
13
10
  export const withAuth = <T extends Record<string, unknown>>(
14
11
  Component: ComponentType<T>
15
12
  ) => {
16
13
  return function AuthenticatedComponent(props: AuthRouteProps<T>) {
17
14
  const router = useRouter();
18
- const { hasCookie, timedOut } = useCookieMonitor();
19
- const reloadAttemptedRef = useRef(false);
20
-
21
- // Debug logging
22
- useEffect(() => {
23
- console.log("[withAuth] Props state:", {
24
- authorized: props?.authorized,
25
- loading: props?.loading,
26
- hasCookie,
27
- timedOut,
28
- reloadAttempted: reloadAttemptedRef.current,
29
- });
30
- }, [props?.authorized, props?.loading, hasCookie, timedOut]);
31
-
32
- useEffect(() => {
33
- // If not authorized and not loading, reload the page
34
- if (
35
- !props?.authorized &&
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);
43
- }
44
- }, [props?.authorized, props?.loading, router]);
45
15
 
46
16
  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
- }
17
+ // If not authorized, reload the page
18
+ if (!props?.authorized) {
19
+ router.reload();
56
20
  }
57
- }, [props?.loading, hasCookie, router]);
21
+ }, [props?.authorized, router]);
58
22
 
59
- useEffect(() => {
60
- // If we're in loading state and timeout reached, redirect to home
61
- if (props?.loading && timedOut && !reloadAttemptedRef.current) {
62
- console.log("[withAuth] Cookie timeout - redirecting to home page");
63
- reloadAttemptedRef.current = true;
64
- router.push("/");
65
- }
66
- }, [props?.loading, timedOut, router]);
67
-
68
- // Always render the component, but pass loading state
69
- // This allows components to handle their own loading states
70
- if (!props?.authorized && !props?.loading) {
71
- // Not authorized and not loading = permanently denied
23
+ // If not authorized, render nothing
24
+ if (!props?.authorized) {
72
25
  return null;
73
26
  }
74
27
 
75
- // Render with whatever data we have (might be empty/partial if loading)
76
- const componentProps = {
77
- ...(props?.data || ({} as T)),
78
- loading: props?.loading || false,
79
- } as T & { loading: boolean };
80
-
81
- return <Component {...componentProps} />;
28
+ // If authorized, render the component with the data
29
+ return <Component {...(props.data as T)} />;
82
30
  };
83
31
  };
@@ -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,57 +8,31 @@ 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
38
  console.error("[withAuthLoader] Auth validation failed:", error);
@@ -69,7 +42,6 @@ export const withAuthLoader = async <T>(
69
42
 
70
43
  return {
71
44
  authorized: false,
72
- loading: false,
73
45
  };
74
46
  }
75
47
  };
@@ -1,107 +1,37 @@
1
- import { useEffect, useRef, type ComponentType } from "react";
1
+ import { useEffect, type ComponentType } from "react";
2
2
 
3
3
  import { useRouter } from "next/router";
4
4
 
5
5
  import { BuyerPortalProvider } from "../components";
6
- import { useCookieMonitor } from "../hooks/useCookieMonitor";
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, timedOut } = 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
- if (!isProduction) {
28
- console.log("[withAuthProvider] Props state:", {
29
- authorized: props?.authorized,
30
- loading: props?.loading,
31
- hasCookie,
32
- timedOut,
33
- reloadAttempted: reloadAttemptedRef.current,
34
- routerPath: router.asPath,
35
- });
20
+ // Se não está autorizado, recarrega a página
21
+ if (!props?.authorized) {
22
+ router.reload();
36
23
  }
37
- }, [
38
- props?.authorized,
39
- props?.loading,
40
- hasCookie,
41
- timedOut,
42
- router.asPath,
43
- isProduction,
44
- ]);
24
+ }, [props?.authorized, router]);
45
25
 
46
- useEffect(() => {
47
- // Se não está autorizado e não está carregando, recarrega a página
48
- if (
49
- !props?.authorized &&
50
- !props?.loading &&
51
- !reloadAttemptedRef.current
52
- ) {
53
- console.log(
54
- "[withAuthProvider] Reloading: not authorized and not loading"
55
- );
56
- reloadAttemptedRef.current = true;
57
- // Use replace to bypass Next.js data cache
58
- router.replace(router.asPath);
59
- }
60
- }, [props?.authorized, props?.loading, router]);
61
-
62
- useEffect(() => {
63
- // If we're in loading state and cookie becomes available, do hard reload
64
- if (props?.loading && hasCookie && !reloadAttemptedRef.current) {
65
- console.log(
66
- "[withAuthProvider] Cookie available, performing hard reload to bypass cache"
67
- );
68
- reloadAttemptedRef.current = true;
69
- // Hard reload to completely bypass Next.js cache
70
- if (typeof window !== "undefined") {
71
- window.location.href = router.asPath;
72
- }
73
- }
74
- }, [props?.loading, hasCookie, router]);
75
-
76
- useEffect(() => {
77
- // If we're in loading state and timeout reached, redirect to home
78
- if (props?.loading && timedOut && !reloadAttemptedRef.current) {
79
- console.log(
80
- "[withAuthProvider] Cookie timeout - redirecting to home page"
81
- );
82
- reloadAttemptedRef.current = true;
83
- router.push("/");
84
- }
85
- }, [props?.loading, timedOut, router]);
86
-
87
- // Always render the component, but pass loading state
88
- // This allows components to handle their own loading states
89
- if (!props?.authorized && !props?.loading) {
90
- // Not authorized and not loading = permanently denied
26
+ // Se não está autorizado, não renderiza nada
27
+ if (!props?.authorized) {
91
28
  return null;
92
29
  }
93
30
 
94
- // Render with whatever data we have (might be empty/partial if loading)
95
- const componentProps = {
96
- ...(props?.data || ({} as T)),
97
- loading: props?.loading || false,
98
- } as T & { loading: boolean };
99
-
100
- const clientContext = props?.clientContext || ({} as ClientContext);
101
-
31
+ // Se autorizado, renderiza o componente envolvido no provider
102
32
  return (
103
- <BuyerPortalProvider clientContext={clientContext}>
104
- <Component {...componentProps} clientContext={clientContext} />
33
+ <BuyerPortalProvider clientContext={props?.clientContext}>
34
+ <Component {...props.data} clientContext={props?.clientContext} />
105
35
  </BuyerPortalProvider>
106
36
  );
107
37
  };
@@ -1,4 +1,4 @@
1
- // import { getClientContext } from "./getClientContext";
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
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
15
- _options: WithLoaderErrorBoundaryOptions = {}
14
+ options: WithLoaderErrorBoundaryOptions = {}
16
15
  ) {
17
- // Bypass: Just call the loader function and serialize the result
16
+ const { componentName, onError, redirectToError = true } = options;
17
+
18
18
  return async (data: LoaderData<TQuery>): Promise<TReturn> => {
19
- const result = await loaderFn(data);
20
- return serializeLoaderData(result);
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
- // Old error handling code - commented out for bypass
24
- // const { componentName, onError, redirectToError = true } = options;
25
- //
26
- // return async (data: LoaderData<TQuery>): Promise<TReturn> => {
27
- // try {
28
- // const result = await loaderFn(data);
29
- // return serializeLoaderData(result);
30
- // } catch (error) {
31
- // console.error(`[${componentName || "Loader"}] Error:`, {
32
- // message: (error as Error).message,
33
- // query: data.query,
34
- // });
35
- //
36
- // if (onError) {
37
- // onError(error as Error, data.query);
38
- // }
39
- //
40
- // if (redirectToError) {
41
- // let clientContext;
42
- // try {
43
- // clientContext = await getClientContext(data);
44
- // } catch (contextError) {
45
- // console.error(
46
- // `[${componentName || "Loader"}] Failed to get client context:`,
47
- // contextError
48
- // );
49
- // clientContext = {
50
- // cookie: "",
51
- // customerId: "",
52
- // userId: "",
53
- // vtexIdclientAutCookie: "",
54
- // };
55
- // }
56
- //
57
- // // Serialize query to ensure it's JSON-safe (use null instead of undefined)
58
- // const serializedQuery = data.query
59
- // ? JSON.parse(JSON.stringify(data.query))
60
- // : null;
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
  }
@@ -1,6 +1,5 @@
1
1
  import { type ComponentType } from "react";
2
2
 
3
- import { withAuth } from "./withAuth";
4
3
  import { withBuyerPortal } from "./withBuyerPortal";
5
4
 
6
5
  /**
@@ -14,7 +13,7 @@ type ProviderHOC = (Component: ComponentType<any>) => ComponentType<any>;
14
13
  * Default project providers applied to all pages.
15
14
  * Order: right to left (like pipe/compose)
16
15
  */
17
- const projectProviders: ProviderHOC[] = [withAuth, withBuyerPortal];
16
+ const projectProviders: ProviderHOC[] = [withBuyerPortal];
18
17
 
19
18
  /**
20
19
  * HOC that applies all default project providers.