@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.
- package/package.json +1 -1
- package/plugin.config.js +4 -4
- package/public/buyer-portal-icons.svg +11 -1
- package/src/features/addresses/components/AddressForm/AddressForm.tsx +33 -27
- package/src/features/addresses/components/AddressLine/AddressLine.tsx +1 -1
- package/src/features/credit-cards/components/CreateCreditCardDrawer/CreateCreditCardDrawer.tsx +135 -0
- package/src/features/credit-cards/components/CreateCreditCardDrawer/create-credit-card-drawer.scss +21 -0
- package/src/features/credit-cards/components/CreditCardDropdownMenu/CreditCardDropdownMenu.tsx +103 -0
- package/src/features/credit-cards/components/CreditCardForm/CreditCardForm.tsx +79 -0
- package/src/features/credit-cards/components/CreditCardForm/credit-card-form.scss +5 -0
- package/src/features/credit-cards/components/DeleteCreditCardDrawer/DeleteCreditCardDrawer.tsx +82 -0
- package/src/features/credit-cards/components/EditCreditCardDrawer/EditCreditCardDrawer.tsx +90 -0
- package/src/features/credit-cards/components/EditCreditCardDrawer/edit-credit-card-drawer.scss +4 -0
- package/src/features/credit-cards/components/RemoveCreditCardDrawer/RemoveCreditCardDrawer.tsx +84 -0
- package/src/features/credit-cards/components/RemoveCreditCardDrawer/remove-credit-card-drawer.scss +9 -0
- package/src/features/credit-cards/components/index.ts +24 -0
- package/src/features/credit-cards/layouts/CreditCardsLayout/CreditCardLayout.tsx +100 -0
- package/src/features/credit-cards/layouts/CreditCardsLayout/credit-card-layout.scss +140 -0
- package/src/features/credit-cards/layouts/index.ts +1 -0
- package/src/features/credit-cards/types/CreditCard.ts +12 -0
- package/src/features/credit-cards/types/index.ts +1 -0
- package/src/features/org-units/components/AddAllToOrgUnitDropdown/AddAllToOrgUnitDropdown.tsx +65 -48
- package/src/features/org-units/layouts/OrgUnitDetailsLayout/org-units-details.scss +1 -0
- package/src/features/shared/utils/creditCard.ts +16 -0
- package/src/features/shared/utils/index.ts +1 -0
- package/src/pages/credit-cards.tsx +71 -0
- package/src/themes/layouts.scss +3 -0
package/package.json
CHANGED
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
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
|
-
{!
|
|
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
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
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
|
package/src/features/credit-cards/components/CreateCreditCardDrawer/CreateCreditCardDrawer.tsx
ADDED
|
@@ -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
|
+
};
|
package/src/features/credit-cards/components/CreateCreditCardDrawer/create-credit-card-drawer.scss
ADDED
|
@@ -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
|
+
}
|
package/src/features/credit-cards/components/CreditCardDropdownMenu/CreditCardDropdownMenu.tsx
ADDED
|
@@ -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
|
+
};
|
package/src/features/credit-cards/components/DeleteCreditCardDrawer/DeleteCreditCardDrawer.tsx
ADDED
|
@@ -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
|
+
};
|
package/src/features/credit-cards/components/RemoveCreditCardDrawer/RemoveCreditCardDrawer.tsx
ADDED
|
@@ -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,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 @@
|
|
|
1
|
+
export type { CreditCard, CreditCardData } from "./CreditCard";
|
package/src/features/org-units/components/AddAllToOrgUnitDropdown/AddAllToOrgUnitDropdown.tsx
CHANGED
|
@@ -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
|
-
|
|
15
|
-
<
|
|
16
|
-
<
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
<
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
<
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
<
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
<
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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;
|
package/src/themes/layouts.scss
CHANGED
|
@@ -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";
|