@licklist/design 0.62.3 → 0.63.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/bitbucket-pipelines.yml +0 -8
- package/dist/date-time-button/DateTimeButton.js +1 -1
- package/dist/events/edit-event-modal/component/EditEventForm/EditEventForm.d.ts +3 -1
- 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 +3 -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 +3 -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.js +1 -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.map +1 -1
- package/dist/iframe/ryft/utils/ryft-form.js +1 -1
- package/dist/product-set/control/DateAndRecurrenceInput.d.ts +1 -5
- 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 +4 -3
- package/dist/product-set/control/ProductSetControl.d.ts.map +1 -1
- package/dist/product-set/control/utils.d.ts +5 -0
- package/dist/product-set/control/utils.d.ts.map +1 -0
- package/dist/product-set/control/utils.js +1 -0
- package/dist/product-set/form/ProductSetForm.d.ts +4 -1
- package/dist/product-set/form/ProductSetForm.d.ts.map +1 -1
- package/dist/product-set/hooks/useSortableTreeFunctions.d.ts.map +1 -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/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 +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 +12 -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/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 +2 -1
- 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/sales/coupon/utils/index.d.ts +7 -0
- package/dist/sales/coupon/utils/index.d.ts.map +1 -0
- package/dist/sales/coupon/utils/index.js +1 -0
- 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 +1 -0
- package/dist/setting/dashboard/DashboardSettingForm.d.ts.map +1 -1
- package/dist/setting/dashboard/DashboardSettingForm.js +1 -1
- package/dist/styles/ryft-payment-form/RyftPaymentForm.scss +99 -113
- package/dist/styles/sales/BookingResults.scss +1 -1
- package/dist/typeahead/Typeahead.d.ts +2 -1
- 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 +0 -2
- 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/package.json +10 -35
- 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/EditEventForm/EditEventForm.tsx +4 -0
- package/src/events/edit-event-modal/component/SelectEventProductSet/SelectEventProductSet.tsx +10 -8
- package/src/events/edit-event-modal/component/SelectEventProductSet/component/EditEventProductSet.tsx +4 -0
- package/src/iframe/payment/order-items-table/utils/paymentSummary.tsx +6 -6
- package/src/iframe/ryft/RyftPaymentForm.tsx +12 -4
- package/src/iframe/ryft/utils/ryft-form.ts +8 -4
- package/src/product-set/control/DateAndRecurrenceInput.tsx +48 -14
- package/src/product-set/control/DateInput.tsx +2 -4
- package/src/product-set/control/ProductSetControl.stories.tsx +1 -1
- package/src/product-set/control/ProductSetControl.tsx +5 -8
- package/src/product-set/control/utils.ts +25 -0
- package/src/product-set/form/ProductCategoriesControl.tsx +1 -1
- package/src/product-set/form/ProductSetForm.stories.tsx +1 -2
- package/src/product-set/form/ProductSetForm.tsx +5 -1
- package/src/product-set/hooks/useSortableTreeFunctions.ts +2 -0
- package/src/product-set/product/ProductControl.tsx +38 -38
- package/src/product-set/product/fixed-duration-fields/FixedDurationOptions.tsx +0 -2
- package/src/provider/working-hours-input/WorkingHoursInputDescription.tsx +4 -18
- package/src/recurring-date-picker-input/RecurrenceAndFrequencyInput.tsx +0 -1
- package/src/recurring-date-picker-input/RecurringDatePickerInput.tsx +11 -1
- package/src/recurring-date-picker-input/utils.ts +77 -0
- package/src/sales/booking/results/BookingResults.stories.tsx +3 -2
- package/src/sales/booking/results/components/ResultCard.tsx +2 -5
- package/src/sales/coupon/control/CouponFormControl.tsx +28 -51
- package/src/sales/coupon/form/CouponFrom.tsx +5 -15
- package/src/sales/coupon/utils/index.ts +13 -0
- package/src/setting/admin/AdminSettingForm.tsx +2 -2
- package/src/setting/dashboard/DashboardSettingForm.tsx +13 -0
- package/src/sortable-tree/SortableTreeItem.tsx +1 -1
- package/src/static/switch/BooleanSwitch.tsx +1 -1
- package/src/styles/ryft-payment-form/RyftPaymentForm.scss +99 -113
- package/src/styles/sales/BookingResults.scss +1 -1
- package/src/typeahead/Typeahead.tsx +16 -3
- package/src/zone/form/ZoneForm.tsx +3 -2
- package/src/zone/form/components/AvailableTimesControl.tsx +0 -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
- package/jest.config.js +0 -29
- package/tests/Auth/Authorizer.test.tsx +0 -194
- package/tests/Auth/Layout/UserNavDropDown.test.tsx +0 -43
- package/tests/Auth/Layout/UserNavDropDownToggle.test.tsx +0 -33
- package/tests/Auth/Login/LoginComponent.test.tsx +0 -246
- package/tests/Auth/Login/LoginFormComponent.test.tsx +0 -182
- package/tests/Auth/Register/RegisterComponent.test.tsx +0 -285
- package/tests/Auth/Register/RegisterFormComponent.test.tsx +0 -170
- package/tests/Auth/Settings/Dashboard/IpInput.test.tsx +0 -130
- package/tests/Auth/Social/SocialCallbackComponent.test.tsx +0 -133
- package/tests/Auth/Social/SocialFormComponent.test.tsx +0 -118
- package/tests/FileUpload/FileUpload.test.tsx +0 -42
- package/tests/Notification/EmailTemplate.test.tsx +0 -82
- package/tests/ProductSet/ProductSetPopover.test.tsx +0 -40
- package/tests/Report/Report.test.tsx +0 -48
- package/tests/Sales/Coupon.test.tsx +0 -51
- package/tests/Sales/SalesAndVIews.test.tsx +0 -63
- package/tests/SnippetTemplates/SnippetTemplates.test.tsx +0 -56
- package/tests/Table/FilterHelperComponent.test.tsx +0 -88
- package/tests/Table/PaginationHelperComponent.test.tsx +0 -109
- package/tests/Table/PerPageHelperComponent.test.tsx +0 -34
- package/tests/Table/TableHelperComponent.test.tsx +0 -295
- package/tests/TipTapEditor/TipTapEditor.test.tsx +0 -28
- package/tests/__mock__/hooks/useAuthApi.ts +0 -13
- package/tests/__mock__/hooks/useAuthMock.ts +0 -13
- package/tests/__mock__/hooks/useFormMock.ts +0 -27
- package/tests/__mock__/hooks/useNotificationMock.ts +0 -13
- package/tests/__mock__/hooks/useQueryMock.ts +0 -16
- package/tests/__mock__/hooks/useSocialApiMock.ts +0 -20
- package/tests/__mock__/hooks/useTranslationMock.ts +0 -17
- package/tests/__mock__/hooks/useUserApiMock.ts +0 -18
- package/tests/__mock__/hooks/useUserMock.ts +0 -13
- package/tests/__mock__/styleMock.js +0 -1
- package/tests/__mock__/windowMock.ts +0 -5
- package/tests/packages/react-query.tsx +0 -28
- package/tests/setupTests.ts +0 -10
package/src/events/edit-event-modal/component/SelectEventProductSet/SelectEventProductSet.tsx
CHANGED
|
@@ -5,6 +5,7 @@ import { useId } from "@react-aria/utils";
|
|
|
5
5
|
import { Controller, useFormContext } from "react-hook-form";
|
|
6
6
|
import { HasPermissionProp } from "@licklist/plugins/dist/types/permission/Permission";
|
|
7
7
|
import { ProductSet } from "@licklist/core/dist/DataMapper/Product/ProductSetDataMapper";
|
|
8
|
+
import { WorkHour } from "@licklist/core/dist/DataMapper/Provider/WorkHourDataMapper";
|
|
8
9
|
import { ConfirmModal } from "../../../../modals/confirmation/ConfirmModal";
|
|
9
10
|
import { EditEventFormValues } from "../EditEventForm/EditEventForm";
|
|
10
11
|
import { EditEventProductSet } from "./component/EditEventProductSet";
|
|
@@ -15,6 +16,7 @@ interface SelectEventProductSetProps extends HasPermissionProp {
|
|
|
15
16
|
setShowEditProductSet: (value: boolean) => void;
|
|
16
17
|
createProductSet: (props: EditEventFormValues) => void;
|
|
17
18
|
setEditProductSetId: (value: string) => void;
|
|
19
|
+
workHours: WorkHour[] | undefined;
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
export const SelectEventProductSet = ({
|
|
@@ -23,6 +25,7 @@ export const SelectEventProductSet = ({
|
|
|
23
25
|
setEditProductSetId,
|
|
24
26
|
showEditProductSet,
|
|
25
27
|
setShowEditProductSet,
|
|
28
|
+
workHours,
|
|
26
29
|
}: SelectEventProductSetProps) => {
|
|
27
30
|
const { t } = useTranslation(["Design"]);
|
|
28
31
|
const form = useFormContext<EditEventFormValues>();
|
|
@@ -199,14 +202,13 @@ export const SelectEventProductSet = ({
|
|
|
199
202
|
</Form.Group>
|
|
200
203
|
</div>
|
|
201
204
|
{showEditProductSet && productSetId && (
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
</>
|
|
205
|
+
<EditEventProductSet
|
|
206
|
+
onSubmit={onSubmit}
|
|
207
|
+
defaultValues={
|
|
208
|
+
productSetId === editedProductSet?.id && editedProductSet
|
|
209
|
+
}
|
|
210
|
+
workHours={workHours}
|
|
211
|
+
/>
|
|
210
212
|
)}
|
|
211
213
|
</>
|
|
212
214
|
);
|
|
@@ -5,6 +5,7 @@ import { isEqual } from "lodash";
|
|
|
5
5
|
import { useParams } from "react-router-dom";
|
|
6
6
|
import { useEventEditProductSetContext } from "@licklist/plugins/dist/context/event/EventEditProductSetContext";
|
|
7
7
|
import { useTranslation } from "react-i18next";
|
|
8
|
+
import { WorkHour } from "@licklist/core/dist/DataMapper/Provider/WorkHourDataMapper";
|
|
8
9
|
import { BlockLoader } from "../../../../../static/loader/BlockLoader";
|
|
9
10
|
import { ProductSetControl } from "../../../../../product-set";
|
|
10
11
|
import { ProductSetContextProvider } from "../../../../../product-set/form/context";
|
|
@@ -22,11 +23,13 @@ export interface EventDates {
|
|
|
22
23
|
interface EditEventProductSetProps {
|
|
23
24
|
onSubmit: (value: EditEventFormValues["editedProductSet"]) => void;
|
|
24
25
|
defaultValues?: EditEventFormValues["editedProductSet"];
|
|
26
|
+
workHours: WorkHour[] | undefined;
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
export const EditEventProductSet = ({
|
|
28
30
|
onSubmit,
|
|
29
31
|
defaultValues,
|
|
32
|
+
workHours,
|
|
30
33
|
}: EditEventProductSetProps) => {
|
|
31
34
|
const { companyId } = useParams<{
|
|
32
35
|
companyId: string;
|
|
@@ -124,6 +127,7 @@ export const EditEventProductSet = ({
|
|
|
124
127
|
companyName={selectedCompany?.title}
|
|
125
128
|
fee={feeInPercent}
|
|
126
129
|
isEventEditProductSet
|
|
130
|
+
workHours={workHours}
|
|
127
131
|
/>
|
|
128
132
|
<Button
|
|
129
133
|
disabled={isLoading}
|
|
@@ -63,7 +63,7 @@ const processedPaymentSummary = ({
|
|
|
63
63
|
const total = calculateTotalPrice(order, externalPaymentDetail);
|
|
64
64
|
|
|
65
65
|
const totalDiscount = calculateTotalDiscount(order.payments);
|
|
66
|
-
|
|
66
|
+
|
|
67
67
|
let summaryItems: SummaryItem[] = [
|
|
68
68
|
{
|
|
69
69
|
translateKey: AMOUNT_TOTAL,
|
|
@@ -74,7 +74,7 @@ const processedPaymentSummary = ({
|
|
|
74
74
|
if (totalDiscount) {
|
|
75
75
|
summaryItems.push({
|
|
76
76
|
translateKey: AMOUNT_WITH_DISCOUNT,
|
|
77
|
-
price:
|
|
77
|
+
price: order.totalToPayAmount,
|
|
78
78
|
});
|
|
79
79
|
}
|
|
80
80
|
|
|
@@ -84,17 +84,17 @@ const processedPaymentSummary = ({
|
|
|
84
84
|
|
|
85
85
|
summaryItems.push({
|
|
86
86
|
translateKey: TOTAL_PAID,
|
|
87
|
-
price:
|
|
87
|
+
price: order.paidAmount,
|
|
88
88
|
});
|
|
89
|
-
if (
|
|
89
|
+
if (order.totalToPayAmount <= 0) {
|
|
90
90
|
return summaryItems;
|
|
91
91
|
}
|
|
92
92
|
summaryItems = [...summaryItems, ...externalPaymentDetail];
|
|
93
93
|
|
|
94
|
-
if (
|
|
94
|
+
if (order.remainingToPay) {
|
|
95
95
|
summaryItems.push({
|
|
96
96
|
translateKey: REMAINING_TO_PAY,
|
|
97
|
-
price:
|
|
97
|
+
price: order.remainingToPay,
|
|
98
98
|
});
|
|
99
99
|
}
|
|
100
100
|
return summaryItems;
|
|
@@ -123,18 +123,26 @@ export const RyftPaymentForm = ({
|
|
|
123
123
|
};
|
|
124
124
|
|
|
125
125
|
useEffect(
|
|
126
|
-
() =>
|
|
126
|
+
() => {
|
|
127
|
+
if (
|
|
128
|
+
!formRef.current?.childNodes?.length ||
|
|
129
|
+
formRef.current?.childNodes?.length < 3 ||
|
|
130
|
+
!accountId.data?.account_id
|
|
131
|
+
) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
127
134
|
injectComponentsInRyftForm({
|
|
128
135
|
t,
|
|
129
136
|
additionalPaymentMethodsEnabled:
|
|
130
137
|
providerPaymentSettings?.additionalPaymentMethodsEnabled,
|
|
131
|
-
})
|
|
138
|
+
});
|
|
139
|
+
},
|
|
132
140
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
133
141
|
[formRef.current?.childNodes?.length]
|
|
134
142
|
);
|
|
135
143
|
|
|
136
144
|
useEffect(() => {
|
|
137
|
-
if (!accountId.data || accountId.isError) return;
|
|
145
|
+
if (!accountId.data?.account_id || accountId.isError) return;
|
|
138
146
|
|
|
139
147
|
initRyft(
|
|
140
148
|
() => {
|
|
@@ -148,7 +156,7 @@ export const RyftPaymentForm = ({
|
|
|
148
156
|
);
|
|
149
157
|
|
|
150
158
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
151
|
-
}, [accountId.data]);
|
|
159
|
+
}, [accountId.data?.account_id]);
|
|
152
160
|
|
|
153
161
|
if (accountId.isLoading || accountId.isFetching || isCreateLoading)
|
|
154
162
|
return (
|
|
@@ -8,13 +8,12 @@ export const injectComponentsInRyftForm = ({
|
|
|
8
8
|
additionalPaymentMethodsEnabled?: boolean;
|
|
9
9
|
}) => {
|
|
10
10
|
const cardContainer = document.getElementById("ryft-pay-iframe");
|
|
11
|
-
const oldCardDividerContainer = document.getElementById(
|
|
12
|
-
"card-title-container"
|
|
13
|
-
);
|
|
14
11
|
|
|
15
|
-
if (!cardContainer
|
|
12
|
+
if (!cardContainer) {
|
|
16
13
|
return;
|
|
17
14
|
}
|
|
15
|
+
// Removing of the old title container
|
|
16
|
+
document.getElementById("card-title-container")?.remove();
|
|
18
17
|
|
|
19
18
|
const cardTitle = document.createElement("div");
|
|
20
19
|
const cardText = document.createElement("div");
|
|
@@ -32,6 +31,10 @@ export const injectComponentsInRyftForm = ({
|
|
|
32
31
|
return;
|
|
33
32
|
}
|
|
34
33
|
|
|
34
|
+
// Removing of the old mobile title container and divider container
|
|
35
|
+
document.getElementById("mobile-pay-title")?.remove();
|
|
36
|
+
document.getElementById("mobile-pay-divider-container")?.remove();
|
|
37
|
+
|
|
35
38
|
// Adding title and divider for apple and google pay button
|
|
36
39
|
const mobilePayTitle = document.createElement("div");
|
|
37
40
|
const dividerText = document.createElement("div");
|
|
@@ -39,6 +42,7 @@ export const injectComponentsInRyftForm = ({
|
|
|
39
42
|
const container = document.createElement("div");
|
|
40
43
|
mobilePayTitle.className = "mobile-pay-title";
|
|
41
44
|
mobilePayTitle.innerText = t("Design:expressCheckoutWith");
|
|
45
|
+
mobilePayTitle.id = "mobile-pay-title";
|
|
42
46
|
dividerText.id = "mobile-pay-divider-text";
|
|
43
47
|
dividerText.innerText = "or";
|
|
44
48
|
divider.id = "mobile-pay-divider";
|
|
@@ -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 } from "react-hook-form";
|
|
5
|
+
import { useFieldArray, useFormContext, useWatch } 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,7 +14,6 @@ import {
|
|
|
14
14
|
SortableContext,
|
|
15
15
|
verticalListSortingStrategy,
|
|
16
16
|
} from "@dnd-kit/sortable";
|
|
17
|
-
|
|
18
17
|
import { restrictToVerticalAxis } from "@dnd-kit/modifiers";
|
|
19
18
|
import { CONFIRM_MODAL_ACTIONS } from "../../modals/confirmation/ConfirmModal";
|
|
20
19
|
import { Icon } from "../../static";
|
|
@@ -27,16 +26,15 @@ import {
|
|
|
27
26
|
AvailableTimesControl,
|
|
28
27
|
AvailableTimesControlRef,
|
|
29
28
|
} from "../../zone/form/components/AvailableTimesControl";
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
29
|
+
import { ProductSetControlValues } from "..";
|
|
30
|
+
import {
|
|
31
|
+
getProductWithSmallestDuration,
|
|
32
|
+
getLatestAvailableDateTime,
|
|
33
|
+
} from "./utils";
|
|
36
34
|
|
|
37
35
|
interface DateAndRecurrenceInputProps {
|
|
38
36
|
isEventEditProductSet?: boolean;
|
|
39
|
-
workHours
|
|
37
|
+
workHours: WorkHour[] | undefined;
|
|
40
38
|
providerHasBookingManagement: boolean;
|
|
41
39
|
isLoading?: boolean;
|
|
42
40
|
}
|
|
@@ -54,7 +52,9 @@ export const DateAndRecurrenceInput = ({
|
|
|
54
52
|
getValues,
|
|
55
53
|
setValue,
|
|
56
54
|
clearErrors,
|
|
57
|
-
} = useFormContext<
|
|
55
|
+
} = useFormContext<ProductSetControlValues>();
|
|
56
|
+
|
|
57
|
+
const steps = useWatch({ control, name: "steps" });
|
|
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,11 +101,13 @@ export const DateAndRecurrenceInput = ({
|
|
|
101
101
|
const isAvailableTimesFormValid =
|
|
102
102
|
await availableTimesFormRef.current?.trigger();
|
|
103
103
|
|
|
104
|
+
const { availableTimes } = availableTimesFormRef.current.getValues();
|
|
105
|
+
|
|
104
106
|
if (next?.startTime && next?.endTime && isAvailableTimesFormValid) {
|
|
105
107
|
const startTime = DateTime.fromISO(next.startTime);
|
|
106
108
|
const endTime = DateTime.fromISO(next.endTime);
|
|
107
|
-
|
|
108
|
-
const
|
|
109
|
+
|
|
110
|
+
const areAvailableTimesValid = availableTimes.every((time) => {
|
|
109
111
|
const currentAvailableTime = DateTime.fromFormat(time, TIME_FORMAT);
|
|
110
112
|
|
|
111
113
|
return (
|
|
@@ -113,7 +115,8 @@ export const DateAndRecurrenceInput = ({
|
|
|
113
115
|
currentAvailableTime.diff(endTime, "minutes").minutes <= 0
|
|
114
116
|
);
|
|
115
117
|
});
|
|
116
|
-
|
|
118
|
+
|
|
119
|
+
if (!areAvailableTimesValid) {
|
|
117
120
|
availableTimesFormRef.current.setError("availableTimes", {
|
|
118
121
|
message: t("Validation:fieldTimeBetween", {
|
|
119
122
|
attribute: t("Design:startTimesSmall"),
|
|
@@ -126,6 +129,36 @@ export const DateAndRecurrenceInput = ({
|
|
|
126
129
|
}
|
|
127
130
|
}
|
|
128
131
|
|
|
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
|
+
|
|
129
162
|
const availableTime =
|
|
130
163
|
availableTimesFormRef?.current?.getValues()?.availableTimes || null;
|
|
131
164
|
|
|
@@ -228,6 +261,7 @@ export const DateAndRecurrenceInput = ({
|
|
|
228
261
|
defaultValues={editState.values}
|
|
229
262
|
onChange={handleRecurringDateChange}
|
|
230
263
|
onDelete={handleDelete}
|
|
264
|
+
workHours={workHours}
|
|
231
265
|
>
|
|
232
266
|
{providerHasBookingManagement && (
|
|
233
267
|
<AvailableTimesControl
|
|
@@ -5,9 +5,8 @@ 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 { UTC_TIMEZONE, TIME_FORMAT } 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";
|
|
11
10
|
import { DateTime } from "luxon";
|
|
12
11
|
import RRule, { Frequency } from "rrule";
|
|
13
12
|
import { WorkHour } from "@licklist/core/dist/DataMapper/Provider/WorkHourDataMapper";
|
|
@@ -27,7 +26,6 @@ import {
|
|
|
27
26
|
import { ProductSetRecurrenceOverridesControl } from "./ProductSetRecurrenceOverridesControl";
|
|
28
27
|
import { MAX_QUANTITY_RECURRENCE_DATE_IN_OVERRIDE } from "../product/constants";
|
|
29
28
|
|
|
30
|
-
|
|
31
29
|
export interface DateAndRecurrenceInputValues {
|
|
32
30
|
menuRecurrences?: Partial<ProductSetRecurrence>[];
|
|
33
31
|
}
|
|
@@ -138,7 +136,7 @@ export const DateInput = ({
|
|
|
138
136
|
until: (start as DateTime).toJSDate(),
|
|
139
137
|
byweekday: [],
|
|
140
138
|
freq: Frequency.DAILY,
|
|
141
|
-
tzid:
|
|
139
|
+
tzid: UTC_TIMEZONE,
|
|
142
140
|
interval: 1,
|
|
143
141
|
}).replace("RRULE:", "");
|
|
144
142
|
|
|
@@ -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";
|
|
5
6
|
import {
|
|
6
7
|
ProductSetControl,
|
|
7
8
|
ProductSetControlProps,
|
|
8
9
|
ProductSetControlValues,
|
|
9
10
|
} 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,14 +22,10 @@ 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";
|
|
25
26
|
import { WarningMessage } from "../../static";
|
|
26
27
|
import { SelectItem } from "../../types/generic/SelectItem";
|
|
27
|
-
import {
|
|
28
|
-
DateAndRecurrenceInput,
|
|
29
|
-
// TODO: Show Date Component, when reccurent date bugs are fixed
|
|
30
|
-
// DateAndRecurrenceInput,
|
|
31
|
-
DateAndRecurrenceInputValues,
|
|
32
|
-
} from "./DateAndRecurrenceInput";
|
|
28
|
+
import { DateAndRecurrenceInput } from "./DateAndRecurrenceInput";
|
|
33
29
|
import TutorialGifCard from "./TutorialGifCard";
|
|
34
30
|
import { Step } from "../types";
|
|
35
31
|
import { StepsControl } from "../form/StepsControl";
|
|
@@ -53,7 +49,7 @@ export interface TemplateItem {
|
|
|
53
49
|
label: string;
|
|
54
50
|
}
|
|
55
51
|
|
|
56
|
-
export interface ProductSetControlValues
|
|
52
|
+
export interface ProductSetControlValues {
|
|
57
53
|
name: string;
|
|
58
54
|
type: ProductSetType;
|
|
59
55
|
termsAndConditions: string;
|
|
@@ -65,6 +61,7 @@ export interface ProductSetControlValues extends DateAndRecurrenceInputValues {
|
|
|
65
61
|
steps: Step[];
|
|
66
62
|
emailTemplates?: TemplateItem[];
|
|
67
63
|
smsTemplates?: TemplateItem[];
|
|
64
|
+
menuRecurrences?: Partial<ProductSetRecurrence>[];
|
|
68
65
|
}
|
|
69
66
|
|
|
70
67
|
export interface ProductSetControlShared {
|
|
@@ -85,7 +82,7 @@ export interface ProductSetControlProps {
|
|
|
85
82
|
fieldSets?: FieldSet[];
|
|
86
83
|
showEmailTemplate?: boolean;
|
|
87
84
|
showSmsTemplate?: boolean;
|
|
88
|
-
workHours
|
|
85
|
+
workHours: WorkHour[] | undefined;
|
|
89
86
|
providerHasBookingManagement?: boolean;
|
|
90
87
|
isOverrides?: boolean;
|
|
91
88
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { TIME_FORMAT } from "@licklist/core/dist/Config";
|
|
2
|
+
import { dateTimesSortFn } from "@licklist/plugins/dist/utils/dateTime";
|
|
3
|
+
import { extractObjectWithLowestKey } from "@licklist/plugins/dist/utils/extractObjectWithLowestKey";
|
|
4
|
+
import { DateTime } from "luxon";
|
|
5
|
+
import { Product, Step } from "../types";
|
|
6
|
+
|
|
7
|
+
const getProductsFromSteps = (steps: Step[]): Product[] =>
|
|
8
|
+
steps.reduce(
|
|
9
|
+
(acc, step) =>
|
|
10
|
+
acc.concat(
|
|
11
|
+
step.productCategories.reduce(
|
|
12
|
+
(acc, productCategory) => acc.concat(productCategory.products),
|
|
13
|
+
[]
|
|
14
|
+
)
|
|
15
|
+
),
|
|
16
|
+
[]
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
export const getProductWithSmallestDuration = (steps: Step[]): Product =>
|
|
20
|
+
extractObjectWithLowestKey(getProductsFromSteps(steps), "duration");
|
|
21
|
+
|
|
22
|
+
export const getLatestAvailableDateTime = (array: string[]): DateTime =>
|
|
23
|
+
array
|
|
24
|
+
.map((time) => DateTime.fromFormat(time, TIME_FORMAT))
|
|
25
|
+
.sort(dateTimesSortFn("desc"))[0];
|
|
@@ -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,
|
|
66
67
|
zoneRecurrences: [
|
|
67
68
|
{
|
|
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,7 +90,6 @@ 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"],
|
|
94
93
|
endDate: "2022-02-22",
|
|
95
94
|
endTime: "22:00:00",
|
|
96
95
|
id: 1,
|
|
@@ -26,12 +26,16 @@ 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
|
+
|
|
29
33
|
export interface WithId {
|
|
30
34
|
id: number;
|
|
31
35
|
}
|
|
32
36
|
export interface ProductSetFormValues
|
|
33
37
|
extends FormValues,
|
|
34
|
-
|
|
38
|
+
WithIdOptional,
|
|
35
39
|
ProductSetControlValues {
|
|
36
40
|
steps: Step[];
|
|
37
41
|
isOverrides?: boolean;
|
|
@@ -24,8 +24,10 @@ 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
|
|
27
28
|
return remove(index);
|
|
28
29
|
}
|
|
30
|
+
// eslint-disable-next-line consistent-return
|
|
29
31
|
return setValue(`${fieldName}.${index}` as const, previousValue);
|
|
30
32
|
};
|
|
31
33
|
|
|
@@ -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,
|
|
@@ -146,7 +149,7 @@ export function ProductControl<T extends FormValues>({
|
|
|
146
149
|
clearErrors,
|
|
147
150
|
} = useFormContext<T>();
|
|
148
151
|
|
|
149
|
-
const { setLoading } = useContext(ProductSetLoadingContext);
|
|
152
|
+
const { setLoading, productGroupList } = useContext(ProductSetLoadingContext);
|
|
150
153
|
const { t } = useTranslation(["Design", "Validation", "ProductSet"]);
|
|
151
154
|
const [expanded, setExpanded] = useState(false);
|
|
152
155
|
const [initialImages, setInitialImages] = useState<Image[] | null>(null);
|
|
@@ -159,8 +162,8 @@ export function ProductControl<T extends FormValues>({
|
|
|
159
162
|
|
|
160
163
|
const advancedId = useId();
|
|
161
164
|
const nameId = useId();
|
|
162
|
-
|
|
163
|
-
|
|
165
|
+
|
|
166
|
+
const productGroupId = useId();
|
|
164
167
|
const descriptionId = useId();
|
|
165
168
|
const termsAndConditionsId = useId();
|
|
166
169
|
const isAvailableId = useId();
|
|
@@ -400,6 +403,35 @@ export function ProductControl<T extends FormValues>({
|
|
|
400
403
|
isRequired={false}
|
|
401
404
|
defaultColors={PRODUCT_DEfAULT_COLORS}
|
|
402
405
|
/>
|
|
406
|
+
|
|
407
|
+
<Form.Group controlId={productGroupId}>
|
|
408
|
+
<Form.Label>{t("productGroup")}</Form.Label>
|
|
409
|
+
<Form.Control
|
|
410
|
+
as="select"
|
|
411
|
+
{...register(`${fieldNamePrefix}.productGroupId` as Path<T>)}
|
|
412
|
+
isInvalid={HookFormService.isInvalid<T>(
|
|
413
|
+
`${fieldNamePrefix}.productGroupId` as Path<T>,
|
|
414
|
+
errors
|
|
415
|
+
)}
|
|
416
|
+
disabled={isLoading}
|
|
417
|
+
defaultValue=""
|
|
418
|
+
>
|
|
419
|
+
<option value="">{t("Design:selectProductGroup")}</option>
|
|
420
|
+
{productGroupList.map((productGroup) => {
|
|
421
|
+
return (
|
|
422
|
+
<option value={productGroup.id} key={productGroup.id}>
|
|
423
|
+
{productGroup.value}
|
|
424
|
+
</option>
|
|
425
|
+
);
|
|
426
|
+
})}
|
|
427
|
+
</Form.Control>
|
|
428
|
+
<Form.Control.Feedback type="invalid">
|
|
429
|
+
{HookFormService.getErrors<T>(
|
|
430
|
+
`${fieldNamePrefix}.productGroupId` as Path<T>,
|
|
431
|
+
errors
|
|
432
|
+
)}
|
|
433
|
+
</Form.Control.Feedback>
|
|
434
|
+
</Form.Group>
|
|
403
435
|
</Col>
|
|
404
436
|
</Row>
|
|
405
437
|
|
|
@@ -672,38 +704,6 @@ export function ProductControl<T extends FormValues>({
|
|
|
672
704
|
</Collapse>
|
|
673
705
|
|
|
674
706
|
<Row>
|
|
675
|
-
{/* @TODO: no need for v1 release
|
|
676
|
-
<Col xs={12} sm={6}>
|
|
677
|
-
<Form.Group controlId={productGroupId}>
|
|
678
|
-
<Form.Label>{t("productGroup")}</Form.Label>
|
|
679
|
-
<Form.Control
|
|
680
|
-
as="select"
|
|
681
|
-
{...register(`${fieldNamePrefix}.productGroupId` as Path<T>)}
|
|
682
|
-
isInvalid={HookFormService.isInvalid<T>(
|
|
683
|
-
`${fieldNamePrefix}.productGroupId` as Path<T>,
|
|
684
|
-
errors
|
|
685
|
-
)}
|
|
686
|
-
disabled={isLoading}
|
|
687
|
-
defaultValue=""
|
|
688
|
-
>
|
|
689
|
-
<option value="">{t("Design:selectProductGroup")}</option>
|
|
690
|
-
{productGroupList.map((productGroup) => {
|
|
691
|
-
return (
|
|
692
|
-
<option value={productGroup.id} key={productGroup.id}>
|
|
693
|
-
{productGroup.value}
|
|
694
|
-
</option>
|
|
695
|
-
);
|
|
696
|
-
})}
|
|
697
|
-
</Form.Control>
|
|
698
|
-
<Form.Control.Feedback type="invalid">
|
|
699
|
-
{HookFormService.getErrors<T>(
|
|
700
|
-
`${fieldNamePrefix}.productGroupId` as Path<T>,
|
|
701
|
-
errors
|
|
702
|
-
)}
|
|
703
|
-
</Form.Control.Feedback>
|
|
704
|
-
</Form.Group>
|
|
705
|
-
</Col> */}
|
|
706
|
-
|
|
707
707
|
<Col xs={12}>
|
|
708
708
|
{hasBookingManagement && (
|
|
709
709
|
<ProductBookingManagementControl<T>
|
|
@@ -5,8 +5,6 @@ import { FieldNamePrefixPath } from "@licklist/plugins/dist/types/services/Form/
|
|
|
5
5
|
import { useWatch } from "react-hook-form";
|
|
6
6
|
import { FormNumberInput } from "../../../static";
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
8
|
interface FixedDurationOptionsProps<T> extends FieldNamePrefixPath<T> {
|
|
11
9
|
isOverrides?: boolean;
|
|
12
10
|
}
|
|
@@ -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
|
);
|