@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vtex/faststore-plugin-buyer-portal",
3
- "version": "1.1.110",
3
+ "version": "1.1.112",
4
4
  "description": "A plugin for faststore with buyer portal",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -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
- <a href={href} data-fs-addresses-line-link>
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
- </a>
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
- // import Link from "next/link";
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
- <a
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
- </a>
44
+ </Link>
45
45
  )}
46
46
  </div>
47
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
- <a href="/" data-fs-bp-org-unit-details-navbar-link>
33
+ <Link href="/" data-fs-bp-org-unit-details-navbar-link>
34
34
  {storeConfig.seo.title}
35
- </a>
35
+ </Link>
36
36
  <div data-fs-bp-org-unit-details-navbar-actions>
37
- <a href="/" data-fs-bp-org-unit-details-navbar-start-shopping-link>
37
+ <Link href="/" data-fs-bp-org-unit-details-navbar-start-shopping-link>
38
38
  Start shopping
39
- </a>
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
- // 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
- <a data-fs-self-profile-summary-org-link href="/buyer-portal">
38
+ <Link data-fs-self-profile-summary-org-link href="/buyer-portal">
39
39
  Manage Organization <Icon name="OpenInNew" width={23} height={23} />
40
- </a>
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
- // 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
- <a href={footerLink} data-fs-card-footer-link>
61
+ <Link href={footerLink} data-fs-card-footer-link>
62
62
  <span>{footerMessage}</span>
63
- </a>
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
- // 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 && <a data-fs-basic-card-line-link href={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
- // 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
- <a href={backLink} data-fs-bp-back-link>
24
+ <Link href={backLink} data-fs-bp-back-link>
25
25
  <Icon name="Back" />
26
- </a>
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
- // 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
- <a href={href}>
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
- </a>
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
- // 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
- <a
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
- </a>
33
+ </Link>
34
34
  </li>
35
35
  );
36
36
  };
@@ -1,4 +1,5 @@
1
1
  export { useBuyerPortal } from "./useBuyerPortal";
2
+ export { useCookieMonitor } from "./useCookieMonitor";
2
3
  export { useDrawerProps, type DrawerProps } from "./useDrawerProps";
3
4
  export {
4
5
  useMutation,
@@ -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
- // 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
- <a href="/" data-fs-bp-org-unit-details-navbar-link>
29
+ <Link href="/" data-fs-bp-org-unit-details-navbar-link>
30
30
  {storeConfig.seo.title}
31
- </a>
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
- // If loading (cookie not yet available), show skeleton
27
- if (props?.loading) {
28
- return <PageLoader />;
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
- // Se está carregando (cookie ainda não disponível), mostra skeleton
28
- if (props?.loading) {
29
- return <PageLoader />;
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} />