@vtex/faststore-plugin-buyer-portal 1.0.39 → 1.0.40

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 (27) hide show
  1. package/package.json +1 -1
  2. package/plugin.config.js +4 -4
  3. package/public/buyer-portal-icons.svg +11 -1
  4. package/src/features/addresses/components/AddressForm/AddressForm.tsx +33 -27
  5. package/src/features/addresses/components/AddressLine/AddressLine.tsx +1 -1
  6. package/src/features/credit-cards/components/CreateCreditCardDrawer/CreateCreditCardDrawer.tsx +135 -0
  7. package/src/features/credit-cards/components/CreateCreditCardDrawer/create-credit-card-drawer.scss +21 -0
  8. package/src/features/credit-cards/components/CreditCardDropdownMenu/CreditCardDropdownMenu.tsx +103 -0
  9. package/src/features/credit-cards/components/CreditCardForm/CreditCardForm.tsx +79 -0
  10. package/src/features/credit-cards/components/CreditCardForm/credit-card-form.scss +5 -0
  11. package/src/features/credit-cards/components/DeleteCreditCardDrawer/DeleteCreditCardDrawer.tsx +82 -0
  12. package/src/features/credit-cards/components/EditCreditCardDrawer/EditCreditCardDrawer.tsx +90 -0
  13. package/src/features/credit-cards/components/EditCreditCardDrawer/edit-credit-card-drawer.scss +4 -0
  14. package/src/features/credit-cards/components/RemoveCreditCardDrawer/RemoveCreditCardDrawer.tsx +84 -0
  15. package/src/features/credit-cards/components/RemoveCreditCardDrawer/remove-credit-card-drawer.scss +9 -0
  16. package/src/features/credit-cards/components/index.ts +24 -0
  17. package/src/features/credit-cards/layouts/CreditCardsLayout/CreditCardLayout.tsx +100 -0
  18. package/src/features/credit-cards/layouts/CreditCardsLayout/credit-card-layout.scss +140 -0
  19. package/src/features/credit-cards/layouts/index.ts +1 -0
  20. package/src/features/credit-cards/types/CreditCard.ts +12 -0
  21. package/src/features/credit-cards/types/index.ts +1 -0
  22. package/src/features/org-units/components/AddAllToOrgUnitDropdown/AddAllToOrgUnitDropdown.tsx +65 -48
  23. package/src/features/org-units/layouts/OrgUnitDetailsLayout/org-units-details.scss +1 -0
  24. package/src/features/shared/utils/creditCard.ts +16 -0
  25. package/src/features/shared/utils/index.ts +1 -0
  26. package/src/pages/credit-cards.tsx +71 -0
  27. package/src/themes/layouts.scss +3 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vtex/faststore-plugin-buyer-portal",
3
- "version": "1.0.39",
3
+ "version": "1.0.40",
4
4
  "description": "A plugin for faststore with buyer portal",
5
5
  "main": "index.js",
