@licklist/design 0.63.0 → 0.63.1-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 (157) 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/SelectEventProductSet/SelectEventProductSet.d.ts.map +1 -1
  4. package/dist/events/edit-event-modal/component/SelectEventProductSet/SelectEventProductSet.js +1 -1
  5. package/dist/events/edit-event-modal/component/SelectEventProductSet/component/EditEventProductSet.d.ts.map +1 -1
  6. package/dist/events/edit-event-modal/component/SelectEventProductSet/component/EditEventProductSet.js +1 -1
  7. package/dist/iframe/payment/order-items-table/utils/paymentSummary.js +1 -1
  8. package/dist/product-set/control/DateAndRecurrenceInput.d.ts +1 -5
  9. package/dist/product-set/control/DateAndRecurrenceInput.d.ts.map +1 -1
  10. package/dist/product-set/control/DateAndRecurrenceInput.js +1 -1
  11. package/dist/product-set/control/DateInput.d.ts.map +1 -1
  12. package/dist/product-set/control/DateInput.js +1 -1
  13. package/dist/product-set/control/ProductSetControl.d.ts +4 -3
  14. package/dist/product-set/control/ProductSetControl.d.ts.map +1 -1
  15. package/dist/product-set/control/ProductSetControl.js +1 -1
  16. package/dist/product-set/control/utils.d.ts +5 -0
  17. package/dist/product-set/control/utils.d.ts.map +1 -0
  18. package/dist/product-set/control/utils.js +1 -0
  19. package/dist/product-set/form/ProductCategoriesControl.d.ts +2 -1
  20. package/dist/product-set/form/ProductCategoriesControl.d.ts.map +1 -1
  21. package/dist/product-set/form/ProductCategoriesControl.js +1 -1
  22. package/dist/product-set/form/ProductSetForm.d.ts +4 -1
  23. package/dist/product-set/form/ProductSetForm.d.ts.map +1 -1
  24. package/dist/product-set/form/ProductsControl.d.ts +2 -1
  25. package/dist/product-set/form/ProductsControl.d.ts.map +1 -1
  26. package/dist/product-set/form/ProductsControl.js +1 -1
  27. package/dist/product-set/form/StepsControl.d.ts +2 -1
  28. package/dist/product-set/form/StepsControl.d.ts.map +1 -1
  29. package/dist/product-set/form/StepsControl.js +1 -1
  30. package/dist/product-set/hooks/useSortableTreeFunctions.d.ts.map +1 -1
  31. package/dist/product-set/product/ProductControl.d.ts +1 -0
  32. package/dist/product-set/product/ProductControl.d.ts.map +1 -1
  33. package/dist/product-set/product/ProductControl.js +1 -1
  34. package/dist/product-set/product/fixed-duration-fields/FixedDurationOptions.d.ts.map +1 -1
  35. package/dist/product-set/step/StepControl.d.ts +2 -1
  36. package/dist/product-set/step/StepControl.d.ts.map +1 -1
  37. package/dist/product-set/step/StepControl.js +1 -1
  38. package/dist/provider/working-hours-input/WorkingHoursInputDescription.d.ts.map +1 -1
  39. package/dist/provider/working-hours-input/WorkingHoursInputDescription.js +1 -1
  40. package/dist/recurring-date-picker-input/RecurrenceAndFrequencyInput.d.ts.map +1 -1
  41. package/dist/recurring-date-picker-input/RecurringDatePickerInput.d.ts +3 -1
  42. package/dist/recurring-date-picker-input/RecurringDatePickerInput.d.ts.map +1 -1
  43. package/dist/recurring-date-picker-input/RecurringDatePickerInput.js +1 -1
  44. package/dist/recurring-date-picker-input/utils.d.ts +6 -0
  45. package/dist/recurring-date-picker-input/utils.d.ts.map +1 -1
  46. package/dist/recurring-date-picker-input/utils.js +1 -1
  47. package/dist/sales/booking/results/components/ResultCard.d.ts.map +1 -1
  48. package/dist/sales/booking/results/components/ResultCard.js +1 -1
  49. package/dist/sales/coupon/control/CouponFormControl.d.ts +2 -1
  50. package/dist/sales/coupon/control/CouponFormControl.d.ts.map +1 -1
  51. package/dist/sales/coupon/control/CouponFormControl.js +1 -1
  52. package/dist/sales/coupon/form/CouponFrom.d.ts +2 -2
  53. package/dist/sales/coupon/form/CouponFrom.d.ts.map +1 -1
  54. package/dist/sales/coupon/utils/index.d.ts +7 -0
  55. package/dist/sales/coupon/utils/index.d.ts.map +1 -0
  56. package/dist/sales/coupon/utils/index.js +1 -0
  57. package/dist/setting/admin/AdminSettingForm.d.ts +2 -2
  58. package/dist/setting/admin/AdminSettingForm.d.ts.map +1 -1
  59. package/dist/setting/dashboard/DashboardSettingForm.d.ts +1 -0
  60. package/dist/setting/dashboard/DashboardSettingForm.d.ts.map +1 -1
  61. package/dist/setting/dashboard/DashboardSettingForm.js +1 -1
  62. package/dist/sortable-tree/SortableTreeItem.d.ts +1 -2
  63. package/dist/sortable-tree/SortableTreeItem.d.ts.map +1 -1
  64. package/dist/sortable-tree/SortableTreeItem.js +1 -1
  65. package/dist/styles/sales/BookingResults.scss +1 -1
  66. package/dist/typeahead/Typeahead.d.ts +2 -1
  67. package/dist/typeahead/Typeahead.d.ts.map +1 -1
  68. package/dist/typeahead/Typeahead.js +1 -1
  69. package/dist/zone/form/ZoneForm.d.ts +2 -2
  70. package/dist/zone/form/ZoneForm.d.ts.map +1 -1
  71. package/dist/zone/form/ZoneForm.js +1 -1
  72. package/dist/zone/form/components/AvailableTimesControl.d.ts +0 -2
  73. package/dist/zone/form/components/AvailableTimesControl.d.ts.map +1 -1
  74. package/dist/zone/form/components/ZoneControl.d.ts +2 -2
  75. package/dist/zone/form/components/ZoneControl.d.ts.map +1 -1
  76. package/dist/zone/form/components/ZoneControl.js +1 -1
  77. package/dist/zone/form/components/ZoneRecurrencesControl.d.ts +4 -4
  78. package/dist/zone/form/components/ZoneRecurrencesControl.d.ts.map +1 -1
  79. package/dist/zone/form/components/ZoneRecurrencesControl.js +1 -1
  80. package/dist/zone/form/utils/dates.d.ts.map +1 -1
  81. package/package.json +10 -35
  82. package/src/date-time-button/DateTimeButton.stories.tsx +2 -1
  83. package/src/date-time-button/DateTimeButton.tsx +7 -5
  84. package/src/events/edit-event-modal/component/SelectEventProductSet/SelectEventProductSet.tsx +14 -9
  85. package/src/events/edit-event-modal/component/SelectEventProductSet/component/EditEventProductSet.tsx +2 -0
  86. package/src/iframe/payment/order-items-table/utils/paymentSummary.tsx +6 -6
  87. package/src/product-set/control/DateAndRecurrenceInput.tsx +48 -14
  88. package/src/product-set/control/DateInput.tsx +2 -4
  89. package/src/product-set/control/ProductSetControl.stories.tsx +1 -1
  90. package/src/product-set/control/ProductSetControl.tsx +12 -11
  91. package/src/product-set/control/utils.ts +25 -0
  92. package/src/product-set/form/ProductCategoriesControl.tsx +8 -4
  93. package/src/product-set/form/ProductSetForm.stories.tsx +1 -2
  94. package/src/product-set/form/ProductSetForm.tsx +5 -1
  95. package/src/product-set/form/ProductsControl.tsx +87 -77
  96. package/src/product-set/form/StepsControl.tsx +11 -6
  97. package/src/product-set/hooks/useSortableTreeFunctions.ts +2 -0
  98. package/src/product-set/product/ProductControl.tsx +39 -39
  99. package/src/product-set/product/fixed-duration-fields/FixedDurationOptions.tsx +0 -2
  100. package/src/product-set/step/StepControl.tsx +4 -3
  101. package/src/provider/working-hours-input/WorkingHoursInputDescription.tsx +4 -18
  102. package/src/recurring-date-picker-input/RecurrenceAndFrequencyInput.tsx +0 -1
  103. package/src/recurring-date-picker-input/RecurringDatePickerInput.stories.tsx +13 -7
  104. package/src/recurring-date-picker-input/RecurringDatePickerInput.tsx +12 -1
  105. package/src/recurring-date-picker-input/utils.ts +82 -1
  106. package/src/sales/booking/results/BookingResults.stories.tsx +3 -2
  107. package/src/sales/booking/results/components/ResultCard.tsx +2 -5
  108. package/src/sales/coupon/control/CouponFormControl.tsx +28 -51
  109. package/src/sales/coupon/form/CouponFrom.tsx +5 -15
  110. package/src/sales/coupon/utils/index.ts +13 -0
  111. package/src/setting/admin/AdminSettingForm.tsx +2 -2
  112. package/src/setting/dashboard/DashboardSettingForm.tsx +13 -0
  113. package/src/sortable-tree/SortableTreeItem.tsx +1 -4
  114. package/src/static/switch/BooleanSwitch.tsx +1 -1
  115. package/src/styles/sales/BookingResults.scss +1 -1
  116. package/src/typeahead/Typeahead.tsx +16 -3
  117. package/src/zone/form/ZoneForm.tsx +3 -2
  118. package/src/zone/form/components/AvailableTimesControl.tsx +0 -2
  119. package/src/zone/form/components/ZoneControl.tsx +3 -3
  120. package/src/zone/form/components/ZoneRecurrencesControl.tsx +7 -5
  121. package/src/zone/form/utils/dates.ts +9 -10
  122. package/jest.config.js +0 -29
  123. package/tests/Auth/Authorizer.test.tsx +0 -194
  124. package/tests/Auth/Layout/UserNavDropDown.test.tsx +0 -43
  125. package/tests/Auth/Layout/UserNavDropDownToggle.test.tsx +0 -33
  126. package/tests/Auth/Login/LoginComponent.test.tsx +0 -246
  127. package/tests/Auth/Login/LoginFormComponent.test.tsx +0 -182
  128. package/tests/Auth/Register/RegisterComponent.test.tsx +0 -285
  129. package/tests/Auth/Register/RegisterFormComponent.test.tsx +0 -170
  130. package/tests/Auth/Settings/Dashboard/IpInput.test.tsx +0 -130
  131. package/tests/Auth/Social/SocialCallbackComponent.test.tsx +0 -133
  132. package/tests/Auth/Social/SocialFormComponent.test.tsx +0 -118
  133. package/tests/FileUpload/FileUpload.test.tsx +0 -42
  134. package/tests/Notification/EmailTemplate.test.tsx +0 -82
  135. package/tests/ProductSet/ProductSetPopover.test.tsx +0 -40
  136. package/tests/Report/Report.test.tsx +0 -48
  137. package/tests/Sales/Coupon.test.tsx +0 -51
  138. package/tests/Sales/SalesAndVIews.test.tsx +0 -63
  139. package/tests/SnippetTemplates/SnippetTemplates.test.tsx +0 -56
  140. package/tests/Table/FilterHelperComponent.test.tsx +0 -88
  141. package/tests/Table/PaginationHelperComponent.test.tsx +0 -109
  142. package/tests/Table/PerPageHelperComponent.test.tsx +0 -34
  143. package/tests/Table/TableHelperComponent.test.tsx +0 -295
  144. package/tests/TipTapEditor/TipTapEditor.test.tsx +0 -28
  145. package/tests/__mock__/hooks/useAuthApi.ts +0 -13
  146. package/tests/__mock__/hooks/useAuthMock.ts +0 -13
  147. package/tests/__mock__/hooks/useFormMock.ts +0 -27
  148. package/tests/__mock__/hooks/useNotificationMock.ts +0 -13
  149. package/tests/__mock__/hooks/useQueryMock.ts +0 -16
  150. package/tests/__mock__/hooks/useSocialApiMock.ts +0 -20
  151. package/tests/__mock__/hooks/useTranslationMock.ts +0 -17
  152. package/tests/__mock__/hooks/useUserApiMock.ts +0 -18
  153. package/tests/__mock__/hooks/useUserMock.ts +0 -13
  154. package/tests/__mock__/styleMock.js +0 -1
  155. package/tests/__mock__/windowMock.ts +0 -5
  156. package/tests/packages/react-query.tsx +0 -28
  157. package/tests/setupTests.ts +0 -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>
