@vtex/faststore-plugin-buyer-portal 1.1.110 → 1.1.112
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/addresses/components/AddressLine/AddressLine.tsx +3 -3
- package/src/features/org-units/components/OrgUnitBreadcrumb/OrgUnitBreadcrumbLink.tsx +3 -3
- package/src/features/org-units/components/OrgUnitDetailsNavbar/OrgUnitDetailsNavbar.tsx +5 -5
- package/src/features/profile/components/ProfileSummary/ProfileSummary.tsx +3 -3
- package/src/features/shared/components/BasicCard/BasicCard.tsx +3 -3
- package/src/features/shared/components/BasicCard/BasicCardLine.tsx +2 -2
- package/src/features/shared/components/HeaderInside/HeaderInside.tsx +3 -3
- package/src/features/shared/components/InternalTopbar/InternalTopbar.tsx +3 -3
- package/src/features/shared/components/VerticalNav/VerticalNavLink.tsx +3 -3
- package/src/features/shared/hooks/index.ts +1 -0
- package/src/features/shared/hooks/useCookieMonitor.ts +58 -0
- package/src/features/shared/layouts/BaseTabsLayout/sidebar-drawer/SidebarDrawer.tsx +3 -3
- package/src/features/shared/utils/withAuth.tsx +10 -5
- package/src/features/shared/utils/withAuthProvider.tsx +12 -6
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import Link from "next/link";
|
|
2
2
|
|
|
3
3
|
import { Dropdown } from "@faststore/ui";
|
|
4
4
|
|
|
@@ -23,7 +23,7 @@ export const AddressLine = ({
|
|
|
23
23
|
currentAddress,
|
|
24
24
|
}: AddressLineProps) => (
|
|
25
25
|
<li data-fs-addresses-line>
|
|
26
|
-
<
|
|
26
|
+
<Link href={href} data-fs-addresses-line-link>
|
|
27
27
|
<Icon
|
|
28
28
|
name="LocalPostOffice"
|
|
29
29
|
width={20}
|
|
@@ -37,7 +37,7 @@ export const AddressLine = ({
|
|
|
37
37
|
{types.map((type) => (
|
|
38
38
|
<Tag key={type}>{type}</Tag>
|
|
39
39
|
))}
|
|
40
|
-
</
|
|
40
|
+
</Link>
|
|
41
41
|
|
|
42
42
|
<Dropdown>
|
|
43
43
|
<BasicDropdownMenu.Trigger />
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useEffect, useRef, useState } from "react";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import Link from "next/link";
|
|
4
4
|
|
|
5
5
|
import { Tooltip } from "@faststore/ui";
|
|
6
6
|
|
|
@@ -34,14 +34,14 @@ export const OrgUnitBreadcrumbLink = ({
|
|
|
34
34
|
{name}
|
|
35
35
|
</p>
|
|
36
36
|
) : (
|
|
37
|
-
<
|
|
37
|
+
<Link
|
|
38
38
|
ref={linkRef as React.RefObject<HTMLAnchorElement>}
|
|
39
39
|
data-fs-bp-breadcrumb-text
|
|
40
40
|
href={item}
|
|
41
41
|
data-fs-bp-breadcrumb-link
|
|
42
42
|
>
|
|
43
43
|
{name}
|
|
44
|
-
</
|
|
44
|
+
</Link>
|
|
45
45
|
)}
|
|
46
46
|
</div>
|
|
47
47
|
);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import storeConfig from "discovery.config";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import Link from "next/link";
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
6
|
Dropdown,
|
|
@@ -30,13 +30,13 @@ export const OrgUnitDetailsNavbar = ({
|
|
|
30
30
|
}: OrgUnitDetailsNavbarProps) => {
|
|
31
31
|
return (
|
|
32
32
|
<header data-fs-bp-org-unit-details-navbar>
|
|
33
|
-
<
|
|
33
|
+
<Link href="/" data-fs-bp-org-unit-details-navbar-link>
|
|
34
34
|
{storeConfig.seo.title}
|
|
35
|
-
</
|
|
35
|
+
</Link>
|
|
36
36
|
<div data-fs-bp-org-unit-details-navbar-actions>
|
|
37
|
-
<
|
|
37
|
+
<Link href="/" data-fs-bp-org-unit-details-navbar-start-shopping-link>
|
|
38
38
|
Start shopping
|
|
39
|
-
</
|
|
39
|
+
</Link>
|
|
40
40
|
{loading ? (
|
|
41
41
|
<Skeleton size={{ width: "2.5rem", height: "2.5rem" }} />
|
|
42
42
|
) : (
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import Link from "next/link";
|
|
4
4
|
|
|
5
5
|
import { Button } from "@faststore/ui";
|
|
6
6
|
|
|
@@ -35,9 +35,9 @@ export const ProfileSummary = ({
|
|
|
35
35
|
<div data-fs-self-profile-summary-header>
|
|
36
36
|
<h2 data-fs-self-profile-summary-org-name>{orgName}</h2>
|
|
37
37
|
{showManageLink && (
|
|
38
|
-
<
|
|
38
|
+
<Link data-fs-self-profile-summary-org-link href="/buyer-portal">
|
|
39
39
|
Manage Organization <Icon name="OpenInNew" width={23} height={23} />
|
|
40
|
-
</
|
|
40
|
+
</Link>
|
|
41
41
|
)}
|
|
42
42
|
</div>
|
|
43
43
|
<div data-fs-self-profile-summary-person-actions>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import Link from "next/link";
|
|
4
4
|
import { useRouter } from "next/router";
|
|
5
5
|
|
|
6
6
|
import { Icon as UIIcon, IconButton } from "@faststore/ui";
|
|
@@ -58,9 +58,9 @@ export const BasicCard = ({
|
|
|
58
58
|
<CardBody>{children}</CardBody>
|
|
59
59
|
{enableFooter && (
|
|
60
60
|
<CardFooter>
|
|
61
|
-
<
|
|
61
|
+
<Link href={footerLink} data-fs-card-footer-link>
|
|
62
62
|
<span>{footerMessage}</span>
|
|
63
|
-
</
|
|
63
|
+
</Link>
|
|
64
64
|
<IconButton
|
|
65
65
|
onClick={() => {
|
|
66
66
|
push(footerLink);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import Link from "next/link";
|
|
4
4
|
|
|
5
5
|
import { Dropdown } from "@faststore/ui";
|
|
6
6
|
|
|
@@ -21,7 +21,7 @@ export const BasicCardLine = ({
|
|
|
21
21
|
}: BasicCardLineProps) => {
|
|
22
22
|
return (
|
|
23
23
|
<span data-fs-basic-card-line title={title}>
|
|
24
|
-
{href && <
|
|
24
|
+
{href && <Link data-fs-basic-card-line-link href={href} />}
|
|
25
25
|
{!!icon && <span data-fs-basic-card-line-icon>{icon}</span>}
|
|
26
26
|
<span data-fs-basic-card-line-title>{title}</span>
|
|
27
27
|
{!!menu && (
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import Link from "next/link";
|
|
4
4
|
|
|
5
5
|
import { Icon } from "../Icon";
|
|
6
6
|
|
|
@@ -21,9 +21,9 @@ export const HeaderInside = ({
|
|
|
21
21
|
return (
|
|
22
22
|
<header data-fs-bp-header-inside {...otherProps}>
|
|
23
23
|
{!!backLink && (
|
|
24
|
-
<
|
|
24
|
+
<Link href={backLink} data-fs-bp-back-link>
|
|
25
25
|
<Icon name="Back" />
|
|
26
|
-
</
|
|
26
|
+
</Link>
|
|
27
27
|
)}
|
|
28
28
|
{title && <h1 data-fs-bp-header-inside-title>{title}</h1>}
|
|
29
29
|
{children}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
import type { HTMLAttributes } from "react";
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
import Link from "next/link";
|
|
5
5
|
|
|
6
6
|
import { IconButton, Dropdown, DropdownButton } from "@faststore/ui";
|
|
7
7
|
|
|
@@ -32,7 +32,7 @@ export const InternalTopBar = ({
|
|
|
32
32
|
return (
|
|
33
33
|
<header data-fs-buyer-portal-topbar>
|
|
34
34
|
<div data-fs-buyer-portal-topbar-navigation>
|
|
35
|
-
<
|
|
35
|
+
<Link href={href}>
|
|
36
36
|
<IconButton
|
|
37
37
|
size="small"
|
|
38
38
|
icon={
|
|
@@ -45,7 +45,7 @@ export const InternalTopBar = ({
|
|
|
45
45
|
}
|
|
46
46
|
aria-label={"topbar goback"}
|
|
47
47
|
/>
|
|
48
|
-
</
|
|
48
|
+
</Link>
|
|
49
49
|
<div data-fs-internal-topbar-icon-wrapper>
|
|
50
50
|
<Icon name="StarFolder" height={24} width={24} />
|
|
51
51
|
</div>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import Link from "next/link";
|
|
4
4
|
import { useRouter } from "next/router";
|
|
5
5
|
|
|
6
6
|
export type VerticalNavLinkProps = {
|
|
@@ -24,13 +24,13 @@ export const VerticalNavLink = ({ link, children }: VerticalNavLinkProps) => {
|
|
|
24
24
|
|
|
25
25
|
return (
|
|
26
26
|
<li key={link} data-fs-vertical-nav-menu-item>
|
|
27
|
-
<
|
|
27
|
+
<Link
|
|
28
28
|
href={link}
|
|
29
29
|
data-fs-vertical-nav-menu-link
|
|
30
30
|
data-fs-vertical-nav-menu-link-is-active={isActive}
|
|
31
31
|
>
|
|
32
32
|
{children}
|
|
33
|
-
</
|
|
33
|
+
</Link>
|
|
34
34
|
</li>
|
|
35
35
|
);
|
|
36
36
|
};
|
|
@@ -0,0 +1,58 @@
|
|
|
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
|
+
return !!authCookie && authCookie.split("=")[1]?.trim() !== "";
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// Check immediately
|
|
31
|
+
const initialCheck = checkCookie();
|
|
32
|
+
setHasCookie(initialCheck);
|
|
33
|
+
|
|
34
|
+
// If no cookie yet, poll for it
|
|
35
|
+
if (!initialCheck) {
|
|
36
|
+
const interval = setInterval(() => {
|
|
37
|
+
const hasAuthCookie = checkCookie();
|
|
38
|
+
|
|
39
|
+
if (hasAuthCookie) {
|
|
40
|
+
setHasCookie(true);
|
|
41
|
+
clearInterval(interval);
|
|
42
|
+
}
|
|
43
|
+
}, 100); // Check every 100ms
|
|
44
|
+
|
|
45
|
+
// Cleanup after 5 seconds max
|
|
46
|
+
const timeout = setTimeout(() => {
|
|
47
|
+
clearInterval(interval);
|
|
48
|
+
}, 5000);
|
|
49
|
+
|
|
50
|
+
return () => {
|
|
51
|
+
clearInterval(interval);
|
|
52
|
+
clearTimeout(timeout);
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}, []);
|
|
56
|
+
|
|
57
|
+
return hasCookie;
|
|
58
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import storeConfig from "discovery.config";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import Link from "next/link";
|
|
4
4
|
|
|
5
5
|
import { BasicDrawer, type BasicDrawerProps } from "../../../components";
|
|
6
6
|
import { SidebarMenu } from "../SidebarMenu";
|
|
@@ -26,9 +26,9 @@ export const SidebarDrawer = ({
|
|
|
26
26
|
>
|
|
27
27
|
<BasicDrawer.Heading
|
|
28
28
|
title={
|
|
29
|
-
<
|
|
29
|
+
<Link href="/" data-fs-bp-org-unit-details-navbar-link>
|
|
30
30
|
{storeConfig.seo.title}
|
|
31
|
-
</
|
|
31
|
+
</Link>
|
|
32
32
|
}
|
|
33
33
|
onClose={close}
|
|
34
34
|
/>
|
|
@@ -3,6 +3,7 @@ import { useEffect, type ComponentType } from "react";
|
|
|
3
3
|
import { useRouter } from "next/router";
|
|
4
4
|
|
|
5
5
|
import { PageLoader } from "../components";
|
|
6
|
+
import { useCookieMonitor } from "../hooks/useCookieMonitor";
|
|
6
7
|
|
|
7
8
|
import type { AuthRouteProps } from "../types";
|
|
8
9
|
|
|
@@ -15,6 +16,7 @@ export const withAuth = <T extends Record<string, unknown>>(
|
|
|
15
16
|
) => {
|
|
16
17
|
return function AuthenticatedComponent(props: AuthRouteProps<T>) {
|
|
17
18
|
const router = useRouter();
|
|
19
|
+
const hasCookie = useCookieMonitor();
|
|
18
20
|
|
|
19
21
|
useEffect(() => {
|
|
20
22
|
// If not authorized and not loading, reload the page
|
|
@@ -23,13 +25,16 @@ export const withAuth = <T extends Record<string, unknown>>(
|
|
|
23
25
|
}
|
|
24
26
|
}, [props?.authorized, props?.loading, router]);
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
if (props?.loading && hasCookie) {
|
|
30
|
+
router.reload();
|
|
31
|
+
}
|
|
32
|
+
}, [props?.loading, hasCookie, router]);
|
|
30
33
|
|
|
31
|
-
// If not authorized and not loading, render nothing
|
|
32
34
|
if (!props?.authorized) {
|
|
35
|
+
if (props?.loading) {
|
|
36
|
+
return <PageLoader />;
|
|
37
|
+
}
|
|
33
38
|
return null;
|
|
34
39
|
}
|
|
35
40
|
|
|
@@ -3,6 +3,7 @@ import { useEffect, type ComponentType } from "react";
|
|
|
3
3
|
import { useRouter } from "next/router";
|
|
4
4
|
|
|
5
5
|
import { BuyerPortalProvider, PageLoader } from "../components";
|
|
6
|
+
import { useCookieMonitor } from "../hooks/useCookieMonitor";
|
|
6
7
|
|
|
7
8
|
import type { AuthRouteProps } from "../types";
|
|
8
9
|
import type { ClientContext } from "./getClientContext";
|
|
@@ -10,12 +11,14 @@ import type { ClientContext } from "./getClientContext";
|
|
|
10
11
|
/**
|
|
11
12
|
* HOC que encapsula lógica de autenticação e provider.
|
|
12
13
|
* Now handles loading state for pre-fetch scenarios.
|
|
14
|
+
* Monitors cookie availability and reloads when cookie becomes available.
|
|
13
15
|
*/
|
|
14
16
|
export const withAuthProvider = <T,>(
|
|
15
17
|
Component: ComponentType<T & { clientContext: ClientContext }>
|
|
16
18
|
) => {
|
|
17
19
|
return function WrappedPage(props: AuthRouteProps<T>) {
|
|
18
20
|
const router = useRouter();
|
|
21
|
+
const hasCookie = useCookieMonitor();
|
|
19
22
|
|
|
20
23
|
useEffect(() => {
|
|
21
24
|
// Se não está autorizado e não está carregando, recarrega a página
|
|
@@ -24,17 +27,20 @@ export const withAuthProvider = <T,>(
|
|
|
24
27
|
}
|
|
25
28
|
}, [props?.authorized, props?.loading, router]);
|
|
26
29
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
// If we're in loading state and cookie becomes available, reload to fetch data
|
|
32
|
+
if (props?.loading && hasCookie) {
|
|
33
|
+
router.reload();
|
|
34
|
+
}
|
|
35
|
+
}, [props?.loading, hasCookie, router]);
|
|
31
36
|
|
|
32
|
-
// Se não está autorizado e não está carregando, não renderiza nada
|
|
33
37
|
if (!props?.authorized) {
|
|
38
|
+
if (props?.loading) {
|
|
39
|
+
return <PageLoader />;
|
|
40
|
+
}
|
|
34
41
|
return null;
|
|
35
42
|
}
|
|
36
43
|
|
|
37
|
-
// Se autorizado, renderiza o componente envolvido no provider
|
|
38
44
|
return (
|
|
39
45
|
<BuyerPortalProvider clientContext={props?.clientContext}>
|
|
40
46
|
<Component {...props.data} clientContext={props?.clientContext} />
|