@vtex/faststore-plugin-buyer-portal 1.0.1 → 1.0.3

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 (30) hide show
  1. package/package.json +4 -3
  2. package/src/components/CustomerSwitch/CustomerSwitchDrawer.tsx +113 -0
  3. package/src/components/CustomerSwitch/CustomerSwitchOption.tsx +32 -0
  4. package/src/components/CustomerSwitch/CustomerSwitchOptionsList.tsx +34 -0
  5. package/src/components/CustomerSwitch/CustomerSwitchSearch.tsx +44 -0
  6. package/src/components/CustomerSwitch/customer-switch.scss +130 -0
  7. package/src/components/Icons/Link.tsx +17 -0
  8. package/src/components/Icons/Load.tsx +42 -0
  9. package/src/components/Icons/Profile.tsx +15 -0
  10. package/src/components/Icons/index.ts +8 -0
  11. package/src/components/Logo/Logo.tsx +18 -0
  12. package/src/components/Navbar/Navbar.tsx +37 -0
  13. package/src/components/Navbar/navbar.scss +50 -0
  14. package/src/components/ProfileSummary/ProfileSummary.tsx +49 -0
  15. package/src/components/ProfileSummary/profile-summary.scss +73 -0
  16. package/src/components/SelfManagementDrawer/SelfManagementDrawer.tsx +57 -0
  17. package/src/components/SelfManagementDrawer/SelfManagementDrawerBody.tsx +23 -0
  18. package/src/components/SelfManagementDrawer/SelfManagementDrawerHeader.tsx +35 -0
  19. package/src/components/SelfManagementDrawer/index.ts +3 -0
  20. package/src/components/SelfManagementDrawer/self-management-drawer.scss +86 -0
  21. package/src/components/SelfManagementSignInButton/SelfManagementSignInButton.tsx +46 -0
  22. package/src/components/SelfManagementSignInButton/index.ts +1 -0
  23. package/src/components/overrides/Navbar.tsx +16 -0
  24. package/src/global.d.ts +1 -0
  25. package/src/mock/profile-data.ts +7 -0
  26. package/src/pages/buyer-portal.tsx +3 -1
  27. package/src/themes/index.scss +11 -1
  28. package/src/utils/logout.tsx +5 -0
  29. package/src/utils/orders.tsx +3 -0
  30. package/tsconfig.json +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vtex/faststore-plugin-buyer-portal",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "A plugin for faststore with buyer portal",
5
5
  "main": "index.js",
6
6
  "dependencies": {
@@ -9,13 +9,14 @@
9
9
  },
10
10
  "devDependencies": {
11
11
  "@faststore/core": "^3.0.147",
12
- "@types/react": "^18.3.12",
13
- "@types/react-dom": "^18.3.1",
12
+ "@faststore/ui": "^3.0.147",
13
+ "@types/react": "^18.2.42",
14
14
  "next": "13.5.6",
15
15
  "typescript": "4.7.3"
16
16
  },
17
17
  "peerDependencies": {
18
18
  "@faststore/core": "^3.0.147",
19
+ "@faststore/ui": "^3.0.147",
19
20
  "next": "13.5.6"
20
21
  },
21
22
  "license": "MIT"