6
6
  "dependencies": {
package/plugin.config.js CHANGED
@@ -24,10 +24,10 @@ module.exports = {
24
24
  // path: "/buyer-portal/payment-methods/[orgUnitId]/[contractId]",
25
25
  // appLayout: false,
26
26
  // },
27
- // "credit-cards": {
28
- // path: "/buyer-portal/credit-cards/[orgUnitId]/[contractId]",
29
- // appLayout: false,
30
- // },
27
+ "credit-cards": {
28
+ path: "/buyer-portal/credit-cards/[orgUnitId]/[contractId]",
29
+ appLayout: false,
30
+ },
31
31
  // collections: {
32
32
  // path: "/buyer-portal/collections/[orgUnitId]/[contractId]",
33
33
  // appLayout: false,
@@ -337,4 +337,14 @@
337
337
  fill="currentColor" />
338
338
 
339
339
  </symbol>
340
- </svg>
340
+
341
+ <symbol
342
+ id="Rename"
343
+ viewBox="0 0 17 13"
344
+ fill="none"
345
+ xmlns="http://www.w3.org/2000/svg">
346
+ <path d="M10.0712 12.6473V2.64734H6.0712V0.647339H16.0712V2.64734H12.0712V12.6473H10.0712ZM2.5712 12.6473V6.64734H0.0711975V4.64734H7.0712V6.64734H4.5712V12.6473H2.5712Z" fill="currentColor"/>
347
+ </symbol>
348
+
349
+
350
+ </svg>
@@ -25,6 +25,7 @@ export type AddressFormProps = {
25
25
  completedAddress?: AddressData;
26
26
  setCompletedAddress?: (completedAddress: AddressData) => void;
27
27
  isEdit?: boolean;
28
+ fixedType?: boolean;
28
29
  };
29
30
 
30
31
  export const AddressForm = ({
@@ -37,6 +38,7 @@ export const AddressForm = ({
37
38
  setUseExistingAddress,
38
39
  completedAddress,
39
40
  setCompletedAddress,
41
+ fixedType = false,
40
42
  }: AddressFormProps) => {
41
43
  const addressTypeOptions = ["Shipping", "Billing", "Sold To"];
42
44
 
@@ -60,11 +62,13 @@ export const AddressForm = ({
60
62
  });
61
63
  };
62
64
 
65
+ const hideLabel = isEdit || fixedType;
66
+
63
67
  return (
64
68
  <>
65
69
  {!useExistingAddress ? (
66
70
  <div>
67
- {!isEdit && <span>Fill in the address details</span>}
71
+ {!hideLabel && <span>Fill in the address details</span>}
68
72
 
69
73
  <AutocompleteDropdown
70
74
  data-fs-bp-create-address-country-selector
@@ -242,32 +246,34 @@ export const AddressForm = ({
242
246
  />
243
247
  )}
244
248
 
245
- <AutocompleteDropdown
246
- label="Address Type"
247
- value={address.types}
248
- options={addressTypeOptions}
249
- onConfirmKeyPress={(option) =>
250
- setAddress({ ...address, types: [option] })
251
- }
252
- renderOption={(option, index) => (
253
- <AutocompleteDropdown.Item
254
- key={`${option}-${index}`}
255
- closeOnClick={true}
256
- index={index}
257
- isSelected={
258
- address?.types[0]?.toLocaleLowerCase() ===
259
- option.toLocaleLowerCase()
260
- }
261
- onClick={() => setAddress({ ...address, types: [option] })}
262
- >
263
- {option}
264
- {address?.types[0]?.toLowerCase() ===
265
- option.toLocaleLowerCase() && (
266
- <Icon name="Check" width={12} height={12} />
267
- )}
268
- </AutocompleteDropdown.Item>
269
- )}
270
- />
249
+ {!fixedType && (
250
+ <AutocompleteDropdown
251
+ label="Address Type"
252
+ value={address.types}
253
+ options={addressTypeOptions}
254
+ onConfirmKeyPress={(option) =>
255
+ setAddress({ ...address, types: [option] })
256
+ }
257
+ renderOption={(option, index) => (
258
+ <AutocompleteDropdown.Item
259
+ key={`${option}-${index}`}
260
+ closeOnClick={true}
261
+ index={index}
262
+ isSelected={
263
+ address?.types[0]?.toLocaleLowerCase() ===
264
+ option.toLocaleLowerCase()
265
+ }
266
+ onClick={() => setAddress({ ...address, types: [option] })}
267
+ >
268
+ {option}
269
+ {address?.types[0]?.toLowerCase() ===
270
+ option.toLocaleLowerCase() && (
271
+ <Icon name="Check" width={12} height={12} />
272
+ )}
273
+ </AutocompleteDropdown.Item>
274
+ )}
275
+ />
276
+ )}
271
277
  </div>
272
278
  ) : (
273
279
  <ExistingAddress
@@ -1,4 +1,4 @@
1
- import { Toggle, Dropdown, DropdownButton } from "@faststore/ui";
1
+ import { Dropdown } from "@faststore/ui";
2
2
  import Link from "next/link";
3
3
  import { BasicDropdownMenu, Icon, Tag } from "../../../shared/components";
4
4
  import type { AddressData } from "../../types";
@@ -0,0 +1,135 @@
1
+ import { useState } from "react";
2
+
3
+ import { useUI } from "@faststore/ui";
4
+ import { useRouter } from "next/router";
5
+ import {
6
+ type BasicDrawerProps,
7
+ BasicDrawer,
8
+ InputText,
9
+ } from "../../../shared/components";
10
+ import { AddressForm } from "../../../addresses/components";
11
+ import type { AddressInput, AddressData } from "../../../addresses/types";
12
+ import type { CreditCard } from "../../types";
13
+ import { CreditCardForm } from "../CreditCardForm/CreditCardForm";
14
+
15
+ export type CreateCreditCardDrawerProps = Omit<BasicDrawerProps, "children"> & {
16
+ readonly?: boolean;
17
+ };
18
+
19
+ export const CreateCreditCardDrawer = ({
20
+ close,
21
+ readonly,
22
+ ...props
23
+ }: CreateCreditCardDrawerProps) => {
24
+ const { pushToast } = useUI();
25
+ const [isTouched, setIsTouched] = useState(false);
26
+ const [useExistingAddress, setUseExistingAddress] = useState(false);
27
+ const [completedAddress, setCompletedAddress] = useState<AddressData>(
28
+ {} as AddressData
29
+ );
30
+
31
+ const router = useRouter();
32
+
33
+ const [address, setAddress] = useState<AddressInput>({
34
+ name: "",
35
+ streetAddress: "",
36
+ streetAddress2: "",
37
+ country: "",
38
+ countryCode: "",
39
+ zip: "",
40
+ state: "",
41
+ geoCordinates: "",
42
+ city: "",
43
+ types: ["Billing"],
44
+ neighborhood: "",
45
+ });
46
+
47
+ const [newCard, setNewCard] = useState<CreditCard>({} as CreditCard);
48
+
49
+ const [invalidAddress, setInvalidAddress] = useState(false);
50
+
51
+ const handleConfirmClick = () => {
52
+ pushToast({
53
+ message: "Credit card added successfully",
54
+ status: "INFO",
55
+ });
56
+ router.reload();
57
+ close();
58
+ };
59
+
60
+ const hasMinimumAddressInformation = () => {
61
+ return (
62
+ (address.name &&
63
+ address.streetAddress &&
64
+ address.country &&
65
+ address.zip &&
66
+ address.state &&
67
+ address.city &&
68
+ address.types.length > 0) ||
69
+ useExistingAddress
70
+ );
71
+ };
72
+
73
+ const hasCardInformation = () => {
74
+ return (
75
+ newCard.cardholder &&
76
+ newCard.nickname &&
77
+ newCard.cvv &&
78
+ newCard.expirationDate &&
79
+ newCard.number
80
+ );
81
+ };
82
+
83
+ const isConfirmButtonEnabled =
84
+ hasMinimumAddressInformation() && hasCardInformation();
85
+
86
+ return (
87
+ <BasicDrawer data-fs-bp-create-credit-card-drawer close={close} {...props}>
88
+ <BasicDrawer.Heading title="Add credit card" onClose={close} />
89
+ <BasicDrawer.Body>
90
+ <div data-fs-bp-create-credit-card-drawer-section-label>
91
+ <span>Card nickname</span>
92
+ </div>
93
+ <InputText
94
+ label="Card nickname"
95
+ value={newCard.nickname}
96
+ wrapperProps={{ style: { marginTop: 16 } }}
97
+ onChange={(event) =>
98
+ setNewCard({ ...newCard, nickname: event.target.value })
99
+ }
100
+ />
101
+
102
+ <CreditCardForm creditCard={newCard} setNewCard={setNewCard} />
103
+
104
+ <div data-fs-bp-create-credit-card-drawer-section-label>
105
+ <span>Billing Address</span>
106
+ </div>
107
+ <AddressForm
108
+ address={address}
109
+ setAddress={setAddress}
110
+ isTouched={isTouched}
111
+ setInvalidAddress={setInvalidAddress}
112
+ useExistingAddress={useExistingAddress}
113
+ setUseExistingAddress={setUseExistingAddress}
114
+ completedAddress={completedAddress}
115
+ setCompletedAddress={setCompletedAddress}
116
+ fixedType={true}
117
+ />
118
+ </BasicDrawer.Body>
119
+
120
+ <BasicDrawer.Footer>
121
+ <BasicDrawer.Button variant="ghost" onClick={close}>
122
+ Cancel
123
+ </BasicDrawer.Button>
124
+ <BasicDrawer.Button
125
+ variant="confirm"
126
+ disabled={!isConfirmButtonEnabled}
127
+ onClick={handleConfirmClick}
128
+ isLoading={false}
129
+ >
130
+ Save
131
+ </BasicDrawer.Button>
132
+ </BasicDrawer.Footer>
133
+ </BasicDrawer>
134
+ );
135
+ };
@@ -0,0 +1,21 @@
1
+ @import "../../../shared/components/BasicDrawer/basic-drawer.scss";
2
+ @import "../../../shared/components/InputText/input-text.scss";
3
+ @import "../../../shared/components/ErrorMessage/error-message.scss";
4
+ @import "@faststore/ui/src/components/atoms/Select/styles.scss";
5
+ @import "@faststore/ui/src/components/atoms/Button/styles.scss";
6
+ @import "@faststore/ui/src/components/molecules/Alert/styles.scss";
7
+ @import "../CreditCardForm/credit-card-form.scss";
8
+
9
+ [data-fs-bp-create-credit-card-drawer] {
10
+ @import "../../../addresses/components/ExistingAddress/existing-address.scss";
11
+
12
+ [data-fs-bp-create-credit-card-drawer-section-label] {
13
+ font-weight: bold;
14
+ margin-top: var(--fs-spacing-3);
15
+ }
16
+
17
+ [data-fs-bp-autocomplete-dropdown] {
18
+ margin-top: var(--fs-spacing-3);
19
+ margin-bottom: var(--fs-spacing-3);
20
+ }
21
+ }
@@ -0,0 +1,103 @@
1
+ import { DropdownItem, Icon as UIIcon } from "@faststore/ui";
2
+
3
+ import {
4
+ DeleteCreditCardDrawer,
5
+ EditCreditCardDrawer,
6
+ RemoveCreditCardDrawer,
7
+ } from "..";
8
+ import { useDrawerProps, useBuyerPortal } from "../../../shared/hooks";
9
+ import { BasicDropdownMenu, Icon } from "../../../shared/components";
10
+ import type { CreditCardData } from "../../types";
11
+
12
+ export type CreditCardDropdownMenuProps = {
13
+ currentCreditCard: CreditCardData;
14
+ onUpdate?: () => void;
15
+ onCreate?: () => void;
16
+ isComplete?: boolean;
17
+ };
18
+
19
+ export const CreditCardDropdownMenu = ({
20
+ currentCreditCard,
21
+ }: CreditCardDropdownMenuProps) => {
22
+ const { currentOrgUnit } = useBuyerPortal();
23
+
24
+ const idsPath = currentOrgUnit?.path?.ids?.split("/") ?? [];
25
+
26
+ const isRootLevelOrgUnit = idsPath.length === 2 ?? false;
27
+
28
+ const {
29
+ open: openEditDrawerProps,
30
+ isOpen: isEditDrawerOpen,
31
+ ...editDrawerProps
32
+ } = useDrawerProps();
33
+
34
+ const {
35
+ open: openRemoveDrawer,
36
+ isOpen: isOpenRemoveDrawer,
37
+ ...removeDrawerProps
38
+ } = useDrawerProps();
39
+
40
+ const {
41
+ open: openDeleteDrawer,
42
+ isOpen: isOpenDeleteDrawer,
43
+ ...deleteDrawerProps
44
+ } = useDrawerProps();
45
+
46
+ const sizeProps = { width: 20, height: 20 };
47
+
48
+ return (
49
+ <>
50
+ <BasicDropdownMenu data-fs-bp-dropdown-menu>
51
+ <DropdownItem onClick={openEditDrawerProps}>
52
+ <Icon name="Rename" {...sizeProps} />
53
+ Rename
54
+ </DropdownItem>
55
+ <DropdownItem onClick={() => {}}>
56
+ <Icon name="BookmarkAdd" {...sizeProps} />
57
+ Set as Default
58
+ </DropdownItem>
59
+
60
+ <BasicDropdownMenu.Separator />
61
+ <DropdownItem onClick={openRemoveDrawer}>
62
+ <UIIcon name="MinusCircle" {...sizeProps} />
63
+ Remove from Unit
64
+ </DropdownItem>
65
+ {isRootLevelOrgUnit && (
66
+ <DropdownItem
67
+ onClick={openDeleteDrawer}
68
+ data-fs-bp-dropdown-menu-item-mode="danger"
69
+ >
70
+ <Icon name="Delete" {...sizeProps} data-fs-bp-delete-dropdown />
71
+ <span data-fs-bp-delete-dropdown>Delete</span>
72
+ </DropdownItem>
73
+ )}
74
+ </BasicDropdownMenu>
75
+ {isEditDrawerOpen && (
76
+ <EditCreditCardDrawer
77
+ readonly
78
+ {...editDrawerProps}
79
+ isOpen={isEditDrawerOpen}
80
+ creditCard={currentCreditCard}
81
+ />
82
+ )}
83
+ {isOpenRemoveDrawer && (
84
+ <RemoveCreditCardDrawer
85
+ readonly
86
+ cardName={currentCreditCard.nickname}
87
+ cardId={currentCreditCard.id}
88
+ {...removeDrawerProps}
89
+ isOpen={isOpenRemoveDrawer}
90
+ />
91
+ )}
92
+ {isOpenDeleteDrawer && (
93
+ <DeleteCreditCardDrawer
94
+ readonly
95
+ cardName={currentCreditCard.nickname}
96
+ cardId={currentCreditCard.id}
97
+ isOpen={isOpenDeleteDrawer}
98
+ {...deleteDrawerProps}
99
+ />
100
+ )}
101
+ </>
102
+ );
103
+ };
@@ -0,0 +1,79 @@
1
+ import { InputText } from "../../../shared/components";
2
+ import type { CreditCard } from "../../types";
3
+ import {
4
+ maskCardNumber,
5
+ maskExpirationDate,
6
+ maskCVV,
7
+ } from "../../../shared/utils";
8
+
9
+ export type CreditCardFormProps = {
10
+ creditCard: CreditCard;
11
+ setNewCard: (newCard: CreditCard) => void;
12
+ };
13
+
14
+ export const CreditCardForm = ({
15
+ creditCard,
16
+ setNewCard,
17
+ }: CreditCardFormProps) => {
18
+ const handleChangeNumber = (cardNumber: string) => {
19
+ setNewCard({
20
+ ...creditCard,
21
+ number: maskCardNumber(cardNumber),
22
+ });
23
+ };
24
+
25
+ const handleChangeExpirationDate = (expirationDate: string) => {
26
+ setNewCard({
27
+ ...creditCard,
28
+ expirationDate: maskExpirationDate(expirationDate),
29
+ });
30
+ };
31
+
32
+ const handleChangeVerificationCode = (verificationCode: string) => {
33
+ setNewCard({
34
+ ...creditCard,
35
+ cvv: maskCVV(verificationCode),
36
+ });
37
+ };
38
+
39
+ return (
40
+ <>
41
+ <div data-fs-bp-create-credit-card-drawer-section-label>
42
+ <span>Card Details</span>
43
+ </div>
44
+
45
+ <InputText
46
+ label="Card number"
47
+ value={creditCard.number}
48
+ wrapperProps={{ style: { marginTop: 16 } }}
49
+ onChange={(event) => handleChangeNumber(event.target.value)}
50
+ />
51
+
52
+ <div data-fs-bp-create-credit-card-security-line>
53
+ <InputText
54
+ label="Exp MM/YY"
55
+ value={creditCard.expirationDate}
56
+ wrapperProps={{ style: { marginTop: 16 } }}
57
+ onChange={(event) => handleChangeExpirationDate(event.target.value)}
58
+ />
59
+
60
+ <InputText
61
+ label="CVV"
62
+ value={creditCard.cvv}
63
+ wrapperProps={{ style: { marginTop: 16 } }}
64
+ onChange={(event) => handleChangeVerificationCode(event.target.value)}
65
+ type="number"
66
+ />
67
+ </div>
68
+
69
+ <InputText
70
+ label="Cardholder name"
71
+ value={creditCard.cardholder}
72
+ wrapperProps={{ style: { marginTop: 16 } }}
73
+ onChange={(event) =>
74
+ setNewCard({ ...creditCard, cardholder: event.target.value })
75
+ }
76
+ />
77
+ </>
78
+ );
79
+ };
@@ -0,0 +1,5 @@
1
+ [data-fs-bp-create-credit-card-security-line] {
2
+ display: inline-flex;
3
+ width: 100%;
4
+ gap: var(--fs-spacing-3);
5
+ }
@@ -0,0 +1,82 @@
1
+ import { useUI } from "@faststore/ui";
2
+ import { useRouter } from "next/router";
3
+
4
+ import {
5
+ type BasicDrawerProps,
6
+ BasicDrawer,
7
+ InputText,
8
+ } from "../../../shared/components";
9
+ import { useState } from "react";
10
+
11
+ export type DeleteCreditCardDrawerProps = Omit<BasicDrawerProps, "children"> & {
12
+ readonly?: boolean;
13
+ cardName: string;
14
+ cardId: string;
15
+ };
16
+
17
+ export const DeleteCreditCardDrawer = ({
18
+ close,
19
+ cardName,
20
+ cardId,
21
+ readonly,
22
+ ...props
23
+ }: DeleteCreditCardDrawerProps) => {
24
+ const { pushToast } = useUI();
25
+ const router = useRouter();
26
+ const [creditCardNameConfirmation, setCreditCardNameConfirmation] =
27
+ useState("");
28
+
29
+ const handleConfirmClick = () => {
30
+ pushToast({
31
+ message: "Credit card deleted successfully",
32
+ status: "INFO",
33
+ });
34
+ router.reload();
35
+ close();
36
+ };
37
+
38
+ const isDeleteButtonEnabled = creditCardNameConfirmation === cardName;
39
+
40
+ return (
41
+ <BasicDrawer data-fs-bp-remove-credit-card-drawer close={close} {...props}>
42
+ <BasicDrawer.Heading title="Delete credit card" onClose={close} />
43
+ <BasicDrawer.Body>
44
+ <div>
45
+ <p>
46
+ Permanently delete <span data-fs-bp-drawer-label>{cardName} </span>?
47
+ </p>
48
+ <br />
49
+ <p>
50
+ This credit card may be used by multiple units. Deleting it will
51
+ permanently remove it and all iits data from all associated units,
52
+ though usage history will be kept for audit. This action can't be
53
+ undone
54
+ </p>
55
+ <br />
56
+ <p>Confirm by typing the card nickname below:</p>
57
+ <br />
58
+ <InputText
59
+ label="Card nickname"
60
+ value={creditCardNameConfirmation}
61
+ onChange={(event) =>
62
+ setCreditCardNameConfirmation(event.currentTarget.value)
63
+ }
64
+ />
65
+ </div>
66
+ </BasicDrawer.Body>
67
+
68
+ <BasicDrawer.Footer>
69
+ <BasicDrawer.Button variant="ghost" onClick={close}>
70
+ Cancel
71
+ </BasicDrawer.Button>
72
+ <BasicDrawer.Button
73
+ variant="confirm"
74
+ onClick={handleConfirmClick}
75
+ disabled={!isDeleteButtonEnabled}
76
+ >
77
+ Delete
78
+ </BasicDrawer.Button>
79
+ </BasicDrawer.Footer>
80
+ </BasicDrawer>
81
+ );
82
+ };
@@ -0,0 +1,90 @@
1
+ import { useState } from "react";
2
+
3
+ import { useUI } from "@faststore/ui";
4
+ import { useRouter } from "next/router";
5
+ import {
6
+ type BasicDrawerProps,
7
+ BasicDrawer,
8
+ InputText,
9
+ } from "../../../shared/components";
10
+ import type { CreditCardData } from "../../types";
11
+
12
+ export type EditCreditCardDrawerProps = Omit<BasicDrawerProps, "children"> & {
13
+ readonly?: boolean;
14
+ creditCard: CreditCardData;
15
+ };
16
+
17
+ export const EditCreditCardDrawer = ({
18
+ close,
19
+ readonly,
20
+ creditCard,
21
+ ...props
22
+ }: EditCreditCardDrawerProps) => {
23
+ const { pushToast } = useUI();
24
+
25
+ const router = useRouter();
26
+
27
+ const [cardToModify, setCardToModify] = useState<CreditCardData>(creditCard);
28
+ const [onConfirmationStep, setOnConfirmationStep] = useState(false);
29
+
30
+ const drawerTitle = onConfirmationStep
31
+ ? "Confirm credit card update"
32
+ : "Rename credit card";
33
+
34
+ const handleConfirmClick = () => {
35
+ if (onConfirmationStep) {
36
+ pushToast({
37
+ message: "Credit edited added successfully",
38
+ status: "INFO",
39
+ });
40
+ router.reload();
41
+ close();
42
+ } else {
43
+ setOnConfirmationStep(true);
44
+ }
45
+ };
46
+
47
+ const isEdited = cardToModify.nickname !== creditCard.nickname;
48
+
49
+ return (
50
+ <BasicDrawer data-fs-bp-edit-credit-card-drawer close={close} {...props}>
51
+ <BasicDrawer.Heading title={drawerTitle} onClose={close} />
52
+ <BasicDrawer.Body>
53
+ {onConfirmationStep ? (
54
+ <div>
55
+ <p>
56
+ Thid credit card may be used by multiple units. Updates will
57
+ affect all of them
58
+ </p>
59
+ <br />
60
+ <p>Proceed with the update?</p>
61
+ <br />
62
+ </div>
63
+ ) : (
64
+ <InputText
65
+ label="Card nickname"
66
+ value={cardToModify.nickname}
67
+ wrapperProps={{ style: { marginTop: 16 } }}
68
+ onChange={(event) =>
69
+ setCardToModify({ ...cardToModify, nickname: event.target.value })
70
+ }
71
+ />
72
+ )}
73
+ </BasicDrawer.Body>
74
+
75
+ <BasicDrawer.Footer>
76
+ <BasicDrawer.Button variant="ghost" onClick={close}>
77
+ Cancel
78
+ </BasicDrawer.Button>
79
+ <BasicDrawer.Button
80
+ variant="confirm"
81
+ disabled={!isEdited}
82
+ onClick={handleConfirmClick}
83
+ isLoading={false}
84
+ >
85
+ {onConfirmationStep ? "Confirm" : "Save"}
86
+ </BasicDrawer.Button>
87
+ </BasicDrawer.Footer>
88
+ </BasicDrawer>
89
+ );
90
+ };
@@ -0,0 +1,4 @@
1
+ @import "../../../shared/components/BasicDrawer/basic-drawer.scss";
2
+ @import "../../../shared/components/InputText/input-text.scss";
3
+ @import "../../../shared/components/ErrorMessage/error-message.scss";
4
+ @import "@faststore/ui/src/components/atoms/Button/styles.scss";
@@ -0,0 +1,84 @@
1
+ import { useUI } from "@faststore/ui";
2
+ import { useRouter } from "next/router";
3
+
4
+ import { type BasicDrawerProps, BasicDrawer } from "../../../shared/components";
5
+ import { useRemoveFromScope, useBuyerPortal } from "../../../shared/hooks";
6
+
7
+ export type RemoveCreditCardDrawerProps = Omit<BasicDrawerProps, "children"> & {
8
+ readonly?: boolean;
9
+ cardId: string;
10
+ cardName: string;
11
+ };
12
+
13
+ export const RemoveCreditCardDrawer = ({
14
+ close,
15
+ cardId,
16
+ cardName,
17
+ readonly,
18
+ ...props
19
+ }: RemoveCreditCardDrawerProps) => {
20
+ const { pushToast } = useUI();
21
+ const router = useRouter();
22
+ const { currentOrgUnit } = useBuyerPortal();
23
+
24
+ const handeRemoveFromScopeSuccess = () => {
25
+ pushToast({
26
+ message: "Credit card removed successfully",
27
+ status: "INFO",
28
+ });
29
+ router.reload();
30
+ close();
31
+ };
32
+
33
+ const { removeFromScope } = useRemoveFromScope({
34
+ onSuccess: handeRemoveFromScopeSuccess,
35
+ onError: () => {
36
+ pushToast({
37
+ message:
38
+ "An error occurred while removing the credit card from the unit",
39
+ status: "ERROR",
40
+ });
41
+ },
42
+ });
43
+
44
+ const handleConfirmClick = () => {
45
+ removeFromScope({
46
+ scopeName: "creditCards",
47
+ unitId: currentOrgUnit?.id ?? "",
48
+ fieldId: cardId,
49
+ });
50
+ };
51
+
52
+ return (
53
+ <BasicDrawer data-fs-bp-remove-credit-card-drawer close={close} {...props}>
54
+ <BasicDrawer.Heading
55
+ title="Remove credit card from unit"
56
+ onClose={close}
57
+ />
58
+ <BasicDrawer.Body>
59
+ <div>
60
+ <p>
61
+ {" "}
62
+ Remove <span data-fs-bp-drawer-label>{cardName}</span> credit card
63
+ from <span data-fs-bp-drawer-label>{currentOrgUnit?.name} </span>{" "}
64
+ organizational unit?
65
+ </p>
66
+ <br />
67
+ <p>
68
+ This action will prevent users in this unit from accessing this
69
+ credit card during checkout
70
+ </p>
71
+ </div>
72
+ </BasicDrawer.Body>
73
+
74
+ <BasicDrawer.Footer>
75
+ <BasicDrawer.Button variant="ghost" onClick={close}>
76
+ Cancel
77
+ </BasicDrawer.Button>
78
+ <BasicDrawer.Button variant="confirm" onClick={handleConfirmClick}>
79
+ Confirm
80
+ </BasicDrawer.Button>
81
+ </BasicDrawer.Footer>
82
+ </BasicDrawer>
83
+ );
84
+ };
@@ -0,0 +1,9 @@
1
+ @import "../../../shared/components/BasicDrawer/basic-drawer.scss";
2
+
3
+ [data-fs-bp-remove-credit-card-drawer] {
4
+ @import "@faststore/ui/src/components/atoms/Button/styles.scss";
5
+
6
+ [data-fs-bp-drawer-label] {
7
+ color: #0366dd;
8
+ }
9
+ }
@@ -0,0 +1,24 @@
1
+ export {
2
+ CreateCreditCardDrawer,
3
+ type CreateCreditCardDrawerProps,
4
+ } from "./CreateCreditCardDrawer/CreateCreditCardDrawer";
5
+ export {
6
+ CreditCardForm,
7
+ type CreditCardFormProps,
8
+ } from "./CreditCardForm/CreditCardForm";
9
+ export {
10
+ EditCreditCardDrawer,
11
+ type EditCreditCardDrawerProps,
12
+ } from "./EditCreditCardDrawer/EditCreditCardDrawer";
13
+ export {
14
+ CreditCardDropdownMenu,
15
+ type CreditCardDropdownMenuProps,
16
+ } from "./CreditCardDropdownMenu/CreditCardDropdownMenu";
17
+ export {
18
+ RemoveCreditCardDrawer,
19
+ type RemoveCreditCardDrawerProps,
20
+ } from "./RemoveCreditCardDrawer/RemoveCreditCardDrawer";
21
+ export {
22
+ DeleteCreditCardDrawer,
23
+ type DeleteCreditCardDrawerProps,
24
+ } from "./DeleteCreditCardDrawer/DeleteCreditCardDrawer";
@@ -0,0 +1,100 @@
1
+ import { Dropdown } from "@faststore/ui";
2
+
3
+ import {
4
+ InternalSearch,
5
+ Icon,
6
+ HeaderInside,
7
+ BasicDropdownMenu,
8
+ } from "../../../shared/components";
9
+
10
+ import {
11
+ useQueryParams,
12
+ useDrawerProps,
13
+ useBuyerPortal,
14
+ } from "../../../shared/hooks";
15
+ import { ContractTabsLayout, GlobalLayout } from "../../../shared/layouts";
16
+ import { CreditCardData } from "../../types";
17
+ import {
18
+ CreateCreditCardDrawer,
19
+ CreditCardDropdownMenu,
20
+ } from "../../components";
21
+
22
+ export type CreditCardsLayoutProps = {
23
+ data: CreditCardData[];
24
+ };
25
+
26
+ export const CreditCardLayout = ({ data }: CreditCardsLayoutProps) => {
27
+ const { setQueryString, removeQueryString } = useQueryParams();
28
+ const {
29
+ open: openCreateDrawer,
30
+ isOpen: isCreateCreditCardDrawerOpen,
31
+ ...createDrawerProps
32
+ } = useDrawerProps();
33
+
34
+ const {
35
+ currentOrgUnit: orgUnit,
36
+ currentUser: user,
37
+ currentContract: contract,
38
+ } = useBuyerPortal();
39
+
40
+ return (
41
+ <GlobalLayout>
42
+ <ContractTabsLayout
43
+ orgUnitName={orgUnit?.name ?? ""}
44
+ orgUnitId={orgUnit?.id ?? ""}
45
+ contractName={contract?.name ?? ""}
46
+ contractId={contract?.id ?? ""}
47
+ pageName="Contract"
48
+ person={{
49
+ image: undefined,
50
+ name: user?.name ?? "",
51
+ role: user?.role ?? "",
52
+ }}
53
+ >
54
+ <section data-fs-credit-card-section>
55
+ <HeaderInside title="Credit cards">
56
+ <HeaderInside.Button onClick={openCreateDrawer} />
57
+ </HeaderInside>
58
+ <div data-fs-bp-credit-card-search-container>
59
+ <InternalSearch
60
+ textSearch={(searchTerm) => {
61
+ searchTerm
62
+ ? setQueryString("search", searchTerm)
63
+ : removeQueryString("search");
64
+ }}
65
+ />
66
+ </div>
67
+
68
+ <ul data-fs-credit-card-list>
69
+ <div data-fs-bp-credit-card-list-title> Card Nickname </div>
70
+ {data.map((creditCard) => (
71
+ <li data-fs-credit-card-line key={creditCard.id}>
72
+ <div data-fs-credit-card-row>
73
+ <div data-fs-credit-card-row-information>
74
+ <span data-fs-credit-card-row-icon-wrapper>
75
+ <Icon name="CreditCard" width={24} height={24} />
76
+ </span>
77
+ <div data-fs-credit-card-name>{creditCard.nickname}</div>
78
+ </div>
79
+ <div data-fs-credit-card-row-action>
80
+ <Dropdown>
81
+ <BasicDropdownMenu.Trigger />
82
+ <CreditCardDropdownMenu currentCreditCard={creditCard} />
83
+ </Dropdown>
84
+ </div>
85
+ </div>
86
+ </li>
87
+ ))}
88
+ </ul>
89
+ {isCreateCreditCardDrawerOpen && (
90
+ <CreateCreditCardDrawer
91
+ readonly
92
+ {...createDrawerProps}
93
+ isOpen={isCreateCreditCardDrawerOpen}
94
+ />
95
+ )}
96
+ </section>
97
+ </ContractTabsLayout>
98
+ </GlobalLayout>
99
+ );
100
+ };
@@ -0,0 +1,140 @@
1
+ @import "../../../shared/components/MainLinksDropdownMenu/main-links-dropdown-menu.scss";
2
+ @import "../../components/CreateCreditCardDrawer/create-credit-card-drawer.scss";
3
+ @import "../../components/EditCreditCardDrawer/edit-credit-card-drawer.scss";
4
+ @import "../../components/RemoveCreditCardDrawer/remove-credit-card-drawer.scss";
5
+
6
+ [data-fs-credit-card-section] {
7
+ @import "../../../shared/components/InternalSearch/internal-search.scss";
8
+ @import "../../../shared/components/DropdownFilter/dropdown-filter.scss";
9
+ @import "../../../shared/components/HeaderInside/header-inside.scss";
10
+
11
+ padding: 0 calc(var(--fs-spacing-9) - var(--fs-spacing-0));
12
+
13
+ [data-fs-topbar-actions-wrapper] {
14
+ display: flex;
15
+ flex-direction: row;
16
+ [data-fs-topbar-dropdown-filter-trigger] {
17
+ display: flex;
18
+ align-items: center;
19
+ cursor: pointer;
20
+
21
+ [data-fs-topbar-dropdown-filter-trigger-label] {
22
+ font-weight: var(--fs-text-weight-medium);
23
+ font-size: var(--fs-text-size-2);
24
+ color: #1f1f1f;
25
+ }
26
+
27
+ [data-fs-topbar-dropdown-filter-trigger-icon] {
28
+ color: #707070;
29
+ }
30
+ }
31
+
32
+ [data-fs-topbar-dropdown-add-trigger] {
33
+ background-color: #0366dd;
34
+ display: flex;
35
+ align-items: center;
36
+ justify-content: space-between;
37
+ padding: calc(var(--fs-spacing-2) - var(--fs-spacing-0))
38
+ var(--fs-spacing-2);
39
+ border-radius: var(--fs-border-radius-pill);
40
+ color: white;
41
+ cursor: pointer;
42
+
43
+ [data-fs-topbar-dropdown-add-trigger-label] {
44
+ font-weight: var(--fs-text-weight-semibold);
45
+ font-size: var(--fs-text-size-1);
46
+ line-height: calc(var(--fs-spacing-3) + var(--fs-spacing-0));
47
+ }
48
+
49
+ svg {
50
+ color: white;
51
+ }
52
+ }
53
+ }
54
+
55
+ [data-fs-bp-credit-card-search-container] {
56
+ display: flex;
57
+ gap: var(--fs-spacing-1);
58
+ padding-bottom: 2rem;
59
+ }
60
+
61
+ [data-fs-credit-card-divider] {
62
+ border: calc(var(--fs-border-width) / 2) solid #e0e0e0;
63
+ }
64
+
65
+ [data-fs-credit-card-list] {
66
+ width: 100%;
67
+ display: flex;
68
+ flex-direction: column;
69
+
70
+ [data-fs-bp-credit-card-list-title] {
71
+ color: #5c5c5c;
72
+ margin-bottom: 0.5rem;
73
+ }
74
+
75
+ [data-fs-credit-card-line] {
76
+ border-top: var(--fs-border-width) solid #e5e5e5;
77
+ }
78
+
79
+ [data-fs-credit-card-row] {
80
+ display: flex;
81
+ justify-content: space-between;
82
+
83
+ &:hover {
84
+ background-color: #f5f5f5;
85
+ }
86
+
87
+ &:visited {
88
+ color: red;
89
+ }
90
+
91
+ [data-fs-credit-card-row-information] {
92
+ display: flex;
93
+ align-items: center;
94
+ margin-left: var(--fs-spacing-3);
95
+ padding: var(--fs-spacing-2) 0;
96
+ size: var(--fs-text-size-1);
97
+ color: #0366dd;
98
+ text-decoration: none;
99
+ flex: 1;
100
+
101
+ [data-fs-credit-card-row-icon-wrapper] {
102
+ display: flex;
103
+ align-items: center;
104
+ justify-content: center;
105
+ width: var(--fs-spacing-6);
106
+ height: var(--fs-spacing-6);
107
+
108
+ margin-right: calc(var(--fs-spacing-2) - var(--fs-spacing-0));
109
+ }
110
+
111
+ [data-fs-credit-card-name] {
112
+ width: var(--data-fs-users-table-width);
113
+ font-weight: 500;
114
+ font-size: var(--fs-text-size-1);
115
+ line-height: calc(var(--fs-spacing-3) + var(--fs-spacing-0));
116
+ text-decoration: none;
117
+ color: #000;
118
+ }
119
+ }
120
+
121
+ [data-fs-credit-card-row-action] {
122
+ align-items: center;
123
+ display: flex;
124
+
125
+ [data-fs-credit-card-row-dropdown-button] {
126
+ height: var(--fs-spacing-6);
127
+ width: var(--fs-spacing-6);
128
+ border-radius: var(--fs-border-radius-pill);
129
+ color: #5c5c5c;
130
+ margin-left: calc(var(--fs-spacing-3) + var(--fs-spacing-0));
131
+
132
+ &:hover {
133
+ background-color: #e0e0e0;
134
+ cursor: pointer;
135
+ }
136
+ }
137
+ }
138
+ }
139
+ }
140
+ }
@@ -0,0 +1 @@
1
+ export { CreditCardLayout } from "./CreditCardsLayout/CreditCardLayout";
@@ -0,0 +1,12 @@
1
+ export type CreditCard = {
2
+ nickname: string;
3
+ number: string;
4
+ expirationDate: string;
5
+ cvv: string;
6
+ cardholder: string;
7
+ };
8
+
9
+ export type CreditCardData = {
10
+ nickname: string;
11
+ id: string;
12
+ };
@@ -0,0 +1 @@
1
+ export type { CreditCard, CreditCardData } from "./CreditCard";
@@ -1,5 +1,7 @@
1
1
  import { DropdownItem } from "@faststore/ui";
2
2
  import { BasicDropdownMenu, Icon } from "../../../shared/components";
3
+ import { useDrawerProps } from "../../../shared/hooks";
4
+ import { CreateCreditCardDrawer } from "../../../credit-cards/components";
3
5
 
4
6
  export type AddAllToOrgUnitDropdownProps = {
5
7
  isSingleContract: boolean;
@@ -10,56 +12,71 @@ export const AddAllToOrgUnitDropdown = ({
10
12
  }: AddAllToOrgUnitDropdownProps) => {
11
13
  const sizeProps = { width: 20, height: 20 };
12
14
 
15
+ const {
16
+ open: openCreditCardDrawer,
17
+ isOpen: isOpenCreditCardDrawer,
18
+ ...creditCardDrawerProps
19
+ } = useDrawerProps();
20
+
13
21
  return (
14
- <BasicDropdownMenu>
15
- <DropdownItem>
16
- <Icon name="Description" {...sizeProps} />
17
- Add contract
18
- </DropdownItem>
19
- {isSingleContract && (
20
- <>
21
- <DropdownItem>
22
- <Icon name="LocalPostOffice" {...sizeProps} />
23
- Add address
24
- </DropdownItem>
25
- <DropdownItem>
26
- <Icon name="CreditCard" {...sizeProps} />
27
- Add credit card
28
- </DropdownItem>
29
- <DropdownItem>
30
- <Icon name="TableEdit" {...sizeProps} />
31
- Add cost center
32
- </DropdownItem>
33
- <DropdownItem>
34
- <Icon name="TableEdit" {...sizeProps} />
35
- Add PO number
36
- </DropdownItem>
37
- <DropdownItem>
38
- <Icon name="TableEdit" {...sizeProps} />
39
- Add release
40
- </DropdownItem>
41
- </>
42
- )}
43
- <BasicDropdownMenu.Separator />
22
+ <>
23
+ <BasicDropdownMenu>
24
+ <DropdownItem>
25
+ <Icon name="Description" {...sizeProps} />
26
+ Add contract
27
+ </DropdownItem>
28
+ {isSingleContract && (
29
+ <>
30
+ <DropdownItem>
31
+ <Icon name="LocalPostOffice" {...sizeProps} />
32
+ Add address
33
+ </DropdownItem>
34
+ <DropdownItem onClick={openCreditCardDrawer}>
35
+ <Icon name="CreditCard" {...sizeProps} />
36
+ Add credit card
37
+ </DropdownItem>
38
+ <DropdownItem>
39
+ <Icon name="TableEdit" {...sizeProps} />
40
+ Add cost center
41
+ </DropdownItem>
42
+ <DropdownItem>
43
+ <Icon name="TableEdit" {...sizeProps} />
44
+ Add PO number
45
+ </DropdownItem>
46
+ <DropdownItem>
47
+ <Icon name="TableEdit" {...sizeProps} />
48
+ Add release
49
+ </DropdownItem>
50
+ </>
51
+ )}
52
+ <BasicDropdownMenu.Separator />
44
53
 
45
- <DropdownItem>
46
- <Icon name="Profile" {...sizeProps} />
47
- Add user
48
- </DropdownItem>
49
- <DropdownItem>
50
- <Icon name="Folder" {...sizeProps} />
51
- Add organization unit
52
- </DropdownItem>
53
- <BasicDropdownMenu.Separator />
54
+ <DropdownItem>
55
+ <Icon name="Profile" {...sizeProps} />
56
+ Add user
57
+ </DropdownItem>
58
+ <DropdownItem>
59
+ <Icon name="Folder" {...sizeProps} />
60
+ Add organization unit
61
+ </DropdownItem>
62
+ <BasicDropdownMenu.Separator />
54
63
 
55
- <DropdownItem>
56
- <Icon name="Paid" {...sizeProps} />
57
- Add budget
58
- </DropdownItem>
59
- <DropdownItem>
60
- <Icon name="Rebase" {...sizeProps} />
61
- Add buying policy
62
- </DropdownItem>
63
- </BasicDropdownMenu>
64
+ <DropdownItem>
65
+ <Icon name="Paid" {...sizeProps} />
66
+ Add budget
67
+ </DropdownItem>
68
+ <DropdownItem>
69
+ <Icon name="Rebase" {...sizeProps} />
70
+ Add buying policy
71
+ </DropdownItem>
72
+ </BasicDropdownMenu>
73
+ {isOpenCreditCardDrawer && (
74
+ <CreateCreditCardDrawer
75
+ readonly
76
+ {...creditCardDrawerProps}
77
+ isOpen={isOpenCreditCardDrawer}
78
+ />
79
+ )}
80
+ </>
64
81
  );
65
82
  };
@@ -1,6 +1,7 @@
1
1
  @import "@faststore/ui/src/components/molecules/Dropdown/styles.scss";
2
2
  @import "../../../shared/components/BasicDropdownMenu/basic-dropdown-menu.scss";
3
3
  @import "../../components/OrgUnitDetailsNavbar/org-unit-details-navbar.scss";
4
+ @import "../../../credit-cards/components/CreateCreditCardDrawer/create-credit-card-drawer.scss";
4
5
 
5
6
  [data-fs-org-units-details-section] {
6
7
  @import "../../../shared/components/BasicCard/basic-card.scss";
@@ -0,0 +1,16 @@
1
+ import mask from "./mask";
2
+
3
+ export const maskCardNumber = (creditCardNumber: string) => {
4
+ return mask(
5
+ creditCardNumber.replace(/[^0-9 ]/g, ""),
6
+ "9999 9999 9999 9999 999"
7
+ ).substring(0, 23);
8
+ };
9
+
10
+ export const maskExpirationDate = (expDate: string) => {
11
+ return mask(expDate.replace(/[^0-9\/]/g, ""), "12/99").substring(0, 5);
12
+ };
13
+
14
+ export const maskCVV = (verificationCode: string) => {
15
+ return mask(verificationCode, "999").substring(0, 3);
16
+ };
@@ -24,3 +24,4 @@ export { toQueryParams } from "./toQueryParams";
24
24
  export { roles, type Role } from "./roles";
25
25
  export { getContractSettingsLinks } from "./getContractSettingsLinks";
26
26
  export { getOrganizationSettingsLinks } from "./getOrganizationSettingsLinks";
27
+ export { maskCardNumber, maskCVV, maskExpirationDate } from "./creditCard";
@@ -0,0 +1,71 @@
1
+ import { type ClientContext, getClientContext } from "../features/shared/utils";
2
+ import { BuyerPortalProvider } from "../features/shared/components";
3
+ import type { LoaderData } from "../features/shared/types";
4
+ import type { OrgUnitBasicData } from "../features/org-units/types";
5
+ import { getOrgUnitBasicDataService } from "../features/org-units/services";
6
+ import { getUserByIdService } from "../features/users/services";
7
+ import type { UserData } from "../features/users/types";
8
+ import type { ContractData } from "../features/contracts/types";
9
+ import { getContractDetailsService } from "../features/contracts/services";
10
+ import { CreditCardData } from "../features/credit-cards/types";
11
+ import { CreditCardLayout } from "../features/credit-cards/layouts";
12
+
13
+ export type CreditCardPageData = {
14
+ data: CreditCardData[];
15
+ context: {
16
+ currentContract: ContractData | null;
17
+ clientContext: ClientContext;
18
+ currentOrgUnit: OrgUnitBasicData | null;
19
+ currentUser: UserData | null;
20
+ };
21
+ };
22
+
23
+ export type CreditCardPageQuery = {
24
+ orgUnitId: string;
25
+ contractId: string;
26
+ };
27
+
28
+ export async function loader(
29
+ data: LoaderData<CreditCardPageQuery>
30
+ ): Promise<CreditCardPageData> {
31
+ const { contractId, orgUnitId } = data.query;
32
+
33
+ const { cookie, userId, ...clientContext } = await getClientContext(data);
34
+
35
+ const currentOrgUnit = await getOrgUnitBasicDataService({
36
+ id: orgUnitId,
37
+ cookie,
38
+ });
39
+
40
+ const user = await getUserByIdService({ userId, cookie });
41
+
42
+ const contract = await getContractDetailsService({
43
+ contractId,
44
+ cookie,
45
+ });
46
+
47
+ const mockCreditCards = [
48
+ {
49
+ id: "123-123",
50
+ nickname: "Credit Card Teste",
51
+ },
52
+ ];
53
+
54
+ return {
55
+ data: mockCreditCards,
56
+ context: {
57
+ clientContext: { cookie, userId, ...clientContext },
58
+ currentOrgUnit,
59
+ currentUser: user,
60
+ currentContract: contract,
61
+ },
62
+ };
63
+ }
64
+
65
+ const CreditCardsPage = ({ data, context }: CreditCardPageData) => (
66
+ <BuyerPortalProvider {...context}>
67
+ <CreditCardLayout data={data} />
68
+ </BuyerPortalProvider>
69
+ );
70
+
71
+ export default CreditCardsPage;
@@ -18,3 +18,6 @@
18
18
  // Org Units
19
19
  @import "../features/org-units/layouts/OrgUnitsLayout/org-units-layout.scss";
20
20
  @import "../features/org-units/layouts/OrgUnitDetailsLayout/org-units-details.scss";
21
+
22
+ // Credit Cards
23
+ @import "../features/credit-cards/layouts/CreditCardsLayout/credit-card-layout.scss";