@vtex/faststore-plugin-buyer-portal 1.1.108 → 1.1.110
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 +4 -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/PageLoader/PageLoader.tsx +22 -0
- package/src/features/shared/components/PageLoader/index.ts +1 -0
- package/src/features/shared/components/PageLoader/page-loader.scss +22 -0
- package/src/features/shared/components/VerticalNav/VerticalNavLink.tsx +3 -3
- package/src/features/shared/components/index.ts +1 -0
- package/src/features/shared/layouts/BaseTabsLayout/sidebar-drawer/SidebarDrawer.tsx +3 -3
- package/src/features/shared/types/AuthRouteProps.ts +3 -2
- package/src/features/shared/utils/constants.ts +4 -4
- package/src/features/shared/utils/withAuth.tsx +13 -5
- package/src/features/shared/utils/withAuthLoader.ts +16 -0
- package/src/features/shared/utils/withAuthProvider.tsx +12 -6
- package/src/themes/index.scss +1 -0
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import Link from "next/link";
|
|
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
|
+
<a 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
|
+
</a>
|
|
41
41
|
|
|
42
42
|
<Dropdown>
|
|
43
43
|
<BasicDropdownMenu.Trigger />
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useEffect, useRef, useState } from "react";
|
|
2
2
|
|
|
3
|
-
import Link from "next/link";
|
|
3
|
+
// import Link from "next/link";
|
|
4
4
|
|
|
5
5
|
import { Tooltip } from "@faststore/ui";
|
|
6
6
|
|
|
@@ -34,13 +34,14 @@ export const OrgUnitBreadcrumbLink = ({
|
|
|
34
34
|
{name}
|
|
35
35
|
</p>
|
|
36
36
|
) : (
|
|
37
|
-
<
|
|
37
|
+
<a
|
|
38
38
|
ref={linkRef as React.RefObject<HTMLAnchorElement>}
|
|
39
39
|
data-fs-bp-breadcrumb-text
|
|
40
40
|
href={item}
|
|
41
|
+
data-fs-bp-breadcrumb-link
|
|
41
42
|
>
|
|
42
43
|
{name}
|
|
43
|
-
</
|
|
44
|
+
</a>
|
|
44
45
|
)}
|
|
45
46
|
</div>
|
|
46
47
|
);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import storeConfig from "discovery.config";
|
|
2
2
|
|
|
3
|
-
import Link from "next/link";
|
|
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
|
+
<a href="/" data-fs-bp-org-unit-details-navbar-link>
|
|
34
34
|
{storeConfig.seo.title}
|
|
35
|
-
</
|
|
35
|
+
</a>
|
|
36
36
|
<div data-fs-bp-org-unit-details-navbar-actions>
|
|
37
|
-
<
|
|
37
|
+
<a href="/" data-fs-bp-org-unit-details-navbar-start-shopping-link>
|
|
38
38
|
Start shopping
|
|
39
|
-
</
|
|
39
|
+
</a>
|
|
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
|
-
import Link from "next/link";
|
|
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
|
+
<a data-fs-self-profile-summary-org-link href="/buyer-portal">
|
|
39
39
|
Manage Organization <Icon name="OpenInNew" width={23} height={23} />
|
|
40
|
-
</
|
|
40
|
+
</a>
|
|
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
|
-
import Link from "next/link";
|
|
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
|
+
<a href={footerLink} data-fs-card-footer-link>
|
|
62
62
|
<span>{footerMessage}</span>
|
|
63
|
-
</
|
|
63
|
+
</a>
|
|
64
64
|
<IconButton
|
|
65
65
|
onClick={() => {
|
|
66
66
|
push(footerLink);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
|
|
3
|
-
import Link from "next/link";
|
|
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 && <a 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
|
-
import Link from "next/link";
|
|
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
|
+
<a href={backLink} data-fs-bp-back-link>
|
|
25
25
|
<Icon name="Back" />
|
|
26
|
-
</
|
|
26
|
+
</a>
|
|
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
|
-
import Link from "next/link";
|
|
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
|
+
<a 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
|
+
</a>
|
|
49
49
|
<div data-fs-internal-topbar-icon-wrapper>
|
|
50
50
|
<Icon name="StarFolder" height={24} width={24} />
|
|
51
51
|
</div>
|
|
@@ -0,0 +1,22 @@
|
|
|
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
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { PageLoader } from "./PageLoader";
|
|
@@ -0,0 +1,22 @@
|
|
|
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,6 +1,6 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
|
|
3
|
-
import Link from "next/link";
|
|
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
|
+
<a
|
|
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
|
+
</a>
|
|
34
34
|
</li>
|
|
35
35
|
);
|
|
36
36
|
};
|
|
@@ -76,3 +76,4 @@ 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";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import storeConfig from "discovery.config";
|
|
2
2
|
|
|
3
|
-
import Link from "next/link";
|
|
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
|
+
<a href="/" data-fs-bp-org-unit-details-navbar-link>
|
|
30
30
|
{storeConfig.seo.title}
|
|
31
|
-
</
|
|
31
|
+
</a>
|
|
32
32
|
}
|
|
33
33
|
onClose={close}
|
|
34
34
|
/>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ClientContext } from "../utils";
|
|
2
2
|
|
|
3
3
|
export type AuthRouteProps<T> =
|
|
4
|
-
| { authorized: true; data: T; clientContext: ClientContext }
|
|
5
|
-
| { authorized: false }
|
|
4
|
+
| { authorized: true; data: T; clientContext: ClientContext; loading: false }
|
|
5
|
+
| { authorized: false; loading: false }
|
|
6
|
+
| { authorized: false; loading: true };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
export const AUT_COOKIE_KEY = "VtexIdclientAutCookie";
|
|
2
2
|
// PROD URL
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
export const API_URL = (checkoutUrl: string, operation?: string) =>
|
|
4
|
+
`${checkoutUrl}/_v/store-front/${operation}`;
|
|
5
5
|
// DEV URL - CHANGE BEFORE MERGE
|
|
6
|
-
export const API_URL = (checkoutUrl?: string, operation?: string) =>
|
|
7
|
-
|
|
6
|
+
// export const API_URL = (checkoutUrl?: string, operation?: string) =>
|
|
7
|
+
// `https://permission--b2bfaststoredev.myvtex.com/_v/store-front/${operation}`;
|
|
8
8
|
|
|
9
9
|
export const DEBOUNCE_TIMEOUT = 500;
|
|
10
10
|
|
|
@@ -2,10 +2,13 @@ import { useEffect, type ComponentType } from "react";
|
|
|
2
2
|
|
|
3
3
|
import { useRouter } from "next/router";
|
|
4
4
|
|
|
5
|
+
import { PageLoader } from "../components";
|
|
6
|
+
|
|
5
7
|
import type { AuthRouteProps } from "../types";
|
|
6
8
|
|
|
7
9
|
/**
|
|
8
|
-
* HOC that checks only for authorization
|
|
10
|
+
* HOC that checks only for authorization.
|
|
11
|
+
* Now handles loading state for pre-fetch scenarios.
|
|
9
12
|
*/
|
|
10
13
|
export const withAuth = <T extends Record<string, unknown>>(
|
|
11
14
|
Component: ComponentType<T>
|
|
@@ -14,13 +17,18 @@ export const withAuth = <T extends Record<string, unknown>>(
|
|
|
14
17
|
const router = useRouter();
|
|
15
18
|
|
|
16
19
|
useEffect(() => {
|
|
17
|
-
// If not authorized, reload the page
|
|
18
|
-
if (!props?.authorized) {
|
|
20
|
+
// If not authorized and not loading, reload the page
|
|
21
|
+
if (!props?.authorized && !props?.loading) {
|
|
19
22
|
router.reload();
|
|
20
23
|
}
|
|
21
|
-
}, [props?.authorized, router]);
|
|
24
|
+
}, [props?.authorized, props?.loading, router]);
|
|
25
|
+
|
|
26
|
+
// If loading (cookie not yet available), show skeleton
|
|
27
|
+
if (props?.loading) {
|
|
28
|
+
return <PageLoader />;
|
|
29
|
+
}
|
|
22
30
|
|
|
23
|
-
// If not authorized, render nothing
|
|
31
|
+
// If not authorized and not loading, render nothing
|
|
24
32
|
if (!props?.authorized) {
|
|
25
33
|
return null;
|
|
26
34
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { validateAccessService } from "../services";
|
|
2
2
|
|
|
3
|
+
import { getAuthCookie } from "./cookie";
|
|
3
4
|
import { ClientContext, getClientContext } from "./getClientContext";
|
|
4
5
|
|
|
5
6
|
import type { AuthRouteProps } from "../types";
|
|
@@ -8,12 +9,24 @@ import type { LoaderData } from "../types";
|
|
|
8
9
|
/**
|
|
9
10
|
* Utility function to encapsulate access validation in loaders.
|
|
10
11
|
* 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.
|
|
11
14
|
*/
|
|
12
15
|
export const withAuthLoader = async <T>(
|
|
13
16
|
data: LoaderData,
|
|
14
17
|
dataLoader: (clientContext: ClientContext) => Promise<T>
|
|
15
18
|
): Promise<AuthRouteProps<T>> => {
|
|
16
19
|
try {
|
|
20
|
+
// Check if auth cookie exists before proceeding
|
|
21
|
+
const authCookie = getAuthCookie(data);
|
|
22
|
+
|
|
23
|
+
if (!authCookie || authCookie === "") {
|
|
24
|
+
return {
|
|
25
|
+
authorized: false,
|
|
26
|
+
loading: true,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
17
30
|
const { cookie, userId, ...clientContext } = await getClientContext(data);
|
|
18
31
|
|
|
19
32
|
const hasAccess = await validateAccessService({ cookie });
|
|
@@ -24,6 +37,7 @@ export const withAuthLoader = async <T>(
|
|
|
24
37
|
|
|
25
38
|
return {
|
|
26
39
|
authorized: false,
|
|
40
|
+
loading: false,
|
|
27
41
|
};
|
|
28
42
|
}
|
|
29
43
|
|
|
@@ -33,6 +47,7 @@ export const withAuthLoader = async <T>(
|
|
|
33
47
|
authorized: true,
|
|
34
48
|
data: pageData,
|
|
35
49
|
clientContext: { cookie, userId, ...clientContext },
|
|
50
|
+
loading: false,
|
|
36
51
|
};
|
|
37
52
|
} catch (error) {
|
|
38
53
|
console.error("Auth validation failed:", error);
|
|
@@ -42,6 +57,7 @@ export const withAuthLoader = async <T>(
|
|
|
42
57
|
|
|
43
58
|
return {
|
|
44
59
|
authorized: false,
|
|
60
|
+
loading: false,
|
|
45
61
|
};
|
|
46
62
|
}
|
|
47
63
|
};
|
|
@@ -2,13 +2,14 @@ import { useEffect, type ComponentType } from "react";
|
|
|
2
2
|
|
|
3
3
|
import { useRouter } from "next/router";
|
|
4
4
|
|
|
5
|
-
import { BuyerPortalProvider } from "../components";
|
|
5
|
+
import { BuyerPortalProvider, PageLoader } from "../components";
|
|
6
6
|
|
|
7
7
|
import type { AuthRouteProps } from "../types";
|
|
8
8
|
import type { ClientContext } from "./getClientContext";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* HOC que encapsula lógica de autenticação e provider
|
|
11
|
+
* HOC que encapsula lógica de autenticação e provider.
|
|
12
|
+
* Now handles loading state for pre-fetch scenarios.
|
|
12
13
|
*/
|
|
13
14
|
export const withAuthProvider = <T,>(
|
|
14
15
|
Component: ComponentType<T & { clientContext: ClientContext }>
|
|
@@ -17,13 +18,18 @@ export const withAuthProvider = <T,>(
|
|
|
17
18
|
const router = useRouter();
|
|
18
19
|
|
|
19
20
|
useEffect(() => {
|
|
20
|
-
// Se não está autorizado, recarrega a página
|
|
21
|
-
if (!props?.authorized) {
|
|
21
|
+
// Se não está autorizado e não está carregando, recarrega a página
|
|
22
|
+
if (!props?.authorized && !props?.loading) {
|
|
22
23
|
router.reload();
|
|
23
24
|
}
|
|
24
|
-
}, [props?.authorized, router]);
|
|
25
|
+
}, [props?.authorized, props?.loading, router]);
|
|
25
26
|
|
|
26
|
-
// Se
|
|
27
|
+
// Se está carregando (cookie ainda não disponível), mostra skeleton
|
|
28
|
+
if (props?.loading) {
|
|
29
|
+
return <PageLoader />;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Se não está autorizado e não está carregando, não renderiza nada
|
|
27
33
|
if (!props?.authorized) {
|
|
28
34
|
return null;
|
|
29
35
|
}
|
package/src/themes/index.scss
CHANGED