@@ -0,0 +1,113 @@
1
+ import { SlideOver, useFadeEffect } from "@faststore/ui";
2
+ import { Button, SlideOverHeader } from "@faststore/ui";
3
+ import { CustomerSwitchSearch } from "./CustomerSwitchSearch";
4
+ import { CustomerSwitchOptionsList } from "./CustomerSwitchOptionsList";
5
+ import { useMemo, useState } from "react";
6
+ import { CustomerSwitchOptionData } from "./CustomerSwitchOption";
7
+ import * as Icons from "../Icons";
8
+
9
+ type CustomerSwitchDrawerProps = {
10
+ isOpen: boolean;
11
+ onCloseDrawer?: () => void;
12
+ };
13
+
14
+ // TODO: Remove mock
15
+ const options = [
16
+ "Finance Solutions",
17
+ "Stellar Innovations",
18
+ "Blue Horizon Corp",
19
+ "Prime Finance Group",
20
+ "Stellar Ventures",
21
+ "Evergreen Holdings",
22
+ "Finance Pro Consulting",
23
+ "Stellar Strategies",
24
+ "Pioneer Technologies",
25
+ "Global Finance Advisors",
26
+ "TechWave Solutions",
27
+ "Stellar Capital Partners",
28
+ "FinanceEdge Analytics",
29
+ "Quantum Dynamics",
30
+ "Stellar Growth Advisors",
31
+ "BrightFuture Enterprises",
32
+ "FinanceLink Solutions",
33
+ "Stellar Insights",
34
+ "Vanguard Finance Group",
35
+ "FinanceBridge Consulting",
36
+ "Stellar Visionary Labs",
37
+ "NextGen Finance",
38
+ "OceanView Investments",
39
+ "Stellar Nexus",
40
+ "Crestpoint Finance Partners ksldkadlsdkapkldjfdlkfjhdlskjfhdsklajfhdslkfjh",
41
+ "Finance Elevate",
42
+ "Lighthouse Consulting Group",
43
+ "Stellar Synergy",
44
+ "FinanceCore Solutions",
45
+ "Nova Finance Advisors",
46
+ ].map((name, index) => ({ name, id: `id-${index}` }));
47
+
48
+ export const CustomerSwitchDrawer = ({
49
+ isOpen,
50
+ onCloseDrawer,
51
+ }: CustomerSwitchDrawerProps) => {
52
+ const { fade, fadeOut } = useFadeEffect();
53
+
54
+ const [option, setOption] = useState<CustomerSwitchOptionData>(options[0]);
55
+ const [loading, setLoading] = useState(false);
56
+ const [searchTerm, setSearchTerm] = useState("");
57
+
58
+ const filteredOptions = useMemo(() => {
59
+ if (!searchTerm) {
60
+ return options;
61
+ }
62
+ return options.filter((currentOption) =>
63
+ currentOption.name?.toLowerCase().includes(searchTerm.toLowerCase())
64
+ );
65
+ }, [options, searchTerm]);
66
+
67
+ const handleSubmitCustomer = () => {
68
+ console.log(option);
69
+ setLoading(true);
70
+ setTimeout(() => {
71
+ setLoading(false);
72
+ onCloseDrawer?.();
73
+ }, 3000);
74
+ };
75
+
76
+ return (
77
+ <SlideOver
78
+ data-fs-customer-switch-drawer
79
+ fade={fade}
80
+ onDismiss={fadeOut}
81
+ onTransitionEnd={() => fade === "out" && onCloseDrawer?.()}
82
+ isOpen={isOpen}
83
+ size="partial"
84
+ direction="rightSide"
85
+ >
86
+ <SlideOverHeader
87
+ data-fs-customer-switch-drawer-header
88
+ onClose={() => onCloseDrawer?.()}
89
+ >
90
+ <h1 data-fs-customer-switch-drawer-title>Switch customer ID</h1>
91
+ </SlideOverHeader>
92
+
93
+ <section data-fs-customer-switch-drawer-body>
94
+ <CustomerSwitchSearch onSearch={setSearchTerm} />
95
+ <CustomerSwitchOptionsList
96
+ currentCustomer={options[0]}
97
+ options={filteredOptions}
98
+ onChange={setOption}
99
+ />
100
+ </section>
101
+
102
+ <footer data-fs-customer-switch-drawer-footer>
103
+ <Button
104
+ data-fs-customer-switch-drawer-button
105
+ onClick={handleSubmitCustomer}
106
+ disabled={option.id === options[0].id || loading}
107
+ >
108
+ {loading ? <Icons.Load width={16} height={16} /> : "Confirm"}
109
+ </Button>
110
+ </footer>
111
+ </SlideOver>
112
+ );
113
+ };
@@ -0,0 +1,32 @@
1
+ export type CustomerSwitchOptionData = { name: string; id: string };
2
+
3
+ export type CustomerSwitchOptionProps = CustomerSwitchOptionData & {
4
+ onChange?: (option: CustomerSwitchOptionProps) => void;
5
+ defaultChecked?: boolean;
6
+ };
7
+
8
+ export const CustomerSwitchOption = ({
9
+ name,
10
+ id,
11
+ onChange,
12
+ ...otherProps
13
+ }: CustomerSwitchOptionProps) => (
14
+ <>
15
+ <input
16
+ data-fs-customer-switch-option-input
17
+ type="radio"
18
+ id={id}
19
+ name="CustomerSwitchOption"
20
+ value={id}
21
+ onChange={() => onChange?.({ name, id })}
22
+ {...otherProps}
23
+ />
24
+ <label
25
+ data-fs-customer-switch-option
26
+ htmlFor={id}
27
+ >
28
+ <div data-fs-customer-switch-option-profile> {name[0]} </div>
29
+ <span data-fs-customer-switch-option-name> {name} </span>
30
+ </label>
31
+ </>
32
+ );
@@ -0,0 +1,34 @@
1
+ import { CustomerSwitchOption, CustomerSwitchOptionProps } from "./CustomerSwitchOption";
2
+
3
+ export type CustomerSwitchOptionsListProps = {
4
+ options: Array<CustomerSwitchOptionProps>;
5
+ currentCustomer: CustomerSwitchOptionProps;
6
+ onChange?: (option: CustomerSwitchOptionProps) => void;
7
+ };
8
+
9
+ export const CustomerSwitchOptionsList = ({
10
+ options,
11
+ currentCustomer,
12
+ onChange,
13
+ }: CustomerSwitchOptionsListProps) => {
14
+ return (
15
+ <div data-fs-customer-options-list>
16
+ <CustomerSwitchOption
17
+ defaultChecked
18
+ name={currentCustomer.name}
19
+ id={currentCustomer.id}
20
+ onChange={onChange}
21
+ />
22
+ {options
23
+ .filter((customerOption) => customerOption.id !== currentCustomer.id)
24
+ .map((customerOption) => (
25
+ <CustomerSwitchOption
26
+ name={customerOption.name}
27
+ id={customerOption.id}
28
+ key={customerOption.id}
29
+ onChange={onChange}
30
+ />
31
+ ))}
32
+ </div>
33
+ );
34
+ };
@@ -0,0 +1,44 @@
1
+ import {
2
+ useRef,
3
+ type FormEvent,
4
+ } from "react";
5
+
6
+ import { Input, IconButton, Icon } from "@faststore/ui";
7
+
8
+ export type CustomerSwitchSearchProps = {
9
+ onSearch?: (term: string) => void
10
+ };
11
+
12
+ export const CustomerSwitchSearch = ({
13
+ onSearch
14
+ }: CustomerSwitchSearchProps) => {
15
+
16
+ const inputRef = useRef<HTMLInputElement>(null);
17
+
18
+ const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
19
+ event.preventDefault();
20
+ const inputValue = inputRef.current?.value;
21
+ onSearch?.(inputValue || "");
22
+ };
23
+
24
+ return (
25
+ <form
26
+ data-fs-customer-switch-search
27
+ onSubmit={handleSubmit}
28
+ role="search"
29
+ >
30
+ <IconButton
31
+ data-fs-customer-switch-search-button
32
+ type="submit"
33
+ aria-label="Submit Search"
34
+ icon={<Icon name="MagnifyingGlass" />}
35
+ size="small"
36
+ />
37
+ <Input
38
+ data-fs-customer-switch-search-input
39
+ placeholder="Search"
40
+ ref={inputRef}
41
+ />
42
+ </form>
43
+ );
44
+ };
@@ -0,0 +1,130 @@
1
+ [data-fs-customer-switch-drawer] {
2
+ // --------------------------------------------------------
3
+ // Colors (Branding Core)
4
+ // --------------------------------------------------------
5
+ --fs-color-tertiary-bkg : #CBE9FF;
6
+ --fs-border-color-light : #EBEBEB;
7
+
8
+ display: flex;
9
+ flex-direction: column;
10
+
11
+ [data-fs-customer-switch-drawer-header] {
12
+ align-items: flex-start;
13
+ padding: calc(var(--fs-spacing-3) + var(--fs-spacing-0));
14
+
15
+ [data-fs-customer-switch-drawer-title] {
16
+ font-size: var(--fs-text-size-title-section);
17
+ font-weight: var(--fs-text-weight-semibold);
18
+ margin-top: var(--fs-spacing-6);
19
+ padding-left: var(--fs-spacing-6);
20
+ text-transform: capitalize;
21
+ }
22
+
23
+ }
24
+
25
+ [data-fs-customer-switch-drawer-body] {
26
+ display: flex;
27
+ flex-direction: column;
28
+ padding: 0 calc(var(--fs-spacing-2) + var(--fs-spacing-7));
29
+ flex: 1;
30
+ overflow: hidden;
31
+
32
+ [data-fs-customer-switch-search] {
33
+ width: 100%;
34
+ border: var(--fs-border-width) solid var(--fs-border-color-light);
35
+ border-radius: var(--fs-border-radius-pill);
36
+ padding: var(--fs-spacing-1) var(--fs-spacing-2);
37
+ display: flex;
38
+ align-items: center;
39
+
40
+ [data-fs-customer-switch-search-button] {
41
+ margin-right: var(--fs-spacing-1);
42
+ }
43
+
44
+ [data-fs-customer-switch-search-input]{
45
+ width: 100%;
46
+ border: 0;
47
+ outline: 0;
48
+ }
49
+ }
50
+
51
+ [data-fs-customer-options-list] {
52
+ display: flex;
53
+ flex-direction: column;
54
+ flex: 1;
55
+ overflow: scroll;
56
+ margin-top: calc(var(--fs-spacing-3) + var(--fs-spacing-0));
57
+
58
+ [data-fs-customer-switch-option-input] {
59
+ display: none;
60
+ }
61
+
62
+ [data-fs-customer-switch-option] {
63
+ display: flex;
64
+ align-items: center;
65
+ margin-top: var(--fs-spacing-1);
66
+ border: var(--fs-border-width) solid var(--fs-border-color-light);
67
+ padding: calc(var(--fs-spacing-3) + var(--fs-spacing-0));
68
+ border-radius: var(--fs-border-radius-medium);
69
+ cursor: pointer;
70
+
71
+ [data-fs-customer-switch-option-profile] {
72
+ min-width: var(--fs-spacing-4);
73
+ aspect-ratio: 1;
74
+ display: flex;
75
+ align-items: center;
76
+ justify-content: center;
77
+ border-radius: var(--fs-border-radius-circle);
78
+ background-color: var(--fs-color-tertiary-bkg);
79
+ font-size: var(--fs-text-size-tiny);
80
+ font-weight: var(--fs-text-weight-semibold);
81
+ margin-right: var(--fs-spacing-2);
82
+ text-transform: capitalize;
83
+ }
84
+
85
+ [data-fs-customer-switch-option-name] {
86
+ font-size: var(--fs-text-size-legend);
87
+ font-weight: var(--fs-text-weight-medium);
88
+ width: 100%;
89
+ overflow: hidden;
90
+ white-space: nowrap;
91
+ text-overflow: ellipsis;
92
+ text-transform: capitalize;
93
+ }
94
+ }
95
+
96
+ [data-fs-customer-switch-option-input]:checked + [data-fs-customer-switch-option] {
97
+ border-color: var(--fs-color-primary-bkg);
98
+ background-color: var(--fs-color-primary-bkg-light-active);
99
+ }
100
+
101
+ [data-fs-customer-switch-option]:first-of-type {
102
+ margin-top: 0;
103
+ }
104
+
105
+ [data-fs-customer-switch-option]:last-of-type {
106
+ margin-bottom: var(--fs-spacing-1);
107
+ }
108
+ }
109
+ }
110
+
111
+ [data-fs-customer-switch-drawer-footer] {
112
+ padding: var(--fs-spacing-4) calc(var(--fs-spacing-2) + var(--fs-spacing-7));
113
+ border-top: var(--fs-border-width) solid var(--fs-border-color-light);
114
+
115
+ [data-fs-customer-switch-drawer-button] {
116
+ width: 100%;
117
+ padding: var(--fs-spacing-3) var(--fs-spacing-5);
118
+ background-color: var(--fs-color-primary-bkg);
119
+ color: var(--fs-color-text-inverse);
120
+ border-radius: var(--fs-border-radius-pill);
121
+ font-size: var(--fs-text-size-1);
122
+ font-weight: var(--fs-text-weight-semibold);
123
+ }
124
+
125
+ [data-fs-customer-switch-drawer-button]:disabled {
126
+ background-color: var(--fs-color-disabled-bkg);
127
+ }
128
+ }
129
+
130
+ }
@@ -0,0 +1,17 @@
1
+ import { IconProps } from ".";
2
+
3
+ export const Link = ({ ...props }: IconProps) => (
4
+ <svg
5
+ xmlns="http://www.w3.org/2000/svg"
6
+ viewBox="0 0 10 10"
7
+ fill="none"
8
+ {...props}
9
+ >
10
+ <path
11
+ fill-rule="evenodd"
12
+ clip-rule="evenodd"
13
+ d="M1.75 1C1.75 0.585786 2.08579 0.25 2.5 0.25H9C9.41421 0.25 9.75 0.585786 9.75 1V7.5C9.75 7.91421 9.41421 8.25 9 8.25C8.58579 8.25 8.25 7.91421 8.25 7.5V2.81066L1.53033 9.53033C1.23744 9.82322 0.762563 9.82322 0.46967 9.53033C0.176777 9.23744 0.176777 8.76256 0.46967 8.46967L7.18934 1.75H2.5C2.08579 1.75 1.75 1.41421 1.75 1Z"
14
+ fill="#3D3D3D"
15
+ />
16
+ </svg>
17
+ );
@@ -0,0 +1,42 @@
1
+ import { IconProps } from ".";
2
+
3
+ export const Load = ({ ...props }: IconProps) => (
4
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" {...props}>
5
+ <g stroke="currentColor">
6
+ <circle
7
+ cx="12"
8
+ cy="12"
9
+ r="9.5"
10
+ fill="none"
11
+ stroke-linecap="round"
12
+ stroke-width="3"
13
+ >
14
+ <animate
15
+ attributeName="stroke-dasharray"
16
+ calcMode="spline"
17
+ dur="1.5s"
18
+ keySplines="0.42,0,0.58,1;0.42,0,0.58,1;0.42,0,0.58,1"
19
+ keyTimes="0;0.475;0.95;1"
20
+ repeatCount="indefinite"
21
+ values="0 150;42 150;42 150;42 150"
22
+ />
23
+ <animate
24
+ attributeName="stroke-dashoffset"
25
+ calcMode="spline"
26
+ dur="1.5s"
27
+ keySplines="0.42,0,0.58,1;0.42,0,0.58,1;0.42,0,0.58,1"
28
+ keyTimes="0;0.475;0.95;1"
29
+ repeatCount="indefinite"
30
+ values="0;-16;-59;-59"
31
+ />
32
+ </circle>
33
+ <animateTransform
34
+ attributeName="transform"
35
+ dur="2s"
36
+ repeatCount="indefinite"
37
+ type="rotate"
38
+ values="0 12 12;360 12 12"
39
+ />
40
+ </g>
41
+ </svg>
42
+ );
@@ -0,0 +1,15 @@
1
+ import { IconProps } from ".";
2
+
3
+ export const Profile = ({ ...props }: IconProps) => (
4
+ <svg
5
+ xmlns="http://www.w3.org/2000/svg"
6
+ viewBox="0 0 14 14"
7
+ fill="none"
8
+ {...props}
9
+ >
10
+ <path
11
+ d="M7.00065 7.00114C6.08398 7.00114 5.29926 6.67475 4.64648 6.02197C3.99371 5.3692 3.66732 4.58447 3.66732 3.66781C3.66732 2.75114 3.99371 1.96642 4.64648 1.31364C5.29926 0.660862 6.08398 0.334473 7.00065 0.334473C7.91732 0.334473 8.70204 0.660862 9.35482 1.31364C10.0076 1.96642 10.334 2.75114 10.334 3.66781C10.334 4.58447 10.0076 5.3692 9.35482 6.02197C8.70204 6.67475 7.91732 7.00114 7.00065 7.00114ZM0.333984 13.6678V11.3345C0.333984 10.8623 0.455512 10.4282 0.698568 10.0324C0.941623 9.63656 1.26454 9.33447 1.66732 9.12614C2.52843 8.69559 3.40343 8.37267 4.29232 8.15739C5.18121 7.94211 6.08398 7.83447 7.00065 7.83447C7.91732 7.83447 8.8201 7.94211 9.70899 8.15739C10.5979 8.37267 11.4729 8.69559 12.334 9.12614C12.7368 9.33447 13.0597 9.63656 13.3027 10.0324C13.5458 10.4282 13.6673 10.8623 13.6673 11.3345V13.6678H0.333984Z"
12
+ fill="#0366DD"
13
+ />
14
+ </svg>
15
+ );
@@ -0,0 +1,8 @@
1
+ export type IconProps = {
2
+ width: number;
3
+ height: number;
4
+ };
5
+
6
+ export { Profile } from "./Profile";
7
+ export { Link } from "./Link";
8
+ export { Load } from "./Load";
@@ -0,0 +1,18 @@
1
+ import { Image_unstable as Image } from "@faststore/core/experimental";
2
+
3
+ const logoSrc =
4
+ "https://b2bfaststoredev.vtexassets.com/unsafe/1440x0/center/middle/https%3A%2F%2Fstoreframework.vtexassets.com%2Fassets%2Fvtex.file-manager-graphql%2Fimages%2Fab9997f4-8fd6-46f5-99d2-9d5af3ef5e34___6d75a203771d7408d8f0d1c660a076dd.png";
5
+
6
+ export const Logo = () => (
7
+ <div data-fs-logo>
8
+ <Image
9
+ alt="Logo"
10
+ src={logoSrc}
11
+ width={0}
12
+ height={0}
13
+ sizes="15vw"
14
+ loading="lazy"
15
+ style={{ width: "100%", height: "auto" }}
16
+ />
17
+ </div>
18
+ );
@@ -0,0 +1,37 @@
1
+ import * as Icons from "../Icons";
2
+ import { Logo } from "../Logo/Logo";
3
+ import Link from "next/link";
4
+
5
+ import { Dropdown, DropdownMenu, DropdownButton } from "@faststore/ui";
6
+ import { ProfileSummary } from "../ProfileSummary/ProfileSummary";
7
+ import { doLogout } from "../../utils/logout";
8
+ import { profileData } from "../../mock/profile-data";
9
+
10
+ export const Navbar = () => {
11
+ return (
12
+ <header data-fs-buyer-portal-navbar>
13
+ <Logo />
14
+ <div data-fs-header-actions>
15
+ <Link href="/" data-fs-start-shopping-link>
16
+ <span>Start Shopping</span>
17
+ <Icons.Link width={10} height={10} />
18
+ </Link>
19
+ <Dropdown>
20
+ <DropdownButton asChild>
21
+ <button data-fs-profile-dropdown-trigger>
22
+ <Icons.Profile width={14} height={14} />
23
+ </button>
24
+ </DropdownButton>
25
+
26
+ <DropdownMenu align="right" data-fs-profile-dropdown-menu>
27
+ <ProfileSummary
28
+ data-fs-profile-dropdown-menu-profile-summary
29
+ onLogoutClick={doLogout}
30
+ {...profileData}
31
+ />
32
+ </DropdownMenu>
33
+ </Dropdown>
34
+ </div>
35
+ </header>
36
+ );
37
+ };
@@ -0,0 +1,50 @@
1
+ [data-fs-buyer-portal-navbar] {
2
+ display: flex;
3
+ justify-content: space-between;
4
+ align-items: center;
5
+ padding: var(--fs-spacing-3) calc(var(--fs-spacing-8) + var(--fs-spacing-0));
6
+ background-color: #f5f5f5;
7
+
8
+ [data-fs-header-actions] {
9
+ display: flex;
10
+ align-items: center;
11
+ }
12
+
13
+ [data-fs-start-shopping-link] {
14
+ display: flex;
15
+ align-items: center;
16
+ justify-content: center;
17
+
18
+ color: #3d3d3d;
19
+ font-weight: var(--fs-text-weight-semibold);
20
+ font-family: "Inter", sans-serif;
21
+ line-height: calc(var(--fs-spacing-3) + var(--fs-spacing-0));
22
+ font-size: var(--fs-text-size-2);
23
+ text-decoration: none;
24
+ margin-right: calc(var(--fs-spacing-3) + var(--fs-spacing-0));
25
+
26
+ span {
27
+ margin-right: var(--fs-spacing-0);
28
+ }
29
+ }
30
+
31
+ [data-fs-profile-dropdown-trigger] {
32
+ display: flex;
33
+ justify-content: center;
34
+ align-items: center;
35
+ border-radius: var(--fs-border-radius-circle);
36
+ background-color: #cbe9ff;
37
+ width: var(--fs-spacing-5);
38
+ height: var(--fs-spacing-5);
39
+ }
40
+ }
41
+
42
+ [data-fs-profile-dropdown-menu] {
43
+ --fs-profile-dropdown-menu-width: 360px;
44
+
45
+ background-color: white;
46
+
47
+ [data-fs-profile-dropdown-menu-profile-summary] {
48
+ min-width: var(--fs-profile-dropdown-menu-width);
49
+ }
50
+ }
@@ -0,0 +1,49 @@
1
+ import { ReactNode } from "react";
2
+ import { Button } from "@faststore/ui";
3
+ import * as Icons from "../Icons";
4
+
5
+ export type ProfileSummaryProps = {
6
+ onLogoutClick?: (storeConfig: any) => void;
7
+ orgName: string;
8
+ bordered?: boolean;
9
+ person: {
10
+ image?: ReactNode;
11
+ name: string;
12
+ role?: string;
13
+ };
14
+ };
15
+
16
+ export const ProfileSummary = ({
17
+ onLogoutClick,
18
+ person: { image, name, role },
19
+ orgName,
20
+ bordered = false,
21
+ ...otherProps
22
+ }: ProfileSummaryProps) => {
23
+ return (
24
+ <section
25
+ data-fs-self-profile-summary
26
+ data-fs-self-profile-summary-bordered={bordered}
27
+ {...otherProps}
28
+ >
29
+ <h2 data-fs-self-profile-summary-org-name>{orgName}</h2>
30
+ <div data-fs-self-profile-summary-person-actions>
31
+ <div data-fs-self-profile-summary-person-image>
32
+ {image ?? <Icons.Profile width={14} height={14} />}
33
+ </div>
34
+ <div data-fs-self-profile-summary-person-data>
35
+ <h2>{name}</h2>
36
+ {role && <h3>{role}</h3>}
37
+ </div>
38
+ <Button
39
+ data-fs-self-profile-summary-logout-button
40
+ onClick={onLogoutClick}
41
+ variant="secondary"
42
+ size="small"
43
+ >
44
+ Logout
45
+ </Button>
46
+ </div>
47
+ </section>
48
+ );
49
+ };
@@ -0,0 +1,73 @@
1
+ [data-fs-self-profile-summary] {
2
+ display: flex;
3
+ flex-direction: column;
4
+ width: 100%;
5
+
6
+ &[data-fs-self-profile-summary-bordered="true"] {
7
+ border: var(--fs-border-width) solid #e0e0e0;
8
+ border-radius: var(--fs-border-radius);
9
+ }
10
+ }
11
+
12
+ [data-fs-self-profile-summary-org-name] {
13
+ font-size: var(--fs-text-size-legend);
14
+ color: #000000;
15
+ font-weight: var(--fs-text-weight-semibold);
16
+ padding: calc(var(--fs-spacing-3) + var(--fs-spacing-0));
17
+ border-bottom: var(--fs-border-width) solid #e0e0e0;
18
+ }
19
+
20
+ [data-fs-self-profile-summary-person-actions] {
21
+ display: flex;
22
+ justify-content: space-between;
23
+ padding: calc(var(--fs-spacing-3) + var(--fs-spacing-0));
24
+
25
+ [data-fs-self-profile-summary-person-image] {
26
+ width: var(--fs-spacing-6);
27
+ height: var(--fs-spacing-6);
28
+ border-radius: var(--fs-border-radius-pill);
29
+ background-color: #cbe9ff;
30
+ display: flex;
31
+ align-items: center;
32
+ justify-content: center;
33
+ overflow: hidden;
34
+ color: var(--fs-border-color-active);
35
+ margin-right: var(--fs-spacing-3);
36
+ }
37
+
38
+ [data-fs-self-profile-summary-person-data] {
39
+ flex: 1;
40
+ font-size: var(--fs-text-size-legend);
41
+
42
+ h2 {
43
+ color: var(--fs-color-text);
44
+ font-weight: var(--fs-text-weight-regular);
45
+ }
46
+
47
+ h3 {
48
+ color: var(--fs-color-text-light);
49
+ font-weight: var(--fs-text-weight-light);
50
+ }
51
+ }
52
+
53
+ [data-fs-self-profile-summary-logout-button] {
54
+ cursor: pointer;
55
+ color: #d31a15;
56
+ font-weight: var(--fs-text-weight-semibold);
57
+
58
+ [data-fs-button-wrapper] {
59
+ border-radius: var(--fs-border-radius-pill);
60
+ color: var(--fs-color-danger-text);
61
+ border: var(--fs-border-width) solid var(--fs-border-color-light);
62
+ padding: var(--fs-spacing-1) var(--fs-spacing-4);
63
+ }
64
+
65
+ [data-fs-button-wrapper]:hover {
66
+ color: var(--fs-color-danger-text);
67
+ }
68
+
69
+ [data-fs-icon] {
70
+ color: var(--fs-color-danger-text);
71
+ }
72
+ }
73
+ }
@@ -0,0 +1,57 @@
1
+ import { SlideOver, useFadeEffect } from "@faststore/ui";
2
+
3
+ import { SelfManagementDrawerHeader } from "./SelfManagementDrawerHeader";
4
+ import { SelfManagementDrawerBody } from "./SelfManagementDrawerBody";
5
+ import { doLogout } from "../../utils/logout";
6
+ import { useState } from "react";
7
+ import { CustomerSwitchDrawer } from "../CustomerSwitch/CustomerSwitchDrawer";
8
+ import { ProfileSummary } from "../ProfileSummary/ProfileSummary";
9
+ import { profileData } from "../../mock/profile-data";
10
+
11
+ type SelfManagementDrawerProps = {
12
+ isOpen: boolean;
13
+ closeDrawer: () => void;
14
+ };
15
+
16
+ export const SelfManagementDrawer = ({
17
+ isOpen,
18
+ closeDrawer,
19
+ }: SelfManagementDrawerProps) => {
20
+ const { fade, fadeOut } = useFadeEffect();
21
+ const [openCustomerDrawer, setOpenCustomerDrawer] = useState(false);
22
+
23
+ return (
24
+ <>
25
+ <SlideOver
26
+ data-fs-self-management-drawer
27
+ fade={fade}
28
+ onDismiss={fadeOut}
29
+ onTransitionEnd={() => fade === "out" && closeDrawer()}
30
+ isOpen={isOpen}
31
+ size="partial"
32
+ direction="rightSide"
33
+ >
34
+ <SelfManagementDrawerHeader
35
+ onCloseDrawer={closeDrawer}
36
+ onSwitchButtonClick={() => setOpenCustomerDrawer(true)}
37
+ orgName="Stellar Inc."
38
+ orgUrl="/self-management"
39
+ />
40
+ <SelfManagementDrawerBody />
41
+ <footer data-fs-self-management-drawer-footer-wrapper>
42
+ <ProfileSummary
43
+ bordered={true}
44
+ onLogoutClick={doLogout}
45
+ {...profileData}
46
+ />
47
+ </footer>
48
+ </SlideOver>
49
+ {openCustomerDrawer && (
50
+ <CustomerSwitchDrawer
51
+ isOpen={openCustomerDrawer}
52
+ onCloseDrawer={() => setOpenCustomerDrawer(false)}
53
+ />
54
+ )}
55
+ </>
56
+ );
57
+ };
@@ -0,0 +1,23 @@
1
+ import { Link } from '@faststore/ui'
2
+
3
+ import { goToOrders } from '../../utils/orders'
4
+
5
+ export const SelfManagementDrawerBody = (storeConfig: any) => {
6
+
7
+ const onClickOrders = (event: any) => {
8
+ event.preventDefault()
9
+
10
+ goToOrders(storeConfig)
11
+ }
12
+
13
+ return (
14
+ <>
15
+ <div data-fs-self-management-drawer-body>
16
+ <div data-fs-self-mamnagement-drawer-body-contents>
17
+ <Link data-fs-self-management-drawer-body-link onClick={onClickOrders} href={'account/orders'}>Orders</Link>
18
+ <Link data-fs-self-management-drawer-body-link href={'account'}>Preferences</Link>
19
+ </div>
20
+ </div>
21
+ </>
22
+ )
23
+ }
@@ -0,0 +1,35 @@
1
+ import { ReactNode } from "react";
2
+ import { Button, IconButton, SlideOverHeader, Link, Icon } from "@faststore/ui";
3
+ import * as Icons from "../Icons";
4
+
5
+ export type SelfManagementDrawerHeaderProps = {
6
+ onCloseDrawer?: () => void;
7
+ onSwitchButtonClick?: () => void;
8
+ onConfigButtonClick?: () => void;
9
+ orgImage?: ReactNode;
10
+ orgName: string;
11
+ orgUrl: string;
12
+ };
13
+
14
+ export const SelfManagementDrawerHeader = ({
15
+ orgUrl,
16
+ orgName,
17
+ orgImage,
18
+ onCloseDrawer,
19
+ onSwitchButtonClick,
20
+ onConfigButtonClick,
21
+ }: SelfManagementDrawerHeaderProps) => {
22
+ return (
23
+ <>
24
+ <SlideOverHeader onClose={() => onCloseDrawer?.()} children={null} />
25
+ <div data-fs-self-management-drawer-header>
26
+ <Link data-fs-self-management-drawer-header-org-link href={orgUrl}>
27
+ <div data-fs-self-management-drawer-header-org-image>
28
+ {orgImage ?? <Icons.Profile width={24} height={24} />}
29
+ </div>
30
+ <h1 data-fs-self-management-drawer-header-org-name>{orgName}</h1>
31
+ </Link>
32
+ </div>
33
+ </>
34
+ );
35
+ };
@@ -0,0 +1,3 @@
1
+ export { SelfManagementDrawer } from "./SelfManagementDrawer";
2
+ export { SelfManagementDrawerHeader } from "./SelfManagementDrawerHeader";
3
+ export { SelfManagementDrawerBody } from "./SelfManagementDrawerBody";
@@ -0,0 +1,86 @@
1
+ [data-fs-self-management-drawer] {
2
+ display: flex;
3
+ flex-direction: column;
4
+ }
5
+
6
+ // Header
7
+ [data-fs-slide-over] [data-fs-slide-over-header] {
8
+ --fs-slide-over-header-height: 100px;
9
+
10
+ align-items: baseline;
11
+ justify-content: space-between;
12
+ flex-direction: row-reverse;
13
+ background-color: #0366dd;
14
+ height: var(--fs-slide-over-header-height);
15
+
16
+ button {
17
+ color: white;
18
+ }
19
+ }
20
+
21
+ [data-fs-self-management-drawer-header] {
22
+ padding: 0 var(--fs-spacing-8);
23
+ display: flex;
24
+ width: 100%;
25
+ justify-content: space-between;
26
+ align-items: flex-end;
27
+ }
28
+
29
+ [data-fs-self-management-drawer-header-org-link] {
30
+ text-decoration: none;
31
+ }
32
+
33
+ [data-fs-self-management-drawer-header-org-name] {
34
+ font-weight: var(--fs-text-weight-bold);
35
+ font-size: var(--fs-text-size-3);
36
+ color: var(--fs-color-text);
37
+ text-transform: capitalize;
38
+ text-decoration: none;
39
+ padding: var(--fs-spacing-1) 0;
40
+ }
41
+
42
+ [data-fs-self-management-drawer-header-org-name]:hover {
43
+ text-decoration: underline;
44
+ }
45
+
46
+ [data-fs-self-management-drawer-header-org-image] {
47
+ width: var(--fs-spacing-8);
48
+ height: var(--fs-spacing-8);
49
+ border-radius: var(--fs-border-radius-pill);
50
+ background-color: #cbe9ff;
51
+ border: var(--fs-border-width-thick) solid white;
52
+ display: flex;
53
+ align-items: center;
54
+ justify-content: center;
55
+ margin-bottom: var(--fs-spacing-1);
56
+ overflow: hidden;
57
+ color: var(--fs-border-color-active);
58
+
59
+ transform: translateY(-50%);
60
+ }
61
+
62
+ // Body
63
+ [data-fs-self-management-drawer-body] {
64
+ flex: 1;
65
+
66
+ [data-fs-self-mamnagement-drawer-body-contents] {
67
+ padding: var(--fs-spacing-5) var(--fs-spacing-8) var(--fs-spacing-5);
68
+ display: grid;
69
+ row-gap: var(--fs-spacing-4);
70
+ width: 100%;
71
+
72
+ [data-fs-self-management-drawer-body-link] {
73
+ color: var(--fs-color-neutral-7);
74
+ text-decoration: none;
75
+ }
76
+
77
+ [data-fs-self-management-drawer-body-link]:hover {
78
+ text-decoration: underline;
79
+ }
80
+ }
81
+ }
82
+
83
+ // Footer
84
+ [data-fs-self-management-drawer-footer-wrapper] {
85
+ padding: var(--fs-spacing-4) var(--fs-spacing-8);
86
+ }
@@ -0,0 +1,46 @@
1
+ import { LinkButton, Icon } from "@faststore/ui";
2
+ import { useState } from "react";
3
+ import { SelfManagementDrawer } from "../SelfManagementDrawer/SelfManagementDrawer";
4
+
5
+ export const SelfManagementSignInButton = ({
6
+ useSession,
7
+ }: {
8
+ useSession: any;
9
+ }) => {
10
+ const [isOpen, setIsOpen] = useState(false);
11
+
12
+ const { ...session } = useSession();
13
+
14
+ const openDrawer = (event: any) => {
15
+ // if (session.person) {
16
+ if (true) {
17
+ event.preventDefault();
18
+
19
+ setIsOpen(true);
20
+ }
21
+ };
22
+
23
+ const closeDrawer = () => {
24
+ setIsOpen(false);
25
+ };
26
+
27
+ return (
28
+ <>
29
+ <LinkButton
30
+ data-fs-button-signin-link
31
+ // href={session.person?.id ? `/account` : `/login`}
32
+ className="text__title-mini"
33
+ variant="tertiary"
34
+ icon={<Icon name={"User"} width={18} height={18} weight="bold" />}
35
+ iconPosition="left"
36
+ onClick={(event) => openDrawer(event)}
37
+ >
38
+ {session.person?.id ? "Company" : "Sign In"}
39
+ </LinkButton>
40
+
41
+ {isOpen && (
42
+ <SelfManagementDrawer isOpen={isOpen} closeDrawer={closeDrawer} />
43
+ )}
44
+ </>
45
+ );
46
+ };
@@ -0,0 +1 @@
1
+ export { SelfManagementSignInButton } from './SelfManagementSignInButton'
@@ -0,0 +1,16 @@
1
+ import { SectionOverride } from "@faststore/core";
2
+ import { useSession_unstable as useSession } from "@faststore/core/experimental";
3
+ import { SelfManagementSignInButton } from "../SelfManagementSignInButton";
4
+
5
+ const SECTION: SectionOverride["section"] = "Navbar";
6
+
7
+ const override: SectionOverride = {
8
+ section: SECTION,
9
+ components: {
10
+ _experimentalButtonSignIn: {
11
+ Component: () => <SelfManagementSignInButton useSession={useSession} />,
12
+ },
13
+ },
14
+ };
15
+
16
+ export { override };
@@ -0,0 +1 @@
1
+ declare module "*.module.scss";
@@ -0,0 +1,7 @@
1
+ export const profileData = {
2
+ person: {
3
+ name: "Donald Green",
4
+ role: "Admin",
5
+ },
6
+ orgName: "Bytech Inc.",
7
+ };
@@ -1,3 +1,5 @@
1
+ import { Navbar } from "../components/Navbar/Navbar";
2
+
1
3
  export type PageLoader = { page: string };
