@licklist/design 0.58.10 → 0.58.11-dev.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. package/bitbucket-pipelines.yml +0 -8
  2. package/dist/assets/iframe/calendar.svg +2 -2
  3. package/dist/assets/iframe/calendar.svg.js +1 -1
  4. package/dist/assets/iframe/ticket.svg +2 -2
  5. package/dist/assets/iframe/ticket.svg.js +1 -1
  6. package/dist/calendar/Calendar.d.ts +1 -1
  7. package/dist/calendar/Calendar.d.ts.map +1 -1
  8. package/dist/calendar/Calendar.js +1 -1
  9. package/dist/calendar/components/CalendarButtons/CalendarButtons.js +1 -1
  10. package/dist/calendar/components/CalendarDates/CalendarDates.d.ts +2 -2
  11. package/dist/calendar/components/CalendarDates/CalendarDates.d.ts.map +1 -1
  12. package/dist/calendar/components/CalendarDates/CalendarDates.js +1 -1
  13. package/dist/events/edit-event-modal/component/EditEventForm/EditEventForm.js +1 -1
  14. package/dist/events/event-statistic-modal/EventStatisticModal.js +1 -1
  15. package/dist/iframe/event/event-card/IframeEventCard.d.ts +2 -1
  16. package/dist/iframe/event/event-card/IframeEventCard.d.ts.map +1 -1
  17. package/dist/iframe/event/event-card/IframeEventCard.js +1 -1
  18. package/dist/iframe/event/event-venue-map/IframeEventVenueMap.js +1 -1
  19. package/dist/iframe/order-process/components/BookingSummary/BookingSummary.d.ts +2 -2
  20. package/dist/iframe/order-process/components/BookingSummary/BookingSummary.d.ts.map +1 -1
  21. package/dist/iframe/order-process/components/BookingSummary/BookingSummary.js +1 -1
  22. package/dist/iframe/order-process/components/BookingSummary/components/BookingSummaryAccordion/BookingSummaryAccordion.d.ts +4 -2
  23. package/dist/iframe/order-process/components/BookingSummary/components/BookingSummaryAccordion/BookingSummaryAccordion.d.ts.map +1 -1
  24. package/dist/iframe/order-process/components/BookingSummary/components/BookingSummaryAccordion/BookingSummaryAccordion.js +1 -1
  25. package/dist/iframe/order-process/components/BookingSummary/components/SummaryTotal/components/SummaryTotalBlock.d.ts +1 -1
  26. package/dist/iframe/order-process/components/BookingSummary/components/SummaryTotal/components/SummaryTotalBlock.d.ts.map +1 -1
  27. package/dist/iframe/order-process/components/BookingSummary/components/SummaryTotal/components/SummaryTotalBlock.js +1 -1
  28. package/dist/iframe/order-process/components/BookingSummary/components/ToggleHeader/ToggleHeader.d.ts +4 -2
  29. package/dist/iframe/order-process/components/BookingSummary/components/ToggleHeader/ToggleHeader.d.ts.map +1 -1
  30. package/dist/iframe/order-process/components/BookingSummary/components/ToggleHeader/ToggleHeader.js +1 -1
  31. package/dist/iframe/order-process/components/BookingSummary/types/index.d.ts +4 -0
  32. package/dist/iframe/order-process/components/BookingSummary/types/index.d.ts.map +1 -1
  33. package/dist/iframe/order-process/components/CalendarStepsForm/CalendarStepsForm.js +1 -1
  34. package/dist/iframe/order-process/components/CategoryProduct/components/NumberInput/NumberInput.js +1 -1
  35. package/dist/iframe/page/components/PageBody/components/LeftBlock/LeftBlock.d.ts.map +1 -1
  36. package/dist/iframe/page/components/PageBody/components/LeftBlock/LeftBlock.js +1 -1
  37. package/dist/iframe/page/components/PageBody/constants.d.ts +1 -0
  38. package/dist/iframe/page/components/PageBody/constants.d.ts.map +1 -1
  39. package/dist/iframe/page/components/PageBody/constants.js +1 -1
  40. package/dist/iframe/page/components/PageBody/hooks/useResizePageBody.d.ts.map +1 -1
  41. package/dist/iframe/page/components/PageBody/hooks/useResizePageBody.js +1 -1
  42. package/dist/iframe/payment/order-items-table/OrderItemsTable.js +1 -1
  43. package/dist/iframe/payment/order-items-table/utils/paymentSummary.js +1 -1
  44. package/dist/iframe/payment/payment-form/PaymentForm.js +1 -1
  45. package/dist/iframe/payment/payment-page/PaymentPage.d.ts.map +1 -1
  46. package/dist/iframe/payment/payment-page/PaymentPage.js +1 -1
  47. package/dist/iframe/payment/payment-page/PaymentTimer.js +1 -1
  48. package/dist/iframe/payment/payment-status-page/PaymentStatusPage.js +1 -1
  49. package/dist/iframe/ryft/RyftPaymentForm.d.ts.map +1 -1
  50. package/dist/iframe/ryft/RyftPaymentForm.js +1 -1
  51. package/dist/iframe/ryft/utils/ryft-form.d.ts +5 -0
  52. package/dist/iframe/ryft/utils/ryft-form.d.ts.map +1 -0
  53. package/dist/iframe/ryft/utils/ryft-form.js +1 -0
  54. package/dist/index.js +1 -1
  55. package/dist/product-set/control/DateAndRecurrenceInput.d.ts.map +1 -1
  56. package/dist/product-set/control/DateAndRecurrenceInput.js +1 -1
  57. package/dist/product-set/control/DateInput.d.ts.map +1 -1
  58. package/dist/product-set/form/ProductSetForm.d.ts +4 -1
  59. package/dist/product-set/form/ProductSetForm.d.ts.map +1 -1
  60. package/dist/product-set/form/VenueMapsControl.js +1 -1
  61. package/dist/product-set/hooks/useSortableTreeFunctions.d.ts.map +1 -1
  62. package/dist/product-set/product/ProductControl.d.ts +1 -0
  63. package/dist/product-set/product/ProductControl.d.ts.map +1 -1
  64. package/dist/product-set/product/ProductControl.js +1 -1
  65. package/dist/product-set/product/fixed-duration-fields/FixedDurationOptions.d.ts.map +1 -1
  66. package/dist/product-set/product-category/ProductCategoryControl.d.ts +1 -0
  67. package/dist/product-set/product-category/ProductCategoryControl.d.ts.map +1 -1
  68. package/dist/product-set/product-category/ProductCategoryControl.js +1 -1
  69. package/dist/provider/working-hours-input/WorkingHoursInputDescription.d.ts.map +1 -1
  70. package/dist/provider/working-hours-input/WorkingHoursInputDescription.js +1 -1
  71. package/dist/recurring-date-picker-input/RecurrenceAndFrequencyInput.d.ts.map +1 -1
  72. package/dist/recurring-date-picker-input/RecurringDatePickerInput.d.ts +3 -1
  73. package/dist/recurring-date-picker-input/RecurringDatePickerInput.d.ts.map +1 -1
  74. package/dist/recurring-date-picker-input/RecurringDatePickerInput.js +1 -1
  75. package/dist/recurring-date-picker-input/utils.d.ts +9 -0
  76. package/dist/recurring-date-picker-input/utils.d.ts.map +1 -1
  77. package/dist/recurring-date-picker-input/utils.js +1 -1
  78. package/dist/sales/booking/results/components/ResultCard.d.ts.map +1 -1
  79. package/dist/sales/booking/results/components/ResultCard.js +1 -1
  80. package/dist/sales/notes/NotesTableRow.js +1 -1
  81. package/dist/setting/admin/AdminSettingForm.d.ts +2 -2
  82. package/dist/setting/admin/AdminSettingForm.d.ts.map +1 -1
  83. package/dist/setting/dashboard/snippets/card/SnippetCard.js +1 -1
  84. package/dist/snippet/snippet-template/control/PropertyControl.d.ts +3 -1
  85. package/dist/snippet/snippet-template/control/PropertyControl.d.ts.map +1 -1
  86. package/dist/snippet/snippet-template/control/PropertyControl.js +1 -1
  87. package/dist/snippet/snippet-template/preview/Preview.js +1 -1
  88. package/dist/static/manual-date-picker/ManualDatePicker.js +1 -1
  89. package/dist/static/manual-date-picker/constants/index.d.ts +4 -1
  90. package/dist/static/manual-date-picker/constants/index.d.ts.map +1 -1
  91. package/dist/static/manual-date-picker/constants/index.js +1 -1
  92. package/dist/static/manual-date-picker/utils/index.d.ts +4 -0
  93. package/dist/static/manual-date-picker/utils/index.d.ts.map +1 -1
  94. package/dist/static/manual-date-picker/utils/index.js +1 -1
  95. package/dist/striped-static-table/StripedStaticTable.js +1 -1
  96. package/dist/styles/iframe-events/Card.scss +24 -8
  97. package/dist/styles/iframe-events/PoweredBy.scss +2 -2
  98. package/dist/styles/iframe-order-process/IframeOrderProcess.scss +57 -20
  99. package/dist/styles/iframe-page/Page.scss +1 -0
  100. package/dist/styles/iframe-page/PageBody.scss +34 -12
  101. package/dist/styles/iframe-page/PageHeader.scss +41 -39
  102. package/dist/styles/ryft-payment-form/RyftPaymentForm.scss +125 -2
  103. package/dist/styles/sales/BookingResults.scss +1 -1
  104. package/dist/venue-map-sets/form/components/VenueMapImageControl.js +1 -1
  105. package/dist/zone/form/utils/dates.d.ts.map +1 -1
  106. package/package.json +10 -35
  107. package/src/assets/iframe/calendar.svg +2 -2
  108. package/src/assets/iframe/ticket.svg +2 -2
  109. package/src/calendar/Calendar.stories.tsx +23 -0
  110. package/src/calendar/Calendar.tsx +5 -5
  111. package/src/calendar/components/CalendarDates/CalendarDates.tsx +0 -5
  112. package/src/iframe/event/event-card/IframeEventCard.stories.tsx +1 -0
  113. package/src/iframe/event/event-card/IframeEventCard.tsx +7 -8
  114. package/src/iframe/order-process/components/BookingSummary/BookingSummary.stories.tsx +9 -0
  115. package/src/iframe/order-process/components/BookingSummary/BookingSummary.tsx +58 -7
  116. package/src/iframe/order-process/components/BookingSummary/components/BookingSummaryAccordion/BookingSummaryAccordion.tsx +8 -0
  117. package/src/iframe/order-process/components/BookingSummary/components/SummaryTotal/components/SummaryTotalBlock.tsx +4 -4
  118. package/src/iframe/order-process/components/BookingSummary/components/ToggleHeader/ToggleHeader.tsx +63 -10
  119. package/src/iframe/order-process/components/BookingSummary/types/index.ts +4 -0
  120. package/src/iframe/order-process/components/CategoryProduct/components/NumberInput/NumberInput.tsx +1 -1
  121. package/src/iframe/page/components/PageBody/components/LeftBlock/LeftBlock.tsx +3 -1
  122. package/src/iframe/page/components/PageBody/constants.ts +2 -0
  123. package/src/iframe/page/components/PageBody/hooks/useResizePageBody.ts +10 -0
  124. package/src/iframe/payment/order-items-table/utils/paymentSummary.tsx +6 -6
  125. package/src/iframe/payment/payment-page/PaymentPage.stories.tsx +546 -6
  126. package/src/iframe/payment/payment-page/PaymentPage.tsx +38 -29
  127. package/src/iframe/ryft/RyftPaymentForm.tsx +11 -5
  128. package/src/iframe/ryft/utils/ryft-form.ts +47 -0
  129. package/src/product-set/control/DateAndRecurrenceInput.tsx +2 -1
  130. package/src/product-set/control/DateInput.tsx +1 -3
  131. package/src/product-set/form/ProductCategoriesControl.tsx +1 -1
  132. package/src/product-set/form/ProductSetForm.tsx +5 -1
  133. package/src/product-set/hooks/useSortableTreeFunctions.ts +2 -0
  134. package/src/product-set/product/ProductControl.tsx +17 -3
  135. package/src/product-set/product/fixed-duration-fields/FixedDurationOptions.tsx +0 -2
  136. package/src/product-set/product-category/ProductCategoryControl.tsx +105 -43
  137. package/src/provider/working-hours-input/WorkingHoursInputDescription.tsx +4 -18
  138. package/src/recurring-date-picker-input/RecurrenceAndFrequencyInput.tsx +0 -1
  139. package/src/recurring-date-picker-input/RecurringDatePickerInput.tsx +11 -1
  140. package/src/recurring-date-picker-input/utils.ts +75 -0
  141. package/src/sales/booking/results/BookingResults.stories.tsx +3 -2
  142. package/src/sales/booking/results/components/ResultCard.tsx +2 -5
  143. package/src/setting/admin/AdminSettingForm.tsx +2 -2
  144. package/src/snippet/snippet-template/control/PropertyControl.tsx +6 -2
  145. package/src/sortable-tree/SortableTreeItem.tsx +1 -1
  146. package/src/static/manual-date-picker/ManualDatePicker.tsx +3 -3
  147. package/src/static/manual-date-picker/constants/index.ts +6 -2
  148. package/src/static/manual-date-picker/utils/index.ts +11 -0
  149. package/src/static/switch/BooleanSwitch.tsx +1 -1
  150. package/src/styles/iframe-events/Card.scss +24 -8
  151. package/src/styles/iframe-events/PoweredBy.scss +2 -2
  152. package/src/styles/iframe-order-process/IframeOrderProcess.scss +57 -20
  153. package/src/styles/iframe-page/Page.scss +1 -0
  154. package/src/styles/iframe-page/PageBody.scss +34 -12
  155. package/src/styles/iframe-page/PageHeader.scss +41 -39
  156. package/src/styles/ryft-payment-form/RyftPaymentForm.scss +125 -2
  157. package/src/styles/sales/BookingResults.scss +1 -1
  158. package/src/zone/form/utils/dates.ts +9 -10
  159. package/jest.config.js +0 -29
  160. package/tests/Auth/Authorizer.test.tsx +0 -194
  161. package/tests/Auth/Layout/UserNavDropDown.test.tsx +0 -43
  162. package/tests/Auth/Layout/UserNavDropDownToggle.test.tsx +0 -33
  163. package/tests/Auth/Login/LoginComponent.test.tsx +0 -246
  164. package/tests/Auth/Login/LoginFormComponent.test.tsx +0 -182
  165. package/tests/Auth/Register/RegisterComponent.test.tsx +0 -285
  166. package/tests/Auth/Register/RegisterFormComponent.test.tsx +0 -170
  167. package/tests/Auth/Settings/Dashboard/IpInput.test.tsx +0 -130
  168. package/tests/Auth/Social/SocialCallbackComponent.test.tsx +0 -133
  169. package/tests/Auth/Social/SocialFormComponent.test.tsx +0 -118
  170. package/tests/FileUpload/FileUpload.test.tsx +0 -42
  171. package/tests/Notification/EmailTemplate.test.tsx +0 -82
  172. package/tests/ProductSet/ProductSetPopover.test.tsx +0 -40
  173. package/tests/Report/Report.test.tsx +0 -48
  174. package/tests/Sales/Coupon.test.tsx +0 -51
  175. package/tests/Sales/SalesAndVIews.test.tsx +0 -63
  176. package/tests/SnippetTemplates/SnippetTemplates.test.tsx +0 -56
  177. package/tests/Table/FilterHelperComponent.test.tsx +0 -88
  178. package/tests/Table/PaginationHelperComponent.test.tsx +0 -109
  179. package/tests/Table/PerPageHelperComponent.test.tsx +0 -34
  180. package/tests/Table/TableHelperComponent.test.tsx +0 -295
  181. package/tests/TipTapEditor/TipTapEditor.test.tsx +0 -28
  182. package/tests/__mock__/hooks/useAuthApi.ts +0 -13
  183. package/tests/__mock__/hooks/useAuthMock.ts +0 -13
  184. package/tests/__mock__/hooks/useFormMock.ts +0 -27
  185. package/tests/__mock__/hooks/useNotificationMock.ts +0 -13
  186. package/tests/__mock__/hooks/useQueryMock.ts +0 -16
  187. package/tests/__mock__/hooks/useSocialApiMock.ts +0 -20
  188. package/tests/__mock__/hooks/useTranslationMock.ts +0 -17
  189. package/tests/__mock__/hooks/useUserApiMock.ts +0 -18
  190. package/tests/__mock__/hooks/useUserMock.ts +0 -13
  191. package/tests/__mock__/styleMock.js +0 -1
  192. package/tests/__mock__/windowMock.ts +0 -5
  193. package/tests/packages/react-query.tsx +0 -28
  194. package/tests/setupTests.ts +0 -10
