@vtex/faststore-plugin-buyer-portal 1.0.44 → 1.0.45

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 (46) hide show
  1. package/CHANGELOG.md +1 -0
  2. package/package.json +1 -1
  3. package/public/buyer-portal-icons.svg +13 -6
  4. package/src/features/buying-policies/components/AddBuyingPolicyDrawer/AddBuyingPolicyDrawer.tsx +83 -0
  5. package/src/features/buying-policies/components/AddBuyingPolicyDrawer/add-buying-policy-drawer.scss +1 -0
  6. package/src/features/buying-policies/components/BasicBuyingPolicyDrawer/BasicBuyingPolicyDrawer.tsx +383 -0
  7. package/src/features/buying-policies/components/BasicBuyingPolicyDrawer/basic-buying-policy-drawer.scss +103 -0
  8. package/src/features/buying-policies/components/BuyingPolicyDropdownMenu/BuyingPolicyDropdownMenu.tsx +78 -16
  9. package/src/features/buying-policies/components/BuyingPolicyDropdownMenu/buying-policy-dropdown-menu.scss +2 -0
  10. package/src/features/buying-policies/components/DeleteBuyingPolicyDrawer/DeleteBuyingPolicyDrawer.tsx +115 -0
  11. package/src/features/buying-policies/components/DeleteBuyingPolicyDrawer/delete-buying-policy-drawer.scss +5 -0
  12. package/src/features/buying-policies/components/UpdateBuyingPolicyDrawer/UpdateBuyingPolicyDrawer.tsx +96 -0
  13. package/src/features/buying-policies/components/UpdateBuyingPolicyDrawer/update-buying-policy-drawer.scss +0 -0
  14. package/src/features/buying-policies/components/index.ts +18 -0
  15. package/src/features/buying-policies/hooks/index.ts +4 -0
  16. package/src/features/buying-policies/hooks/useAddBuyingPolicy.ts +26 -0
  17. package/src/features/buying-policies/hooks/useGetBuyingPolicy.ts +27 -0
  18. package/src/features/buying-policies/hooks/useRemoveBuyingPolicy.ts +26 -0
  19. package/src/features/buying-policies/hooks/useUpdateBuyingPolicy.ts +26 -0
  20. package/src/features/buying-policies/layouts/BuyingPoliciesLayout/BuyingPoliciesLayout.tsx +64 -37
  21. package/src/features/buying-policies/layouts/BuyingPoliciesLayout/buying-policies-layout.scss +3 -1
  22. package/src/features/buying-policies/layouts/BuyingPolicyDetailsLayout/BuyingPolicyDetailsLayout.tsx +15 -10
  23. package/src/features/buying-policies/mocks/buying-policy-data.ts +35 -15
  24. package/src/features/buying-policies/services/add-buying-policy.service.ts +15 -0
  25. package/src/features/buying-policies/services/get-buying-policy.service.ts +19 -0
  26. package/src/features/buying-policies/services/index.ts +19 -0
  27. package/src/features/buying-policies/services/remove-buying-policy.service.ts +11 -0
  28. package/src/features/buying-policies/services/update-buying-policy.service.ts +18 -0
  29. package/src/features/buying-policies/types/BuyingPolicy.ts +19 -0
  30. package/src/features/buying-policies/types/index.ts +1 -1
  31. package/src/features/buying-policies/utils/buyingPolicyDefault.ts +17 -0
  32. package/src/features/buying-policies/utils/index.ts +3 -0
  33. package/src/features/buying-policies/utils/orderFieldsCriteriaOptions.ts +47 -0
  34. package/src/features/buying-policies/utils/spendingLimitsCriteriaOptions.ts +27 -0
  35. package/src/features/shared/components/AutocompleteDropdown/AutocompleteDropdown.tsx +1 -1
  36. package/src/features/shared/components/BasicDrawer/BasicDrawerBody.tsx +1 -1
  37. package/src/features/shared/components/InputText/InputText.tsx +16 -2
  38. package/src/features/shared/components/InputText/Legend.tsx +9 -0
  39. package/src/features/shared/components/InputText/input-text.scss +8 -0
  40. package/src/features/shared/components/LevelDivider/LevelDivider.tsx +11 -0
  41. package/src/features/shared/components/LevelDivider/level-divider.scss +21 -0
  42. package/src/features/shared/components/OptionSelected/OptionSelected.tsx +7 -3
  43. package/src/features/shared/components/OrgUnitInputSearch/OrgUnitInputSearch.tsx +74 -0
  44. package/src/features/shared/components/OrgUnitInputSearch/org-unit-input-search.scss +4 -0
  45. package/src/features/shared/components/index.ts +4 -0
  46. package/src/features/buying-policies/types/BuyingPolicies.ts +0 -10