2
4
 
3
5
  export async function loader(): Promise<PageLoader> {
@@ -5,5 +7,5 @@ export async function loader(): Promise<PageLoader> {
5
7
  }
6
8
 
7
9
  export default function MyAccount(data: PageLoader) {
8
- return <h1>Page: {data.page}</h1>;
10
+ return <Navbar />;
9
11
  }
@@ -1,3 +1,13 @@
1
+ @import "@faststore/ui/src/components/atoms/Overlay/styles.scss";
2
+ @import "@faststore/ui/src/components/atoms/Logo/styles.scss";
3
+ @import "@faststore/ui/src/components/organisms/SlideOver/styles.scss";
4
+ @import "@faststore/ui/src/components/molecules/Dropdown/styles.scss";
5
+ @import "../components/CustomerSwitch/customer-switch.scss";
6
+ @import "../components/Navbar/navbar.scss";
7
+ @import "../components/SelfManagementDrawer/self-management-drawer.scss";
8
+ @import "../components/SelfManagementDrawer/self-management-drawer.scss";
9
+ @import "../components/ProfileSummary/profile-summary.scss";
10
+
1
11
  // ----------------------------------------------------------
2
12
  // GLOBAL TOKENS
3
13
  // Custom Theme
@@ -8,7 +18,7 @@
8
18
  // --------------------------------------------------------
9
19
  // Colors (Branding Core)
10
20
  // --------------------------------------------------------
11
- --fs-color-main-0: blue;
21
+ // --fs-color-main-0: blue;
12
22
  // --------------------------------------------------------
13
23
  // Typography (Branding Core)
14
24
  // --------------------------------------------------------
@@ -0,0 +1,5 @@
1
+ export const doLogout = (storeConfig: any) => {
2
+ window.location.assign(
3
+ `${storeConfig.secureSubdomain}/api/vtexid/pub/logout?scope=${storeConfig.api.storeId}&returnUrl=${storeConfig.storeUrl}`
4
+ );
5
+ };
@@ -0,0 +1,3 @@
1
+ export const goToOrders = (storeConfig: any) => {
2
+ window.location.href = `${storeConfig.accountUrl}/#orders`;
3
+ };
package/tsconfig.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "DOM.Iterable",
18
18
  "ES2016"
19
19
  ] /* Specify a set of bundled library declaration files that describe the target runtime environment. */,
20
- "jsx": "react-jsx" /* Specify what JSX code is generated. */,
20
+ "jsx": "preserve" /* Specify what JSX code is generated. */,
21
21
  // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
22
22
  // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
23
23
  // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */