@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.
- package/CHANGELOG.md +1 -0
- package/package.json +1 -1
- package/public/buyer-portal-icons.svg +13 -6
- package/src/features/buying-policies/components/AddBuyingPolicyDrawer/AddBuyingPolicyDrawer.tsx +83 -0
- package/src/features/buying-policies/components/AddBuyingPolicyDrawer/add-buying-policy-drawer.scss +1 -0
- package/src/features/buying-policies/components/BasicBuyingPolicyDrawer/BasicBuyingPolicyDrawer.tsx +383 -0
- package/src/features/buying-policies/components/BasicBuyingPolicyDrawer/basic-buying-policy-drawer.scss +103 -0
- package/src/features/buying-policies/components/BuyingPolicyDropdownMenu/BuyingPolicyDropdownMenu.tsx +78 -16
- package/src/features/buying-policies/components/BuyingPolicyDropdownMenu/buying-policy-dropdown-menu.scss +2 -0
- package/src/features/buying-policies/components/DeleteBuyingPolicyDrawer/DeleteBuyingPolicyDrawer.tsx +115 -0
- package/src/features/buying-policies/components/DeleteBuyingPolicyDrawer/delete-buying-policy-drawer.scss +5 -0
- package/src/features/buying-policies/components/UpdateBuyingPolicyDrawer/UpdateBuyingPolicyDrawer.tsx +96 -0
- package/src/features/buying-policies/components/UpdateBuyingPolicyDrawer/update-buying-policy-drawer.scss +0 -0
- package/src/features/buying-policies/components/index.ts +18 -0
- package/src/features/buying-policies/hooks/index.ts +4 -0
- package/src/features/buying-policies/hooks/useAddBuyingPolicy.ts +26 -0
- package/src/features/buying-policies/hooks/useGetBuyingPolicy.ts +27 -0
- package/src/features/buying-policies/hooks/useRemoveBuyingPolicy.ts +26 -0
- package/src/features/buying-policies/hooks/useUpdateBuyingPolicy.ts +26 -0
- package/src/features/buying-policies/layouts/BuyingPoliciesLayout/BuyingPoliciesLayout.tsx +64 -37
- package/src/features/buying-policies/layouts/BuyingPoliciesLayout/buying-policies-layout.scss +3 -1
- package/src/features/buying-policies/layouts/BuyingPolicyDetailsLayout/BuyingPolicyDetailsLayout.tsx +15 -10
- package/src/features/buying-policies/mocks/buying-policy-data.ts +35 -15
- package/src/features/buying-policies/services/add-buying-policy.service.ts +15 -0
- package/src/features/buying-policies/services/get-buying-policy.service.ts +19 -0
- package/src/features/buying-policies/services/index.ts +19 -0
- package/src/features/buying-policies/services/remove-buying-policy.service.ts +11 -0
- package/src/features/buying-policies/services/update-buying-policy.service.ts +18 -0
- package/src/features/buying-policies/types/BuyingPolicy.ts +19 -0
- package/src/features/buying-policies/types/index.ts +1 -1
- package/src/features/buying-policies/utils/buyingPolicyDefault.ts +17 -0
- package/src/features/buying-policies/utils/index.ts +3 -0
- package/src/features/buying-policies/utils/orderFieldsCriteriaOptions.ts +47 -0
- package/src/features/buying-policies/utils/spendingLimitsCriteriaOptions.ts +27 -0
- package/src/features/shared/components/AutocompleteDropdown/AutocompleteDropdown.tsx +1 -1
- package/src/features/shared/components/BasicDrawer/BasicDrawerBody.tsx +1 -1
- package/src/features/shared/components/InputText/InputText.tsx +16 -2
- package/src/features/shared/components/InputText/Legend.tsx +9 -0
- package/src/features/shared/components/InputText/input-text.scss +8 -0
- package/src/features/shared/components/LevelDivider/LevelDivider.tsx +11 -0
- package/src/features/shared/components/LevelDivider/level-divider.scss +21 -0
- package/src/features/shared/components/OptionSelected/OptionSelected.tsx +7 -3
- package/src/features/shared/components/OrgUnitInputSearch/OrgUnitInputSearch.tsx +74 -0
- package/src/features/shared/components/OrgUnitInputSearch/org-unit-input-search.scss +4 -0
- package/src/features/shared/components/index.ts +4 -0
- package/src/features/buying-policies/types/BuyingPolicies.ts +0 -10
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -339,12 +339,19 @@
|
|
|
339
339
|
</symbol>
|
|
340
340
|
|
|
341
341
|
<symbol
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
<path
|
|
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>
|
package/src/features/buying-policies/components/AddBuyingPolicyDrawer/AddBuyingPolicyDrawer.tsx
ADDED
|
@@ -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
|
+
};
|
package/src/features/buying-policies/components/AddBuyingPolicyDrawer/add-buying-policy-drawer.scss
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import "../BasicBuyingPolicyDrawer/basic-buying-policy-drawer.scss";
|
package/src/features/buying-policies/components/BasicBuyingPolicyDrawer/BasicBuyingPolicyDrawer.tsx
ADDED
|
@@ -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
|
+
}
|