@licklist/design 0.44.542 → 0.44.544

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 (87) hide show
  1. package/dist/availability-indicator/AvailabilityIndicator.d.ts +5 -4
  2. package/dist/availability-indicator/AvailabilityIndicator.d.ts.map +1 -1
  3. package/dist/availability-indicator/AvailabilityIndicator.js +1 -1
  4. package/dist/calendar/Calendar.d.ts +2 -4
  5. package/dist/calendar/Calendar.d.ts.map +1 -1
  6. package/dist/date-time-button/DateTimeButton.d.ts +4 -5
  7. package/dist/date-time-button/DateTimeButton.d.ts.map +1 -1
  8. package/dist/date-time-button/DateTimeButton.js +1 -1
  9. package/dist/events/edit-event-modal/utils/getDefaultProductSet.d.ts.map +1 -1
  10. package/dist/events/edit-event-modal/utils/getDefaultProductSet.js +1 -1
  11. package/dist/events/event-card/utils.d.ts +27 -0
  12. package/dist/events/event-card/utils.d.ts.map +1 -1
  13. package/dist/events/event-card/utils.js +1 -1
  14. package/dist/events/event-statistic-modal/EventStatisticModal.d.ts +3 -1
  15. package/dist/events/event-statistic-modal/EventStatisticModal.d.ts.map +1 -1
  16. package/dist/events/event-statistic-modal/EventStatisticModal.js +1 -1
  17. package/dist/events/event-statistic-modal/hooks/useTableData.d.ts +2 -1
  18. package/dist/events/event-statistic-modal/hooks/useTableData.d.ts.map +1 -1
  19. package/dist/events/event-statistic-modal/hooks/useTableData.js +1 -1
  20. package/dist/events/event-statistic-modal/utils/index.d.ts +1 -1
  21. package/dist/events/event-statistic-modal/utils/index.d.ts.map +1 -1
  22. package/dist/events/event-statistic-modal/utils/index.js +1 -1
  23. package/dist/iframe/activity-card/ActivityCard.d.ts +1 -3
  24. package/dist/iframe/activity-card/ActivityCard.d.ts.map +1 -1
  25. package/dist/iframe/activity-card/ActivityCard.js +1 -1
  26. package/dist/iframe/order-process/components/CategoryProduct/components/ProductQuantityInput/ProductQuantityInput.d.ts +3 -1
  27. package/dist/iframe/order-process/components/CategoryProduct/components/ProductQuantityInput/ProductQuantityInput.d.ts.map +1 -1
  28. package/dist/iframe/order-process/components/CategoryProduct/components/ProductQuantityInput/ProductQuantityInput.js +1 -1
  29. package/dist/product-set/control/DateAndRecurrenceInput.d.ts +5 -1
  30. package/dist/product-set/control/DateAndRecurrenceInput.d.ts.map +1 -1
  31. package/dist/product-set/control/DateAndRecurrenceInput.js +1 -1
  32. package/dist/product-set/control/ProductSetControl.d.ts +4 -2
  33. package/dist/product-set/control/ProductSetControl.d.ts.map +1 -1
  34. package/dist/product-set/control/ProductSetControl.js +1 -1
  35. package/dist/product-set/control/ProductSetRecurrenceControl.d.ts +2 -1
  36. package/dist/product-set/control/ProductSetRecurrenceControl.d.ts.map +1 -1
  37. package/dist/product-set/control/ProductSetRecurrenceControl.js +1 -1
  38. package/dist/product-set/form/ProductSetForm.d.ts +3 -1
  39. package/dist/product-set/form/ProductSetForm.d.ts.map +1 -1
  40. package/dist/product-set/form/ProductSetForm.js +1 -1
  41. package/dist/product-set/utils/index.d.ts +10 -0
  42. package/dist/product-set/utils/index.d.ts.map +1 -1
  43. package/dist/product-set/utils/index.js +1 -1
  44. package/dist/recurring-date-picker-input/RecurringDatePickerInput.js +1 -1
  45. package/dist/sales/payment-form/SalePaymentForm.js +1 -1
  46. package/dist/styles/activity-card/GridActivitiesCard.scss +0 -8
  47. package/dist/styles/form/CustomCheckbox.scss +1 -0
  48. package/dist/styles/zones/ZoneForm.scss +3 -0
  49. package/dist/zone/form/ZoneForm.d.ts +1 -1
  50. package/dist/zone/form/ZoneForm.d.ts.map +1 -1
  51. package/dist/zone/form/ZoneForm.js +1 -1
  52. package/dist/zone/form/components/AvailableTimesControl.d.ts +2 -0
  53. package/dist/zone/form/components/AvailableTimesControl.d.ts.map +1 -1
  54. package/dist/zone/form/components/AvailableTimesControl.js +1 -1
  55. package/dist/zone/form/components/ZoneControl.d.ts +1 -1
  56. package/dist/zone/form/components/ZoneControl.d.ts.map +1 -1
  57. package/dist/zone/form/components/ZoneControl.js +1 -1
  58. package/dist/zone/form/components/ZoneRecurrencesControl.d.ts +1 -1
  59. package/dist/zone/form/components/ZoneRecurrencesControl.d.ts.map +1 -1
  60. package/dist/zone/form/components/ZoneRecurrencesControl.js +1 -1
  61. package/package.json +1 -1
  62. package/src/availability-indicator/AvailabilityIndicator.tsx +41 -33
  63. package/src/calendar/Calendar.tsx +2 -3
  64. package/src/date-time-button/DateTimeButton.tsx +11 -6
  65. package/src/events/edit-event-modal/component/EditEventForm/EditEventForm.stories.tsx +0 -3
  66. package/src/events/edit-event-modal/utils/getDefaultProductSet.ts +0 -1
  67. package/src/events/event-card/utils.ts +71 -17
  68. package/src/events/event-statistic-modal/EventStatisticModal.tsx +5 -1
  69. package/src/events/event-statistic-modal/hooks/useTableData.tsx +12 -5
  70. package/src/events/event-statistic-modal/utils/index.ts +39 -34
  71. package/src/iframe/activity-card/ActivityCard.stories.tsx +27 -51
  72. package/src/iframe/activity-card/ActivityCard.tsx +2 -13
  73. package/src/iframe/order-process/components/CategoryProduct/components/ProductQuantityInput/ProductQuantityInput.tsx +13 -32
  74. package/src/product-set/control/DateAndRecurrenceInput.tsx +73 -2
  75. package/src/product-set/control/ProductSetControl.stories.tsx +0 -2
  76. package/src/product-set/control/ProductSetControl.tsx +8 -10
  77. package/src/product-set/control/ProductSetRecurrenceControl.tsx +6 -1
  78. package/src/product-set/form/ProductSetForm.stories.tsx +6 -6
  79. package/src/product-set/form/ProductSetForm.tsx +19 -3
  80. package/src/product-set/utils/index.ts +38 -0
  81. package/src/styles/activity-card/GridActivitiesCard.scss +0 -8
  82. package/src/styles/form/CustomCheckbox.scss +1 -0
  83. package/src/styles/zones/ZoneForm.scss +3 -0
  84. package/src/zone/form/ZoneForm.tsx +1 -2
  85. package/src/zone/form/components/AvailableTimesControl.tsx +89 -83
  86. package/src/zone/form/components/ZoneControl.tsx +2 -5
  87. package/src/zone/form/components/ZoneRecurrencesControl.tsx +2 -51
