@licklist/design 0.62.1 → 0.62.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.
Files changed (143) hide show
  1. package/bitbucket-pipelines.yml +0 -8
  2. package/dist/date-time-button/DateTimeButton.js +1 -1
  3. package/dist/events/edit-event-modal/component/EditEventForm/EditEventForm.d.ts +3 -1
  4. package/dist/events/edit-event-modal/component/EditEventForm/EditEventForm.d.ts.map +1 -1
  5. package/dist/events/edit-event-modal/component/EditEventForm/EditEventForm.js +1 -1
  6. package/dist/events/edit-event-modal/component/SelectEventProductSet/SelectEventProductSet.d.ts +3 -1
  7. package/dist/events/edit-event-modal/component/SelectEventProductSet/SelectEventProductSet.d.ts.map +1 -1
  8. package/dist/events/edit-event-modal/component/SelectEventProductSet/SelectEventProductSet.js +1 -1
  9. package/dist/events/edit-event-modal/component/SelectEventProductSet/component/EditEventProductSet.d.ts +3 -1
  10. package/dist/events/edit-event-modal/component/SelectEventProductSet/component/EditEventProductSet.d.ts.map +1 -1
  11. package/dist/events/edit-event-modal/component/SelectEventProductSet/component/EditEventProductSet.js +1 -1
  12. package/dist/iframe/payment/order-items-table/utils/paymentSummary.js +1 -1
  13. package/dist/iframe/ryft/RyftPaymentForm.d.ts.map +1 -1
  14. package/dist/iframe/ryft/RyftPaymentForm.js +1 -1
  15. package/dist/iframe/ryft/utils/ryft-form.d.ts.map +1 -1
  16. package/dist/iframe/ryft/utils/ryft-form.js +1 -1
  17. package/dist/product-set/control/DateAndRecurrenceInput.d.ts +1 -1
  18. package/dist/product-set/control/DateAndRecurrenceInput.d.ts.map +1 -1
  19. package/dist/product-set/control/DateAndRecurrenceInput.js +1 -1
  20. package/dist/product-set/control/DateInput.d.ts.map +1 -1
  21. package/dist/product-set/control/DateInput.js +1 -1
  22. package/dist/product-set/control/ProductSetControl.d.ts +1 -1
  23. package/dist/product-set/control/ProductSetControl.d.ts.map +1 -1
  24. package/dist/product-set/form/ProductSetForm.d.ts +4 -1
  25. package/dist/product-set/form/ProductSetForm.d.ts.map +1 -1
  26. package/dist/product-set/hooks/useSortableTreeFunctions.d.ts.map +1 -1
  27. package/dist/product-set/product/ProductControl.d.ts.map +1 -1
  28. package/dist/product-set/product/ProductControl.js +1 -1
  29. package/dist/product-set/product/fixed-duration-fields/FixedDurationOptions.d.ts.map +1 -1
  30. package/dist/provider/working-hours-input/WorkingHoursInputDescription.d.ts.map +1 -1
  31. package/dist/provider/working-hours-input/WorkingHoursInputDescription.js +1 -1
  32. package/dist/recurring-date-picker-input/RecurrenceAndFrequencyInput.d.ts.map +1 -1
  33. package/dist/recurring-date-picker-input/RecurringDatePickerInput.d.ts +3 -1
  34. package/dist/recurring-date-picker-input/RecurringDatePickerInput.d.ts.map +1 -1
  35. package/dist/recurring-date-picker-input/RecurringDatePickerInput.js +1 -1
  36. package/dist/recurring-date-picker-input/utils.d.ts +12 -0
  37. package/dist/recurring-date-picker-input/utils.d.ts.map +1 -1
  38. package/dist/recurring-date-picker-input/utils.js +1 -1
  39. package/dist/sales/booking/results/components/ResultCard.d.ts.map +1 -1
  40. package/dist/sales/booking/results/components/ResultCard.js +1 -1
  41. package/dist/sales/coupon/control/CouponFormControl.d.ts +2 -1
  42. package/dist/sales/coupon/control/CouponFormControl.d.ts.map +1 -1
  43. package/dist/sales/coupon/control/CouponFormControl.js +1 -1
  44. package/dist/sales/coupon/form/CouponFrom.d.ts +2 -2
  45. package/dist/sales/coupon/form/CouponFrom.d.ts.map +1 -1
  46. package/dist/sales/coupon/utils/index.d.ts +7 -0
  47. package/dist/sales/coupon/utils/index.d.ts.map +1 -0
  48. package/dist/sales/coupon/utils/index.js +1 -0
  49. package/dist/setting/admin/AdminSettingForm.d.ts +2 -2
  50. package/dist/setting/admin/AdminSettingForm.d.ts.map +1 -1
  51. package/dist/setting/dashboard/DashboardSettingForm.d.ts +1 -0
  52. package/dist/setting/dashboard/DashboardSettingForm.d.ts.map +1 -1
  53. package/dist/setting/dashboard/DashboardSettingForm.js +1 -1
  54. package/dist/styles/iframe-external-modal/IframeExternalModal.scss +5 -2
  55. package/dist/styles/ryft-payment-form/RyftPaymentForm.scss +99 -113
  56. package/dist/styles/sales/BookingResults.scss +1 -1
  57. package/dist/typeahead/Typeahead.d.ts +2 -1
  58. package/dist/typeahead/Typeahead.d.ts.map +1 -1
  59. package/dist/typeahead/Typeahead.js +1 -1
  60. package/dist/zone/form/ZoneForm.d.ts +2 -2
  61. package/dist/zone/form/ZoneForm.d.ts.map +1 -1
  62. package/dist/zone/form/ZoneForm.js +1 -1
  63. package/dist/zone/form/components/ZoneControl.d.ts +2 -2
  64. package/dist/zone/form/components/ZoneControl.d.ts.map +1 -1
  65. package/dist/zone/form/components/ZoneControl.js +1 -1
  66. package/dist/zone/form/components/ZoneRecurrencesControl.d.ts +4 -4
  67. package/dist/zone/form/components/ZoneRecurrencesControl.d.ts.map +1 -1
  68. package/dist/zone/form/components/ZoneRecurrencesControl.js +1 -1
  69. package/dist/zone/form/utils/dates.d.ts.map +1 -1
  70. package/package.json +10 -35
  71. package/src/date-time-button/DateTimeButton.stories.tsx +2 -1
  72. package/src/date-time-button/DateTimeButton.tsx +7 -5
  73. package/src/events/edit-event-modal/component/EditEventForm/EditEventForm.tsx +4 -0
  74. package/src/events/edit-event-modal/component/SelectEventProductSet/SelectEventProductSet.tsx +10 -8
  75. package/src/events/edit-event-modal/component/SelectEventProductSet/component/EditEventProductSet.tsx +4 -0
  76. package/src/iframe/payment/order-items-table/utils/paymentSummary.tsx +6 -6
  77. package/src/iframe/ryft/RyftPaymentForm.tsx +12 -4
  78. package/src/iframe/ryft/utils/ryft-form.ts +8 -4
  79. package/src/product-set/control/DateAndRecurrenceInput.tsx +3 -2
  80. package/src/product-set/control/DateInput.tsx +2 -4
  81. package/src/product-set/control/ProductSetControl.tsx +1 -1
  82. package/src/product-set/form/ProductCategoriesControl.tsx +1 -1
  83. package/src/product-set/form/ProductSetForm.tsx +5 -1
  84. package/src/product-set/hooks/useSortableTreeFunctions.ts +2 -0
  85. package/src/product-set/product/ProductControl.tsx +38 -38
  86. package/src/product-set/product/fixed-duration-fields/FixedDurationOptions.tsx +0 -2
  87. package/src/provider/working-hours-input/WorkingHoursInputDescription.tsx +4 -18
  88. package/src/recurring-date-picker-input/RecurrenceAndFrequencyInput.tsx +0 -1
  89. package/src/recurring-date-picker-input/RecurringDatePickerInput.tsx +11 -1
  90. package/src/recurring-date-picker-input/utils.ts +77 -0
  91. package/src/sales/booking/results/BookingResults.stories.tsx +3 -2
  92. package/src/sales/booking/results/components/ResultCard.tsx +2 -5
  93. package/src/sales/coupon/control/CouponFormControl.tsx +29 -50
  94. package/src/sales/coupon/form/CouponFrom.tsx +5 -15
  95. package/src/sales/coupon/utils/index.ts +13 -0
  96. package/src/setting/admin/AdminSettingForm.tsx +2 -2
  97. package/src/setting/dashboard/DashboardSettingForm.tsx +13 -0
  98. package/src/sortable-tree/SortableTreeItem.tsx +1 -1
  99. package/src/static/switch/BooleanSwitch.tsx +1 -1
  100. package/src/styles/iframe-external-modal/IframeExternalModal.scss +5 -2
  101. package/src/styles/ryft-payment-form/RyftPaymentForm.scss +99 -113
  102. package/src/styles/sales/BookingResults.scss +1 -1
  103. package/src/typeahead/Typeahead.tsx +16 -3
  104. package/src/zone/form/ZoneForm.tsx +3 -2
  105. package/src/zone/form/components/ZoneControl.tsx +3 -3
  106. package/src/zone/form/components/ZoneRecurrencesControl.tsx +7 -5
  107. package/src/zone/form/utils/dates.ts +9 -10
  108. package/jest.config.js +0 -29
  109. package/tests/Auth/Authorizer.test.tsx +0 -194
  110. package/tests/Auth/Layout/UserNavDropDown.test.tsx +0 -43
  111. package/tests/Auth/Layout/UserNavDropDownToggle.test.tsx +0 -33
  112. package/tests/Auth/Login/LoginComponent.test.tsx +0 -246
  113. package/tests/Auth/Login/LoginFormComponent.test.tsx +0 -182
  114. package/tests/Auth/Register/RegisterComponent.test.tsx +0 -285
  115. package/tests/Auth/Register/RegisterFormComponent.test.tsx +0 -170
  116. package/tests/Auth/Settings/Dashboard/IpInput.test.tsx +0 -130
  117. package/tests/Auth/Social/SocialCallbackComponent.test.tsx +0 -133
  118. package/tests/Auth/Social/SocialFormComponent.test.tsx +0 -118
  119. package/tests/FileUpload/FileUpload.test.tsx +0 -42
  120. package/tests/Notification/EmailTemplate.test.tsx +0 -82
  121. package/tests/ProductSet/ProductSetPopover.test.tsx +0 -40
  122. package/tests/Report/Report.test.tsx +0 -48
  123. package/tests/Sales/Coupon.test.tsx +0 -51
  124. package/tests/Sales/SalesAndVIews.test.tsx +0 -63
  125. package/tests/SnippetTemplates/SnippetTemplates.test.tsx +0 -56
  126. package/tests/Table/FilterHelperComponent.test.tsx +0 -88
  127. package/tests/Table/PaginationHelperComponent.test.tsx +0 -109
  128. package/tests/Table/PerPageHelperComponent.test.tsx +0 -34
  129. package/tests/Table/TableHelperComponent.test.tsx +0 -295
  130. package/tests/TipTapEditor/TipTapEditor.test.tsx +0 -28
  131. package/tests/__mock__/hooks/useAuthApi.ts +0 -13
  132. package/tests/__mock__/hooks/useAuthMock.ts +0 -13
  133. package/tests/__mock__/hooks/useFormMock.ts +0 -27
  134. package/tests/__mock__/hooks/useNotificationMock.ts +0 -13
  135. package/tests/__mock__/hooks/useQueryMock.ts +0 -16
  136. package/tests/__mock__/hooks/useSocialApiMock.ts +0 -20
  137. package/tests/__mock__/hooks/useTranslationMock.ts +0 -17
  138. package/tests/__mock__/hooks/useUserApiMock.ts +0 -18
  139. package/tests/__mock__/hooks/useUserMock.ts +0 -13
  140. package/tests/__mock__/styleMock.js +0 -1
  141. package/tests/__mock__/windowMock.ts +0 -5
  142. package/tests/packages/react-query.tsx +0 -28
  143. package/tests/setupTests.ts +0 -10