package/CHANGELOG.md CHANGED
@@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
16
16
 
17
17
  - Add Buying Policies Page
18
18
  - Add Buying Policy Details Page
19
+ - Add Buying Policy Drawers
19
20
 
20
21
  ### Added
21
22
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vtex/faststore-plugin-buyer-portal",
3
- "version": "1.0.44",
3
+ "version": "1.0.45",
4
4
  "description": "A plugin for faststore with buyer portal",
5
5
  "main": "index.js",
6
6
  "dependencies": {
@@ -339,12 +339,19 @@
339
339
  </symbol>
340
340
 
341
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"/>
342
+ id="Rename"
343
+ viewBox="0 0 17 13"
344
+ fill="none"
345
+ xmlns="http://www.w3.org/2000/svg">
346
+ <path
347
+ d="M10.0712 12.6473V2.64734H6.0712V0.647339H16.0712V2.64734H12.0712V12.6473H10.0712ZM2.5712 12.6473V6.64734H0.0711975V4.64734H7.0712V6.64734H4.5712V12.6473H2.5712Z"
348
+ fill="currentColor" />
347
349
  </symbol>
348
350
 
351
+ <symbol id="MinusCircle" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
352
+ <path
353
+ d="M7 13H17V11H7V13ZM12 22C10.6167 22 9.31667 21.7375 8.1 21.2125C6.88333 20.6875 5.825 19.975 4.925 19.075C4.025 18.175 3.3125 17.1167 2.7875 15.9C2.2625 14.6833 2 13.3833 2 12C2 10.6167 2.2625 9.31667 2.7875 8.1C3.3125 6.88333 4.025 5.825 4.925 4.925C5.825 4.025 6.88333 3.3125 8.1 2.7875C9.31667 2.2625 10.6167 2 12 2C13.3833 2 14.6833 2.2625 15.9 2.7875C17.1167 3.3125 18.175 4.025 19.075 4.925C19.975 5.825 20.6875 6.88333 21.2125 8.1C21.7375 9.31667 22 10.6167 22 12C22 13.3833 21.7375 14.6833 21.2125 15.9C20.6875 17.1167 19.975 18.175 19.075 19.075C18.175 19.975 17.1167 20.6875 15.9 21.2125C14.6833 21.7375 13.3833 22 12 22ZM12 20C14.2333 20 16.125 19.225 17.675 17.675C19.225 16.125 20 14.2333 20 12C20 9.76667 19.225 7.875 17.675 6.325C16.125 4.775 14.2333 4 12 4C9.76667 4 7.875 4.775 6.325 6.325C4.775 7.875 4 9.76667 4 12C4 14.2333 4.775 16.125 6.325 17.675C7.875 19.225 9.76667 20 12 20Z"
354
+ fill="currentColor" />
355
+ </symbol>
349
356
 
350
- </svg>
357
+ </svg>
@@ -0,0 +1,83 @@
1
+ import { useUI } from "@faststore/ui";
2
+ import { useRouter } from "next/router";
3
+ import type { BasicDrawerProps } from "../../../shared/components";
4
+ import { useAddBuyingPolicy } from "../../hooks";
5
+ import type { BuyingPolicy } from "../../types";
6
+ import { buyerPortalRoutes } from "../../../shared/utils/buyerPortalRoutes";
7
+ import { BasicBuyingPolicyDrawer, type BasicBuyingPolicyDrawerProps } from "..";
8
+
9
+ export type AddBuyingPolicyDrawerProps = Omit<
10
+ BasicBuyingPolicyDrawerProps,
11
+ "children"
12
+ > & {
13
+ onCreate?: () => void;
14
+ orgUnitId: string;
15
+ contractId: string;
16
+ };
17
+
18
+ export const AddBuyingPolicyDrawer = ({
19
+ close,
20
+ onCreate,
21
+ orgUnitId,
22
+ contractId,
23
+ ...props
24
+ }: AddBuyingPolicyDrawerProps) => {
25
+ const { pushToast } = useUI();
26
+ const router = useRouter();
27
+
28
+ const handleAddBuyingPolicySuccess = (data: BuyingPolicy) => {
29
+ pushToast({
30
+ message: "Buying policy added successfully",
31
+ status: "INFO",
32
+ icon: (
33
+ <button
34
+ data-fs-bp-toast-view-button
35
+ type="button"
36
+ onClick={() => {
37
+ //TODO: Redirect to the user page
38
+ router.push(
39
+ buyerPortalRoutes.buyingPolicyDetails({
40
+ orgUnitId,
41
+ contractId,
42
+ buyingPolicyId: data.id,
43
+ })
44
+ );
45
+ }}
46
+ >
47
+ View
48
+ </button>
49
+ ),
50
+ });
51
+ onCreate?.();
52
+ close();
53
+ };
54
+
55
+ const { addBuyingPolicy, isAddBuyingPolicyLoading } = useAddBuyingPolicy({
56
+ onSuccess: handleAddBuyingPolicySuccess,
57
+ onError: () => {
58
+ pushToast({
59
+ message: "Error adding buying policy",
60
+ status: "ERROR",
61
+ });
62
+ },
63
+ });
64
+
65
+ return (
66
+ <BasicBuyingPolicyDrawer
67
+ close={close}
68
+ isLoading={isAddBuyingPolicyLoading}
69
+ onConfirm={(form) =>
70
+ addBuyingPolicy({
71
+ buyingPolicy: {
72
+ ...form,
73
+ },
74
+ orgUnitId,
75
+ contractId,
76
+ })
77
+ }
78
+ orgUnitId={orgUnitId}
79
+ contractId={contractId}
80
+ {...props}
81
+ />
82
+ );
83
+ };
@@ -0,0 +1 @@
1
+ @import "../BasicBuyingPolicyDrawer/basic-buying-policy-drawer.scss";
@@ -0,0 +1,383 @@
1
+ import {
2
+ type DetailedHTMLProps,
3
+ Fragment,
4
+ type HTMLAttributes,
5
+ useEffect,
6
+ useState,
7
+ } from "react";
8
+
9
+ import {
10
+ type BasicDrawerProps,
11
+ AutocompleteDropdown,
12
+ BasicDrawer,
13
+ BasicDropdownMenu,
14
+ ErrorMessage,
15
+ Icon,
16
+ InputText,
17
+ LevelDivider,
18
+ } from "../../../shared/components";
19
+ import { buyingPolicyOptions, type BuyingPolicy } from "../../types";
20
+ import { OrgUnitInputSearch } from "../../../shared/components/OrgUnitInputSearch/OrgUnitInputSearch";
21
+ import {
22
+ buyingPolicyDefault,
23
+ orderFieldsCriteriaOptions,
24
+ spendingLimitsCriteriaOptions,
25
+ } from "../../utils";
26
+ import { Dropdown, DropdownButton, DropdownItem } from "@faststore/ui";
27
+
28
+ const LIMIT_OF_LEVELS = 5;
29
+
30
+ export type BuyingPolicyForm = Omit<BuyingPolicy, "id"> & {
31
+ id?: string;
32
+ };
33
+
34
+ const defaultBuyingPolicyValues: BuyingPolicyForm = buyingPolicyDefault;
35
+
36
+ export type BasicBuyingPolicyDrawerProps = Omit<
37
+ BasicDrawerProps,
38
+ "children"
39
+ > & {
40
+ onCreate?: () => void;
41
+ onConfirm?: (buyingPolicyForm: BuyingPolicyForm) => void;
42
+ isLoading?: boolean;
43
+ orgUnitId: string;
44
+ contractId: string;
45
+ initialValues?: BuyingPolicyForm;
46
+ drawerTitle?: string;
47
+ saveButtonLabel?: string;
48
+ };
49
+
50
+ export const BasicBuyingPolicyDrawer = ({
51
+ drawerTitle = "Add new buying policy",
52
+ saveButtonLabel = "Add",
53
+ close,
54
+ onCreate,
55
+ isLoading,
56
+ onConfirm,
57
+ orgUnitId,
58
+ contractId,
59
+ initialValues = defaultBuyingPolicyValues,
60
+ ...props
61
+ }: BasicBuyingPolicyDrawerProps) => {
62
+ const [form, setForm] = useState<BuyingPolicyForm>(initialValues);
63
+
64
+ useEffect(() => {
65
+ if (initialValues) {
66
+ setForm((prev) => ({
67
+ ...prev,
68
+ ...initialValues,
69
+ }));
70
+ }
71
+ }, [initialValues]);
72
+
73
+ const [isTouched, setIsTouched] = useState(false);
74
+
75
+ const { name, description, criteria, action } = form;
76
+
77
+ const updateField = (field: keyof typeof form, value: string | object) => {
78
+ setForm((prev) => ({
79
+ ...prev,
80
+ [field]: value,
81
+ }));
82
+ };
83
+
84
+ const isAllFeldsFilled = Object.keys(form).every((key) => {
85
+ const value = form[key as keyof typeof form];
86
+
87
+ if (key === "action") {
88
+ const valueAction = value as BuyingPolicy["action"];
89
+
90
+ if (!valueAction.type) {
91
+ return false;
92
+ }
93
+
94
+ if (valueAction.type === "Sequential approval workflow") {
95
+ return (
96
+ valueAction.levels?.length &&
97
+ valueAction.levels.every((level) => {
98
+ return level.id;
99
+ })
100
+ );
101
+ }
102
+
103
+ return true;
104
+ }
105
+
106
+ return (form[key as keyof typeof form] as string)?.trim();
107
+ });
108
+
109
+ const handleConfirmClick = () => {
110
+ setIsTouched(true);
111
+
112
+ if (!isAllFeldsFilled) {
113
+ return;
114
+ }
115
+
116
+ onConfirm?.({
117
+ ...form,
118
+ orgUnitId,
119
+ contractId,
120
+ } as BuyingPolicyForm);
121
+ };
122
+
123
+ const addEmptyLevel = () => {
124
+ updateField("action", {
125
+ type: action.type,
126
+ levels: [
127
+ ...(action.levels ?? []),
128
+ {
129
+ id: "",
130
+ name: "",
131
+ },
132
+ ],
133
+ });
134
+ };
135
+
136
+ const selectLevel = (
137
+ orgUnit: { name: string; id: string },
138
+ index: number
139
+ ) => {
140
+ const updatedLevels = [...(action.levels ?? [])];
141
+ updatedLevels[index] = {
142
+ id: orgUnit.id,
143
+ name: orgUnit.name,
144
+ };
145
+ updateField("action", {
146
+ type: action.type,
147
+ levels: updatedLevels,
148
+ });
149
+ };
150
+
151
+ const removeLevel = (levelIndex: number) => {
152
+ const updatedLevels = (action.levels ?? []).filter(
153
+ (_, idx) => idx !== levelIndex
154
+ );
155
+
156
+ updateField("action", {
157
+ type: action.type,
158
+ levels: updatedLevels,
159
+ });
160
+ };
161
+
162
+ const isConfirmButtonEnabled = isAllFeldsFilled && !isLoading;
163
+
164
+ return (
165
+ <BasicDrawer data-fs-bp-basic-buying-policy-drawer close={close} {...props}>
166
+ <BasicDrawer.Heading title={drawerTitle} onClose={close} />
167
+
168
+ <BasicDrawer.Body>
169
+ <h3>Basic information</h3>
170
+ <h4>
171
+ Define policy name and description to inform buyers during checkout
172
+ </h4>
173
+
174
+ <InputText
175
+ label="Name"
176
+ value={name}
177
+ hasError={isTouched && !name?.trim()}
178
+ onChange={(event) => updateField("name", event.target.value)}
179
+ />
180
+
181
+ <ErrorMessage
182
+ show={isTouched && !name?.trim()}
183
+ message="Name is required"
184
+ />
185
+
186
+ <InputText
187
+ label="Description"
188
+ value={description}
189
+ wrapperProps={{ style: { marginTop: 16, marginBottom: 16 } }}
190
+ hasError={isTouched && !description?.trim()}
191
+ onChange={(event) => updateField("description", event.target.value)}
192
+ />
193
+
194
+ <ErrorMessage
195
+ show={isTouched && !name?.trim()}
196
+ message="Description is required"
197
+ />
198
+
199
+ <h3>Criteria</h3>
200
+ <h4>
201
+ Define the conditions that will trigger this buying policy using{" "}
202
+ <a href="https://jsonata.org/">JSONata</a>
203
+ </h4>
204
+
205
+ <InputText
206
+ label=""
207
+ value={criteria}
208
+ wrapperProps={
209
+ {
210
+ style: { marginTop: 16, marginBottom: 16 },
211
+ "data-fs-bp-input-text-criteria": true,
212
+ "data-fs-bp-input-text-code": true,
213
+ } as DetailedHTMLProps<
214
+ HTMLAttributes<HTMLDivElement>,
215
+ HTMLDivElement
216
+ >
217
+ }
218
+ hasError={isTouched && !description?.trim()}
219
+ onChange={(event) => updateField("criteria", event.target.value)}
220
+ />
221
+
222
+ <ErrorMessage
223
+ show={isTouched && !name?.trim()}
224
+ message="Criteria is required"
225
+ />
226
+
227
+ <div data-fs-bp-criteria-selectors-wrapper>
228
+ <Dropdown>
229
+ <DropdownButton asChild>
230
+ <button data-fs-bp-criteria-selector-trigger type="button">
231
+ Set spending limit criteria
232
+ </button>
233
+ </DropdownButton>
234
+ <BasicDropdownMenu>
235
+ {spendingLimitsCriteriaOptions.map((option) => (
236
+ <DropdownItem
237
+ key={option.label}
238
+ onClick={() => {
239
+ updateField("criteria", option.criteria);
240
+ }}
241
+ >
242
+ {option.label}
243
+ </DropdownItem>
244
+ ))}
245
+ </BasicDropdownMenu>
246
+ </Dropdown>
247
+
248
+ <Dropdown>
249
+ <DropdownButton asChild>
250
+ <button type="button" data-fs-bp-criteria-selector-trigger>
251
+ Set order field criteria
252
+ </button>
253
+ </DropdownButton>
254
+ <BasicDropdownMenu>
255
+ {orderFieldsCriteriaOptions.map((option) => (
256
+ <DropdownItem
257
+ key={option.label}
258
+ onClick={() => {
259
+ updateField("criteria", option.criteria);
260
+ }}
261
+ dismissOnClick
262
+ >
263
+ {option.label}
264
+ </DropdownItem>
265
+ ))}
266
+ </BasicDropdownMenu>
267
+ </Dropdown>
268
+ </div>
269
+
270
+ <h3>Action</h3>
271
+ <h4>Define how orders that meet the criteria will be handled</h4>
272
+
273
+ <AutocompleteDropdown
274
+ label=""
275
+ wrapperProps={
276
+ {
277
+ "data-fs-bp-input-text-criteria": true,
278
+ } as DetailedHTMLProps<
279
+ HTMLAttributes<HTMLDivElement>,
280
+ HTMLDivElement
281
+ >
282
+ }
283
+ value={action.type}
284
+ options={[...buyingPolicyOptions]}
285
+ onConfirmKeyPress={(option) => {
286
+ updateField("action", {
287
+ type: option,
288
+ levels: [],
289
+ });
290
+ }}
291
+ hasError={isTouched && !action.type?.trim()}
292
+ renderOption={(optionActionType, index) => (
293
+ <AutocompleteDropdown.Item
294
+ key={optionActionType}
295
+ closeOnClick
296
+ index={index}
297
+ isSelected={action.type === optionActionType}
298
+ onClick={() => {
299
+ updateField("action", {
300
+ type: optionActionType,
301
+ levels: [
302
+ {
303
+ id: "",
304
+ name: "",
305
+ },
306
+ ],
307
+ });
308
+ }}
309
+ >
310
+ {optionActionType}
311
+ </AutocompleteDropdown.Item>
312
+ )}
313
+ />
314
+
315
+ {action.type === "Bypass all buying policies" && (
316
+ <InputText.Legend>
317
+ When this policy is applied, all opther buying policy will be
318
+ ignored
319
+ </InputText.Legend>
320
+ )}
321
+
322
+ <ErrorMessage
323
+ show={isTouched && !action.type?.trim()}
324
+ message="Action is required"
325
+ />
326
+
327
+ {form.action.type === "Sequential approval workflow" && (
328
+ <>
329
+ {form.action.levels?.map((level, index) => (
330
+ <Fragment key={`${level.id}-${index}`}>
331
+ <LevelDivider label={`Level ${index + 1}`} />
332
+ <div data-fs-bp-buying-policy-level-wrapper>
333
+ <OrgUnitInputSearch
334
+ orgUnit={{
335
+ name: level.name ?? "",
336
+ id: level.id,
337
+ }}
338
+ onSelect={(orgUnit) => selectLevel(orgUnit, index)}
339
+ selectedTriggerIcon={<Icon name="MinusCircle" />}
340
+ onSelectedTriggerClick={() => removeLevel(index)}
341
+ hasError={isTouched && !level.name?.trim()}
342
+ />
343
+ <button type="button" onClick={() => removeLevel(index)}>
344
+ <Icon name="MinusCircle" />
345
+ </button>
346
+ </div>
347
+
348
+ <ErrorMessage
349
+ show={isTouched && !name?.trim()}
350
+ message="Criteria is required"
351
+ />
352
+ </Fragment>
353
+ ))}
354
+
355
+ {(action.levels?.length ?? 0) < LIMIT_OF_LEVELS && (
356
+ <button
357
+ type="button"
358
+ onClick={addEmptyLevel}
359
+ data-fs-bp-buying-policy-add-level-button
360
+ >
361
+ Add approval level
362
+ </button>
363
+ )}
364
+ </>
365
+ )}
366
+ </BasicDrawer.Body>
367
+
368
+ <BasicDrawer.Footer>
369
+ <BasicDrawer.Button variant="ghost" onClick={close}>
370
+ Cancel
371
+ </BasicDrawer.Button>
372
+ <BasicDrawer.Button
373
+ variant="confirm"
374
+ disabled={!isConfirmButtonEnabled}
375
+ onClick={handleConfirmClick}
376
+ isLoading={isLoading}
377
+ >
378
+ {saveButtonLabel}
379
+ </BasicDrawer.Button>
380
+ </BasicDrawer.Footer>
381
+ </BasicDrawer>
382
+ );
383
+ };
@@ -0,0 +1,103 @@
1
+ @import "../../../shared/components/BasicDrawer/basic-drawer.scss";
2
+ @import "../../../shared/components/OrgUnitInputSearch/org-unit-input-search.scss";
3
+
4
+ [data-fs-bp-basic-buying-policy-drawer] {
5
+ @import "../../../shared/components/InputText/input-text.scss";
6
+ @import "../../../shared/components/ErrorMessage/error-message.scss";
7
+ @import "../../../shared/components/LevelDivider/level-divider.scss";
8
+
9
+ [data-fs-bp-basic-drawer-body] {
10
+ padding-bottom: 90px;
11
+ h3 {
12
+ font-weight: var(--fs-text-weight-semibold);
13
+ font-size: var(--fs-text-size-2);
14
+ line-height: var(--fs-spacing-4);
15
+ margin-top: var(--fs-spacing-6);
16
+
17
+ &:first-of-type {
18
+ margin-top: 0;
19
+ }
20
+ }
21
+
22
+ h4 {
23
+ font-weight: var(--fs-text-weight-regular);
24
+ font-size: var(--fs-text-size-1);
25
+ line-height: calc(var(--fs-spacing-0) + var(--fs-spacing-3));
26
+ margin-bottom: calc(var(--fs-spacing-0) + var(--fs-spacing-3));
27
+ }
28
+
29
+ a {
30
+ color: #0366dd;
31
+ }
32
+
33
+ [data-fs-bp-buying-policy-level-wrapper] {
34
+ width: 100%;
35
+ position: relative;
36
+
37
+ button {
38
+ cursor: pointer;
39
+ position: absolute;
40
+ top: 50%;
41
+ right: var(--fs-spacing-1);
42
+ transform: translateY(-50%);
43
+ background-color: white;
44
+ }
45
+ }
46
+
47
+ [data-fs-bp-criteria-selectors-wrapper] {
48
+ width: 100%;
49
+ display: flex;
50
+ align-items: center;
51
+ justify-content: flex-start;
52
+ gap: var(--fs-spacing-2);
53
+ }
54
+
55
+ [data-fs-bp-input-text-criteria] {
56
+ color: #5c5c5c;
57
+
58
+ &[data-fs-bp-input-text-code] {
59
+ background-color: #f5f5f5;
60
+ }
61
+
62
+ [data-fs-bp-input-text-input] {
63
+ bottom: 50%;
64
+ transform: translateY(50%);
65
+ font-size: var(--fs-text-size-2);
66
+ }
67
+ }
68
+
69
+ [data-fs-bp-criteria-selector-trigger] {
70
+ border: var(--fs-border-width) solid #e0e0e0;
71
+ background-color: #ffffff;
72
+ color: #0068d7;
73
+ display: flex;
74
+ align-items: center;
75
+ justify-content: center;
76
+ position: relative;
77
+ cursor: pointer;
78
+ padding: var(--fs-spacing-2)
79
+ calc(var(--fs-spacing-3) + var(--fs-spacing-0));
80
+ min-width: 10.625rem;
81
+ border-radius: var(--fs-border-radius-pill);
82
+ font-size: var(--fs-text-size-1);
83
+ font-weight: 600;
84
+ line-height: var(--fs-spacing-3);
85
+ text-align: center;
86
+ }
87
+
88
+ [data-fs-bp-buying-policy-add-level-button] {
89
+ padding: var(--fs-spacing-2)
90
+ calc(var(--fs-spacing-0) + var(--fs-spacing-3));
91
+ margin: calc(var(--fs-spacing-0) + var(--fs-spacing-3)) 0;
92
+ border-radius: var(--fs-border-radius-pill);
93
+ border: var(--fs-border-width) solid #d6d6d6;
94
+ cursor: pointer;
95
+
96
+ font-weight: var(--fs-text-weight-semibold);
97
+ font-size: var(--fs-text-size-1);
98
+ line-height: calc(var(--fs-spacing-0) + var(--fs-spacing-3));
99
+ text-align: center;
100
+ color: #0366dd;
101
+ }
102
+ }
103
+ }