@licklist/design 0.65.0 → 0.66.0-dev.0
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/dist/date-time-button/DateTimeButton.js +1 -1
- package/dist/events/edit-event-modal/component/SelectEventProductSet/SelectEventProductSet.d.ts.map +1 -1
- package/dist/events/edit-event-modal/component/SelectEventProductSet/SelectEventProductSet.js +1 -1
- package/dist/events/edit-event-modal/component/SelectEventProductSet/component/EditEventProductSet.d.ts.map +1 -1
- package/dist/events/edit-event-modal/component/SelectEventProductSet/component/EditEventProductSet.js +1 -1
- package/dist/iframe/payment/order-items-table/utils/paymentSummary.d.ts.map +1 -1
- package/dist/iframe/ryft/RyftPaymentForm.d.ts +4 -1
- package/dist/iframe/ryft/RyftPaymentForm.d.ts.map +1 -1
- package/dist/iframe/ryft/RyftPaymentForm.js +1 -1
- package/dist/iframe/ryft/utils/ryft-form.d.ts +5 -2
- package/dist/iframe/ryft/utils/ryft-form.d.ts.map +1 -1
- package/dist/iframe/ryft/utils/ryft-form.js +1 -1
- package/dist/product-set/control/DateAndRecurrenceInput.d.ts +1 -1
- package/dist/product-set/control/DateAndRecurrenceInput.d.ts.map +1 -1
- package/dist/product-set/control/DateAndRecurrenceInput.js +1 -1
- package/dist/product-set/control/DateInput.js +1 -1
- package/dist/product-set/control/ProductSetControl.d.ts +3 -2
- package/dist/product-set/control/ProductSetControl.d.ts.map +1 -1
- package/dist/product-set/control/ProductSetControl.js +1 -1
- package/dist/product-set/form/ProductCategoriesControl.d.ts +3 -1
- package/dist/product-set/form/ProductCategoriesControl.d.ts.map +1 -1
- package/dist/product-set/form/ProductCategoriesControl.js +1 -1
- package/dist/product-set/form/ProductSetForm.d.ts +6 -2
- package/dist/product-set/form/ProductSetForm.d.ts.map +1 -1
- package/dist/product-set/form/ProductSetForm.js +1 -1
- package/dist/product-set/form/ProductsControl.d.ts +3 -1
- package/dist/product-set/form/ProductsControl.d.ts.map +1 -1
- package/dist/product-set/form/ProductsControl.js +1 -1
- package/dist/product-set/form/StepsControl.d.ts +3 -1
- package/dist/product-set/form/StepsControl.d.ts.map +1 -1
- package/dist/product-set/form/StepsControl.js +1 -1
- package/dist/product-set/product/ProductControl.d.ts +1 -0
- package/dist/product-set/product/ProductControl.d.ts.map +1 -1
- package/dist/product-set/product/ProductControl.js +1 -1
- package/dist/product-set/step/StepControl.d.ts +2 -1
- package/dist/product-set/step/StepControl.d.ts.map +1 -1
- package/dist/product-set/step/StepControl.js +1 -1
- package/dist/provider/working-hours-input/WorkingHoursInputDescription.d.ts.map +1 -1
- package/dist/provider/working-hours-input/WorkingHoursInputDescription.js +1 -1
- package/dist/recurring-date-picker-input/RecurrenceIntervalAndFrequencyInput.d.ts.map +1 -1
- package/dist/recurring-date-picker-input/RecurrenceIntervalAndFrequencyInput.js +1 -1
- package/dist/recurring-date-picker-input/RecurringDatePickerInput.d.ts +3 -1
- package/dist/recurring-date-picker-input/RecurringDatePickerInput.d.ts.map +1 -1
- package/dist/recurring-date-picker-input/RecurringDatePickerInput.js +1 -1
- package/dist/recurring-date-picker-input/utils.d.ts +5 -0
- package/dist/recurring-date-picker-input/utils.d.ts.map +1 -1
- package/dist/recurring-date-picker-input/utils.js +1 -1
- package/dist/report/ReportRunnerModal/ReportRunnerModal.d.ts +1 -1
- package/dist/report/ReportRunnerModal/ReportRunnerModal.d.ts.map +1 -1
- package/dist/report/ReportRunnerModal/ReportRunnerModal.js +1 -1
- package/dist/sales/booking/results/components/ResultCard.d.ts.map +1 -1
- package/dist/setting/admin/AdminSettingForm.d.ts +2 -2
- package/dist/setting/admin/AdminSettingForm.d.ts.map +1 -1
- package/dist/sortable-tree/SortableTreeItem.d.ts +1 -2
- package/dist/sortable-tree/SortableTreeItem.d.ts.map +1 -1
- package/dist/sortable-tree/SortableTreeItem.js +1 -1
- package/dist/styles/date-time-button/DateTimeButton.scss +1 -0
- package/dist/styles/iframe-page/PageBody.scss +0 -1
- package/dist/styles/ryft-payment-form/RyftPaymentForm.scss +8 -0
- package/dist/styles/sales/BookingResults.scss +1 -1
- package/dist/styles/zones/ZoneForm.scss +2 -1
- package/dist/zone/form/ZoneForm.d.ts +2 -2
- package/dist/zone/form/ZoneForm.d.ts.map +1 -1
- package/dist/zone/form/ZoneForm.js +1 -1
- package/dist/zone/form/components/ZoneControl.d.ts +2 -2
- package/dist/zone/form/components/ZoneControl.d.ts.map +1 -1
- package/dist/zone/form/components/ZoneControl.js +1 -1
- package/dist/zone/form/components/ZoneRecurrencesControl.d.ts +4 -4
- package/dist/zone/form/components/ZoneRecurrencesControl.d.ts.map +1 -1
- package/dist/zone/form/components/ZoneRecurrencesControl.js +1 -1
- package/dist/zone/form/utils/dates.d.ts.map +1 -1
- package/package.json +3 -5
- package/src/date-time-button/DateTimeButton.stories.tsx +2 -1
- package/src/date-time-button/DateTimeButton.tsx +7 -5
- package/src/events/edit-event-modal/component/SelectEventProductSet/SelectEventProductSet.tsx +14 -9
- package/src/events/edit-event-modal/component/SelectEventProductSet/component/EditEventProductSet.tsx +2 -0
- package/src/iframe/payment/order-items-table/utils/paymentSummary.tsx +1 -0
- package/src/iframe/ryft/RyftPaymentForm.tsx +11 -2
- package/src/iframe/ryft/utils/ryft-form.ts +23 -4
- package/src/product-set/control/DateAndRecurrenceInput.tsx +3 -4
- package/src/product-set/control/DateInput.tsx +2 -2
- package/src/product-set/control/ProductSetControl.tsx +17 -5
- package/src/product-set/form/ProductCategoriesControl.tsx +15 -4
- package/src/product-set/form/ProductSetForm.tsx +13 -2
- package/src/product-set/form/ProductsControl.tsx +93 -77
- package/src/product-set/form/StepsControl.tsx +15 -7
- package/src/product-set/product/ProductControl.tsx +8 -5
- package/src/product-set/step/StepControl.tsx +4 -3
- package/src/provider/working-hours-input/WorkingHoursInputDescription.tsx +4 -18
- package/src/recurring-date-picker-input/RecurrenceIntervalAndFrequencyInput.tsx +49 -21
- package/src/recurring-date-picker-input/RecurringDatePickerInput.stories.tsx +13 -7
- package/src/recurring-date-picker-input/RecurringDatePickerInput.tsx +12 -1
- package/src/recurring-date-picker-input/utils.ts +90 -1
- package/src/report/ReportRunnerModal/ReportRunnerModal.stories.tsx +307 -0
- package/src/report/ReportRunnerModal/ReportRunnerModal.tsx +24 -14
- package/src/sales/booking/results/components/ResultCard.tsx +0 -3
- package/src/setting/admin/AdminSettingForm.tsx +2 -2
- package/src/sortable-tree/SortableTreeItem.tsx +0 -3
- package/src/static/switch/BooleanSwitch.tsx +1 -1
- package/src/styles/date-time-button/DateTimeButton.scss +1 -0
- package/src/styles/iframe-page/PageBody.scss +0 -1
- package/src/styles/ryft-payment-form/RyftPaymentForm.scss +8 -0
- package/src/styles/sales/BookingResults.scss +1 -1
- package/src/styles/zones/ZoneForm.scss +2 -1
- package/src/zone/form/ZoneForm.tsx +3 -2
- package/src/zone/form/components/ZoneControl.tsx +3 -3
- package/src/zone/form/components/ZoneRecurrencesControl.tsx +7 -5
- package/src/zone/form/utils/dates.ts +9 -10
|
@@ -35,6 +35,8 @@ interface ProductsControlProps extends WithIsLoading {
|
|
|
35
35
|
categoryType: CategoryType;
|
|
36
36
|
zones?: Zone[];
|
|
37
37
|
isOverrides?: boolean;
|
|
38
|
+
isEventEditProductSet?: boolean;
|
|
39
|
+
isCreateNewOverrides?: boolean;
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
const getDefaultProductValue = (sort: number): Product => ({
|
|
@@ -57,6 +59,7 @@ const getDefaultProductValue = (sort: number): Product => ({
|
|
|
57
59
|
quantitySelector: 1,
|
|
58
60
|
hasSpecialNotes: false,
|
|
59
61
|
weight: 0,
|
|
62
|
+
originalProductId: null,
|
|
60
63
|
type: DEFAULT_PRODUCT_TYPE,
|
|
61
64
|
tierId: Number(uniqueId()),
|
|
62
65
|
zoneId: null,
|
|
@@ -79,6 +82,8 @@ export function ProductsControl({
|
|
|
79
82
|
categoryType,
|
|
80
83
|
zones,
|
|
81
84
|
isOverrides,
|
|
85
|
+
isEventEditProductSet,
|
|
86
|
+
isCreateNewOverrides,
|
|
82
87
|
}: ProductsControlProps) {
|
|
83
88
|
const { t } = useTranslation("Design");
|
|
84
89
|
const form = useFormContext<ProductSetFormValues>();
|
|
@@ -203,90 +208,101 @@ export function ProductsControl({
|
|
|
203
208
|
onDragEnd={handleDragEnd}
|
|
204
209
|
sensors={[mouseSensor]}
|
|
205
210
|
>
|
|
206
|
-
{fields.map((product, index) =>
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
<
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
211
|
+
{fields.map((product, index) => {
|
|
212
|
+
const isOverridesProductSet = isEventEditProductSet
|
|
213
|
+
? !!product.id
|
|
214
|
+
: isOverrides && !!product.originalProductId;
|
|
215
|
+
|
|
216
|
+
const isNewProductOverrides = isCreateNewOverrides && !!product.id;
|
|
217
|
+
|
|
218
|
+
return (
|
|
219
|
+
<Controller
|
|
220
|
+
key={product._id}
|
|
221
|
+
control={control}
|
|
222
|
+
name={`${productControlFieldName}.${index}.name` as const}
|
|
223
|
+
rules={{
|
|
224
|
+
required: t("Validation:fieldRequired", {
|
|
225
|
+
attribute: t("name"),
|
|
226
|
+
}) as string,
|
|
227
|
+
}}
|
|
228
|
+
render={({ field: { value, onChange } }) => (
|
|
229
|
+
<SortableTree.Item
|
|
230
|
+
key={`product-${product._id}`}
|
|
231
|
+
id={String(product._id)}
|
|
232
|
+
isExpanded={isFirstProductAdded}
|
|
233
|
+
isInvalid={!!categoryProductErrors}
|
|
234
|
+
title={value}
|
|
235
|
+
isOverride={isOverrides}
|
|
236
|
+
badge={
|
|
237
|
+
<Badge className="product-badge">{t("product")}</Badge>
|
|
238
|
+
}
|
|
239
|
+
isIconInHeader={false}
|
|
240
|
+
cancelChanges={() => cancelChanges(index)}
|
|
241
|
+
edit={() => edit(index)}
|
|
242
|
+
secondaryBadge={getBadgeConfig(categoryType, t(categoryType))}
|
|
243
|
+
subTitle={
|
|
244
|
+
<div className="product-set-badges-container">
|
|
245
|
+
<div className="product-set-subtitle-dot product-set-subtitle-product-dot" />
|
|
246
|
+
<span>
|
|
247
|
+
{`£${prices[index]} ${t("each")} - ${t("qty")}:${
|
|
248
|
+
!isUnlimitedQuantities[index]
|
|
249
|
+
? ` ${quantities[index]}`
|
|
250
|
+
: t(" unlimited")
|
|
251
|
+
} ${
|
|
252
|
+
!isUnlimitedQuantities[index]
|
|
253
|
+
? ` - ${t("possibleRevenue")} £${
|
|
254
|
+
prices[index] * quantities[index]
|
|
255
|
+
}`
|
|
256
|
+
: ""
|
|
257
|
+
} `}
|
|
258
|
+
</span>
|
|
259
|
+
</div>
|
|
260
|
+
}
|
|
261
|
+
modalLabel={t("addNewProduct")}
|
|
262
|
+
modalClass={ProductSetModalClasses.product}
|
|
263
|
+
isNewAdded={showProductModal}
|
|
264
|
+
body={
|
|
265
|
+
<ProductControl<ProductSetFormValues>
|
|
266
|
+
isLoading={isLoading}
|
|
267
|
+
quantityType={quantityType}
|
|
268
|
+
allowDeposits={allowDeposits}
|
|
269
|
+
hasBookingManagement={false}
|
|
270
|
+
fieldNamePrefix={
|
|
271
|
+
`${productControlFieldName}.${index}` as const
|
|
272
|
+
}
|
|
273
|
+
productName={value}
|
|
274
|
+
onProductNameChange={onChange}
|
|
275
|
+
hasTicket={hasTicket}
|
|
276
|
+
categoryType={categoryType}
|
|
277
|
+
zoneDuration={catergoryZone?.defaultDuration}
|
|
278
|
+
isOverrides={
|
|
279
|
+
isNewProductOverrides || isOverridesProductSet
|
|
280
|
+
}
|
|
281
|
+
/>
|
|
282
|
+
}
|
|
283
|
+
onDelete={() => onProductRemove(index)}
|
|
284
|
+
validate={() =>
|
|
285
|
+
trigger(`${productControlFieldName}.${index}`)
|
|
286
|
+
}
|
|
287
|
+
saveValidField={saveValidField}
|
|
288
|
+
// preItem={<Popover className="d-none d-sm-block" />}
|
|
289
|
+
>
|
|
290
|
+
<SubProductsControl
|
|
253
291
|
isLoading={isLoading}
|
|
254
292
|
quantityType={quantityType}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
`${productControlFieldName}.${index}` as const
|
|
259
|
-
}
|
|
260
|
-
productName={value}
|
|
261
|
-
onProductNameChange={onChange}
|
|
262
|
-
hasTicket={hasTicket}
|
|
263
|
-
categoryType={categoryType}
|
|
264
|
-
zoneDuration={catergoryZone?.defaultDuration}
|
|
265
|
-
isOverrides={isOverrides}
|
|
293
|
+
stepIndex={stepIndex}
|
|
294
|
+
productCategoryIndex={productCategoryIndex}
|
|
295
|
+
productIndex={index}
|
|
266
296
|
/>
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
>
|
|
273
|
-
<SubProductsControl
|
|
274
|
-
isLoading={isLoading}
|
|
275
|
-
quantityType={quantityType}
|
|
276
|
-
stepIndex={stepIndex}
|
|
277
|
-
productCategoryIndex={productCategoryIndex}
|
|
278
|
-
productIndex={index}
|
|
279
|
-
/>
|
|
280
|
-
</SortableTree.Item>
|
|
281
|
-
)}
|
|
282
|
-
/>
|
|
283
|
-
))}
|
|
297
|
+
</SortableTree.Item>
|
|
298
|
+
)}
|
|
299
|
+
/>
|
|
300
|
+
);
|
|
301
|
+
})}
|
|
284
302
|
</SortableTree>
|
|
285
303
|
<CreateProductSetItem
|
|
286
304
|
title={t("addProduct")}
|
|
287
|
-
isOverride={isOverrides}
|
|
288
305
|
onClick={() => {
|
|
289
|
-
if (isOverrides) return;
|
|
290
306
|
append(getDefaultProductValue(fields.length));
|
|
291
307
|
setShowProductModal(true);
|
|
292
308
|
|
|
@@ -19,9 +19,16 @@ import { ProductSetFormValues } from "./ProductSetForm";
|
|
|
19
19
|
interface StepsControlProps {
|
|
20
20
|
isLoading: boolean;
|
|
21
21
|
isOverrides?: boolean;
|
|
22
|
+
isEventEditProductSet?: boolean;
|
|
23
|
+
isCreateNewOverrides?: boolean;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
|
-
export function StepsControl({
|
|
26
|
+
export function StepsControl({
|
|
27
|
+
isLoading,
|
|
28
|
+
isOverrides,
|
|
29
|
+
isEventEditProductSet,
|
|
30
|
+
isCreateNewOverrides,
|
|
31
|
+
}: StepsControlProps) {
|
|
25
32
|
const form = useFormContext<ProductSetFormValues>();
|
|
26
33
|
const { t } = useTranslation("Design");
|
|
27
34
|
const [showStepModal, setShowStepModal] = useState(false);
|
|
@@ -68,9 +75,9 @@ export function StepsControl({ isLoading, isOverrides }: StepsControlProps) {
|
|
|
68
75
|
<>
|
|
69
76
|
{fields.map((step, index) => {
|
|
70
77
|
const stepFieldName = `steps.${index}` as const;
|
|
71
|
-
|
|
72
78
|
const stepData = getValues(stepFieldName);
|
|
73
|
-
|
|
79
|
+
const isOverrideStep =
|
|
80
|
+
(isOverrides || isCreateNewOverrides) && !!step.id;
|
|
74
81
|
return (
|
|
75
82
|
<Controller
|
|
76
83
|
key={`step-${step._id}`}
|
|
@@ -92,9 +99,9 @@ export function StepsControl({ isLoading, isOverrides }: StepsControlProps) {
|
|
|
92
99
|
modalLabel={t("addNewStep")}
|
|
93
100
|
modalClass={ProductSetModalClasses.step}
|
|
94
101
|
isNewAdded={showStepModal}
|
|
95
|
-
edit={() =>
|
|
102
|
+
edit={() => edit(index)}
|
|
96
103
|
cancelChanges={() => cancelChanges(index)}
|
|
97
|
-
isOverride={
|
|
104
|
+
isOverride={isOverrideStep}
|
|
98
105
|
subTitle={
|
|
99
106
|
<div className="product-set-badges-container">
|
|
100
107
|
<div className="product-set-subtitle-dot product-set-subtitle-step-dot" />
|
|
@@ -110,6 +117,7 @@ export function StepsControl({ isLoading, isOverrides }: StepsControlProps) {
|
|
|
110
117
|
stepIndex={index}
|
|
111
118
|
stepName={value}
|
|
112
119
|
onStepNameChange={onChange}
|
|
120
|
+
isOverrides={isOverrideStep}
|
|
113
121
|
/>
|
|
114
122
|
}
|
|
115
123
|
onDelete={() => remove(index)}
|
|
@@ -140,6 +148,8 @@ export function StepsControl({ isLoading, isOverrides }: StepsControlProps) {
|
|
|
140
148
|
isLoading={isLoading}
|
|
141
149
|
stepIndex={index}
|
|
142
150
|
isOverrides={isOverrides}
|
|
151
|
+
isCreateNewOverrides={isCreateNewOverrides}
|
|
152
|
+
isEventEditProductSet={isEventEditProductSet}
|
|
143
153
|
/>
|
|
144
154
|
</SortableTree.Item>
|
|
145
155
|
)}
|
|
@@ -149,9 +159,7 @@ export function StepsControl({ isLoading, isOverrides }: StepsControlProps) {
|
|
|
149
159
|
|
|
150
160
|
<CreateProductSetItem
|
|
151
161
|
title={t("addStep")}
|
|
152
|
-
isOverride={isOverrides}
|
|
153
162
|
onClick={() => {
|
|
154
|
-
if (isOverrides) return;
|
|
155
163
|
append(getDefaultStepsValues());
|
|
156
164
|
setShowStepModal(true);
|
|
157
165
|
if (errors.steps?.type === HookFormService.manualErrorType) {
|
|
@@ -7,14 +7,17 @@ import {
|
|
|
7
7
|
QUANTITY_TYPE_LIST_DTO,
|
|
8
8
|
QUANTITY_TYPE_RECHARGING,
|
|
9
9
|
} from "@licklist/core/dist/DataMapper/Product/ProductCategoryDataMapper";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
ProductType,
|
|
12
|
+
PRODUCT_DEfAULT_COLORS,
|
|
13
|
+
} from "@licklist/core/dist/DataMapper/Product/ProductDataMapper";
|
|
11
14
|
import HookFormService from "@licklist/plugins/dist/services/Form/HookFormService";
|
|
15
|
+
import clsx from "clsx";
|
|
12
16
|
import {
|
|
13
17
|
FieldNamePrefixPath,
|
|
14
18
|
FormValues,
|
|
15
19
|
} from "@licklist/plugins/dist/types/services/Form/hook-form-service";
|
|
16
20
|
import { useId } from "@react-aria/utils";
|
|
17
|
-
import clsx from "clsx";
|
|
18
21
|
import React, {
|
|
19
22
|
ChangeEvent,
|
|
20
23
|
useCallback,
|
|
@@ -36,7 +39,7 @@ import {
|
|
|
36
39
|
} from "react-hook-form";
|
|
37
40
|
import { useTranslation } from "react-i18next";
|
|
38
41
|
import { useImages } from "@licklist/plugins/dist/hooks/Media/useImages";
|
|
39
|
-
|
|
42
|
+
|
|
40
43
|
import {
|
|
41
44
|
Image,
|
|
42
45
|
IMAGE_TYPE_IMAGE,
|
|
@@ -86,6 +89,7 @@ export interface ProductControlValues
|
|
|
86
89
|
totalQuantity: number;
|
|
87
90
|
isAvailable: boolean;
|
|
88
91
|
isSoldOut: boolean;
|
|
92
|
+
originalProductId: number | null;
|
|
89
93
|
isUnlimited: boolean;
|
|
90
94
|
isRequired: boolean;
|
|
91
95
|
quantitySelector: number;
|
|
@@ -156,7 +160,6 @@ export function ProductControl<T extends FormValues>({
|
|
|
156
160
|
);
|
|
157
161
|
const capacity = watch(`${fieldNamePrefix}.capacity` as Path<T>);
|
|
158
162
|
const disabledDuration = capacity === "0" || !capacity;
|
|
159
|
-
|
|
160
163
|
const advancedId = useId();
|
|
161
164
|
const nameId = useId();
|
|
162
165
|
|
|
@@ -410,7 +413,7 @@ export function ProductControl<T extends FormValues>({
|
|
|
410
413
|
`${fieldNamePrefix}.productGroupId` as Path<T>,
|
|
411
414
|
errors
|
|
412
415
|
)}
|
|
413
|
-
disabled={isLoading}
|
|
416
|
+
disabled={isLoading || isOverrides}
|
|
414
417
|
defaultValue=""
|
|
415
418
|
>
|
|
416
419
|
<option value="">{t("Design:selectProductGroup")}</option>
|
|
@@ -26,6 +26,7 @@ export interface StepControlProps extends IsDeletableEvent {
|
|
|
26
26
|
stepIndex: number;
|
|
27
27
|
stepName: string;
|
|
28
28
|
onStepNameChange: (args: any) => void;
|
|
29
|
+
isOverrides?: boolean;
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
export function StepControl({
|
|
@@ -33,6 +34,7 @@ export function StepControl({
|
|
|
33
34
|
stepIndex,
|
|
34
35
|
stepName,
|
|
35
36
|
onStepNameChange,
|
|
37
|
+
isOverrides = false,
|
|
36
38
|
}: StepControlProps) {
|
|
37
39
|
const { providerHasMap } = useContext(ProductSetLoadingContext);
|
|
38
40
|
const {
|
|
@@ -42,7 +44,6 @@ export function StepControl({
|
|
|
42
44
|
watch,
|
|
43
45
|
} = useFormContext<ProductSetFormValues>();
|
|
44
46
|
const { t } = useTranslation("Design");
|
|
45
|
-
|
|
46
47
|
const fieldName = `steps.${stepIndex}.name` as const;
|
|
47
48
|
const productCategoriesFieldName =
|
|
48
49
|
`steps.${stepIndex}.productCategories` as const;
|
|
@@ -71,7 +72,7 @@ export function StepControl({
|
|
|
71
72
|
fieldName,
|
|
72
73
|
errors
|
|
73
74
|
)}
|
|
74
|
-
disabled={isLoading}
|
|
75
|
+
disabled={isLoading || isOverrides}
|
|
75
76
|
/>
|
|
76
77
|
)}
|
|
77
78
|
control={control}
|
|
@@ -114,7 +115,7 @@ export function StepControl({
|
|
|
114
115
|
name={name}
|
|
115
116
|
value={Boolean(value)}
|
|
116
117
|
onChange={onChange}
|
|
117
|
-
disabled={isLoading}
|
|
118
|
+
disabled={isLoading || isOverrides}
|
|
118
119
|
/>
|
|
119
120
|
)}
|
|
120
121
|
control={control}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { DateTime } from "luxon";
|
|
2
1
|
import React from "react";
|
|
3
2
|
import { Col, Row } from "react-bootstrap";
|
|
4
3
|
import { useFormContext } from "react-hook-form";
|
|
5
4
|
import { useTranslation } from "react-i18next";
|
|
6
|
-
import { TIME_FORMAT } from "@licklist/core/dist/Config";
|
|
7
5
|
import { WorkingHoursInputValues } from ".";
|
|
8
6
|
import { useWeekdays } from "./utils";
|
|
9
7
|
|
|
@@ -25,22 +23,10 @@ export function WorkingHoursInputDescription() {
|
|
|
25
23
|
<Row key={i}>
|
|
26
24
|
<Col xs="auto">{weekdays[i]}:</Col>
|
|
27
25
|
<Col>
|
|
28
|
-
{
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
TIME_FORMAT
|
|
33
|
-
),
|
|
34
|
-
end: DateTime.fromISO(weekday.start).toFormat(
|
|
35
|
-
TIME_FORMAT
|
|
36
|
-
),
|
|
37
|
-
})
|
|
38
|
-
: t("timeFrom", {
|
|
39
|
-
start: DateTime.fromISO(weekday.start).toFormat(
|
|
40
|
-
TIME_FORMAT
|
|
41
|
-
),
|
|
42
|
-
})
|
|
43
|
-
: null}
|
|
26
|
+
{t("timeInterval", {
|
|
27
|
+
start: weekday.start,
|
|
28
|
+
end: weekday.end,
|
|
29
|
+
})}
|
|
44
30
|
</Col>
|
|
45
31
|
</Row>
|
|
46
32
|
);
|
|
@@ -2,8 +2,18 @@ import React, { useEffect } from "react";
|
|
|
2
2
|
import { DateTime } from "luxon";
|
|
3
3
|
import { Col, Form, Row } from "react-bootstrap";
|
|
4
4
|
import { useTranslation } from "react-i18next";
|
|
5
|
-
import {
|
|
6
|
-
|
|
5
|
+
import {
|
|
6
|
+
RegisterOptions,
|
|
7
|
+
useFormContext,
|
|
8
|
+
useWatch,
|
|
9
|
+
Validate,
|
|
10
|
+
} from "react-hook-form";
|
|
11
|
+
import {
|
|
12
|
+
DATE_FORMAT,
|
|
13
|
+
TIME_FORMAT,
|
|
14
|
+
TIME_FULL_FORMAT,
|
|
15
|
+
} from "@licklist/core/dist/Config";
|
|
16
|
+
import { fromFormat } from "@licklist/plugins/dist/utils/dateTime";
|
|
7
17
|
import { RecurringDatePickerInputValues } from "./RecurringDatePickerInput";
|
|
8
18
|
|
|
9
19
|
interface RecurrenceIntervalAndFrequencyInputProps {
|
|
@@ -23,6 +33,15 @@ interface RecurrenceIntervalAndFrequencyInputProps {
|
|
|
23
33
|
>;
|
|
24
34
|
}
|
|
25
35
|
|
|
36
|
+
const fromTimeFormat = fromFormat(TIME_FORMAT);
|
|
37
|
+
const fromTimeFullFormat = fromFormat(TIME_FULL_FORMAT);
|
|
38
|
+
|
|
39
|
+
// default values and entered values are in different formats
|
|
40
|
+
const fromTimeFormats = (time: string) =>
|
|
41
|
+
fromTimeFormat(time).isValid
|
|
42
|
+
? fromTimeFormat(time)
|
|
43
|
+
: fromTimeFullFormat(time);
|
|
44
|
+
|
|
26
45
|
function RecurrenceIntervalAndFrequencyInput({
|
|
27
46
|
disabled = false,
|
|
28
47
|
minDate,
|
|
@@ -36,16 +55,20 @@ function RecurrenceIntervalAndFrequencyInput({
|
|
|
36
55
|
const { t } = useTranslation(["Design", "Notification", "App"]);
|
|
37
56
|
|
|
38
57
|
const {
|
|
39
|
-
getValues,
|
|
40
58
|
formState: { errors },
|
|
41
59
|
register,
|
|
42
60
|
trigger,
|
|
61
|
+
control,
|
|
43
62
|
} = useFormContext<RecurringDatePickerInputValues>();
|
|
44
63
|
|
|
45
|
-
const startDate =
|
|
46
|
-
const endDate =
|
|
47
|
-
|
|
48
|
-
const
|
|
64
|
+
const startDate = useWatch({ control, name: "startDate" });
|
|
65
|
+
const endDate = useWatch({ control, name: "endDate" });
|
|
66
|
+
|
|
67
|
+
const _startTime = useWatch({ control, name: "startTime" });
|
|
68
|
+
const startTime = fromTimeFormats(_startTime).toFormat(TIME_FORMAT);
|
|
69
|
+
|
|
70
|
+
const _endTime = useWatch({ control, name: "endTime" });
|
|
71
|
+
const endTime = fromTimeFormats(_endTime).toFormat(TIME_FORMAT);
|
|
49
72
|
|
|
50
73
|
useEffect(() => {
|
|
51
74
|
if (!startDate || !endDate) {
|
|
@@ -149,22 +172,27 @@ function RecurrenceIntervalAndFrequencyInput({
|
|
|
149
172
|
type="time"
|
|
150
173
|
{...register("endTime", {
|
|
151
174
|
required: false,
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
175
|
+
...endTimeRules,
|
|
176
|
+
validate: {
|
|
177
|
+
external: endTimeRules?.validate
|
|
178
|
+
? (endTimeRules?.validate as Validate<string>)
|
|
179
|
+
: () => true,
|
|
180
|
+
time: (time) => {
|
|
181
|
+
if (!startTime || !time) {
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
184
|
+
const currentStartTime = DateTime.fromISO(startTime);
|
|
185
|
+
const currentEndTime = DateTime.fromISO(time);
|
|
158
186
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
187
|
+
return currentEndTime?.diff(currentStartTime, ["minutes"])
|
|
188
|
+
?.minutes >= 0
|
|
189
|
+
? true
|
|
190
|
+
: `${t(`Validation:fieldLaterDate`, {
|
|
191
|
+
attribute: t("Design:endTimeSmall"),
|
|
192
|
+
min: t("Design:startTimeSmall"),
|
|
193
|
+
})}`;
|
|
194
|
+
},
|
|
166
195
|
},
|
|
167
|
-
...endTimeRules,
|
|
168
196
|
})}
|
|
169
197
|
placeholder="hh:mm"
|
|
170
198
|
defaultValue={endTime}
|
|
@@ -1,22 +1,19 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Meta, Story } from "@storybook/react";
|
|
3
3
|
import { Card } from "react-bootstrap";
|
|
4
|
+
import { DateTime } from "luxon";
|
|
5
|
+
import { DATE_FORMAT, TIME_FORMAT } from "@licklist/core/dist/Config/Date";
|
|
4
6
|
import {
|
|
5
7
|
RecurringDatePickerInput,
|
|
6
8
|
RecurringDatePickerInputProps,
|
|
7
9
|
} from "./RecurringDatePickerInput";
|
|
8
|
-
import { DateTime } from "luxon";
|
|
9
|
-
import { DATE_FORMAT, TIME_FORMAT } from "@licklist/core/dist/Config/Date";
|
|
10
10
|
|
|
11
11
|
export default {
|
|
12
12
|
title: "RecurringDatePickerInput",
|
|
13
13
|
component: RecurringDatePickerInput,
|
|
14
14
|
} as Meta;
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
extends RecurringDatePickerInputProps {}
|
|
18
|
-
|
|
19
|
-
export const Default: Story<DefaultRecurringDatePickerInputProps> = (args) => {
|
|
16
|
+
export const Default: Story<RecurringDatePickerInputProps> = (args) => {
|
|
20
17
|
return (
|
|
21
18
|
<Card style={{ maxWidth: "max-content" }}>
|
|
22
19
|
<Card.Body>
|
|
@@ -25,7 +22,7 @@ export const Default: Story<DefaultRecurringDatePickerInputProps> = (args) => {
|
|
|
25
22
|
</Card>
|
|
26
23
|
);
|
|
27
24
|
};
|
|
28
|
-
export const Valid: Story<
|
|
25
|
+
export const Valid: Story<RecurringDatePickerInputProps> = (args) => {
|
|
29
26
|
return (
|
|
30
27
|
<Card style={{ maxWidth: "max-content" }}>
|
|
31
28
|
<Card.Body>
|
|
@@ -36,6 +33,15 @@ export const Valid: Story<DefaultRecurringDatePickerInputProps> = (args) => {
|
|
|
36
33
|
};
|
|
37
34
|
Default.args = {
|
|
38
35
|
onChange: (data) => console.log("onSubmit", data),
|
|
36
|
+
workHours: [
|
|
37
|
+
{ start: "20:00", end: "04:00", day: 0, description: "" },
|
|
38
|
+
{ start: "20:00", end: "04:00", day: 1, description: "" },
|
|
39
|
+
{ start: "20:00", end: "04:00", day: 2, description: "" },
|
|
40
|
+
{ start: "20:00", end: "12:00", day: 3, description: "" },
|
|
41
|
+
{ start: "20:00", end: "23:00", day: 4, description: "" },
|
|
42
|
+
{ start: "08:00", end: "12:00", day: 5, description: "" },
|
|
43
|
+
{ start: "10:00", end: "16:00", day: 6, description: "" },
|
|
44
|
+
],
|
|
39
45
|
};
|
|
40
46
|
Valid.args = {
|
|
41
47
|
onChange: (data) => console.log("onSubmit", data),
|
|
@@ -12,9 +12,14 @@ import {
|
|
|
12
12
|
import { usePreviousValue } from "@licklist/plugins/dist/hooks/Value/usePreviousValue";
|
|
13
13
|
import { FormProvider, useForm } from "react-hook-form";
|
|
14
14
|
import { Form } from "react-bootstrap";
|
|
15
|
+
import { WorkHour } from "@licklist/core/dist/DataMapper/Provider/WorkHourDataMapper";
|
|
15
16
|
import RecurrenceIntervalAndFrequencyInput from "./RecurrenceIntervalAndFrequencyInput";
|
|
16
17
|
import RecurrenceWeekdaysInput from "./RecurrenceWeekdaysInput";
|
|
17
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
parseAndValidateRRule,
|
|
20
|
+
SupportedFrequency,
|
|
21
|
+
useWorkHoursValidation,
|
|
22
|
+
} from "./utils";
|
|
18
23
|
import { ConfirmModal } from "../modals";
|
|
19
24
|
import { DeleteFieldButton } from "../product-set/elements";
|
|
20
25
|
|
|
@@ -26,6 +31,7 @@ export interface RecurringDatePickerInputProps {
|
|
|
26
31
|
initialFrequency?: Frequency;
|
|
27
32
|
setInitialStartDateAfterSelect?: boolean;
|
|
28
33
|
minDate?: string;
|
|
34
|
+
workHours: WorkHour[] | undefined;
|
|
29
35
|
}
|
|
30
36
|
|
|
31
37
|
export interface RecurringDatePickerInputValues {
|
|
@@ -51,6 +57,7 @@ export function RecurringDatePickerInput({
|
|
|
51
57
|
setInitialStartDateAfterSelect = false,
|
|
52
58
|
children,
|
|
53
59
|
minDate,
|
|
60
|
+
workHours,
|
|
54
61
|
}: PropsWithChildren<RecurringDatePickerInputProps>) {
|
|
55
62
|
const { t } = useTranslation(["Design"]);
|
|
56
63
|
|
|
@@ -84,6 +91,8 @@ export function RecurringDatePickerInput({
|
|
|
84
91
|
byWeekDay,
|
|
85
92
|
});
|
|
86
93
|
|
|
94
|
+
const validator = useWorkHoursValidation(byWeekDay, workHours);
|
|
95
|
+
|
|
87
96
|
const onSubmit = (nextState: RecurringDatePickerInputValues) => {
|
|
88
97
|
const end = getDateTimeObject(endDate, endTime || "23:59:59");
|
|
89
98
|
|
|
@@ -188,6 +197,8 @@ export function RecurringDatePickerInput({
|
|
|
188
197
|
<RecurrenceIntervalAndFrequencyInput
|
|
189
198
|
disabled={disabled}
|
|
190
199
|
minDate={minDate}
|
|
200
|
+
startTimeRules={validator}
|
|
201
|
+
endTimeRules={validator}
|
|
191
202
|
/>
|
|
192
203
|
|
|
193
204
|
{children}
|