@licklist/design 0.63.0-dev.1 → 0.63.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/bitbucket-pipelines.yml +8 -0
- package/dist/date-time-button/DateTimeButton.js +1 -1
- package/dist/events/edit-event-modal/component/EditEventForm/EditEventForm.d.ts +1 -3
- package/dist/events/edit-event-modal/component/EditEventForm/EditEventForm.d.ts.map +1 -1
- package/dist/events/edit-event-modal/component/EditEventForm/EditEventForm.js +1 -1
- package/dist/events/edit-event-modal/component/SelectEventProductSet/SelectEventProductSet.d.ts +1 -3
- 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 +1 -3
- 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.js +1 -1
- package/dist/product-set/control/DateAndRecurrenceInput.d.ts +5 -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.d.ts.map +1 -1
- package/dist/product-set/control/DateInput.js +1 -1
- package/dist/product-set/control/ProductSetControl.d.ts +3 -4
- 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 +1 -2
- 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 +1 -4
- package/dist/product-set/form/ProductSetForm.d.ts.map +1 -1
- package/dist/product-set/form/ProductsControl.d.ts +1 -2
- 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 +1 -2
- package/dist/product-set/form/StepsControl.d.ts.map +1 -1
- package/dist/product-set/form/StepsControl.js +1 -1
- package/dist/product-set/hooks/useSortableTreeFunctions.d.ts.map +1 -1
- package/dist/product-set/product/ProductControl.d.ts +0 -1
- package/dist/product-set/product/ProductControl.d.ts.map +1 -1
- package/dist/product-set/product/ProductControl.js +1 -1
- package/dist/product-set/product/fixed-duration-fields/FixedDurationOptions.d.ts.map +1 -1
- package/dist/product-set/step/StepControl.d.ts +1 -2
- 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/RecurrenceAndFrequencyInput.d.ts.map +1 -1
- package/dist/recurring-date-picker-input/RecurringDatePickerInput.d.ts +1 -3
- 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 +0 -12
- package/dist/recurring-date-picker-input/utils.d.ts.map +1 -1
- package/dist/recurring-date-picker-input/utils.js +1 -1
- package/dist/sales/booking/results/components/ResultCard.d.ts.map +1 -1
- package/dist/sales/booking/results/components/ResultCard.js +1 -1
- package/dist/sales/coupon/control/CouponFormControl.d.ts +1 -2
- package/dist/sales/coupon/control/CouponFormControl.d.ts.map +1 -1
- package/dist/sales/coupon/control/CouponFormControl.js +1 -1
- package/dist/sales/coupon/form/CouponFrom.d.ts +2 -2
- package/dist/sales/coupon/form/CouponFrom.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/setting/dashboard/DashboardSettingForm.d.ts +0 -1
- package/dist/setting/dashboard/DashboardSettingForm.d.ts.map +1 -1
- package/dist/setting/dashboard/DashboardSettingForm.js +1 -1
- package/dist/sortable-tree/SortableTreeItem.d.ts +2 -1
- package/dist/sortable-tree/SortableTreeItem.d.ts.map +1 -1
- package/dist/sortable-tree/SortableTreeItem.js +1 -1
- package/dist/styles/sales/BookingResults.scss +1 -1
- package/dist/typeahead/Typeahead.d.ts +1 -2
- package/dist/typeahead/Typeahead.d.ts.map +1 -1
- package/dist/typeahead/Typeahead.js +1 -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/AvailableTimesControl.d.ts +2 -0
- package/dist/zone/form/components/AvailableTimesControl.d.ts.map +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/jest.config.js +29 -0
- package/package.json +35 -10
- package/src/date-time-button/DateTimeButton.stories.tsx +1 -2
- package/src/date-time-button/DateTimeButton.tsx +5 -7
- package/src/events/edit-event-modal/component/EditEventForm/EditEventForm.tsx +0 -4
- package/src/events/edit-event-modal/component/SelectEventProductSet/SelectEventProductSet.tsx +9 -18
- package/src/events/edit-event-modal/component/SelectEventProductSet/component/EditEventProductSet.tsx +0 -5
- package/src/iframe/payment/order-items-table/utils/paymentSummary.tsx +6 -6
- package/src/product-set/control/DateAndRecurrenceInput.tsx +14 -48
- package/src/product-set/control/DateInput.tsx +4 -2
- package/src/product-set/control/ProductSetControl.stories.tsx +1 -1
- package/src/product-set/control/ProductSetControl.tsx +11 -12
- package/src/product-set/form/ProductCategoriesControl.tsx +4 -8
- package/src/product-set/form/ProductSetForm.stories.tsx +2 -1
- package/src/product-set/form/ProductSetForm.tsx +1 -5
- package/src/product-set/form/ProductsControl.tsx +77 -87
- package/src/product-set/form/StepsControl.tsx +6 -11
- package/src/product-set/hooks/useSortableTreeFunctions.ts +0 -2
- package/src/product-set/product/ProductControl.tsx +39 -39
- package/src/product-set/product/fixed-duration-fields/FixedDurationOptions.tsx +2 -0
- package/src/product-set/step/StepControl.tsx +3 -4
- package/src/provider/working-hours-input/WorkingHoursInputDescription.tsx +18 -4
- package/src/recurring-date-picker-input/RecurrenceAndFrequencyInput.tsx +1 -0
- package/src/recurring-date-picker-input/RecurringDatePickerInput.tsx +1 -11
- package/src/recurring-date-picker-input/utils.ts +0 -77
- package/src/sales/booking/results/BookingResults.stories.tsx +2 -3
- package/src/sales/booking/results/components/ResultCard.tsx +5 -2
- package/src/sales/coupon/control/CouponFormControl.tsx +51 -28
- package/src/sales/coupon/form/CouponFrom.tsx +15 -5
- package/src/setting/admin/AdminSettingForm.tsx +2 -2
- package/src/setting/dashboard/DashboardSettingForm.tsx +0 -13
- package/src/sortable-tree/SortableTreeItem.tsx +4 -1
- package/src/static/switch/BooleanSwitch.tsx +1 -1
- package/src/styles/sales/BookingResults.scss +1 -1
- package/src/typeahead/Typeahead.tsx +3 -16
- package/src/zone/form/ZoneForm.tsx +2 -3
- package/src/zone/form/components/AvailableTimesControl.tsx +2 -0
- package/src/zone/form/components/ZoneControl.tsx +3 -3
- package/src/zone/form/components/ZoneRecurrencesControl.tsx +5 -7
- package/src/zone/form/utils/dates.ts +10 -9
- package/tests/Auth/Authorizer.test.tsx +194 -0
- package/tests/Auth/Layout/UserNavDropDown.test.tsx +43 -0
- package/tests/Auth/Layout/UserNavDropDownToggle.test.tsx +33 -0
- package/tests/Auth/Login/LoginComponent.test.tsx +246 -0
- package/tests/Auth/Login/LoginFormComponent.test.tsx +182 -0
- package/tests/Auth/Register/RegisterComponent.test.tsx +285 -0
- package/tests/Auth/Register/RegisterFormComponent.test.tsx +170 -0
- package/tests/Auth/Settings/Dashboard/IpInput.test.tsx +130 -0
- package/tests/Auth/Social/SocialCallbackComponent.test.tsx +133 -0
- package/tests/Auth/Social/SocialFormComponent.test.tsx +118 -0
- package/tests/FileUpload/FileUpload.test.tsx +42 -0
- package/tests/Notification/EmailTemplate.test.tsx +82 -0
- package/tests/ProductSet/ProductSetPopover.test.tsx +40 -0
- package/tests/Report/Report.test.tsx +48 -0
- package/tests/Sales/Coupon.test.tsx +51 -0
- package/tests/Sales/SalesAndVIews.test.tsx +63 -0
- package/tests/SnippetTemplates/SnippetTemplates.test.tsx +56 -0
- package/tests/Table/FilterHelperComponent.test.tsx +88 -0
- package/tests/Table/PaginationHelperComponent.test.tsx +109 -0
- package/tests/Table/PerPageHelperComponent.test.tsx +34 -0
- package/tests/Table/TableHelperComponent.test.tsx +295 -0
- package/tests/TipTapEditor/TipTapEditor.test.tsx +28 -0
- package/tests/__mock__/hooks/useAuthApi.ts +13 -0
- package/tests/__mock__/hooks/useAuthMock.ts +13 -0
- package/tests/__mock__/hooks/useFormMock.ts +27 -0
- package/tests/__mock__/hooks/useNotificationMock.ts +13 -0
- package/tests/__mock__/hooks/useQueryMock.ts +16 -0
- package/tests/__mock__/hooks/useSocialApiMock.ts +20 -0
- package/tests/__mock__/hooks/useTranslationMock.ts +17 -0
- package/tests/__mock__/hooks/useUserApiMock.ts +18 -0
- package/tests/__mock__/hooks/useUserMock.ts +13 -0
- package/tests/__mock__/styleMock.js +1 -0
- package/tests/__mock__/windowMock.ts +5 -0
- package/tests/packages/react-query.tsx +28 -0
- package/tests/setupTests.ts +10 -0
- package/dist/product-set/control/utils.d.ts +0 -5
- package/dist/product-set/control/utils.d.ts.map +0 -1
- package/dist/product-set/control/utils.js +0 -1
- package/dist/sales/coupon/utils/index.d.ts +0 -7
- package/dist/sales/coupon/utils/index.d.ts.map +0 -1
- package/dist/sales/coupon/utils/index.js +0 -1
- package/src/product-set/control/utils.ts +0 -25
- package/src/sales/coupon/utils/index.ts +0 -13
|
@@ -2,7 +2,7 @@ import React, { useEffect, useRef, useState } from "react";
|
|
|
2
2
|
import { Modifier } from "@popperjs/core";
|
|
3
3
|
import { useId } from "@react-aria/utils";
|
|
4
4
|
import { Form, OverlayTrigger, Popover } from "react-bootstrap";
|
|
5
|
-
import { useFieldArray, useFormContext
|
|
5
|
+
import { useFieldArray, useFormContext } from "react-hook-form";
|
|
6
6
|
import { useTranslation } from "react-i18next";
|
|
7
7
|
import { useClickAway } from "react-use";
|
|
8
8
|
import { DateTime } from "luxon";
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
SortableContext,
|
|
15
15
|
verticalListSortingStrategy,
|
|
16
16
|
} from "@dnd-kit/sortable";
|
|
17
|
+
|
|
17
18
|
import { restrictToVerticalAxis } from "@dnd-kit/modifiers";
|
|
18
19
|
import { CONFIRM_MODAL_ACTIONS } from "../../modals/confirmation/ConfirmModal";
|
|
19
20
|
import { Icon } from "../../static";
|
|
@@ -26,15 +27,16 @@ import {
|
|
|
26
27
|
AvailableTimesControl,
|
|
27
28
|
AvailableTimesControlRef,
|
|
28
29
|
} from "../../zone/form/components/AvailableTimesControl";
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
|
|
31
|
+
// eslint-disable-next-line max-len
|
|
32
|
+
|
|
33
|
+
export interface DateAndRecurrenceInputValues {
|
|
34
|
+
menuRecurrences?: Partial<ProductSetRecurrence>[];
|
|
35
|
+
}
|
|
34
36
|
|
|
35
37
|
interface DateAndRecurrenceInputProps {
|
|
36
38
|
isEventEditProductSet?: boolean;
|
|
37
|
-
workHours
|
|
39
|
+
workHours?: WorkHour[];
|
|
38
40
|
providerHasBookingManagement: boolean;
|
|
39
41
|
isLoading?: boolean;
|
|
40
42
|
}
|
|
@@ -52,9 +54,7 @@ export const DateAndRecurrenceInput = ({
|
|
|
52
54
|
getValues,
|
|
53
55
|
setValue,
|
|
54
56
|
clearErrors,
|
|
55
|
-
} = useFormContext<
|
|
56
|
-
|
|
57
|
-
const steps = useWatch({ control, name: "steps" });
|
|
57
|
+
} = useFormContext<DateAndRecurrenceInputValues>();
|
|
58
58
|
|
|
59
59
|
const [availableTimes, setAvailableTimes] = useState<string[]>([]);
|
|
60
60
|
const availableTimesFormRef = useRef<AvailableTimesControlRef>();
|
|
@@ -90,7 +90,7 @@ export const DateAndRecurrenceInput = ({
|
|
|
90
90
|
clearEditState();
|
|
91
91
|
});
|
|
92
92
|
|
|
93
|
-
const popoverId = useId()
|
|
93
|
+
const popoverId = useId()!;
|
|
94
94
|
|
|
95
95
|
const { t } = useTranslation("Design");
|
|
96
96
|
|
|
@@ -101,13 +101,11 @@ export const DateAndRecurrenceInput = ({
|
|
|
101
101
|
const isAvailableTimesFormValid =
|
|
102
102
|
await availableTimesFormRef.current?.trigger();
|
|
103
103
|
|
|
104
|
-
const { availableTimes } = availableTimesFormRef.current.getValues();
|
|
105
|
-
|
|
106
104
|
if (next?.startTime && next?.endTime && isAvailableTimesFormValid) {
|
|
107
105
|
const startTime = DateTime.fromISO(next.startTime);
|
|
108
106
|
const endTime = DateTime.fromISO(next.endTime);
|
|
109
|
-
|
|
110
|
-
const
|
|
107
|
+
const { availableTimes } = availableTimesFormRef.current.getValues();
|
|
108
|
+
const validAvalilableTimes = availableTimes.every((time) => {
|
|
111
109
|
const currentAvailableTime = DateTime.fromFormat(time, TIME_FORMAT);
|
|
112
110
|
|
|
113
111
|
return (
|
|
@@ -115,8 +113,7 @@ export const DateAndRecurrenceInput = ({
|
|
|
115
113
|
currentAvailableTime.diff(endTime, "minutes").minutes <= 0
|
|
116
114
|
);
|
|
117
115
|
});
|
|
118
|
-
|
|
119
|
-
if (!areAvailableTimesValid) {
|
|
116
|
+
if (!validAvalilableTimes) {
|
|
120
117
|
availableTimesFormRef.current.setError("availableTimes", {
|
|
121
118
|
message: t("Validation:fieldTimeBetween", {
|
|
122
119
|
attribute: t("Design:startTimesSmall"),
|
|
@@ -129,36 +126,6 @@ export const DateAndRecurrenceInput = ({
|
|
|
129
126
|
}
|
|
130
127
|
}
|
|
131
128
|
|
|
132
|
-
// this check is required to prevent user from adding available time
|
|
133
|
-
// less than the lowest duration product, e.g. if lowest duration product
|
|
134
|
-
// is 1 hour and user tries to add time 15 minutes before end time,
|
|
135
|
-
// such time can never be booked
|
|
136
|
-
const lowestDurationProduct = getProductWithSmallestDuration(steps);
|
|
137
|
-
|
|
138
|
-
if (lowestDurationProduct) {
|
|
139
|
-
const endTime = next?.endTime
|
|
140
|
-
? DateTime.fromFormat(next?.endTime, TIME_FORMAT)
|
|
141
|
-
: // this is to allow user to add 23:00 if end is at 23:59
|
|
142
|
-
DateTime.fromFormat("23:59", TIME_FORMAT).plus({ minutes: 1 });
|
|
143
|
-
|
|
144
|
-
const latestAvailableTime = getLatestAvailableDateTime(availableTimes);
|
|
145
|
-
|
|
146
|
-
const latestAllowedTime = endTime.minus({
|
|
147
|
-
minutes: lowestDurationProduct.duration,
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
if (latestAvailableTime > latestAllowedTime) {
|
|
151
|
-
availableTimesFormRef.current.setError("availableTimes", {
|
|
152
|
-
message: t("Validation:fieldTimeBefore", {
|
|
153
|
-
attribute: t("Design:timeLowercase"),
|
|
154
|
-
time: latestAllowedTime.toFormat(TIME_FORMAT),
|
|
155
|
-
}),
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
129
|
const availableTime =
|
|
163
130
|
availableTimesFormRef?.current?.getValues()?.availableTimes || null;
|
|
164
131
|
|
|
@@ -261,7 +228,6 @@ export const DateAndRecurrenceInput = ({
|
|
|
261
228
|
defaultValues={editState.values}
|
|
262
229
|
onChange={handleRecurringDateChange}
|
|
263
230
|
onDelete={handleDelete}
|
|
264
|
-
workHours={workHours}
|
|
265
231
|
>
|
|
266
232
|
{providerHasBookingManagement && (
|
|
267
233
|
<AvailableTimesControl
|
|
@@ -5,8 +5,9 @@ import { Form, OverlayTrigger, Popover } from "react-bootstrap";
|
|
|
5
5
|
import { useFieldArray, useFormContext } from "react-hook-form";
|
|
6
6
|
import { useTranslation } from "react-i18next";
|
|
7
7
|
import { useClickAway } from "react-use";
|
|
8
|
-
import {
|
|
8
|
+
import { TIMEZONE } from "@licklist/core/dist/Config/Date";
|
|
9
9
|
import { ProductSetRecurrence } from "@licklist/core/dist/DataMapper/Product/ProductSetRecurrenceDataMapper";
|
|
10
|
+
import { TIME_FORMAT } from "@licklist/core/dist/Config/Date";
|
|
10
11
|
import { DateTime } from "luxon";
|
|
11
12
|
import RRule, { Frequency } from "rrule";
|
|
12
13
|
import { WorkHour } from "@licklist/core/dist/DataMapper/Provider/WorkHourDataMapper";
|
|
@@ -26,6 +27,7 @@ import {
|
|
|
26
27
|
import { ProductSetRecurrenceOverridesControl } from "./ProductSetRecurrenceOverridesControl";
|
|
27
28
|
import { MAX_QUANTITY_RECURRENCE_DATE_IN_OVERRIDE } from "../product/constants";
|
|
28
29
|
|
|
30
|
+
|
|
29
31
|
export interface DateAndRecurrenceInputValues {
|
|
30
32
|
menuRecurrences?: Partial<ProductSetRecurrence>[];
|
|
31
33
|
}
|
|
@@ -136,7 +138,7 @@ export const DateInput = ({
|
|
|
136
138
|
until: (start as DateTime).toJSDate(),
|
|
137
139
|
byweekday: [],
|
|
138
140
|
freq: Frequency.DAILY,
|
|
139
|
-
tzid:
|
|
141
|
+
tzid: TIMEZONE,
|
|
140
142
|
interval: 1,
|
|
141
143
|
}).replace("RRULE:", "");
|
|
142
144
|
|
|
@@ -2,12 +2,12 @@ import { Meta, Story } from "@storybook/react";
|
|
|
2
2
|
import React from "react";
|
|
3
3
|
import Form from "react-bootstrap/Form";
|
|
4
4
|
import { FormProvider, useForm } from "react-hook-form";
|
|
5
|
-
import { OPERATIONAL_COST_CUSTOMER } from "@licklist/core/dist/DataMapper/Product/ProductSetDataMapper";
|
|
6
5
|
import {
|
|
7
6
|
ProductSetControl,
|
|
8
7
|
ProductSetControlProps,
|
|
9
8
|
ProductSetControlValues,
|
|
10
9
|
} from "./ProductSetControl";
|
|
10
|
+
import { OPERATIONAL_COST_CUSTOMER } from "@licklist/core/dist/DataMapper/Product/ProductSetDataMapper";
|
|
11
11
|
|
|
12
12
|
export default {
|
|
13
13
|
title: "Product Set/Control",
|
|
@@ -22,10 +22,14 @@ import { SmsTemplate } from "@licklist/core/dist/DataMapper/Notification/SmsTemp
|
|
|
22
22
|
import HookFormService from "@licklist/plugins/dist/services/Form/HookFormService";
|
|
23
23
|
import { ruleForUrlWithProtocol } from "@licklist/plugins/dist/validation/Rules/urlRule";
|
|
24
24
|
import { WorkHour } from "@licklist/core/dist/DataMapper/Provider/WorkHourDataMapper";
|
|
25
|
-
import { ProductSetRecurrence } from "@licklist/core/dist/DataMapper/Product/ProductSetRecurrenceDataMapper";
|
|
26
25
|
import { WarningMessage } from "../../static";
|
|
27
26
|
import { SelectItem } from "../../types/generic/SelectItem";
|
|
28
|
-
import {
|
|
27
|
+
import {
|
|
28
|
+
DateAndRecurrenceInput,
|
|
29
|
+
// TODO: Show Date Component, when reccurent date bugs are fixed
|
|
30
|
+
// DateAndRecurrenceInput,
|
|
31
|
+
DateAndRecurrenceInputValues,
|
|
32
|
+
} from "./DateAndRecurrenceInput";
|
|
29
33
|
import TutorialGifCard from "./TutorialGifCard";
|
|
30
34
|
import { Step } from "../types";
|
|
31
35
|
import { StepsControl } from "../form/StepsControl";
|
|
@@ -49,7 +53,7 @@ export interface TemplateItem {
|
|
|
49
53
|
label: string;
|
|
50
54
|
}
|
|
51
55
|
|
|
52
|
-
export interface ProductSetControlValues {
|
|
56
|
+
export interface ProductSetControlValues extends DateAndRecurrenceInputValues {
|
|
53
57
|
name: string;
|
|
54
58
|
type: ProductSetType;
|
|
55
59
|
termsAndConditions: string;
|
|
@@ -61,7 +65,6 @@ export interface ProductSetControlValues {
|
|
|
61
65
|
steps: Step[];
|
|
62
66
|
emailTemplates?: TemplateItem[];
|
|
63
67
|
smsTemplates?: TemplateItem[];
|
|
64
|
-
menuRecurrences?: Partial<ProductSetRecurrence>[];
|
|
65
68
|
}
|
|
66
69
|
|
|
67
70
|
export interface ProductSetControlShared {
|
|
@@ -82,7 +85,7 @@ export interface ProductSetControlProps {
|
|
|
82
85
|
fieldSets?: FieldSet[];
|
|
83
86
|
showEmailTemplate?: boolean;
|
|
84
87
|
showSmsTemplate?: boolean;
|
|
85
|
-
workHours
|
|
88
|
+
workHours?: WorkHour[];
|
|
86
89
|
providerHasBookingManagement?: boolean;
|
|
87
90
|
isOverrides?: boolean;
|
|
88
91
|
}
|
|
@@ -120,7 +123,7 @@ export function ProductSetControl({
|
|
|
120
123
|
|
|
121
124
|
const showSmsTemplateSelector = showSmsTemplate && !isOverrides;
|
|
122
125
|
const showEmailTemplateSelector = showEmailTemplate && !isOverrides;
|
|
123
|
-
|
|
126
|
+
|
|
124
127
|
return (
|
|
125
128
|
<Row
|
|
126
129
|
className={`product-set-form ${
|
|
@@ -162,7 +165,7 @@ export function ProductSetControl({
|
|
|
162
165
|
</Form.Control.Feedback>
|
|
163
166
|
</Form.Group>
|
|
164
167
|
|
|
165
|
-
{
|
|
168
|
+
{isOverrides ? (
|
|
166
169
|
<DateInput
|
|
167
170
|
workHours={workHours}
|
|
168
171
|
isLoading={isLoading}
|
|
@@ -185,11 +188,7 @@ export function ProductSetControl({
|
|
|
185
188
|
|
|
186
189
|
<TutorialGifCard isOverrides={isOverrides} />
|
|
187
190
|
|
|
188
|
-
<StepsControl
|
|
189
|
-
isLoading={isLoading}
|
|
190
|
-
isEventEditProductSet={isEventEditProductSet}
|
|
191
|
-
isOverrides={isOverrides}
|
|
192
|
-
/>
|
|
191
|
+
<StepsControl isLoading={isLoading} isOverrides={isOverrides} />
|
|
193
192
|
</Col>
|
|
194
193
|
<Col md={6} sm={12}>
|
|
195
194
|
<div className="second-column">
|
|
@@ -36,7 +36,6 @@ import { useSortableTreeFunctions } from "../hooks/useSortableTreeFunctions";
|
|
|
36
36
|
interface ProductCategoriesControlProps extends WithIsLoading {
|
|
37
37
|
stepIndex: number;
|
|
38
38
|
isOverrides?: boolean;
|
|
39
|
-
isEventEditProductSet?: boolean;
|
|
40
39
|
}
|
|
41
40
|
|
|
42
41
|
const getCategoryDefaultValue = (
|
|
@@ -68,7 +67,6 @@ export function ProductCategoriesControl({
|
|
|
68
67
|
isLoading,
|
|
69
68
|
stepIndex,
|
|
70
69
|
isOverrides,
|
|
71
|
-
isEventEditProductSet,
|
|
72
70
|
}: ProductCategoriesControlProps) {
|
|
73
71
|
const { t } = useTranslation("Design");
|
|
74
72
|
const {
|
|
@@ -216,10 +214,6 @@ export function ProductCategoriesControl({
|
|
|
216
214
|
? String(productCategory.id)
|
|
217
215
|
: productCategory.uniqueId;
|
|
218
216
|
|
|
219
|
-
const isOverridesCategory = productCategory.products.some((product) =>
|
|
220
|
-
isEventEditProductSet ? !!product.id : !!product.originalProductId
|
|
221
|
-
);
|
|
222
|
-
|
|
223
217
|
const onSetIsExpanded = () => {
|
|
224
218
|
setIsExpanded(productCategoryId);
|
|
225
219
|
};
|
|
@@ -275,7 +269,7 @@ export function ProductCategoriesControl({
|
|
|
275
269
|
categoryName={value}
|
|
276
270
|
stepIndex={stepIndex}
|
|
277
271
|
productCategoryIndex={index}
|
|
278
|
-
isOverride={isOverrides
|
|
272
|
+
isOverride={isOverrides}
|
|
279
273
|
/>
|
|
280
274
|
}
|
|
281
275
|
isOverride={isOverrides}
|
|
@@ -302,7 +296,6 @@ export function ProductCategoriesControl({
|
|
|
302
296
|
productCategoryIndex={index}
|
|
303
297
|
categoryType={productCategory.type}
|
|
304
298
|
isOverrides={isOverrides}
|
|
305
|
-
isEventEditProductSet={isEventEditProductSet}
|
|
306
299
|
/>
|
|
307
300
|
</SortableTree.Item>
|
|
308
301
|
)}
|
|
@@ -312,7 +305,9 @@ export function ProductCategoriesControl({
|
|
|
312
305
|
</SortableTree>
|
|
313
306
|
<CreateProductSetItem
|
|
314
307
|
title={t("addCategory")}
|
|
308
|
+
isOverride={isOverrides}
|
|
315
309
|
onClick={() => {
|
|
310
|
+
if (isOverrides) return;
|
|
316
311
|
setIsSelectCategoryVisible(true);
|
|
317
312
|
}}
|
|
318
313
|
/>
|
|
@@ -321,6 +316,7 @@ export function ProductCategoriesControl({
|
|
|
321
316
|
isVisible={isSelectCategoryVisible}
|
|
322
317
|
onHide={() => setIsSelectCategoryVisible(false)}
|
|
323
318
|
onCategorySelect={(categoryType) => {
|
|
319
|
+
if (isOverrides) return;
|
|
324
320
|
append(getCategoryDefaultValue(categoryType, fields.length));
|
|
325
321
|
setShowCategoryModal(true);
|
|
326
322
|
if (
|
|
@@ -63,9 +63,9 @@ Default.args = {
|
|
|
63
63
|
sort: 100,
|
|
64
64
|
type: "standard",
|
|
65
65
|
updatedAt: "2023-05-08T15:55:28.000+03:00",
|
|
66
|
-
defaultDuration: 30,
|
|
67
66
|
zoneRecurrences: [
|
|
68
67
|
{
|
|
68
|
+
availableTimes: ["10:05", "10:25", "10:45"],
|
|
69
69
|
endDate: "2022-02-22",
|
|
70
70
|
endTime: "22:00:00",
|
|
71
71
|
id: 1,
|
|
@@ -90,6 +90,7 @@ Default.args = {
|
|
|
90
90
|
updatedAt: "2023-05-08T15:55:28.000+03:00",
|
|
91
91
|
zoneRecurrences: [
|
|
92
92
|
{
|
|
93
|
+
availableTimes: ["10:05", "10:25", "10:45"],
|
|
93
94
|
endDate: "2022-02-22",
|
|
94
95
|
endTime: "22:00:00",
|
|
95
96
|
id: 1,
|
|
@@ -26,16 +26,12 @@ import { checkAvailableTimesErrors, getFilteredTemplates } from "../utils";
|
|
|
26
26
|
export interface WithIsLoading {
|
|
27
27
|
isLoading: boolean;
|
|
28
28
|
}
|
|
29
|
-
export interface WithIdOptional {
|
|
30
|
-
id?: number;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
29
|
export interface WithId {
|
|
34
30
|
id: number;
|
|
35
31
|
}
|
|
36
32
|
export interface ProductSetFormValues
|
|
37
33
|
extends FormValues,
|
|
38
|
-
|
|
34
|
+
WithId,
|
|
39
35
|
ProductSetControlValues {
|
|
40
36
|
steps: Step[];
|
|
41
37
|
isOverrides?: boolean;
|
|
@@ -35,7 +35,6 @@ interface ProductsControlProps extends WithIsLoading {
|
|
|
35
35
|
categoryType: CategoryType;
|
|
36
36
|
zones?: Zone[];
|
|
37
37
|
isOverrides?: boolean;
|
|
38
|
-
isEventEditProductSet?: boolean;
|
|
39
38
|
}
|
|
40
39
|
|
|
41
40
|
const getDefaultProductValue = (sort: number): Product => ({
|
|
@@ -58,7 +57,6 @@ const getDefaultProductValue = (sort: number): Product => ({
|
|
|
58
57
|
quantitySelector: 1,
|
|
59
58
|
hasSpecialNotes: false,
|
|
60
59
|
weight: 0,
|
|
61
|
-
originalProductId: null,
|
|
62
60
|
type: DEFAULT_PRODUCT_TYPE,
|
|
63
61
|
tierId: Number(uniqueId()),
|
|
64
62
|
zoneId: null,
|
|
@@ -81,7 +79,6 @@ export function ProductsControl({
|
|
|
81
79
|
categoryType,
|
|
82
80
|
zones,
|
|
83
81
|
isOverrides,
|
|
84
|
-
isEventEditProductSet,
|
|
85
82
|
}: ProductsControlProps) {
|
|
86
83
|
const { t } = useTranslation("Design");
|
|
87
84
|
const form = useFormContext<ProductSetFormValues>();
|
|
@@ -206,97 +203,90 @@ export function ProductsControl({
|
|
|
206
203
|
onDragEnd={handleDragEnd}
|
|
207
204
|
sensors={[mouseSensor]}
|
|
208
205
|
>
|
|
209
|
-
{fields.map((product, index) =>
|
|
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
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
}
|
|
257
|
-
modalLabel={t("addNewProduct")}
|
|
258
|
-
modalClass={ProductSetModalClasses.product}
|
|
259
|
-
isNewAdded={showProductModal}
|
|
260
|
-
body={
|
|
261
|
-
<ProductControl<ProductSetFormValues>
|
|
262
|
-
isLoading={isLoading}
|
|
263
|
-
quantityType={quantityType}
|
|
264
|
-
allowDeposits={allowDeposits}
|
|
265
|
-
hasBookingManagement={false}
|
|
266
|
-
fieldNamePrefix={
|
|
267
|
-
`${productControlFieldName}.${index}` as const
|
|
268
|
-
}
|
|
269
|
-
productName={value}
|
|
270
|
-
onProductNameChange={onChange}
|
|
271
|
-
hasTicket={hasTicket}
|
|
272
|
-
categoryType={categoryType}
|
|
273
|
-
zoneDuration={catergoryZone?.defaultDuration}
|
|
274
|
-
isOverrides={isOverridesProductSet}
|
|
275
|
-
/>
|
|
276
|
-
}
|
|
277
|
-
onDelete={() => onProductRemove(index)}
|
|
278
|
-
validate={() =>
|
|
279
|
-
trigger(`${productControlFieldName}.${index}`)
|
|
280
|
-
}
|
|
281
|
-
saveValidField={saveValidField}
|
|
282
|
-
// preItem={<Popover className="d-none d-sm-block" />}
|
|
283
|
-
>
|
|
284
|
-
<SubProductsControl
|
|
206
|
+
{fields.map((product, index) => (
|
|
207
|
+
<Controller
|
|
208
|
+
key={product._id}
|
|
209
|
+
control={control}
|
|
210
|
+
name={`${productControlFieldName}.${index}.name` as const}
|
|
211
|
+
rules={{
|
|
212
|
+
required: t("Validation:fieldRequired", {
|
|
213
|
+
attribute: t("name"),
|
|
214
|
+
}) as string,
|
|
215
|
+
}}
|
|
216
|
+
render={({ field: { value, onChange } }) => (
|
|
217
|
+
<SortableTree.Item
|
|
218
|
+
key={`product-${product._id}`}
|
|
219
|
+
id={String(product._id)}
|
|
220
|
+
isExpanded={isFirstProductAdded}
|
|
221
|
+
isInvalid={!!categoryProductErrors}
|
|
222
|
+
title={value}
|
|
223
|
+
isOverride={isOverrides}
|
|
224
|
+
badge={<Badge className="product-badge">{t("product")}</Badge>}
|
|
225
|
+
isIconInHeader={false}
|
|
226
|
+
cancelChanges={() => cancelChanges(index)}
|
|
227
|
+
edit={() => edit(index)}
|
|
228
|
+
isProduct
|
|
229
|
+
secondaryBadge={getBadgeConfig(categoryType, t(categoryType))}
|
|
230
|
+
subTitle={
|
|
231
|
+
<div className="product-set-badges-container">
|
|
232
|
+
<div className="product-set-subtitle-dot product-set-subtitle-product-dot" />
|
|
233
|
+
<span>
|
|
234
|
+
{`£${prices[index]} ${t("each")} - ${t("qty")}:${
|
|
235
|
+
!isUnlimitedQuantities[index]
|
|
236
|
+
? ` ${quantities[index]}`
|
|
237
|
+
: t(" unlimited")
|
|
238
|
+
} ${
|
|
239
|
+
!isUnlimitedQuantities[index]
|
|
240
|
+
? ` - ${t("possibleRevenue")} £${
|
|
241
|
+
prices[index] * quantities[index]
|
|
242
|
+
}`
|
|
243
|
+
: ""
|
|
244
|
+
} `}
|
|
245
|
+
</span>
|
|
246
|
+
</div>
|
|
247
|
+
}
|
|
248
|
+
modalLabel={t("addNewProduct")}
|
|
249
|
+
modalClass={ProductSetModalClasses.product}
|
|
250
|
+
isNewAdded={showProductModal}
|
|
251
|
+
body={
|
|
252
|
+
<ProductControl<ProductSetFormValues>
|
|
285
253
|
isLoading={isLoading}
|
|
286
254
|
quantityType={quantityType}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
255
|
+
allowDeposits={allowDeposits}
|
|
256
|
+
hasBookingManagement={false}
|
|
257
|
+
fieldNamePrefix={
|
|
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}
|
|
290
266
|
/>
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
267
|
+
}
|
|
268
|
+
onDelete={() => onProductRemove(index)}
|
|
269
|
+
validate={() => trigger(`${productControlFieldName}.${index}`)}
|
|
270
|
+
saveValidField={saveValidField}
|
|
271
|
+
// preItem={<Popover className="d-none d-sm-block" />}
|
|
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
|
+
))}
|
|
296
284
|
</SortableTree>
|
|
297
285
|
<CreateProductSetItem
|
|
298
286
|
title={t("addProduct")}
|
|
287
|
+
isOverride={isOverrides}
|
|
299
288
|
onClick={() => {
|
|
289
|
+
if (isOverrides) return;
|
|
300
290
|
append(getDefaultProductValue(fields.length));
|
|
301
291
|
setShowProductModal(true);
|
|
302
292
|
|
|
@@ -19,14 +19,9 @@ import { ProductSetFormValues } from "./ProductSetForm";
|
|
|
19
19
|
interface StepsControlProps {
|
|
20
20
|
isLoading: boolean;
|
|
21
21
|
isOverrides?: boolean;
|
|
22
|
-
isEventEditProductSet?: boolean;
|
|
23
22
|
}
|
|
24
23
|
|
|
25
|
-
export function StepsControl({
|
|
26
|
-
isLoading,
|
|
27
|
-
isOverrides,
|
|
28
|
-
isEventEditProductSet,
|
|
29
|
-
}: StepsControlProps) {
|
|
24
|
+
export function StepsControl({ isLoading, isOverrides }: StepsControlProps) {
|
|
30
25
|
const form = useFormContext<ProductSetFormValues>();
|
|
31
26
|
const { t } = useTranslation("Design");
|
|
32
27
|
const [showStepModal, setShowStepModal] = useState(false);
|
|
@@ -73,8 +68,8 @@ export function StepsControl({
|
|
|
73
68
|
<>
|
|
74
69
|
{fields.map((step, index) => {
|
|
75
70
|
const stepFieldName = `steps.${index}` as const;
|
|
71
|
+
|
|
76
72
|
const stepData = getValues(stepFieldName);
|
|
77
|
-
const isOverrideStep = !!step.id;
|
|
78
73
|
|
|
79
74
|
return (
|
|
80
75
|
<Controller
|
|
@@ -97,9 +92,9 @@ export function StepsControl({
|
|
|
97
92
|
modalLabel={t("addNewStep")}
|
|
98
93
|
modalClass={ProductSetModalClasses.step}
|
|
99
94
|
isNewAdded={showStepModal}
|
|
100
|
-
edit={() => edit(index)}
|
|
95
|
+
edit={() => !isOverrides && edit(index)}
|
|
101
96
|
cancelChanges={() => cancelChanges(index)}
|
|
102
|
-
isOverride={
|
|
97
|
+
isOverride={isOverrides}
|
|
103
98
|
subTitle={
|
|
104
99
|
<div className="product-set-badges-container">
|
|
105
100
|
<div className="product-set-subtitle-dot product-set-subtitle-step-dot" />
|
|
@@ -115,7 +110,6 @@ export function StepsControl({
|
|
|
115
110
|
stepIndex={index}
|
|
116
111
|
stepName={value}
|
|
117
112
|
onStepNameChange={onChange}
|
|
118
|
-
isOverrides={isOverrideStep}
|
|
119
113
|
/>
|
|
120
114
|
}
|
|
121
115
|
onDelete={() => remove(index)}
|
|
@@ -146,7 +140,6 @@ export function StepsControl({
|
|
|
146
140
|
isLoading={isLoading}
|
|
147
141
|
stepIndex={index}
|
|
148
142
|
isOverrides={isOverrides}
|
|
149
|
-
isEventEditProductSet={isEventEditProductSet}
|
|
150
143
|
/>
|
|
151
144
|
</SortableTree.Item>
|
|
152
145
|
)}
|
|
@@ -156,7 +149,9 @@ export function StepsControl({
|
|
|
156
149
|
|
|
157
150
|
<CreateProductSetItem
|
|
158
151
|
title={t("addStep")}
|
|
152
|
+
isOverride={isOverrides}
|
|
159
153
|
onClick={() => {
|
|
154
|
+
if (isOverrides) return;
|
|
160
155
|
append(getDefaultStepsValues());
|
|
161
156
|
setShowStepModal(true);
|
|
162
157
|
if (errors.steps?.type === HookFormService.manualErrorType) {
|
|
@@ -24,10 +24,8 @@ export const useSortableTreeFunctions = ({
|
|
|
24
24
|
const cancelChanges = (index: number) => {
|
|
25
25
|
if (isOverrides) return;
|
|
26
26
|
if (!previousValue) {
|
|
27
|
-
// eslint-disable-next-line consistent-return
|
|
28
27
|
return remove(index);
|
|
29
28
|
}
|
|
30
|
-
// eslint-disable-next-line consistent-return
|
|
31
29
|
return setValue(`${fieldName}.${index}` as const, previousValue);
|
|
32
30
|
};
|
|
33
31
|
|