@@ -4,10 +4,14 @@ import { useIntl } from "react-intl";
4
4
  import { useTranslation } from "react-i18next";
5
5
  import * as Config from "@licklist/core/dist/Config";
6
6
  import { EventStatistic } from "@licklist/core/dist/DataMapper/Provider/EventStatisticDataMapper";
7
+ import { Event } from "@licklist/core/dist/DataMapper/Provider/EventDataMapper";
7
8
  import { convertEventStatisticToTableData, TRANSLATION_KEYS } from "../utils";
8
9
  import { StaticTableData } from "../../../table";
9
10
 
10
- export const useTableData = (eventStatistic: EventStatistic | null) => {
11
+ export const useTableData = (
12
+ date: Event["startAt"] | null,
13
+ eventStatistic: EventStatistic | null
14
+ ) => {
11
15
  const { t } = useTranslation("Design");
12
16
  const { formatNumber } = useIntl();
13
17
  const [tableRows, setTableRows] = useState<StaticTableData[]>([]);
@@ -28,14 +32,17 @@ export const useTableData = (eventStatistic: EventStatistic | null) => {
28
32
  return t(key);
29
33
  };
30
34
 
31
- const transformStatisticToTableRows = (statistic: EventStatistic | null) => {
35
+ const transformStatisticToTableRows = (
36
+ date: Event["startAt"],
37
+ statistic: EventStatistic | null
38
+ ) => {
32
39
  if (!statistic) {
33
40
  return [];
34
41
  }
35
42
 
36
43
  const tableDataRows: StaticTableData[] = [];
37
44
 
38
- convertEventStatisticToTableData(statistic).forEach(
45
+ convertEventStatisticToTableData(date, statistic).forEach(
39
46
  ({ name, quantity, total, isBold, isHeader, key }) => {
40
47
  const formattedTotal = !Object.keys(TRANSLATION_KEYS).includes(
41
48
  String(total)
@@ -77,9 +84,9 @@ export const useTableData = (eventStatistic: EventStatistic | null) => {
77
84
  };
78
85
 
79
86
  useEffect(() => {
80
- setTableRows(transformStatisticToTableRows(eventStatistic));
87
+ setTableRows(transformStatisticToTableRows(date, eventStatistic));
81
88
  // eslint-disable-next-line react-hooks/exhaustive-deps
82
- }, [eventStatistic]);
89
+ }, [date, eventStatistic]);
83
90
 
84
91
  return tableRows;
85
92
  };
@@ -1,4 +1,6 @@
1
1
  import { EventStatistic } from "@licklist/core/dist/DataMapper/Provider/EventStatisticDataMapper";
2
+ import { DateTime } from "luxon";
3
+ import { DATE_TIME_FULL_FORMAT } from "@licklist/core/dist/Config";
2
4
 
3
5
  export const TRANSLATION_KEYS = {
4
6
  shortQuantity: "shortQuantity",
@@ -7,6 +9,7 @@ export const TRANSLATION_KEYS = {
7
9
  };
8
10
 
9
11
  export const convertEventStatisticToTableData = (
12
+ date: string,
10
13
  eventStatistic: EventStatistic
11
14
  ) => {
12
15
  let totalAmount = 0;
@@ -25,49 +28,51 @@ export const convertEventStatisticToTableData = (
25
28
  total: string | number;
26
29
  }[] = [];
27
30
 
28
- Object.values(eventStatistic?.productCategorySummary)?.forEach(
29
- (categories) => {
30
- categories?.forEach(
31
- ({ totalPerCategory, productsSummary = [], categoryName, eventId }) => {
32
- let quantity = 0;
31
+ const summaryFormattedDate = DateTime.fromISO(date)
32
+ .toUTC()
33
+ .toFormat(DATE_TIME_FULL_FORMAT);
33
34
 
34
- totalAmount += totalPerCategory || 0;
35
+ Object.values(
36
+ eventStatistic?.productCategorySummary[summaryFormattedDate] ?? {}
37
+ )?.forEach(
38
+ ({ totalPerCategory, productsSummary = [], categoryName, eventId }) => {
39
+ let quantity = 0;
35
40
 
36
- tableDataArray.push({
37
- name: categoryName,
38
- key: `${eventId}.${categoryName}`,
39
- isBold: true,
40
- isHeader: true,
41
- quantity: TRANSLATION_KEYS.shortQuantity,
42
- total: TRANSLATION_KEYS.total,
43
- });
41
+ totalAmount += totalPerCategory || 0;
44
42
 
45
- productsSummary?.forEach(
46
- ({ productsSold, name, totalQuantity, total }) => {
47
- quantity += productsSold;
43
+ tableDataArray.push({
44
+ name: categoryName,
45
+ key: `${eventId}.${categoryName}`,
46
+ isBold: true,
47
+ isHeader: true,
48
+ quantity: TRANSLATION_KEYS.shortQuantity,
49
+ total: TRANSLATION_KEYS.total,
50
+ });
48
51
 
49
- tableDataArray.push({
50
- name,
51
- key: `${eventId}.${categoryName}.${name}`,
52
- quantity: totalQuantity
53
- ? `${productsSold} / ${totalQuantity}`
54
- : String(productsSold),
55
- total: String(total),
56
- });
57
- }
58
- );
52
+ productsSummary?.forEach(
53
+ ({ productsSold, name, totalQuantity, total }) => {
54
+ quantity += productsSold;
59
55
 
60
56
  tableDataArray.push({
61
- name: TRANSLATION_KEYS.totalPerCategory,
62
- key: `${eventId}.${categoryName}.${TRANSLATION_KEYS.totalPerCategory}`,
63
- quantity,
64
- total: totalPerCategory,
65
- isBold: true,
57
+ name,
58
+ key: `${eventId}.${categoryName}.${name}`,
59
+ quantity: totalQuantity
60
+ ? `${productsSold} / ${totalQuantity}`
61
+ : String(productsSold),
62
+ total: String(total),
66
63
  });
67
-
68
- totalQuantity += quantity;
69
64
  }
70
65
  );
66
+
67
+ tableDataArray.push({
68
+ name: TRANSLATION_KEYS.totalPerCategory,
69
+ key: `${eventId}.${categoryName}.${TRANSLATION_KEYS.totalPerCategory}`,
70
+ quantity,
71
+ total: totalPerCategory,
72
+ isBold: true,
73
+ });
74
+
75
+ totalQuantity += quantity;
71
76
  }
72
77
  );
73
78
 
@@ -1,75 +1,51 @@
1
1
  import React from "react";
2
2
  import { Meta, Story } from "@storybook/react";
3
- import { ActivityCard, ActivityCardProps, LAYOUT_LIST } from "./ActivityCard";
3
+ import {
4
+ ActivityCard,
5
+ ActivityCardProps,
6
+ LAYOUT_GRID,
7
+ LAYOUT_LIST,
8
+ } from "./ActivityCard";
4
9
 
5
10
  export default {
6
11
  title: "Iframe/ActivityCard",
7
12
  component: ActivityCard,
8
13
  } as Meta;
9
14
 
10
- export const Default: Story<ActivityCardProps> = (props) => {
11
- return <ActivityCard {...props} />;
12
- };
15
+ export const GridView: Story<ActivityCardProps> = (props) => {
16
+ const [isSelected, setIsSelected] = React.useState(false);
13
17
 
14
- Default.args = {
15
- title: "Clay Pigeons & Axe Thowing",
16
- duration: "60 mins",
17
- price: "from £20",
18
- image: {
19
- hash: "0b37b130e22aa2d3",
20
- id: 195,
21
- imageType: "cover",
22
- imageableId: 25,
23
- imageableType: "zone",
24
- path: "images/original/000/000/000/000/195-0b37b130e22aa2d3.jpeg",
25
- // eslint-disable-next-line max-len
26
- url: "https://cdn.lickli.st/doNktZRze1yuz3Uo2OPrLSvXVtUcdUsF/images/original/000/000/000/000/195-0b37b130e22aa2d3.jpeg",
27
- },
28
- onSelect: () => null,
29
- isSelected: false,
18
+ return (
19
+ <ActivityCard
20
+ {...props}
21
+ isSelected={isSelected}
22
+ onSelect={() => setIsSelected(true)}
23
+ />
24
+ );
30
25
  };
31
26
 
32
- export const Selected: Story<ActivityCardProps> = (props) => {
33
- return <ActivityCard {...props} />;
34
- };
35
-
36
- Selected.args = {
27
+ GridView.args = {
28
+ layout: LAYOUT_GRID,
37
29
  title: "Clay Pigeons & Axe Thowing",
38
30
  duration: "60 mins",
39
31
  price: "from £20",
40
- image: {
41
- hash: "0b37b130e22aa2d3",
42
- id: 195,
43
- imageType: "cover",
44
- imageableId: 25,
45
- imageableType: "zone",
46
- path: "images/original/000/000/000/000/195-0b37b130e22aa2d3.jpeg",
47
- // eslint-disable-next-line max-len
48
- url: "https://cdn.lickli.st/doNktZRze1yuz3Uo2OPrLSvXVtUcdUsF/images/original/000/000/000/000/195-0b37b130e22aa2d3.jpeg",
49
- },
50
- onSelect: () => null,
51
- isSelected: true,
52
32
  };
53
33
 
54
34
  export const ListView: Story<ActivityCardProps> = (props) => {
55
- return <ActivityCard {...props} />;
35
+ const [isSelected, setIsSelected] = React.useState(false);
36
+
37
+ return (
38
+ <ActivityCard
39
+ {...props}
40
+ isSelected={isSelected}
41
+ onSelect={() => setIsSelected(true)}
42
+ />
43
+ );
56
44
  };
57
45
 
58
- Default.args = {
46
+ ListView.args = {
59
47
  layout: LAYOUT_LIST,
60
48
  title: "Clay Pigeons & Axe Thowing",
61
49
  duration: "60 mins",
62
50
  price: "from £20",
63
- image: {
64
- hash: "0b37b130e22aa2d3",
65
- id: 195,
66
- imageType: "cover",
67
- imageableId: 25,
68
- imageableType: "zone",
69
- path: "images/original/000/000/000/000/195-0b37b130e22aa2d3.jpeg",
70
- // eslint-disable-next-line max-len
71
- url: "https://cdn.lickli.st/doNktZRze1yuz3Uo2OPrLSvXVtUcdUsF/images/original/000/000/000/000/195-0b37b130e22aa2d3.jpeg",
72
- },
73
- onSelect: () => null,
74
- isSelected: false,
75
51
  };
@@ -1,6 +1,5 @@
1
1
  import React, { ReactNode } from "react";
2
2
  import clsx from "clsx";
3
- import { Image } from "@licklist/core/dist/DataMapper/Media/ImageDataMapper";
4
3
 
5
4
  export const LAYOUT_GRID = "grid";
6
5
  export const LAYOUT_LIST = "list";
@@ -11,7 +10,6 @@ export type ActivityCardProps = {
11
10
  title: ReactNode;
12
11
  duration: ReactNode;
13
12
  price: ReactNode;
14
- image?: Image | null;
15
13
  onSelect: () => void;
16
14
  isSelected: boolean;
17
15
  layout?: Layout;
@@ -21,7 +19,7 @@ export const ActivityCard = ({
21
19
  title,
22
20
  duration,
23
21
  price,
24
- image,
22
+ // image,
25
23
  onSelect,
26
24
  isSelected,
27
25
  layout = LAYOUT_GRID,
@@ -33,10 +31,7 @@ export const ActivityCard = ({
33
31
  className={clsx("activity-card", isSelected && "active")}
34
32
  onClick={onSelect}
35
33
  >
36
- {image && (
37
- <img className="activity-card-image" alt="" src={image.url} />
38
- )}
39
- <div className={clsx("d-flex", "flex-column", !image && "no-image")}>
34
+ <div className={clsx("d-flex", "flex-column")}>
40
35
  <div className="activity-card-title">{title}</div>
41
36
 
42
37
  {duration && <div>{duration}</div>}
@@ -64,12 +59,6 @@ export const ActivityCard = ({
64
59
 
65
60
  {price && <div>{price}</div>}
66
61
  </div>
67
-
68
- {image && (
69
- <div className="image-container">
70
- <img className="image" src={image.url} alt="" />
71
- </div>
72
- )}
73
62
  </div>
74
63
  <hr className="list-activity-card-hr" />
75
64
  </div>
@@ -3,6 +3,7 @@ import clsx from "clsx";
3
3
  import { Button } from "react-bootstrap";
4
4
  import { useTranslation } from "react-i18next";
5
5
  import { FieldValues, RefCallBack, UseFormClearErrors } from "react-hook-form";
6
+ import { Zone } from "@licklist/core/dist/DataMapper/Provider/ZoneDataMapper";
6
7
  import { NumberInput } from "../NumberInput";
7
8
  import { Product, ProductCategory } from "../../../../../../types";
8
9
 
@@ -11,6 +12,7 @@ interface FormOrderItem {
11
12
  name: string;
12
13
  price: number;
13
14
  productsCategoryId: number;
15
+ zoneId?: Zone["id"];
14
16
  deposit?: number | null;
15
17
  quantity: number;
16
18
  capacity?: number | null;
@@ -30,7 +32,7 @@ interface ProductQuantityInputProps {
30
32
  export const ProductQuantityInput = ({
31
33
  product,
32
34
  category,
33
- onChange,
35
+ onChange: _onChange,
34
36
  clearErrors,
35
37
  refCallback,
36
38
  productInfo,
@@ -39,14 +41,15 @@ export const ProductQuantityInput = ({
39
41
  }: ProductQuantityInputProps) => {
40
42
  const { t } = useTranslation("Design");
41
43
 
42
- const onClick = () => {
43
- onChange({
44
+ const onChange = (quantity: number | null) => {
45
+ _onChange({
44
46
  id: product.id,
45
47
  name: product.name,
46
48
  deposit,
47
49
  price: product.price,
48
50
  productsCategoryId: category.id,
49
- quantity: productInfo?.quantity ? 0 : 1,
51
+ zoneId: category.zone?.id,
52
+ quantity,
50
53
  capacity: product?.capacity,
51
54
  });
52
55
  };
@@ -58,6 +61,7 @@ export const ProductQuantityInput = ({
58
61
  </div>
59
62
  );
60
63
  }
64
+
61
65
  if (product?.maxAmount === 1) {
62
66
  return (
63
67
  <Button
@@ -69,49 +73,26 @@ export const ProductQuantityInput = ({
69
73
  }`,
70
74
  invalid && "error"
71
75
  )}
72
- onClick={onClick}
76
+ onClick={() => onChange(productInfo?.quantity ? 0 : 1)}
73
77
  >
74
78
  {t(`Design:${productInfo?.quantity ? "unselect" : "select"}`)}
75
79
  </Button>
76
80
  );
77
81
  }
82
+
78
83
  return (
79
84
  <NumberInput
80
85
  ref={refCallback}
81
86
  onChange={(val) => {
82
- onChange({
83
- id: product.id,
84
- name: product.name,
85
- deposit,
86
- price: product.price,
87
- productsCategoryId: category.id,
88
- quantity: val || null,
89
- capacity: product?.capacity,
90
- });
87
+ onChange(val || null);
91
88
  clearErrors(`${product.id}` as const);
92
89
  }}
93
90
  onArrowDown={() => {
94
- onChange({
95
- id: product.id,
96
- name: product.name,
97
- deposit,
98
- price: product.price,
99
- productsCategoryId: category.id,
100
- quantity: productInfo?.quantity - 1 || 0,
101
- capacity: product?.capacity,
102
- });
91
+ onChange(productInfo?.quantity - 1 || 0);
103
92
  clearErrors(`${product.id}` as const);
104
93
  }}
105
94
  onArrowUp={() => {
106
- onChange({
107
- id: product.id,
108
- name: product.name,
109
- deposit,
110
- price: product.price,
111
- productsCategoryId: category.id,
112
- quantity: (productInfo?.quantity ?? 0) + 1,
113
- capacity: product?.capacity,
114
- });
95
+ onChange((productInfo?.quantity ?? 0) + 1);
115
96
  clearErrors(`${product.id}` as const);
116
97
  }}
117
98
  min={0}
@@ -5,8 +5,11 @@ 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 { DateTime } from "luxon";
9
+ import { WorkHour } from "@licklist/core/dist/DataMapper/Provider/WorkHourDataMapper";
8
10
  import { ProductSetRecurrence } from "@licklist/core/dist/DataMapper/Product/ProductSetRecurrenceDataMapper";
9
11
  import { DndContext } from "@dnd-kit/core";
12
+ import { TIME_FORMAT } from "@licklist/core/dist/Config/Date";
10
13
  import {
11
14
  SortableContext,
12
15
  verticalListSortingStrategy,
@@ -20,6 +23,11 @@ import {
20
23
  RecurringDatePickerInputValues,
21
24
  } from "../../recurring-date-picker-input/RecurringDatePickerInput";
22
25
  import { ProductSetRecurrenceControl } from "./ProductSetRecurrenceControl";
26
+ import {
27
+ AvailableTimesControl,
28
+ AvailableTimesControlRef,
29
+ } from "../../zone/form/components/AvailableTimesControl";
30
+
23
31
  // eslint-disable-next-line max-len
24
32
 
25
33
  export interface DateAndRecurrenceInputValues {
@@ -28,10 +36,16 @@ export interface DateAndRecurrenceInputValues {
28
36
 
29
37
  interface DateAndRecurrenceInputProps {
30
38
  isEventEditProductSet?: boolean;
39
+ workHours?: WorkHour[];
40
+ providerHasBookingManagement: boolean;
41
+ isLoading?: boolean;
31
42
  }
32
43
 
33
44
  export const DateAndRecurrenceInput = ({
34
45
  isEventEditProductSet,
46
+ providerHasBookingManagement,
47
+ workHours,
48
+ isLoading,
35
49
  }: DateAndRecurrenceInputProps) => {
36
50
  const {
37
51
  control,
@@ -42,6 +56,9 @@ export const DateAndRecurrenceInput = ({
42
56
  clearErrors,
43
57
  } = useFormContext<DateAndRecurrenceInputValues>();
44
58
 
59
+ const [availableTimes, setAvailableTimes] = useState<string[]>([]);
60
+ const availableTimesFormRef = useRef<AvailableTimesControlRef>();
61
+
45
62
  const { fields, append, update, move } = useFieldArray({
46
63
  name: "menuRecurrences",
47
64
  control,
@@ -78,13 +95,44 @@ export const DateAndRecurrenceInput = ({
78
95
  const { t } = useTranslation("Design");
79
96
 
80
97
  // in this method we should fulfill the form with a proper data
81
- const handleRecurringDateChange = (next: RecurringDatePickerInputValues) => {
98
+ const handleRecurringDateChange = async (
99
+ next: RecurringDatePickerInputValues
100
+ ) => {
101
+ const isAvailableTimesFormValid =
102
+ await availableTimesFormRef.current?.trigger();
103
+
104
+ if (next?.startTime && next?.endTime && isAvailableTimesFormValid) {
105
+ const startTime = DateTime.fromISO(next.startTime);
106
+ const endTime = DateTime.fromISO(next.endTime);
107
+ const { availableTimes } = availableTimesFormRef.current.getValues();
108
+ const validAvalilableTimes = availableTimes.every((time) => {
109
+ const currentAvailableTime = DateTime.fromFormat(time, TIME_FORMAT);
110
+
111
+ return (
112
+ currentAvailableTime.diff(startTime, "minutes").minutes >= 0 &&
113
+ currentAvailableTime.diff(endTime, "minutes").minutes <= 0
114
+ );
115
+ });
116
+ if (!validAvalilableTimes) {
117
+ availableTimesFormRef.current.setError("availableTimes", {
118
+ message: t("Validation:fieldTimeBetween", {
119
+ attribute: t("Design:startTimesSmall"),
120
+ min: startTime.toFormat(TIME_FORMAT),
121
+ max: endTime.toFormat(TIME_FORMAT),
122
+ }),
123
+ });
124
+
125
+ return;
126
+ }
127
+ }
128
+
82
129
  const values = {
83
130
  rrule: next.rrule,
84
131
  startDate: next.startDate,
85
132
  endDate: next.endDate,
86
133
  startTime: next.startTime,
87
134
  endTime: next.endTime,
135
+ ...availableTimesFormRef?.current?.getValues(),
88
136
  } as Partial<ProductSetRecurrence>;
89
137
 
90
138
  if (editState.values?.id) {
@@ -107,6 +155,7 @@ export const DateAndRecurrenceInput = ({
107
155
  // Hotfix for an issue with Popover close & open actions
108
156
  setTimeout(() => {
109
157
  setEditState({ index, values: next });
158
+ setAvailableTimes(next.availableTimes || []);
110
159
  setIsDatePopoverVisible(() => true);
111
160
  }, 100);
112
161
  };
@@ -176,7 +225,25 @@ export const DateAndRecurrenceInput = ({
176
225
  defaultValues={editState.values}
177
226
  onChange={handleRecurringDateChange}
178
227
  onDelete={handleDelete}
179
- />
228
+ >
229
+ {providerHasBookingManagement && (
230
+ <AvailableTimesControl
231
+ workHours={workHours}
232
+ isLoading={isLoading}
233
+ defaultValues={availableTimes}
234
+ ref={availableTimesFormRef}
235
+ errorMessage={
236
+ errors?.menuRecurrences?.[`${editState?.index}`]
237
+ ?.availableTimes?.message
238
+ }
239
+ clearErrorMessage={() =>
240
+ clearErrors(
241
+ `menuRecurrences.${editState?.index}.availableTimes`
242
+ )
243
+ }
244
+ />
245
+ )}
246
+ </RecurringDatePickerInput>
180
247
  </Popover.Content>
181
248
  </Popover>
182
249
  }
@@ -201,6 +268,10 @@ export const DateAndRecurrenceInput = ({
201
268
  key={menuRecurrence._id}
202
269
  menuRecurrence={menuRecurrence}
203
270
  onEdit={() => handleOnEdit(menuRecurrence, index)}
271
+ errorMessage={
272
+ errors?.menuRecurrences?.[`${index}`]?.availableTimes
273
+ ?.message
274
+ }
204
275
  />
205
276
  ))}
206
277
  </SortableContext>
@@ -67,7 +67,6 @@ Empty.args = {
67
67
  type: "sale",
68
68
  termsAndConditions: "",
69
69
  operationalCost: OPERATIONAL_COST_CUSTOMER,
70
- isDefault: false,
71
70
  menuRecurrence: {
72
71
  id: 38,
73
72
  menuId: 257,
@@ -87,7 +86,6 @@ Default.args = {
87
86
  type: "sale",
88
87
  termsAndConditions: "",
89
88
  operationalCost: OPERATIONAL_COST_CUSTOMER,
90
- isDefault: true,
91
89
  menuRecurrence: {
92
90
  id: 38,
93
91
  menuId: 257,
@@ -21,6 +21,7 @@ import { EmailTemplate } from "@licklist/core/dist/DataMapper/Notification/Email
21
21
  import { SmsTemplate } from "@licklist/core/dist/DataMapper/Notification/SmsTemplateDataMapper";
22
22
  import HookFormService from "@licklist/plugins/dist/services/Form/HookFormService";
23
23
  import { ruleForUrlWithProtocol } from "@licklist/plugins/dist/validation/Rules/urlRule";
24
+ import { WorkHour } from "@licklist/core/dist/DataMapper/Provider/WorkHourDataMapper";
24
25
  import { WarningMessage } from "../../static";
25
26
  import { SelectItem } from "../../types/generic/SelectItem";
26
27
  import {
@@ -56,7 +57,6 @@ export interface ProductSetControlValues extends DateAndRecurrenceInputValues {
56
57
  type: ProductSetType;
57
58
  termsAndConditions: string;
58
59
  thankYouPageUrl: string;
59
- isDefault: boolean;
60
60
  operationalCost: OperationalCostType;
61
61
  productGroups?: SelectItem[];
62
62
  relyOnPeopleType?: RelyOnPeopleType | null;
@@ -84,6 +84,8 @@ export interface ProductSetControlProps {
84
84
  fieldSets?: FieldSet[];
85
85
  showEmailTemplate?: boolean;
86
86
  showSmsTemplate?: boolean;
87
+ workHours?: WorkHour[];
88
+ providerHasBookingManagement?: boolean;
87
89
  }
88
90
 
89
91
  export function ProductSetControl({
@@ -97,6 +99,8 @@ export function ProductSetControl({
97
99
  isCreateAction,
98
100
  showEmailTemplate,
99
101
  showSmsTemplate,
102
+ workHours,
103
+ providerHasBookingManagement = false,
100
104
  }: ProductSetControlProps) {
101
105
  const { t } = useTranslation(["Design", "Validation", "Notification"]);
102
106
  const {
@@ -158,6 +162,9 @@ export function ProductSetControl({
158
162
  {isCreateAction && (
159
163
  <DateAndRecurrenceInput
160
164
  isEventEditProductSet={isEventEditProductSet}
165
+ workHours={workHours}
166
+ isLoading={isLoading}
167
+ providerHasBookingManagement={providerHasBookingManagement}
161
168
  />
162
169
  )}
163
170
 
@@ -189,15 +196,6 @@ export function ProductSetControl({
189
196
  </Form.Group>
190
197
  )}
191
198
  /> */}
192
- {/* <Form.Check
193
- {...register("isDefault")}
194
- id="isDefaultId"
195
- name="isDefault"
196
- label={t("Design:setAsDraft")}
197
- custom
198
- className="is-default-checkbox"
199
- disabled={isLoading}
200
- /> */}
201
199
 
202
200
  <Form.Group>
203
201
  <Form.Label className="mb-0">
@@ -11,11 +11,13 @@ import { Icon } from "../../static";
11
11
  export interface ProductSetRecurrenceControlProps {
12
12
  menuRecurrence?: { _id: string } & Partial<ProductSetRecurrence>;
13
13
  onEdit?: (onEdit: Partial<ProductSetRecurrence>) => void;
14
+ errorMessage?: string;
14
15
  }
15
16
 
16
17
  export const ProductSetRecurrenceControl = ({
17
18
  menuRecurrence,
18
19
  onEdit,
20
+ errorMessage,
19
21
  }: ProductSetRecurrenceControlProps) => {
20
22
  const { formatDate } = useIntl();
21
23
  const { t } = useTranslation("Design");
@@ -30,7 +32,7 @@ export const ProductSetRecurrenceControl = ({
30
32
 
31
33
  return (
32
34
  <div
33
- className="sortable-tree-root"
35
+ className="sortable-tree-root flex-column"
34
36
  style={{
35
37
  transform: CSS.Translate.toString(transform),
36
38
  transition,
@@ -84,6 +86,9 @@ export const ProductSetRecurrenceControl = ({
84
86
  {getHumanReadableDate(menuRecurrence)}
85
87
  </span>
86
88
  </div>
89
+ <div className={`manual-form-error ${!errorMessage && "d-none"}`}>
90
+ {errorMessage}
91
+ </div>
87
92
  </div>
88
93
  );
89
94
  };