@@ -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
- interface DefaultRecurringDatePickerInputProps
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<DefaultRecurringDatePickerInputProps> = (args) => {
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 { parseAndValidateRRule, SupportedFrequency } from "./utils";
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,8 @@
1
- import { DateTime } from "luxon";
1
+ import { TIME_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 { 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,79 @@ export const parseAndValidateRRule = ({
109
114
  until: options.until,
110
115
  } as ParsedRRuleOptions;
111
116
  };
117
+
118
+ export const useWorkHoursValidation = (
119
+ byWeekDay: Weekday[] = [],
120
+ workHours: WorkHour[] | undefined
121
+ ) => {
122
+ const { t } = useTranslation("Validation");
123
+ if (!workHours) return {};
124
+
125
+ const fromTimeFormat = fromFormat(TIME_FORMAT);
126
+
127
+ // map every day to array of intervals describing workhours for that day
128
+ let intervalsByDay = workHours.map((workhour, index, self) => {
129
+ const res: Interval[] = [];
130
+
131
+ const startTime = fromTimeFormat(workhour.start);
132
+ const endTime = fromTimeFormat(workhour.end);
133
+
134
+ if (endTime > startTime) {
135
+ res.push(Interval.fromDateTimes(startTime, endTime));
136
+ } else {
137
+ // if end is before start, then it means that end is on the next day
138
+ // so count only to the end of current day
139
+ res.push(Interval.fromDateTimes(startTime, startTime.endOf("day")));
140
+ }
141
+
142
+ const prevIndex = index === 0 ? self.length - 1 : index - 1;
143
+
144
+ const prevStartTime = fromTimeFormat(self[prevIndex].start);
145
+ const prevEndTime = fromTimeFormat(self[prevIndex].end);
146
+
147
+ // if prevStartTime > prevEndTime then it means that prevEndTime is on the current day
148
+ // so we need to add interval from start of current day to prevEndTime
149
+ if (prevStartTime > prevEndTime) {
150
+ res.push(Interval.fromDateTimes(prevEndTime.startOf("day"), prevEndTime));
151
+ }
152
+
153
+ return res;
154
+ });
155
+
156
+ // if length === 0 or length === 7 then all workhours are selected, no need to filter
157
+ if (![0, 7].includes(byWeekDay.length)) {
158
+ intervalsByDay = intervalsByDay.filter((_, index) =>
159
+ byWeekDay.find(({ weekday }) => weekday === index)
160
+ );
161
+ }
162
+
163
+ return {
164
+ validate: (_time: string) => {
165
+ const time = fromTimeFormat(_time);
166
+
167
+ const notFittingIntervalsByDay = intervalsByDay.reduce<Interval[][]>(
168
+ (acc, intervalsByDay) => {
169
+ if (!intervalsByDay.some((interval) => interval.contains(time))) {
170
+ acc.push(intervalsByDay);
171
+ }
172
+ return acc;
173
+ },
174
+ []
175
+ );
176
+
177
+ const notFittingIntervals = notFittingIntervalsByDay
178
+ .flat()
179
+ .filter((interval) => !interval.contains(time));
180
+
181
+ if (notFittingIntervalsByDay.length !== 0) {
182
+ return t("outsideWorkingHours", {
183
+ attribute: notFittingIntervals
184
+ .map((interval) => interval.toFormat("HH:mm"))
185
+ .join(", "),
186
+ });
187
+ }
188
+
189
+ return true;
190
+ },
191
+ };
192
+ };
@@ -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,21 @@ 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
- );
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 { 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
@@ -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);
@@ -374,7 +371,7 @@ export function SortableTreeItem({
374
371
  items={sortableItems}
375
372
  strategy={verticalListSortingStrategy}
376
373
  >
377
- <Collapse in={expanded}>
374
+ <Collapse in={expanded}>
378
375
  <div className="ml-0">{children}</div>
379
376
  </Collapse>
380
377
  </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
 
@@ -5,7 +5,7 @@
5
5
  flex-wrap: wrap;
6
6
 
7
7
  .result-card {
8
- height: 14.25rem;
8
+ height: 14rem;
9
9
  border: 1px solid $gray-400;
10
10
  max-width: calc(50% - 0.75rem);
11
11
  flex: 0 0 calc(50% - 0.75rem);
@@ -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 getErrorStyle = (): CSSObjectWithLabel =>
33
- isInvalid ? { borderColor: "red" } : {};
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
- ...getErrorStyle(),
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?: WorkHour[];
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
@@ -21,8 +21,6 @@ type AvailableTimesControlProps = {
21
21
  isLoading: boolean;
22
22
  workHours?: WorkHour[];
23
23
  defaultValues?: string[];
24
- startTime?: string;
25
- endTime?: string;
26
24
  errorMessage?: string;
27
25
  clearErrorMessage: () => void;
28
26
  };
@@ -11,15 +11,15 @@ import { GameDurationControl } from "./GameDurationControl";
11
11
 
12
12
  export type ZoneControlProps = {
13
13
  isLoading: boolean;
14
- workHours?: WorkHour[];
14
+ workHours: WorkHour[] | undefined;
15
15
  };
16
16
 
17
- export const ZoneControl = ({ isLoading }: ZoneControlProps) => {
17
+ export const ZoneControl = ({ isLoading, workHours }: ZoneControlProps) => {
18
18
  return (
19
19
  <Row>
20
20
  <Col md={6} sm={12} className="pr-5">
21
21
  <NameControl isLoading={isLoading} />
22
- <ZoneRecurrencesControl />
22
+ <ZoneRecurrencesControl workHours={workHours} />
23
23
  <hr />
24
24
  <Row>
25
25
  <Col md={6} sm={6}>