@@ -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 { ProductType } from "@licklist/core/dist/DataMapper/Product/ProductDataMapper";
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
- import { PRODUCT_DEfAULT_COLORS } from "@licklist/core/dist/DataMapper/Product/ProductDataMapper";
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
- // @TODO: no need for v1 release
163
- // const productGroupId = useId();
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
- {weekday?.end
29
- ? weekday.start
30
- ? t("timeInterval", {
31
- start: DateTime.fromISO(weekday.start).toFormat(
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
  );
@@ -72,7 +72,6 @@ function RecurrenceAndFrequencyInput({
72
72
  </Form.Control.Feedback>
73
73
  </Form.Group>
74
74
  </Col>
75
-
76
75
  </Row>
77
76
 
78
77
  <Row>
@@ -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 { parseAndValidateRRule, SupportedFrequency } from "./utils";
18
+ import {
19
+ parseAndValidateRRule,
20
+ SupportedFrequency,
21
+ useWorkHoursValidationRules,
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 validationRules = useWorkHoursValidationRules(byWeekDay, workHours);
95
+
87
96
  const onSubmit = (nextState: RecurringDatePickerInputValues) => {
88
97
  const end = getDateTimeObject(endDate, endTime || "23:59:59");
89
98
 
@@ -188,6 +197,7 @@ export function RecurringDatePickerInput({
188
197
  <RecurrenceIntervalAndFrequencyInput
189
198
  disabled={disabled}
190
199
  minDate={minDate}
200
+ {...validationRules}
191
201
  />
192
202
 
193
203
  {children}
@@ -1,4 +1,8 @@
1
+ import { TIME_FORMAT } from "@licklist/core/dist/Config";
2
+ import { WorkHour } from "@licklist/core/dist/DataMapper/Provider/WorkHourDataMapper";
3
+ import { dateTimesSortFn } from "@licklist/plugins/dist/utils/dateTime";
1
4
  import { DateTime } from "luxon";
5
+ import { useTranslation } from "react-i18next";
2
6
  import RRule, { Frequency, Weekday } from "rrule";
3
7
 
4
8
  export const getWeekdayForFrequency = ({
@@ -11,6 +15,7 @@ export const getWeekdayForFrequency = ({
11
15
  const parsedDate = DateTime.fromISO(date);
12
16
  return new Weekday(
13
17
  parsedDate.weekday - 1,
18
+ // eslint-disable-next-line no-nested-ternary
14
19
  frequency !== Frequency.MONTHLY
15
20
  ? undefined
16
21
  : parsedDate.day + 7 > parsedDate.daysInMonth
@@ -109,3 +114,75 @@ export const parseAndValidateRRule = ({
109
114
  until: options.until,
110
115
  } as ParsedRRuleOptions;
111
116
  };
117
+
118
+ export const useWorkHoursValidationRules = (
119
+ byWeekDay: Weekday[] = [],
120
+ workHours: WorkHour[] | undefined
121
+ ) => {
122
+ const { t } = useTranslation("Validation");
123
+ if (!workHours) return {};
124
+
125
+ // workhours of selected days, all if no days selected
126
+ const selectedWorkHours = byWeekDay.length
127
+ ? byWeekDay.map(({ weekday }) =>
128
+ workHours.find(({ day }) => day === weekday)
129
+ )
130
+ : workHours;
131
+
132
+ /**
133
+ * start time
134
+ */
135
+ const startTimes = selectedWorkHours
136
+ .map((workhour) => DateTime.fromFormat(workhour.start, TIME_FORMAT))
137
+ .sort(dateTimesSortFn("desc"));
138
+
139
+ const latestStartTime = startTimes[0];
140
+
141
+ const startTimeRules = {
142
+ validate: (date: string) => {
143
+ const selectedDate = DateTime.fromFormat(date, TIME_FORMAT);
144
+ if (selectedDate >= latestStartTime) return true;
145
+
146
+ return t("fieldTimeAfter", {
147
+ attribute: t("Design:startTimeSmall"),
148
+ time: latestStartTime.toFormat(TIME_FORMAT),
149
+ });
150
+ },
151
+ };
152
+
153
+ /**
154
+ * end time
155
+ */
156
+ const endTimes = selectedWorkHours
157
+ .map<string>(({ start, end }) => {
158
+ const startDateTime = DateTime.fromFormat(start, TIME_FORMAT);
159
+ const endDateTime = DateTime.fromFormat(end, TIME_FORMAT);
160
+
161
+ if (startDateTime <= endDateTime) return end;
162
+
163
+ // if end is before start, then it means that end is on the next day
164
+ // so count only to the end of current day
165
+ return "23:59";
166
+ })
167
+ .map((workhour) => DateTime.fromFormat(workhour, TIME_FORMAT))
168
+ .sort(dateTimesSortFn("asc"));
169
+
170
+ const earliestEndTime = endTimes[0];
171
+
172
+ const endTimeRules = {
173
+ validate: (date: string) => {
174
+ const selectedDate = DateTime.fromFormat(date, TIME_FORMAT);
175
+ if (selectedDate <= earliestEndTime) return true;
176
+
177
+ return t("fieldTimeBefore", {
178
+ attribute: t("Design:endTimeSmall"),
179
+ time: earliestEndTime.toFormat(TIME_FORMAT),
180
+ });
181
+ },
182
+ };
183
+
184
+ return {
185
+ startTimeRules,
186
+ endTimeRules,
187
+ };
188
+ };
@@ -3,11 +3,12 @@ import { Meta } from "@storybook/react";
3
3
  import { Event } from "@licklist/core/dist/DataMapper/Provider/EventDataMapper";
4
4
  import { User } from "@licklist/core/dist/DataMapper/User/UserDataMapper";
5
5
  import { Product } from "@licklist/core/dist/DataMapper/Product/ProductDataMapper";
6
- import { Order } from "@licklist/core/dist/DataMapper/Order/OrderDataMapper";
7
6
  import {
7
+ Order,
8
8
  ORDER_SOURCE_IFRAME,
9
9
  ORDER_SOURCE_MANUAL,
10
- } from "@licklist/core/src/DataMapper/Order/OrderDataMapper";
10
+ } from "@licklist/core/dist/DataMapper/Order/OrderDataMapper";
11
+
11
12
  import { BookingResults } from "./BookingResults";
12
13
 
13
14
  export default {
@@ -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,
@@ -41,10 +38,10 @@ export const ResultCard = ({
41
38
  startDate,
42
39
  products,
43
40
  source,
44
- totalAmount,
45
41
  event,
46
42
  menu,
47
43
  remainingToPay,
44
+ paidAmount,
48
45
  } = order;
49
46
 
50
47
  const productList = products.map((product) => product.name)?.join(", ") || "";
@@ -108,7 +105,7 @@ export const ResultCard = ({
108
105
  )}
109
106
  <p>
110
107
  {t("paidAmount")}:{" "}
111
- {formatNumber(totalAmount, {
108
+ {formatNumber(paidAmount, {
112
109
  style: "currency",
113
110
  currency: Config.Currency.GBP,
114
111
  })}
@@ -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: string[];
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<string[]>(
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
- setSelectedProductGroups(getValues("productGroupIds"));
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,23 @@ export const CouponFormControl = ({
251
258
  </Form.Group>
252
259
  </Col>
253
260
  </Row>
254
- {productGroups && productGroups?.length > 0 && (
255
- <Row>
256
- <Col md={12}>
257
- <h5 className="mt-4">{t("Design:productGroups")}</h5>
258
- <Form.Group className="d-flex flex-wrap justify-content-between mt-4 mb-5">
259
- {productGroups?.map((productGroup) => {
260
- const isGroupSelected =
261
- getValues("productGroupIds")?.includes(
262
- String(productGroup.id)
263
- ) ?? false;
264
-
265
- return (
266
- <Form.Check
267
- key={productGroup.id}
268
- label={productGroup.name}
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
- );
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:noActiveTemplates", {
272
+ notification: t("Design:email"),
288
273
  })}
289
- <Form.Control
290
- {...register("productGroupIds")}
291
- hidden
292
- value={selectedProductGroups}
293
- disabled={isLoading}
294
- />
295
- </Form.Group>
296
- </Col>
297
- </Row>
298
- )}
274
+ />
275
+ </Form.Group>
276
+ </Col>
277
+ </Row>
299
278
 
300
279
  {/* TODO: Show Recurrent date, when reccurent date bugs are fixed */}
301
280
  {/* {startFromValue && (
@@ -1,5 +1,8 @@
1
1
  import React, { useEffect } from "react";
2
- import { ProductGroup } from "@licklist/core/dist/DataMapper/Product/ProductGroupDataMapper";
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: string[];
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 { ProviderType } from "@licklist/core/dist/DataMapper/Provider/ProvidableDataMapper";
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?: ProviderType;
36
+ providerType?: ProvidableType;
37
37
  };
38
38
  }
39
39
 
@@ -31,6 +31,7 @@ export type DashboardSettingFormFieldValues = {
31
31
  isEnquiryOnly: boolean;
32
32
  hasUserVerification: boolean;
33
33
  metaPixelId?: number;
34
+ eventDeadlineErrorMessage?: string;
34
35
  } & EventSettingFormFieldValues &
35
36
  ProviderSettingFormFieldValues;
36
37
 
@@ -81,6 +82,7 @@ export const DashboardSettingForm = ({
81
82
  const orderReportFormatId = useId();
82
83
  const userVerificationId = useId();
83
84
  const metaPixelId = useId();
85
+ const eventDeadlineErrorMessageId = useId();
84
86
 
85
87
  const orderReportFormatList: SelectItem[] = [
86
88
  { id: 1, value: t("groupItemsByOrder") },
@@ -234,6 +236,17 @@ export const DashboardSettingForm = ({
234
236
  <EventSettingForm isLoading={isLoading} />
235
237
 
236
238
  <ProviderSettingForm isLoading={isLoading} />
239
+ <Form.Group controlId={eventDeadlineErrorMessageId}>
240
+ <Form.Label>{t("eventDeadlineErrorMessage")}</Form.Label>
241
+ <Form.Control
242
+ {...register("eventDeadlineErrorMessage")}
243
+ isInvalid={Boolean(errors.eventDeadlineErrorMessage)}
244
+ disabled={isLoading}
245
+ />
246
+ <Form.Control.Feedback type="invalid">
247
+ {errors.eventDeadlineErrorMessage?.message}
248
+ </Form.Control.Feedback>
249
+ </Form.Group>
237
250
  </FormProvider>
238
251
  {hasPermission && (
239
252
  <Button
@@ -374,7 +374,7 @@ export function SortableTreeItem({
374
374
  items={sortableItems}
375
375
  strategy={verticalListSortingStrategy}
376
376
  >
377
- <Collapse in={expanded}>
377
+ <Collapse in={expanded}>
378
378
  <div className="ml-0">{children}</div>
379
379
  </Collapse>
380
380
  </SortableContext>
@@ -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 ?? t("yes") },
26
+ { id: 1, value: firstValueTitle ?? t("yes") },
27
27
  { id: 0, value: secondValueTitle ?? t("no") },
28
28
  ];
29
29
 
@@ -4,7 +4,8 @@ html[bkdt-scrollable="false"] {
4
4
  overflow: hidden !important;
5
5
  }
6
6
 
7
- body[bkdt-scrollable="false"] .bkdt-modal, body[bkdt-scrollable="false"] .bkdt-mask {
7
+ body[bkdt-scrollable="false"] .bkdt-modal,
8
+ body[bkdt-scrollable="false"] .bkdt-mask {
8
9
  display: block;
9
10
  }
10
11
 
@@ -15,7 +16,7 @@ body[bkdt-scrollable="false"] .bkdt-modal, body[bkdt-scrollable="false"] .bkdt-m
15
16
  width: 100%;
16
17
  height: 100%;
17
18
  z-index: 1000000;
18
- background-color: rgba(0,0,0,0.5);
19
+ background-color: rgba(0, 0, 0, 0.5);
19
20
  display: none;
20
21
  }
21
22
 
@@ -82,6 +83,7 @@ body[bkdt-scrollable="false"] .bkdt-modal, body[bkdt-scrollable="false"] .bkdt-m
82
83
  width: 100%;
83
84
  height: 100%;
84
85
  max-width: 800px;
86
+ min-height: unset;
85
87
  }
86
88
  }
87
89
  }
@@ -98,6 +100,7 @@ body[bkdt-scrollable="false"] .bkdt-modal, body[bkdt-scrollable="false"] .bkdt-m
98
100
  .bkdt-modal-content {
99
101
  .bkdt-modal-body {
100
102
  height: 35rem;
103
+ max-height: 85vh;
101
104
  }
102
105
  }
103
106
  }