@licklist/design 0.63.2 → 0.63.3-dev.1
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/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/sales/booking/results/components/ResultCard.d.ts.map +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/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/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/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/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 +12 -37
- 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 +11 -4
- 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 +39 -39
- 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 +40 -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/sales/booking/results/components/ResultCard.tsx +0 -3
- 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/sortable-tree/SortableTreeItem.tsx +0 -3
- package/src/static/switch/BooleanSwitch.tsx +1 -1
- 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/typeahead/Typeahead.tsx +16 -3
- 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
- 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
|
@@ -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,8 @@ interface RecurrenceIntervalAndFrequencyInputProps {
|
|
|
23
33
|
>;
|
|
24
34
|
}
|
|
25
35
|
|
|
36
|
+
const fromTimeFullFormat = fromFormat(TIME_FULL_FORMAT);
|
|
37
|
+
|
|
26
38
|
function RecurrenceIntervalAndFrequencyInput({
|
|
27
39
|
disabled = false,
|
|
28
40
|
minDate,
|
|
@@ -36,16 +48,20 @@ function RecurrenceIntervalAndFrequencyInput({
|
|
|
36
48
|
const { t } = useTranslation(["Design", "Notification", "App"]);
|
|
37
49
|
|
|
38
50
|
const {
|
|
39
|
-
getValues,
|
|
40
51
|
formState: { errors },
|
|
41
52
|
register,
|
|
42
53
|
trigger,
|
|
54
|
+
control,
|
|
43
55
|
} = useFormContext<RecurringDatePickerInputValues>();
|
|
44
56
|
|
|
45
|
-
const startDate =
|
|
46
|
-
const endDate =
|
|
47
|
-
|
|
48
|
-
const
|
|
57
|
+
const startDate = useWatch({ control, name: "startDate" });
|
|
58
|
+
const endDate = useWatch({ control, name: "endDate" });
|
|
59
|
+
|
|
60
|
+
const _startTime = useWatch({ control, name: "startTime" });
|
|
61
|
+
const startTime = fromTimeFullFormat(_startTime).toFormat(TIME_FORMAT);
|
|
62
|
+
|
|
63
|
+
const _endTime = useWatch({ control, name: "endTime" });
|
|
64
|
+
const endTime = fromTimeFullFormat(_endTime).toFormat(TIME_FORMAT);
|
|
49
65
|
|
|
50
66
|
useEffect(() => {
|
|
51
67
|
if (!startDate || !endDate) {
|
|
@@ -149,22 +165,25 @@ function RecurrenceIntervalAndFrequencyInput({
|
|
|
149
165
|
type="time"
|
|
150
166
|
{...register("endTime", {
|
|
151
167
|
required: false,
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
168
|
+
...endTimeRules,
|
|
169
|
+
validate: {
|
|
170
|
+
external: endTimeRules.validate as Validate<string>,
|
|
171
|
+
time: (time) => {
|
|
172
|
+
if (!startTime || !time) {
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
const currentStartTime = DateTime.fromISO(startTime);
|
|
176
|
+
const currentEndTime = DateTime.fromISO(time);
|
|
158
177
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
178
|
+
return currentEndTime?.diff(currentStartTime, ["minutes"])
|
|
179
|
+
?.minutes >= 0
|
|
180
|
+
? true
|
|
181
|
+
: `${t(`Validation:fieldLaterDate`, {
|
|
182
|
+
attribute: t("Design:endTimeSmall"),
|
|
183
|
+
min: t("Design:startTimeSmall"),
|
|
184
|
+
})}`;
|
|
185
|
+
},
|
|
166
186
|
},
|
|
167
|
-
...endTimeRules,
|
|
168
187
|
})}
|
|
169
188
|
placeholder="hh:mm"
|
|
170
189
|
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}
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { TIME_FORMAT, TIME_FULL_FORMAT } from "@licklist/core/dist/Config";
|
|
2
|
+
import { WorkHour } from "@licklist/core/dist/DataMapper/Provider/WorkHourDataMapper";
|
|
3
|
+
import { fromFormat } from "@licklist/plugins/dist/utils/dateTime";
|
|
4
|
+
import { DateTime, Interval } from "luxon";
|
|
5
|
+
import { Validate } from "react-hook-form";
|
|
6
|
+
import { useTranslation } from "react-i18next";
|
|
2
7
|
import RRule, { Frequency, Weekday } from "rrule";
|
|
3
8
|
|
|
4
9
|
export const getWeekdayForFrequency = ({
|
|
@@ -11,6 +16,7 @@ export const getWeekdayForFrequency = ({
|
|
|
11
16
|
const parsedDate = DateTime.fromISO(date);
|
|
12
17
|
return new Weekday(
|
|
13
18
|
parsedDate.weekday - 1,
|
|
19
|
+
// eslint-disable-next-line no-nested-ternary
|
|
14
20
|
frequency !== Frequency.MONTHLY
|
|
15
21
|
? undefined
|
|
16
22
|
: parsedDate.day + 7 > parsedDate.daysInMonth
|
|
@@ -109,3 +115,86 @@ export const parseAndValidateRRule = ({
|
|
|
109
115
|
until: options.until,
|
|
110
116
|
} as ParsedRRuleOptions;
|
|
111
117
|
};
|
|
118
|
+
|
|
119
|
+
export const useWorkHoursValidation = (
|
|
120
|
+
byWeekDay: Weekday[] = [],
|
|
121
|
+
workHours: WorkHour[] | undefined
|
|
122
|
+
): {
|
|
123
|
+
validate?: Validate<string>;
|
|
124
|
+
} => {
|
|
125
|
+
const { t } = useTranslation("Validation");
|
|
126
|
+
if (!workHours) return {};
|
|
127
|
+
|
|
128
|
+
const fromTimeFormat = fromFormat(TIME_FORMAT);
|
|
129
|
+
const fromTimeFullFormat = fromFormat(TIME_FULL_FORMAT);
|
|
130
|
+
|
|
131
|
+
// map every day to array of intervals describing workhours for that day
|
|
132
|
+
let intervalsByDay = workHours.map((workhour, index, self) => {
|
|
133
|
+
const res: Interval[] = [];
|
|
134
|
+
|
|
135
|
+
const startTime = fromTimeFormat(workhour.start);
|
|
136
|
+
const endTime = fromTimeFormat(workhour.end);
|
|
137
|
+
|
|
138
|
+
if (endTime > startTime) {
|
|
139
|
+
res.push(Interval.fromDateTimes(startTime, endTime));
|
|
140
|
+
} else {
|
|
141
|
+
// if end is before start, then it means that end is on the next day
|
|
142
|
+
// so count only to the end of current day
|
|
143
|
+
res.push(Interval.fromDateTimes(startTime, startTime.endOf("day")));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const prevIndex = index === 0 ? self.length - 1 : index - 1;
|
|
147
|
+
|
|
148
|
+
const prevStartTime = fromTimeFormat(self[prevIndex].start);
|
|
149
|
+
const prevEndTime = fromTimeFormat(self[prevIndex].end);
|
|
150
|
+
|
|
151
|
+
// if prevStartTime > prevEndTime then it means that prevEndTime is on the current day
|
|
152
|
+
// so we need to add interval from start of current day to prevEndTime
|
|
153
|
+
if (prevStartTime > prevEndTime) {
|
|
154
|
+
res.push(Interval.fromDateTimes(prevEndTime.startOf("day"), prevEndTime));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return res;
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// if length === 0 or length === 7 then all workhours are selected, no need to filter
|
|
161
|
+
if (![0, 7].includes(byWeekDay.length)) {
|
|
162
|
+
intervalsByDay = intervalsByDay.filter((_, index) =>
|
|
163
|
+
byWeekDay.find(({ weekday }) => weekday === index)
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return {
|
|
168
|
+
validate: (_time: string) => {
|
|
169
|
+
// workaround for issue with form values
|
|
170
|
+
// default values and entered values have different formats
|
|
171
|
+
const time = fromTimeFormat(_time).isValid
|
|
172
|
+
? fromTimeFormat(_time)
|
|
173
|
+
: fromTimeFullFormat(_time);
|
|
174
|
+
|
|
175
|
+
const notFittingIntervalsByDay = intervalsByDay.reduce<Interval[][]>(
|
|
176
|
+
(acc, intervalsByDay) => {
|
|
177
|
+
if (!intervalsByDay.some((interval) => interval.contains(time))) {
|
|
178
|
+
acc.push(intervalsByDay);
|
|
179
|
+
}
|
|
180
|
+
return acc;
|
|
181
|
+
},
|
|
182
|
+
[]
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
const notFittingIntervals = notFittingIntervalsByDay
|
|
186
|
+
.flat()
|
|
187
|
+
.filter((interval) => !interval.contains(time));
|
|
188
|
+
|
|
189
|
+
const attribute = notFittingIntervals
|
|
190
|
+
.map((interval) => interval.toFormat("HH:mm"))
|
|
191
|
+
.join(", ");
|
|
192
|
+
|
|
193
|
+
if (notFittingIntervalsByDay.length !== 0) {
|
|
194
|
+
return t("outsideWorkingHours", { attribute }) as string;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return true;
|
|
198
|
+
},
|
|
199
|
+
};
|
|
200
|
+
};
|
|
@@ -12,7 +12,6 @@ import { TIME_FORMAT } from "@licklist/core/dist/Config";
|
|
|
12
12
|
import * as Config from "@licklist/core/dist/Config";
|
|
13
13
|
import { formatDateStringForEvent } from "@licklist/plugins/dist/utils/formatDate";
|
|
14
14
|
import { getOrderSourceTitle } from "@licklist/plugins/dist/utils/sourceTitle";
|
|
15
|
-
|
|
16
15
|
import Icon from "../../../../static/Icon";
|
|
17
16
|
|
|
18
17
|
export type ResultCardProps = {
|
|
@@ -22,8 +21,6 @@ export type ResultCardProps = {
|
|
|
22
21
|
onCardClick?: (id: number) => void;
|
|
23
22
|
};
|
|
24
23
|
|
|
25
|
-
// @TODO integrate when API will be available
|
|
26
|
-
// activity and staff keys
|
|
27
24
|
export const ResultCard = ({
|
|
28
25
|
order,
|
|
29
26
|
className,
|
|
@@ -21,12 +21,14 @@ import couponCodeRules from "@licklist/plugins/dist/validation/Rules/couponCodeR
|
|
|
21
21
|
// import { useId } from "@react-aria/utils";
|
|
22
22
|
|
|
23
23
|
import HTMLInputDateElement from "../../../types/static/HTMLInputDateElement";
|
|
24
|
+
import { Typeahead, TypeaheadOptions } from "../../../typeahead";
|
|
25
|
+
import { convertToTypeaheadOptions } from "../utils";
|
|
24
26
|
|
|
25
27
|
export interface CouponFormValues {
|
|
26
28
|
name?: string;
|
|
27
29
|
code: string;
|
|
28
30
|
discountType: CouponType;
|
|
29
|
-
productGroupIds:
|
|
31
|
+
productGroupIds: Array<TypeaheadOptions | ProductGroup>;
|
|
30
32
|
discount: number;
|
|
31
33
|
totalType: CouponTotalType;
|
|
32
34
|
startFrom: string;
|
|
@@ -58,9 +60,9 @@ export const CouponFormControl = ({
|
|
|
58
60
|
watch,
|
|
59
61
|
} = useFormContext<CouponFormValues>();
|
|
60
62
|
const { t } = useTranslation(["Design", "Notification", "App"]);
|
|
61
|
-
const [selectedProductGroups, setSelectedProductGroups] = useState<
|
|
62
|
-
[]
|
|
63
|
-
);
|
|
63
|
+
const [selectedProductGroups, setSelectedProductGroups] = useState<
|
|
64
|
+
TypeaheadOptions[]
|
|
65
|
+
>([]);
|
|
64
66
|
/* TODO: Show Recurrent date, when reccurent date bugs are fixed */
|
|
65
67
|
// const rrule = watch("rrule");
|
|
66
68
|
// const [recurrent, setRecurrent] = useState(Boolean(rrule));
|
|
@@ -85,15 +87,20 @@ export const CouponFormControl = ({
|
|
|
85
87
|
[COUPON_TOTAL_TYPE_TOTAL]: t("Design:depositTotal"),
|
|
86
88
|
};
|
|
87
89
|
|
|
88
|
-
// Set pre-selected Product Groups
|
|
89
90
|
useEffect(() => {
|
|
90
|
-
|
|
91
|
+
const defaultProductGroup = getValues("productGroupIds");
|
|
92
|
+
|
|
93
|
+
setSelectedProductGroups(
|
|
94
|
+
convertToTypeaheadOptions(defaultProductGroup as ProductGroup[])
|
|
95
|
+
);
|
|
91
96
|
}, [getValues]);
|
|
92
97
|
|
|
93
98
|
useEffect(() => {
|
|
94
99
|
setValue("productGroupIds", selectedProductGroups);
|
|
95
100
|
}, [getValues, setValue, selectedProductGroups]);
|
|
96
101
|
|
|
102
|
+
const productGroupList = convertToTypeaheadOptions(productGroups);
|
|
103
|
+
|
|
97
104
|
/* TODO: Show Recurrent date, when reccurent date bugs are fixed */
|
|
98
105
|
// useEffect(() => {
|
|
99
106
|
// if (!recurrent && rrule) {
|
|
@@ -251,51 +258,21 @@ export const CouponFormControl = ({
|
|
|
251
258
|
</Form.Group>
|
|
252
259
|
</Col>
|
|
253
260
|
</Row>
|
|
254
|
-
|
|
255
|
-
<
|
|
256
|
-
<
|
|
257
|
-
<
|
|
258
|
-
<
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
defaultChecked={isGroupSelected}
|
|
270
|
-
disabled={isLoading}
|
|
271
|
-
onChange={(e) => {
|
|
272
|
-
if (e.target.checked) {
|
|
273
|
-
setSelectedProductGroups((prevGroups) =>
|
|
274
|
-
Array.from(
|
|
275
|
-
new Set([...prevGroups, String(productGroup.id)])
|
|
276
|
-
)
|
|
277
|
-
);
|
|
278
|
-
} else {
|
|
279
|
-
setSelectedProductGroups((prevGroups) => {
|
|
280
|
-
return prevGroups.filter(
|
|
281
|
-
(id) => String(productGroup.id) !== id
|
|
282
|
-
);
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
}}
|
|
286
|
-
/>
|
|
287
|
-
);
|
|
288
|
-
})}
|
|
289
|
-
<Form.Control
|
|
290
|
-
{...register("productGroupIds")}
|
|
291
|
-
hidden
|
|
292
|
-
value={selectedProductGroups}
|
|
293
|
-
disabled={isLoading}
|
|
294
|
-
/>
|
|
295
|
-
</Form.Group>
|
|
296
|
-
</Col>
|
|
297
|
-
</Row>
|
|
298
|
-
)}
|
|
261
|
+
<Row>
|
|
262
|
+
<Col>
|
|
263
|
+
<Form.Group className="mb-3">
|
|
264
|
+
<Form.Label>{t("Design:productGroups")}</Form.Label>
|
|
265
|
+
<Typeahead
|
|
266
|
+
name="productGroupIds"
|
|
267
|
+
options={productGroupList}
|
|
268
|
+
isMultipleChoise
|
|
269
|
+
isCouponForm
|
|
270
|
+
placeholder={t("Design:choose")}
|
|
271
|
+
noOptionsMessage={t("Design:noSelectedProductGroups")}
|
|
272
|
+
/>
|
|
273
|
+
</Form.Group>
|
|
274
|
+
</Col>
|
|
275
|
+
</Row>
|
|
299
276
|
|
|
300
277
|
{/* TODO: Show Recurrent date, when reccurent date bugs are fixed */}
|
|
301
278
|
{/* {startFromValue && (
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import React, { useEffect } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
ProductGroup,
|
|
4
|
+
ProductGroupDTO,
|
|
5
|
+
} from "@licklist/core/dist/DataMapper/Product/ProductGroupDataMapper";
|
|
3
6
|
import {
|
|
4
7
|
CouponTotalType,
|
|
5
8
|
CouponType,
|
|
@@ -16,7 +19,7 @@ export interface CouponFormValues {
|
|
|
16
19
|
name?: string;
|
|
17
20
|
code: string;
|
|
18
21
|
discountType: CouponType;
|
|
19
|
-
productGroupIds:
|
|
22
|
+
productGroupIds: ProductGroupDTO[];
|
|
20
23
|
discount: number;
|
|
21
24
|
totalType: CouponTotalType;
|
|
22
25
|
startFrom: string;
|
|
@@ -54,19 +57,6 @@ export const CouponForm = ({
|
|
|
54
57
|
const { setError } = form;
|
|
55
58
|
const { t } = useTranslation(["Design", "Notification", "App"]);
|
|
56
59
|
|
|
57
|
-
// @TODO: dont need for v1 release
|
|
58
|
-
// const [selectedProductGroups, setSelectedProductGroups] = useState<string[]>(
|
|
59
|
-
// []
|
|
60
|
-
// );
|
|
61
|
-
// Set pre-selected Product Groups
|
|
62
|
-
// useEffect(() => {
|
|
63
|
-
// setSelectedProductGroups(getValues("productGroupIds"));
|
|
64
|
-
// }, [getValues]);
|
|
65
|
-
|
|
66
|
-
// useEffect(() => {
|
|
67
|
-
// setValue("productGroupIds", selectedProductGroups);
|
|
68
|
-
// }, [getValues, setValue, selectedProductGroups]);
|
|
69
|
-
|
|
70
60
|
useEffect(() => {
|
|
71
61
|
FormErrorService.handleServerErrors(serverErrors, setError);
|
|
72
62
|
}, [serverErrors, setError]);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ProductGroup } from "@licklist/core/dist/DataMapper/Product/ProductGroupDataMapper";
|
|
2
|
+
|
|
3
|
+
export const convertToTypeaheadOptions = (productGroups?: ProductGroup[]) => {
|
|
4
|
+
if (!productGroups || !productGroups.length) {
|
|
5
|
+
return [];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
return productGroups.map(({ id, name }: ProductGroup) => ({
|
|
9
|
+
id: Number(id),
|
|
10
|
+
value: name,
|
|
11
|
+
label: name,
|
|
12
|
+
}));
|
|
13
|
+
};
|
|
@@ -11,7 +11,7 @@ import Row from "react-bootstrap/Row";
|
|
|
11
11
|
import Col from "react-bootstrap/Col";
|
|
12
12
|
import { Link } from "react-router-dom";
|
|
13
13
|
import HookFormService from "@licklist/plugins/dist/services/Form/HookFormService";
|
|
14
|
-
import {
|
|
14
|
+
import { ProvidableType } from "@licklist/core/dist/DataMapper/Provider/ProvidableDataMapper";
|
|
15
15
|
import Icon from "../../static/Icon";
|
|
16
16
|
import { PaymentFeeForm, PaymentFeeFormFieldValues } from "./PaymentFeeForm";
|
|
17
17
|
import { Currency } from "../../types/currency";
|
|
@@ -33,7 +33,7 @@ export interface AdminSettingFormProps extends HasPermissionProp {
|
|
|
33
33
|
providerMetadata: {
|
|
34
34
|
country?: string;
|
|
35
35
|
providableId?: number;
|
|
36
|
-
providerType?:
|
|
36
|
+
providerType?: ProvidableType;
|
|
37
37
|
};
|
|
38
38
|
}
|
|
39
39
|
|
|
@@ -53,7 +53,6 @@ export interface SortableTreeItemProps {
|
|
|
53
53
|
};
|
|
54
54
|
setIsExpanded?: () => void;
|
|
55
55
|
isOverride?: boolean;
|
|
56
|
-
isProduct?: boolean;
|
|
57
56
|
}
|
|
58
57
|
|
|
59
58
|
export function SortableTreeItem({
|
|
@@ -81,7 +80,6 @@ export function SortableTreeItem({
|
|
|
81
80
|
secondaryBadge,
|
|
82
81
|
setIsExpanded,
|
|
83
82
|
isOverride,
|
|
84
|
-
isProduct = false,
|
|
85
83
|
}: SortableTreeItemProps) {
|
|
86
84
|
const [expanded, setExpanded] = useState(isExpanded);
|
|
87
85
|
const [isModalVisible, setIsModalVisible] = useState(isNewAdded);
|
|
@@ -152,7 +150,6 @@ export function SortableTreeItem({
|
|
|
152
150
|
};
|
|
153
151
|
|
|
154
152
|
const onEdit = (e) => {
|
|
155
|
-
if (isOverride && !isProduct) return;
|
|
156
153
|
e.stopPropagation();
|
|
157
154
|
if (edit && !isModalVisible) edit();
|
|
158
155
|
setIsModalVisible(true);
|
|
@@ -23,7 +23,7 @@ export function BooleanSwitch({
|
|
|
23
23
|
const { t } = useTranslation("Design");
|
|
24
24
|
|
|
25
25
|
const options: SelectItem[] = [
|
|
26
|
-
{ id: 1, value: firstValueTitle ??
|
|
26
|
+
{ id: 1, value: firstValueTitle ?? t("yes") },
|
|
27
27
|
{ id: 0, value: secondValueTitle ?? t("no") },
|
|
28
28
|
];
|
|
29
29
|
|
|
@@ -135,6 +135,14 @@
|
|
|
135
135
|
margin-bottom: 0.5rem;
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
|
+
.ryft-pay-grid {
|
|
139
|
+
display: flex;
|
|
140
|
+
flex-direction: column;
|
|
141
|
+
.apple-pay-button {
|
|
142
|
+
height: 2.5rem;
|
|
143
|
+
margin-top: 1rem;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
138
146
|
.mobile-pay-title {
|
|
139
147
|
display: block;
|
|
140
148
|
font-weight: 600;
|
|
@@ -16,6 +16,7 @@ export interface TypeaheadProps {
|
|
|
16
16
|
isMultipleChoise?: boolean;
|
|
17
17
|
noOptionsMessage: string;
|
|
18
18
|
isInvalid?: boolean;
|
|
19
|
+
isCouponForm?: boolean;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
function Typeahead({
|
|
@@ -24,13 +25,25 @@ function Typeahead({
|
|
|
24
25
|
isRequired = false,
|
|
25
26
|
isMultipleChoise,
|
|
26
27
|
name = "",
|
|
28
|
+
isCouponForm = false,
|
|
27
29
|
noOptionsMessage = "",
|
|
28
30
|
isInvalid,
|
|
29
31
|
}: TypeaheadProps) {
|
|
30
32
|
const { control } = useFormContext();
|
|
31
33
|
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
+
const getStyle = (): CSSObjectWithLabel => {
|
|
35
|
+
const couponFormStyle = isCouponForm
|
|
36
|
+
? {
|
|
37
|
+
borderRadius: "1rem",
|
|
38
|
+
minHeight: "3rem",
|
|
39
|
+
}
|
|
40
|
+
: {};
|
|
41
|
+
return isInvalid
|
|
42
|
+
? { borderColor: "red", ...couponFormStyle }
|
|
43
|
+
: {
|
|
44
|
+
...couponFormStyle,
|
|
45
|
+
};
|
|
46
|
+
};
|
|
34
47
|
|
|
35
48
|
return (
|
|
36
49
|
<>
|
|
@@ -46,7 +59,7 @@ function Typeahead({
|
|
|
46
59
|
styles={{
|
|
47
60
|
control: (base) => ({
|
|
48
61
|
...base,
|
|
49
|
-
...
|
|
62
|
+
...getStyle(),
|
|
50
63
|
}),
|
|
51
64
|
}}
|
|
52
65
|
onChange={(value) => {
|
|
@@ -13,7 +13,7 @@ export type ZoneFormProps = {
|
|
|
13
13
|
onSubmit: (values: Partial<Zone>) => void;
|
|
14
14
|
serverErrors?: ServerError;
|
|
15
15
|
isLoading?: boolean;
|
|
16
|
-
workHours
|
|
16
|
+
workHours: WorkHour[] | undefined;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
export type ZoneFormValues = Partial<Zone> & {
|
|
@@ -25,6 +25,7 @@ export const ZoneForm = ({
|
|
|
25
25
|
onSubmit,
|
|
26
26
|
serverErrors,
|
|
27
27
|
isLoading = false,
|
|
28
|
+
workHours,
|
|
28
29
|
}: ZoneFormProps) => {
|
|
29
30
|
const { t } = useTranslation("Design");
|
|
30
31
|
const form = useForm<ZoneFormValues>({
|
|
@@ -54,7 +55,7 @@ export const ZoneForm = ({
|
|
|
54
55
|
return (
|
|
55
56
|
<FormProvider {...form}>
|
|
56
57
|
<Form onSubmit={handleSubmit(onFormSubmit)}>
|
|
57
|
-
<ZoneControl isLoading={isLoading} />
|
|
58
|
+
<ZoneControl isLoading={isLoading} workHours={workHours} />
|
|
58
59
|
<Row>
|
|
59
60
|
<Col md={6} sm={12} />
|
|
60
61
|
<Col
|