@@ -1,7 +1,6 @@
1
- import React, { useEffect, useState } from "react";
1
+ import React, { useEffect, useRef, useState } from "react";
2
2
  import { useTranslation } from "react-i18next";
3
3
  import { useForm } from "react-hook-form";
4
- import Form from "react-bootstrap/Form";
5
4
 
6
5
  import Button from "react-bootstrap/Button";
7
6
  import { useHistory } from "react-router-dom";
@@ -14,6 +13,7 @@ import {
14
13
  AttemptPaymentResponse,
15
14
  } from "@licklist/plugins/dist/hooks/Ryft/useRyftPayment";
16
15
  import { BlockLoader, ButtonLoader } from "../../static";
16
+ import { injectComponentsInRyftForm } from "./utils/ryft-form";
17
17
 
18
18
  export const ryftErrorMap: Record<string, string> = {
19
19
  insufficient_funds: "insufficientFunds",
@@ -50,6 +50,7 @@ export const RyftPaymentForm = ({
50
50
  onSubmit,
51
51
  }: RyftPaymentFormProps) => {
52
52
  const { t } = useTranslation(["Design", "Validation", "Ryft"]);
53
+ const formRef = useRef<HTMLFormElement | null>(null);
53
54
  const history = useHistory();
54
55
 
55
56
  const [isValid, setIsValid] = useState(false);
@@ -117,6 +118,12 @@ export const RyftPaymentForm = ({
117
118
  }
118
119
  };
119
120
 
121
+ useEffect(
122
+ () => injectComponentsInRyftForm({ t }),
123
+ // eslint-disable-next-line react-hooks/exhaustive-deps
124
+ [formRef.current?.childNodes?.length]
125
+ );
126
+
120
127
  useEffect(() => {
121
128
  if (!accountId.data || accountId.isError) return;
122
129
 
@@ -175,15 +182,14 @@ export const RyftPaymentForm = ({
175
182
 
176
183
  return (
177
184
  <>
178
- <Form.Label>{t("Design:paymentDetails")}</Form.Label>
179
- {/* For unknown reasons ryft doesn't work with bootstrap form */}
180
185
  <form
186
+ ref={formRef}
181
187
  id="ryft-pay-form"
182
188
  noValidate
183
189
  onSubmit={methods.handleSubmit(handleSubmit)}
184
190
  className="ryft-payment-form"
185
191
  >
186
- <div className="submit-button-wrapper mt-3 p-1">
192
+ <div className="submit-button-wrapper mt-4 p-1">
187
193
  <Button type="submit" disabled={isBtnDisabled || !isValid}>
188
194
  {isBtnDisabled && <ButtonLoader />}
189
195
  {t("Design:buyNow")}
@@ -0,0 +1,47 @@
1
+ import { TFunction } from "react-i18next";
2
+
3
+ export const injectComponentsInRyftForm = ({
4
+ t,
5
+ }: {
6
+ t: TFunction<string[]>;
7
+ }) => {
8
+ const cardContainer = document.getElementById("ryft-pay-iframe");
9
+ const oldCardDividerContainer = document.getElementById(
10
+ "card-title-container"
11
+ );
12
+
13
+ if (!cardContainer || oldCardDividerContainer) {
14
+ return;
15
+ }
16
+
17
+ const cardTitle = document.createElement("div");
18
+ const cardText = document.createElement("div");
19
+ const cardTitleContainer = document.createElement("div");
20
+ cardTitleContainer.id = "card-title-container";
21
+ cardTitle.textContent = t("Design:enterCardDetails");
22
+ cardText.className = "bold-text form-label";
23
+ cardText.innerText = t("Design:paymentDetails");
24
+ cardTitleContainer.append(cardTitle, cardText);
25
+ cardContainer?.before(cardTitleContainer);
26
+
27
+ const payGrid = document.getElementById("ryft-pay-grid");
28
+
29
+ if (!payGrid) {
30
+ return;
31
+ }
32
+
33
+ // Adding title and divider for apple and google pay button
34
+ const mobilePayTitle = document.createElement("div");
35
+ const dividerText = document.createElement("div");
36
+ const divider = document.createElement("div");
37
+ const container = document.createElement("div");
38
+ mobilePayTitle.className = "mobile-pay-title";
39
+ mobilePayTitle.innerText = t("Design:expressCheckoutWith");
40
+ dividerText.id = "mobile-pay-divider-text";
41
+ dividerText.innerText = "or";
42
+ divider.id = "mobile-pay-divider";
43
+ container.id = "mobile-pay-divider-container";
44
+ container.append(dividerText, divider);
45
+ payGrid.before(mobilePayTitle);
46
+ payGrid.after(container);
47
+ };
@@ -90,7 +90,7 @@ export const DateAndRecurrenceInput = ({
90
90
  clearEditState();
91
91
  });
92
92
 
93
- const popoverId = useId()!;
93
+ const popoverId = useId();
94
94
 
95
95
  const { t } = useTranslation("Design");
96
96
 
@@ -228,6 +228,7 @@ export const DateAndRecurrenceInput = ({
228
228
  defaultValues={editState.values}
229
229
  onChange={handleRecurringDateChange}
230
230
  onDelete={handleDelete}
231
+ workHours={workHours}
231
232
  >
232
233
  {providerHasBookingManagement && (
233
234
  <AvailableTimesControl
@@ -5,9 +5,8 @@ import { Form, OverlayTrigger, Popover } from "react-bootstrap";
5
5
  import { useFieldArray, useFormContext } from "react-hook-form";
6
6
  import { useTranslation } from "react-i18next";
7
7
  import { useClickAway } from "react-use";
8
- import { TIMEZONE } from "@licklist/core/dist/Config/Date";
8
+ import { TIMEZONE, TIME_FORMAT } from "@licklist/core/dist/Config/Date";
9
9
  import { ProductSetRecurrence } from "@licklist/core/dist/DataMapper/Product/ProductSetRecurrenceDataMapper";
10
- import { TIME_FORMAT } from "@licklist/core/dist/Config/Date";
11
10
  import { DateTime } from "luxon";
12
11
  import RRule, { Frequency } from "rrule";
13
12
  import { WorkHour } from "@licklist/core/dist/DataMapper/Provider/WorkHourDataMapper";
@@ -27,7 +26,6 @@ import {
27
26
  import { ProductSetRecurrenceOverridesControl } from "./ProductSetRecurrenceOverridesControl";
28
27
  import { MAX_QUANTITY_RECURRENCE_DATE_IN_OVERRIDE } from "../product/constants";
29
28
 
30
-
31
29
  export interface DateAndRecurrenceInputValues {
32
30
  menuRecurrences?: Partial<ProductSetRecurrence>[];
33
31
  }
@@ -307,7 +307,7 @@ export function ProductCategoriesControl({
307
307
  title={t("addCategory")}
308
308
  isOverride={isOverrides}
309
309
  onClick={() => {
310
- if (isOverrides) return;
310
+ if (isOverrides) return;
311
311
  setIsSelectCategoryVisible(true);
312
312
  }}
313
313
  />
@@ -26,12 +26,16 @@ import { checkAvailableTimesErrors, getFilteredTemplates } from "../utils";
26
26
  export interface WithIsLoading {
27
27
  isLoading: boolean;
28
28
  }
29
+ export interface WithIdOptional {
30
+ id?: number;
31
+ }
32
+
29
33
  export interface WithId {
30
34
  id: number;
31
35
  }
32
36
  export interface ProductSetFormValues
33
37
  extends FormValues,
34
- WithId,
38
+ WithIdOptional,
35
39
  ProductSetControlValues {
36
40
  steps: Step[];
37
41
  isOverrides?: boolean;
@@ -24,8 +24,10 @@ export const useSortableTreeFunctions = ({
24
24
  const cancelChanges = (index: number) => {
25
25
  if (isOverrides) return;
26
26
  if (!previousValue) {
27
+ // eslint-disable-next-line consistent-return
27
28
  return remove(index);
28
29
  }
30
+ // eslint-disable-next-line consistent-return
29
31
  return setValue(`${fieldName}.${index}` as const, previousValue);
30
32
  };
31
33
 
@@ -7,14 +7,17 @@ import {
7
7
  QUANTITY_TYPE_LIST_DTO,
8
8
  QUANTITY_TYPE_RECHARGING,
9
9
  } from "@licklist/core/dist/DataMapper/Product/ProductCategoryDataMapper";
10
- import { 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,6 +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";
42
+
39
43
  import {
40
44
  Image,
41
45
  IMAGE_TYPE_IMAGE,
@@ -60,6 +64,7 @@ import {
60
64
  ProductQuantityControl,
61
65
  ProductQuantityRechargingControl,
62
66
  } from "./quantity";
67
+ import { PropertyControl } from "../../snippet";
63
68
  import { TipTapEditor } from "../../tiptap-editor";
64
69
  import { IsDeletableEvent } from "../types";
65
70
  import { FixedDurationOptions } from "./fixed-duration-fields";
@@ -99,6 +104,7 @@ export interface ProductControlValues
99
104
  offset: number;
100
105
  serviceTime: number;
101
106
  sort: number | null;
107
+ color?: string;
102
108
  }
103
109
 
104
110
  export interface ProductControlProps<T>
@@ -144,7 +150,7 @@ export function ProductControl<T extends FormValues>({
144
150
  } = useFormContext<T>();
145
151
 
146
152
  const { setLoading } = useContext(ProductSetLoadingContext);
147
- const { t } = useTranslation(["Design", "Validation"]);
153
+ const { t } = useTranslation(["Design", "Validation", "ProductSet"]);
148
154
  const [expanded, setExpanded] = useState(false);
149
155
  const [initialImages, setInitialImages] = useState<Image[] | null>(null);
150
156
  // @TODO: After checking "isUnlimited" checkbox need to reset field totalQuantity
@@ -389,6 +395,14 @@ export function ProductControl<T extends FormValues>({
389
395
  )}
390
396
  </Form.Control.Feedback>
391
397
  </Form.Group>
398
+
399
+ <PropertyControl<T>
400
+ item={`${fieldNamePrefix}.color` as Path<T>}
401
+ label={t("ProductSet:selectColor")}
402
+ isDisabled={isOverrides}
403
+ isRequired={false}
404
+ defaultColors={PRODUCT_DEfAULT_COLORS}
405
+ />
392
406
  </Col>
393
407
  </Row>
394
408
 
@@ -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
  }
@@ -26,6 +26,7 @@ export interface ProductCategoryControlValues extends FormValues {
26
26
  name: string;
27
27
  minSubItems: number | null;
28
28
  maxSubItems: number | null;
29
+ overallQuantity?: number | null;
29
30
  quantityType: QuantityType;
30
31
  type: CategoryType;
31
32
  isTimeRelated: boolean;
@@ -102,6 +103,7 @@ export function ProductCategoryControl({
102
103
  const collectUserInfoId = useId();
103
104
  const hasTicketId = useId();
104
105
  const zoneId = useId();
106
+ const overallCapacityId = useId();
105
107
 
106
108
  const allowDepositsId = useId();
107
109
  const remainderExpireAfterId = useId();
@@ -127,7 +129,7 @@ export function ProductCategoryControl({
127
129
  // eslint-disable-next-line react-hooks/exhaustive-deps
128
130
  }, [maxSubItems, fieldNamePrefix]);
129
131
 
130
- const shouldShowZoneSelect =
132
+ const isZoneCategory =
131
133
  category.type === CATEGORY_TYPE_FIXED_DURATION ||
132
134
  category.type === CATEGORY_TYPE_GAME;
133
135
 
@@ -328,50 +330,110 @@ export function ProductCategoryControl({
328
330
  </Col>
329
331
  </Row>
330
332
 
331
- {shouldShowZoneSelect && (
332
- <Row>
333
- <Col>
334
- <Form.Group controlId={zoneId}>
335
- <Form.Label>{t("Design:zone")}</Form.Label>
336
- <Controller
337
- control={control}
338
- name={`${fieldNamePrefix}.zoneId`}
339
- render={({ field }) => (
340
- <Form.Control
341
- as="select"
342
- disabled={isOverride}
343
- isInvalid={HookFormService.isInvalid<ProductSetFormValues>(
344
- `${fieldNamePrefix}.zoneId`,
333
+ {isZoneCategory && (
334
+ <>
335
+ <Row>
336
+ <Col md={6} sm={6} xs={6}>
337
+ <Form.Group controlId={overallCapacityId}>
338
+ <Form.Label>{t("Design:overallQuantity")}</Form.Label>
339
+ <InputGroup hasValidation>
340
+ <InputGroup.Prepend
341
+ className="arrow-up-btn"
342
+ onClick={() => {
343
+ const currentOverallCapacity = Number(
344
+ getValues(`${fieldNamePrefix}.overallQuantity`) || 0
345
+ );
346
+ setValue(
347
+ `${fieldNamePrefix}.overallQuantity`,
348
+ currentOverallCapacity + 1,
349
+ { shouldValidate: true }
350
+ );
351
+ }}
352
+ >
353
+ <InputGroup.Text className="py-0 px-3">
354
+ <IncrementIcon />
355
+ </InputGroup.Text>
356
+ </InputGroup.Prepend>
357
+ <Controller
358
+ control={control}
359
+ name={`${fieldNamePrefix}.overallQuantity`}
360
+ render={({ field }) => (
361
+ <Form.Control
362
+ min={0}
363
+ step={1}
364
+ type="number"
365
+ disabled={isOverride}
366
+ isInvalid={HookFormService.isInvalid<ProductSetFormValues>(
367
+ `${fieldNamePrefix}.overallQuantity`,
368
+ errors
369
+ )}
370
+ {...field}
371
+ />
372
+ )}
373
+ rules={{
374
+ min: {
375
+ value: 0,
376
+ message: t("Validation:fieldMinNumber", {
377
+ attribute: t("overallQuantity"),
378
+ min: 0,
379
+ }) as string,
380
+ },
381
+ }}
382
+ />
383
+ <Form.Control.Feedback type="invalid">
384
+ {HookFormService.getErrors<ProductSetFormValues>(
385
+ `${fieldNamePrefix}.overallQuantity`,
345
386
  errors
346
387
  )}
347
- {...field}
348
- >
349
- <option value={null}>{t("Design:choose")}</option>
350
- {zones.map((zone) => (
351
- <option key={zone.id} value={zone.id}>
352
- {zone.name}
353
- </option>
354
- ))}
355
- </Form.Control>
356
- )}
357
- rules={{
358
- required: {
359
- value: providerHasBookingManagement,
360
- message: t("Validation:fieldRequired", {
361
- attribute: t("zone"),
362
- }),
363
- },
364
- }}
365
- />
366
- <Form.Control.Feedback type="invalid">
367
- {HookFormService.getErrors<ProductSetFormValues>(
368
- `${fieldNamePrefix}.zoneId`,
369
- errors
370
- )}
371
- </Form.Control.Feedback>
372
- </Form.Group>
373
- </Col>
374
- </Row>
388
+ </Form.Control.Feedback>
389
+ </InputGroup>
390
+ </Form.Group>
391
+ </Col>
392
+ </Row>
393
+ <Row>
394
+ <Col>
395
+ <Form.Group controlId={zoneId}>
396
+ <Form.Label>{t("Design:zone")}</Form.Label>
397
+ <Controller
398
+ control={control}
399
+ name={`${fieldNamePrefix}.zoneId`}
400
+ render={({ field }) => (
401
+ <Form.Control
402
+ as="select"
403
+ disabled={isOverride}
404
+ isInvalid={HookFormService.isInvalid<ProductSetFormValues>(
405
+ `${fieldNamePrefix}.zoneId`,
406
+ errors
407
+ )}
408
+ {...field}
409
+ >
410
+ <option value={null}>{t("Design:choose")}</option>
411
+ {zones.map((zone) => (
412
+ <option key={zone.id} value={zone.id}>
413
+ {zone.name}
414
+ </option>
415
+ ))}
416
+ </Form.Control>
417
+ )}
418
+ rules={{
419
+ required: {
420
+ value: providerHasBookingManagement,
421
+ message: t("Validation:fieldRequired", {
422
+ attribute: t("zone"),
423
+ }),
424
+ },
425
+ }}
426
+ />
427
+ <Form.Control.Feedback type="invalid">
428
+ {HookFormService.getErrors<ProductSetFormValues>(
429
+ `${fieldNamePrefix}.zoneId`,
430
+ errors
431
+ )}
432
+ </Form.Control.Feedback>
433
+ </Form.Group>
434
+ </Col>
435
+ </Row>
436
+ </>
375
437
  )}
376
438
  </Col>
377
439
 
@@ -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[];
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,73 @@ 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[]
121
+ ) => {
122
+ const { t } = useTranslation("Validation");
123
+ // workhours of selected days, all if no days selected
124
+ const selectedWorkHours = byWeekDay.length
125
+ ? byWeekDay.map(({ weekday }) =>
126
+ workHours.find(({ day }) => day === weekday)
127
+ )
128
+ : workHours;
129
+
130
+ /**
131
+ * start time
132
+ */
133
+ const startTimes = selectedWorkHours
134
+ .map((workhour) => DateTime.fromFormat(workhour.start, TIME_FORMAT))
135
+ .sort(dateTimesSortFn("desc"));
136
+
137
+ const latestStartTime = startTimes[0];
138
+
139
+ const startTimeRules = {
140
+ validate: (date: string) => {
141
+ const selectedDate = DateTime.fromFormat(date, TIME_FORMAT);
142
+ if (selectedDate >= latestStartTime) return true;
143
+
144
+ return t("fieldTimeBefore", {
145
+ attribute: t("Design:startTimeSmall"),
146
+ time: latestStartTime.toFormat(TIME_FORMAT),
147
+ });
148
+ },
149
+ };
150
+
151
+ /**
152
+ * end time
153
+ */
154
+ const endTimes = selectedWorkHours
155
+ .map<string>(({ start, end }) => {
156
+ const startDateTime = DateTime.fromFormat(start, TIME_FORMAT);
157
+ const endDateTime = DateTime.fromFormat(end, TIME_FORMAT);
158
+
159
+ if (startDateTime <= endDateTime) return end;
160
+
161
+ // if end is before start, then it means that end is on the next day
162
+ // so count only to the end of current day
163
+ return "23:59";
164
+ })
165
+ .map((workhour) => DateTime.fromFormat(workhour, TIME_FORMAT))
166
+ .sort(dateTimesSortFn("asc"));
167
+
168
+ const earliestEndTime = endTimes[0];
169
+
170
+ const endTimeRules = {
171
+ validate: (date: string) => {
172
+ const selectedDate = DateTime.fromFormat(date, TIME_FORMAT);
173
+ if (selectedDate <= earliestEndTime) return true;
174
+
175
+ return t("fieldTimeAfter", {
176
+ attribute: t("Design:endTimeSmall"),
177
+ time: earliestEndTime.toFormat(TIME_FORMAT),
178
+ });
179
+ },
180
+ };
181
+
182
+ return {
183
+ startTimeRules,
184
+ endTimeRules,
185
+ };
186
+ };
@@ -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
  })}