@licklist/design 0.71.18-dev.1 → 0.71.18-dev.10

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 (125) hide show
  1. package/dist/events/edit-event-modal/component/SelectEventProductSet/component/EditEventProductSet.js +1 -0
  2. package/dist/events/event-statistic-modal/utils/index.js +3 -3
  3. package/dist/iframe/ProductWithModifierModal/ModifierSetModal/ProductWithModifierSetForm.d.ts +18 -0
  4. package/dist/iframe/ProductWithModifierModal/ModifierSetModal/ProductWithModifierSetForm.d.ts.map +1 -0
  5. package/dist/iframe/ProductWithModifierModal/ModifierSetModal/ProductWithModifierSetForm.js +295 -0
  6. package/dist/iframe/ProductWithModifierModal/ModifierSetModal/ProductWithModifierSetModal.d.ts +15 -0
  7. package/dist/iframe/ProductWithModifierModal/ModifierSetModal/ProductWithModifierSetModal.d.ts.map +1 -0
  8. package/dist/iframe/ProductWithModifierModal/ModifierSetModal/ProductWithModifierSetModal.js +89 -0
  9. package/dist/iframe/ProductWithModifierModal/ModifierSetModal/controll/ModifierSetControll.d.ts +14 -0
  10. package/dist/iframe/ProductWithModifierModal/ModifierSetModal/controll/ModifierSetControll.d.ts.map +1 -0
  11. package/dist/iframe/ProductWithModifierModal/ModifierSetModal/controll/ModifierSetControll.js +404 -0
  12. package/dist/iframe/ProductWithModifierModal/ModifierSetModal/controll/ProductControll.d.ts +10 -0
  13. package/dist/iframe/ProductWithModifierModal/ModifierSetModal/controll/ProductControll.d.ts.map +1 -0
  14. package/dist/iframe/ProductWithModifierModal/ModifierSetModal/controll/ProductControll.js +87 -0
  15. package/dist/iframe/ProductWithModifierModal/ModifierSetModal/index.d.ts +2 -0
  16. package/dist/iframe/ProductWithModifierModal/ModifierSetModal/index.d.ts.map +1 -0
  17. package/dist/iframe/ProductWithModifierModal/index.d.ts +2 -0
  18. package/dist/iframe/ProductWithModifierModal/index.d.ts.map +1 -0
  19. package/dist/iframe/ProductWithModifierModal/utils.d.ts +5 -0
  20. package/dist/iframe/ProductWithModifierModal/utils.d.ts.map +1 -0
  21. package/dist/iframe/ProductWithModifierModal/utils.js +21 -0
  22. package/dist/iframe/activity-card/ActivityCard.d.ts +1 -2
  23. package/dist/iframe/activity-card/ActivityCard.d.ts.map +1 -1
  24. package/dist/iframe/activity-card/ActivityCard.js +1 -7
  25. package/dist/iframe/event/ticket-description/TicketDescription.d.ts +2 -1
  26. package/dist/iframe/event/ticket-description/TicketDescription.d.ts.map +1 -1
  27. package/dist/iframe/event/ticket-description/TicketDescription.js +4 -3
  28. package/dist/iframe/order-process/components/BookingSummary/components/ProductSummary/ProductSummary.d.ts.map +1 -1
  29. package/dist/iframe/order-process/components/BookingSummary/components/ProductSummary/ProductSummary.js +15 -2
  30. package/dist/iframe/order-process/components/BookingSummary/utils/index.d.ts +4 -0
  31. package/dist/iframe/order-process/components/BookingSummary/utils/index.d.ts.map +1 -1
  32. package/dist/iframe/order-process/components/BookingSummary/utils/index.js +29 -2
  33. package/dist/iframe/order-process/components/CategoryProduct/CategoryProduct.d.ts.map +1 -1
  34. package/dist/iframe/order-process/components/CategoryProduct/CategoryProduct.js +106 -2
  35. package/dist/iframe/order-process/components/CategoryProduct/components/ProductQuantityInput/ProductQuantityInput.d.ts +3 -1
  36. package/dist/iframe/order-process/components/CategoryProduct/components/ProductQuantityInput/ProductQuantityInput.d.ts.map +1 -1
  37. package/dist/iframe/order-process/components/CategoryProduct/components/ProductQuantityInput/ProductQuantityInput.js +95 -1
  38. package/dist/iframe/order-process/components/CategoryProduct/components/ProductWithModifier/ProductWithModifier.d.ts +23 -0
  39. package/dist/iframe/order-process/components/CategoryProduct/components/ProductWithModifier/ProductWithModifier.d.ts.map +1 -0
  40. package/dist/iframe/order-process/components/CategoryProduct/components/ProductWithModifier/ProductWithModifier.js +62 -0
  41. package/dist/iframe/order-process/components/CategoryProduct/constants.d.ts +2 -0
  42. package/dist/iframe/order-process/components/CategoryProduct/constants.d.ts.map +1 -0
  43. package/dist/iframe/order-process/components/CategoryProduct/constants.js +4 -0
  44. package/dist/iframe/order-process/components/utils/useOnWindowUnmount.d.ts +6 -0
  45. package/dist/iframe/order-process/components/utils/useOnWindowUnmount.d.ts.map +1 -0
  46. package/dist/iframe/order-process/components/utils/useOnWindowUnmount.js +18 -0
  47. package/dist/iframe/payment/order-items-table/hooks/useTableData.d.ts.map +1 -1
  48. package/dist/iframe/payment/order-items-table/hooks/useTableData.js +83 -10
  49. package/dist/iframe/payment/order-items-table/utils/index.d.ts.map +1 -1
  50. package/dist/iframe/payment/order-items-table/utils/index.js +15 -0
  51. package/dist/iframe/payment/order-items-table/utils/paymentSummary.js +2 -2
  52. package/dist/index.js +1 -1
  53. package/dist/product-set/form/ProductSetForm.d.ts +3 -1
  54. package/dist/product-set/form/ProductSetForm.d.ts.map +1 -1
  55. package/dist/product-set/form/ProductSetForm.js +6 -4
  56. package/dist/product-set/form/ProductsControl.d.ts.map +1 -1
  57. package/dist/product-set/form/ProductsControl.js +24 -5
  58. package/dist/product-set/form/context.d.ts +3 -1
  59. package/dist/product-set/form/context.d.ts.map +1 -1
  60. package/dist/product-set/form/context.js +2 -1
  61. package/dist/product-set/product/ProductControl.d.ts +8 -0
  62. package/dist/product-set/product/ProductControl.d.ts.map +1 -1
  63. package/dist/product-set/product/ProductControl.js +25 -1
  64. package/dist/product-set/utils/index.d.ts +88 -0
  65. package/dist/product-set/utils/index.d.ts.map +1 -1
  66. package/dist/product-set/utils/index.js +19 -1
  67. package/dist/report/ReportRunnerModal/ReportRunnerModal.d.ts +1 -1
  68. package/dist/report/ReportRunnerModal/ReportRunnerModal.d.ts.map +1 -1
  69. package/dist/sales/coupon/utils/index.d.ts +2 -1
  70. package/dist/sales/coupon/utils/index.d.ts.map +1 -1
  71. package/dist/sales/modals/refund-modal/RefundModal.d.ts +6 -2
  72. package/dist/sales/modals/refund-modal/RefundModal.d.ts.map +1 -1
  73. package/dist/sales/modals/refund-modal/RefundModal.js +8 -4
  74. package/dist/sales/modals/refund-modal/index.d.ts +2 -2
  75. package/dist/sales/modals/refund-modal/index.d.ts.map +1 -1
  76. package/dist/styles/date-time-button/DateTimeButton.scss +8 -1
  77. package/dist/styles/events/EditEventModal.scss +2 -0
  78. package/dist/styles/iframe-page/Page.scss +16 -0
  79. package/dist/styles/iframe-page/PageBody.scss +4 -0
  80. package/dist/styles/modals/Modals.scss +16 -0
  81. package/dist/styles/product-set/EditProductSetElement.scss +1 -0
  82. package/dist/styles/product-set/ProductSetForm.scss +11 -0
  83. package/dist/styles/sales/ManualBooking.scss +6 -0
  84. package/dist/styles/themes/bookedit/index.scss +19 -0
  85. package/package.json +6 -6
  86. package/src/events/event-statistic-modal/utils/index.ts +4 -4
  87. package/src/iframe/ProductWithModifierModal/ModifierSetModal/ProductWithModifierSetForm.tsx +212 -0
  88. package/src/iframe/ProductWithModifierModal/ModifierSetModal/ProductWithModifierSetModal.tsx +75 -0
  89. package/src/iframe/ProductWithModifierModal/ModifierSetModal/controll/ModifierSetControll.tsx +393 -0
  90. package/src/iframe/ProductWithModifierModal/ModifierSetModal/controll/ProductControll.tsx +98 -0
  91. package/src/iframe/ProductWithModifierModal/ModifierSetModal/index.ts +1 -0
  92. package/src/iframe/ProductWithModifierModal/index.ts +1 -0
  93. package/src/iframe/ProductWithModifierModal/utils.ts +29 -0
  94. package/src/iframe/activity-card/ActivityCard.stories.tsx +0 -2
  95. package/src/iframe/activity-card/ActivityCard.tsx +0 -4
  96. package/src/iframe/event/ticket-description/TicketDescription.tsx +5 -3
  97. package/src/iframe/order-process/components/BookingSummary/components/ProductSummary/ProductSummary.tsx +21 -1
  98. package/src/iframe/order-process/components/BookingSummary/utils/index.ts +42 -1
  99. package/src/iframe/order-process/components/CategoryProduct/CategoryProduct.tsx +155 -75
  100. package/src/iframe/order-process/components/CategoryProduct/components/ProductQuantityInput/ProductQuantityInput.tsx +58 -1
  101. package/src/iframe/order-process/components/CategoryProduct/components/ProductWithModifier/ProductWithModifier.tsx +86 -0
  102. package/src/iframe/order-process/components/CategoryProduct/constants.ts +1 -0
  103. package/src/iframe/order-process/components/utils/useOnWindowUnmount.ts +25 -0
  104. package/src/iframe/payment/order-items-table/hooks/useTableData.tsx +84 -14
  105. package/src/iframe/payment/order-items-table/utils/index.ts +23 -0
  106. package/src/iframe/payment/order-items-table/utils/paymentSummary.tsx +2 -2
  107. package/src/product-set/form/ProductSetForm.tsx +11 -3
  108. package/src/product-set/form/ProductsControl.tsx +33 -15
  109. package/src/product-set/form/context.tsx +5 -0
  110. package/src/product-set/product/ProductControl.tsx +37 -1
  111. package/src/product-set/utils/index.ts +19 -0
  112. package/src/report/ReportRunnerModal/ReportRunnerModal.tsx +2 -2
  113. package/src/sales/coupon/utils/index.ts +5 -3
  114. package/src/sales/modals/refund-modal/RefundModal.tsx +15 -6
  115. package/src/sales/modals/refund-modal/index.ts +7 -2
  116. package/src/styles/date-time-button/DateTimeButton.scss +8 -1
  117. package/src/styles/events/EditEventModal.scss +2 -0
  118. package/src/styles/iframe-page/Page.scss +16 -0
  119. package/src/styles/iframe-page/PageBody.scss +4 -0
  120. package/src/styles/modals/Modals.scss +16 -0
  121. package/src/styles/product-set/EditProductSetElement.scss +1 -0
  122. package/src/styles/product-set/ProductSetForm.scss +11 -0
  123. package/src/styles/sales/ManualBooking.scss +6 -0
  124. package/src/styles/themes/bookedit/index.scss +19 -0
  125. package/yarn.lock +334 -333
@@ -0,0 +1,393 @@
1
+ import { Col, Form } from 'react-bootstrap'
2
+ import { useTranslation } from 'react-i18next'
3
+ import { OrderModifier } from '@licklist/core/dist/DataMapper/Order/OrderModifierDataMapper'
4
+ import { Modifier } from '@licklist/core/dist/DataMapper/Product/ModifierDataMapper'
5
+ import { ModifierSet } from '@licklist/core/dist/DataMapper/Product/ModifierSetDataMapper'
6
+ import { ChangeEvent, useEffect, useMemo } from 'react'
7
+ import { useId } from '@mantine/hooks'
8
+ import { Controller, useFormContext } from 'react-hook-form'
9
+ import { xor } from 'lodash'
10
+ import clsx from 'clsx'
11
+ import { Currency } from '@licklist/core/dist/Config'
12
+ import { useIntl } from 'react-intl'
13
+ import { MAX_PRODUCT_NUMBER } from 'src/iframe/order-process/components/CategoryProduct/constants'
14
+ import { NumberInputHorizontal } from 'src/sales'
15
+ import { selectModifierType } from '../../utils'
16
+
17
+ interface ModifiersSetControllProps {
18
+ modifiers?: Modifier[]
19
+ modifierSet: ModifierSet
20
+ isLoading?: boolean
21
+ isEditMode?: boolean
22
+ productId: number
23
+ orderProductModifierSets?: OrderModifier[]
24
+ }
25
+
26
+ export const ModifiersSetControl = ({
27
+ modifierSet,
28
+ modifiers,
29
+ productId,
30
+ isLoading = false,
31
+ isEditMode = false,
32
+ orderProductModifierSets,
33
+ }: ModifiersSetControllProps) => {
34
+ const { control, watch, setValue, trigger } = useFormContext()
35
+ const { t } = useTranslation('App')
36
+
37
+ const orderModifiersSets = watch(`${productId}.orderProductModifiers`)
38
+
39
+ const { formatNumber } = useIntl()
40
+ const formatToCurrency = (value: number) =>
41
+ formatNumber(value, { style: 'currency', currency: Currency.GBP })
42
+
43
+ const currentOrderModifiersSets = useMemo(
44
+ () =>
45
+ orderProductModifierSets?.filter(
46
+ (modifier) => modifier.modifierSetId === modifierSet.id,
47
+ ) || [],
48
+ [orderProductModifierSets, modifierSet.id],
49
+ )
50
+
51
+ const onChangeModifiers = (
52
+ e: ChangeEvent<HTMLInputElement>,
53
+ type: selectModifierType,
54
+ quantity?: number,
55
+ ) => {
56
+ if (!modifiers) return
57
+
58
+ const selectedModifier = modifiers?.find(
59
+ (item) => item.id === Number(e.target.defaultValue || e.target.id),
60
+ )
61
+ const checkSelectedModifier =
62
+ orderModifiersSets?.find(
63
+ (modifier) => modifier?.modifierId === selectedModifier?.id,
64
+ )?.quantity === 1
65
+
66
+ if (selectedModifier && type === 'radio') {
67
+ modifiers.forEach((modifier) => {
68
+ const isSelected = modifier.id === selectedModifier.id
69
+ const orderModifiers: OrderModifier = {
70
+ modifierId: modifier.id,
71
+ price: modifier.price,
72
+ productId,
73
+ name: modifier.name,
74
+ quantity: isSelected ? 1 : 0,
75
+ modifierSetId: modifierSet.id,
76
+ }
77
+
78
+ setValue(
79
+ `${productId}.orderProductModifiers.${modifierSet.id}.${orderModifiers.modifierId}`,
80
+ orderModifiers,
81
+ )
82
+ })
83
+ }
84
+
85
+ if (selectedModifier && type === 'checkbox') {
86
+ const orderModifiers: OrderModifier = {
87
+ modifierId: selectedModifier.id,
88
+ price: selectedModifier.price,
89
+ productId,
90
+ name: selectedModifier.name,
91
+ quantity: checkSelectedModifier ? 0 : 1,
92
+ modifierSetId: modifierSet.id,
93
+ }
94
+ setValue(
95
+ `${productId}.orderProductModifiers.${modifierSet.id}.${selectedModifier.id}`,
96
+ orderModifiers,
97
+ )
98
+ }
99
+
100
+ if (selectedModifier && type === 'selector') {
101
+ const orderModifiers: OrderModifier = {
102
+ modifierId: selectedModifier.id,
103
+ price: selectedModifier.price,
104
+ productId,
105
+ quantity,
106
+ name: selectedModifier.name,
107
+ modifierSetId: modifierSet.id,
108
+ }
109
+ setValue(
110
+ `${productId}.orderProductModifiers.${modifierSet.id}.${selectedModifier.id}`,
111
+ orderModifiers,
112
+ )
113
+ }
114
+
115
+ trigger(`${productId}.orderProductModifiers`)
116
+ }
117
+
118
+ useEffect(() => {
119
+ if (!orderProductModifierSets?.length) return
120
+ orderProductModifierSets.forEach((orderModifier) =>
121
+ setValue(
122
+ `${productId}.orderProductModifiers.${orderModifier.modifierSetId}.${orderModifier.modifierId}`,
123
+ orderModifier,
124
+ ),
125
+ )
126
+ }, [isEditMode])
127
+
128
+ const radioButtonDefaultModifier = currentOrderModifiersSets.find((modifier) =>
129
+ modifierSet.modifiers.some((rl) => rl.id === modifier.modifierId)
130
+ )?.modifierId.toString();
131
+
132
+ return (
133
+ <>
134
+ {modifierSet?.maxItems === 1 &&
135
+ modifiers.every((modifier) => modifier.maxItems === 1) ? (
136
+ <>
137
+ <Controller
138
+ name={`${productId}.modifier`}
139
+ control={control}
140
+ rules={{
141
+ required: {
142
+ value: !!modifierSet.minItems,
143
+ message: t('Validation:fieldRequired') as string,
144
+ },
145
+ }}
146
+ render={({ field, fieldState }) => {
147
+ const onChange = (e: ChangeEvent<HTMLInputElement>) => {
148
+ onChangeModifiers(e, 'radio')
149
+ field.onChange(e.target.id)
150
+ }
151
+
152
+ return (
153
+ <>
154
+ {modifiers.map((modifier) => {
155
+ const selectedOrderModifierId = currentOrderModifiersSets
156
+ ?.find(
157
+ (orderModifier) =>
158
+ orderModifier.modifierId === modifier.id,
159
+ )
160
+ ?.modifierId?.toString()
161
+
162
+ return (
163
+ <Col key={modifier.id}>
164
+ <div className='modifier-container d-flex flex-column p-2'>
165
+ <Form.Check
166
+ className='custom-radio p-2'
167
+ inline
168
+ id={modifier.id.toString()}
169
+ defaultChecked={!!selectedOrderModifierId}
170
+ defaultValue={selectedOrderModifierId || modifier.id.toString()}
171
+ checked={field.value === modifier.id.toString()}
172
+ onChange={onChange}
173
+ type='radio'
174
+ label={modifier.name}
175
+ name={modifier.name}
176
+ />
177
+ <div className='mt-3 w-100 pl-2'>
178
+ <p>{modifier.description}</p>
179
+ <div className='modifier-price'>
180
+ + {formatToCurrency(modifier.price)}
181
+ </div>
182
+ </div>
183
+ </div>
184
+ </Col>
185
+ )
186
+ })}
187
+ {fieldState.error && (
188
+ <div className='invalid-feedback d-block'>
189
+ {fieldState.error.message}
190
+ </div>
191
+ )}
192
+ </>
193
+ )
194
+ }}
195
+ defaultValue={radioButtonDefaultModifier}
196
+ />
197
+ </>
198
+ ) : (
199
+ <>
200
+ {modifiers?.map((modifier, index) => {
201
+ const selectedOrderModifier = currentOrderModifiersSets?.find(
202
+ (orderModifier) => orderModifier.modifierId === modifier.id,
203
+ )?.quantity
204
+
205
+ return (
206
+ <>
207
+ {modifier.maxItems === 1 ? (
208
+ <>
209
+ <Controller
210
+ name={`${productId}.${modifierSet.id}.modifiers[${index}]`}
211
+ control={control}
212
+ rules={{
213
+ required: {
214
+ value: !!modifier.minItems,
215
+ message: t('Validation:fieldRequired') as string,
216
+ },
217
+ validate: (value) => {
218
+ const { maxItems, minItems } = modifier
219
+ if (value?.length > maxItems) {
220
+ return t('Validation:quantityMaxNumberModifier', {
221
+ max: maxItems,
222
+ }) as string
223
+ }
224
+
225
+ if (value?.length < minItems) {
226
+ return t('Validation:quantityMinNumberModifier', {
227
+ min: minItems,
228
+ }) as string
229
+ }
230
+
231
+ return true
232
+ },
233
+ }}
234
+ render={({ field, fieldState: { error } }) => {
235
+ const onChange = (e: ChangeEvent<HTMLInputElement>) => {
236
+ onChangeModifiers(e, 'checkbox')
237
+ field.onChange(
238
+ xor(field.value, [Number(e.target.value)]),
239
+ )
240
+ }
241
+
242
+ return (
243
+ <Col
244
+ className='modifier-container pl-4'
245
+ key={modifier.id.toString()}
246
+ >
247
+ <div className='d-flex justify-content-between pl-2 align-items-center'>
248
+ <Checkbox
249
+ value={modifier.id}
250
+ onChange={onChange}
251
+ label={modifier.name}
252
+ defaultChecked={!!selectedOrderModifier}
253
+ />
254
+ </div>
255
+ <div className='mt-3 w-100 pl-2'>
256
+ <p>{modifier.description}</p>
257
+ <div className='modifier-price'>
258
+ + {formatToCurrency(modifier.price)}
259
+ </div>
260
+ </div>
261
+ {error?.message && (
262
+ <div className='invalid-feedback d-flex'>
263
+ {error?.message}
264
+ </div>
265
+ )}
266
+ </Col>
267
+ )
268
+ }}
269
+ />
270
+ </>
271
+ ) : (
272
+ <>
273
+ <div className='modifier-header m-0'>
274
+ <div className='title'>{modifier.name}</div>
275
+ </div>
276
+ <Controller
277
+ control={control}
278
+ name={`${productId}.${modifierSet.id}.modifiers[${index}].quantity`}
279
+ rules={{
280
+ required: {
281
+ value: !!modifier.minItems,
282
+ message: t('Validation:fieldRequired') as string,
283
+ },
284
+ validate: (value) => {
285
+ const { maxItems, minItems } = modifier
286
+ if (value > maxItems) {
287
+ return t('Validation:quantityMaxNumberModifier', {
288
+ max: maxItems,
289
+ }) as string
290
+ }
291
+
292
+ if (value < minItems) {
293
+ return t('Validation:quantityMinNumberModifier', {
294
+ min: minItems,
295
+ }) as string
296
+ }
297
+
298
+ return true
299
+ },
300
+ }}
301
+ render={({
302
+ field: { onChange, value, ref },
303
+ fieldState: { invalid, error },
304
+ }) => {
305
+ const onChangeProductQuantity = (val: number) => {
306
+ const quantity = Math.min(
307
+ MAX_PRODUCT_NUMBER,
308
+ Math.max(0, Math.ceil(val)),
309
+ )
310
+ onChange(quantity)
311
+ trigger(
312
+ `${productId}.${modifierSet.id}.modifiers[${index}].quantity`,
313
+ )
314
+ onChangeModifiers(
315
+ { target: { id: modifier.id.toString() } },
316
+ 'selector',
317
+ quantity,
318
+ )
319
+ }
320
+
321
+ return (
322
+ <div className='modifier-container'>
323
+ <div className='d-flex align-items-center column mb-8 pl-6 pt-2'>
324
+ <div className='quantity-container mb-0'>
325
+ <NumberInputHorizontal
326
+ ref={ref}
327
+ size='big'
328
+ onChange={onChangeProductQuantity}
329
+ onMinusClick={onChangeProductQuantity}
330
+ onPlusClick={onChangeProductQuantity}
331
+ min={0}
332
+ max={MAX_PRODUCT_NUMBER}
333
+ value={value ?? selectedOrderModifier ?? 0}
334
+ className={clsx(invalid && 'error')}
335
+ isLoading={isLoading}
336
+ />
337
+ </div>
338
+ </div>
339
+ <div className='p-2 mt-3 w-100 pl-4'>
340
+ <p className='pl-2'>{modifier.description}</p>
341
+ <div className='pl-2 modifier-price'>
342
+ + {formatToCurrency(modifier.price)}
343
+ </div>
344
+ {error?.message && (
345
+ <div className='d-flex mt-3 w-100'>
346
+ <p className='iframe-event__message-error'>
347
+ {error.message}
348
+ </p>
349
+ </div>
350
+ )}
351
+ </div>
352
+ </div>
353
+ )
354
+ }}
355
+ />
356
+ </>
357
+ )}
358
+ </>
359
+ )
360
+ })}
361
+ </>
362
+ )}
363
+ </>
364
+ )
365
+ }
366
+
367
+ type CheckboxProps = {
368
+ onChange: (e: ChangeEvent<HTMLInputElement>) => void
369
+ value: number
370
+ label: string
371
+ defaultChecked: boolean
372
+ }
373
+
374
+ const Checkbox = ({
375
+ onChange,
376
+ value,
377
+ label,
378
+ defaultChecked,
379
+ }: CheckboxProps) => {
380
+ const checkboxId = useId()
381
+
382
+ return (
383
+ <Form.Group controlId={checkboxId} className='custom-checkbox mt-0'>
384
+ <Form.Check
385
+ label={label}
386
+ value={value}
387
+ defaultChecked={defaultChecked}
388
+ onChange={onChange}
389
+ type='checkbox'
390
+ />
391
+ </Form.Group>
392
+ )
393
+ }
@@ -0,0 +1,98 @@
1
+ import { useEffect } from 'react'
2
+ import { useFormContext, Controller } from 'react-hook-form'
3
+ import { OrderModifierByProduct } from '@licklist/core/dist/DataMapper/Order/OrderModifiierByProduct'
4
+ import { Product } from '@licklist/plugins/dist/types/context/sale/menuSteps'
5
+ import { useTranslation } from 'react-i18next' // Added translation hook
6
+ import { ModifiersSetControl } from './ModifierSetControll'
7
+ import { orderProductModifiersQuantity } from '../../utils'
8
+
9
+ interface ProductControlProps {
10
+ product: Product
11
+ isLoading?: boolean
12
+ editOrderModifier?: OrderModifierByProduct
13
+ }
14
+
15
+ export const ProductControl = ({
16
+ product,
17
+ isLoading = false,
18
+ editOrderModifier,
19
+ }: ProductControlProps) => {
20
+ const { t } = useTranslation() // Added translation hook
21
+ const {
22
+ control,
23
+ watch,
24
+ formState: { isValid },
25
+ clearErrors,
26
+ } = useFormContext()
27
+ const modifiersSet = product?.modifiersSet || []
28
+ const orderModifiersSets = watch(`${product.id}.orderProductModifiers`)
29
+
30
+ useEffect(() => {
31
+ if (!isValid) return
32
+ clearErrors()
33
+ }, [isValid, clearErrors])
34
+
35
+ return (
36
+ <div className='mb-8 pt-4'>
37
+ <div className='d-flex flex-column'>
38
+ {modifiersSet.map((modifierSet) => {
39
+ const orderProductModifiersMaxQuantity =
40
+ orderProductModifiersQuantity(orderModifiersSets, modifierSet)
41
+
42
+ return (
43
+ <div className='modifier-set-container' key={modifierSet.id}>
44
+ <div className='modifier-header'>
45
+ <div className='title'>{modifierSet.name}</div>
46
+ </div>
47
+ <Controller
48
+ control={control}
49
+ name={`${product.id}.${modifierSet.id}`}
50
+ rules={{
51
+ validate: () => {
52
+ const { maxItems, minItems } = modifierSet
53
+
54
+ if (
55
+ !!minItems &&
56
+ orderProductModifiersMaxQuantity < minItems
57
+ ) {
58
+ return t('Validation:quantityMinNumberModifier', {
59
+ min: minItems,
60
+ }) as string
61
+ }
62
+
63
+ if (orderProductModifiersMaxQuantity > maxItems) {
64
+ return t('Validation:quantityMaxNumberModifier', {
65
+ max: maxItems,
66
+ }) as string
67
+ }
68
+
69
+ return true
70
+ },
71
+ }}
72
+ render={({ fieldState: { error } }) => {
73
+ return(
74
+ <>
75
+ <ModifiersSetControl
76
+ modifierSet={modifierSet}
77
+ productId={product.id}
78
+ modifiers={modifierSet.modifiers}
79
+ isEditMode={!!editOrderModifier?.modifiers}
80
+ orderProductModifierSets={editOrderModifier?.modifiers}
81
+ isLoading={isLoading}
82
+ />
83
+ {error?.message && (
84
+ <div className='invalid-feedback d-flex pl-4'>
85
+ {error?.message}!
86
+ </div>
87
+ )}
88
+ </>,
89
+ )
90
+ }}
91
+ />
92
+ </div>
93
+ )
94
+ })}
95
+ </div>
96
+ </div>
97
+ )
98
+ }
@@ -0,0 +1 @@
1
+ import './ProductWithModifierSetModal.js'
@@ -0,0 +1 @@
1
+ export { ProductWithModifierSetModal } from './ModifierSetModal/ProductWithModifierSetModal'
@@ -0,0 +1,29 @@
1
+ import { OrderModifier } from "@licklist/core/dist/DataMapper/Order/OrderModifierDataMapper"
2
+ import { uniqBy } from "lodash"
3
+
4
+ export type selectModifierType = 'radio' | 'checkbox' | 'selector'
5
+
6
+ export const filteredOrderModifierSets = (
7
+ modifiersSet: OrderModifier[],
8
+ ): OrderModifier[] => {
9
+ if (!modifiersSet) return []
10
+ const orderModifier = modifiersSet
11
+ ?.flat()
12
+ ?.filter((modifier) => !!modifier?.quantity)
13
+
14
+ return uniqBy(
15
+ orderModifier,
16
+ (item) => `${item.modifierId}-${item.modifierSetId}`,
17
+ )
18
+ }
19
+
20
+ export const orderProductModifiersQuantity = (
21
+ orderModifiersSets: OrderModifier[],
22
+ modifierSet,
23
+ ) => {
24
+ if (!orderModifiersSets?.length) return 0
25
+ const filteredOrderModifier = filteredOrderModifierSets(orderModifiersSets)
26
+ return filteredOrderModifier.filter(
27
+ (item) => item?.modifierSetId === modifierSet.id,
28
+ ).length
29
+ }
@@ -27,7 +27,6 @@ export const GridView: Story<ActivityCardProps> = (props) => {
27
27
  GridView.args = {
28
28
  layout: LAYOUT_GRID,
29
29
  title: 'Clay Pigeons & Axe Thowing',
30
- duration: '60 mins',
31
30
  price: 'from £20',
32
31
  }
33
32
 
@@ -46,6 +45,5 @@ export const ListView: Story<ActivityCardProps> = (props) => {
46
45
  ListView.args = {
47
46
  layout: LAYOUT_LIST,
48
47
  title: 'Clay Pigeons & Axe Thowing',
49
- duration: '60 mins',
50
48
  price: 'from £20',
51
49
  }
@@ -10,7 +10,6 @@ export const LAYOUT_LIST = 'list'
10
10
 
11
11
  export type ActivityCardProps = {
12
12
  title: ReactNode
13
- duration: ReactNode
14
13
  price: ReactNode
15
14
  description?: ReactNode
16
15
  onSelect: () => void
@@ -24,7 +23,6 @@ export type ActivityCardProps = {
24
23
 
25
24
  export const ActivityCard = ({
26
25
  title,
27
- duration,
28
26
  price,
29
27
  description,
30
28
  availableTimes,
@@ -48,7 +46,6 @@ export const ActivityCard = ({
48
46
 
49
47
  <div>
50
48
  <div className='activity-card-title'>{title}</div>
51
- {duration && <div>{duration}</div>}
52
49
  {price && <div>{price}</div>}
53
50
  {description && (
54
51
  <div className='mt-2 activity-card-description'>{description}</div>
@@ -79,7 +76,6 @@ export const ActivityCard = ({
79
76
  <div className='activity-card-info'>
80
77
  <div className='activity-card-title mb-2'>{title}</div>
81
78
  {availableTimes && <div>{availableTimes}</div>}
82
- {duration && <div>{duration}</div>}
83
79
  {price && <div>{price}</div>}
84
80
  {description && (
85
81
  <div className='mt-2 activity-card-description'>{description}</div>
@@ -12,6 +12,7 @@ interface TicketDescriptionProps {
12
12
  title: string
13
13
  description: string
14
14
  className?: string
15
+ classNameProductModal?: string
15
16
  images: Image[] | null
16
17
  price?: ReactNode
17
18
  isRequired?: boolean
@@ -24,6 +25,7 @@ export function TicketDescription({
24
25
  title,
25
26
  description,
26
27
  className = '',
28
+ classNameProductModal = '',
27
29
  images,
28
30
  price,
29
31
  isRequired = false,
@@ -47,10 +49,10 @@ export function TicketDescription({
47
49
  className='ticket-description__wrapper'
48
50
  style={descriptionWrapperStyle}
49
51
  >
50
- <div className='ticket-description__wrapper-children'>
52
+ <div className={clsx('ticket-description__wrapper-children', classNameProductModal)}>
51
53
  {imageSrc && (
52
- <div className='image-wrapper'>
53
- <img src={imageSrc} alt={title} />
54
+ <div className={clsx('image-wrapper', classNameProductModal && 'w-100 h-25')}>
55
+ <img className={clsx(classNameProductModal && 'w-100')} src={imageSrc} alt={title} />
54
56
  </div>
55
57
  )}
56
58
  {canExpand && description.length > DESCRIPTION_MAX_LENGTH ? (
@@ -2,6 +2,8 @@ import { useTranslation } from 'react-i18next'
2
2
  import { useIntl } from 'react-intl'
3
3
  import * as Config from '@licklist/core/dist/Config'
4
4
  import { OrderItem } from '@licklist/plugins/dist/types/context/Iframe/orderItems'
5
+ import { calculateTotalModifiersPrice } from '../../utils'
6
+ import { ProductWithModifier } from '../../../CategoryProduct/components/ProductWithModifier/ProductWithModifier'
5
7
 
6
8
  type ProductSummaryProps = {
7
9
  name?: string
@@ -19,11 +21,16 @@ export const ProductSummary = ({
19
21
 
20
22
  const priceForOneProduct = orderProduct?.price
21
23
 
24
+ const modifierSetsPrice = calculateTotalModifiersPrice(
25
+ orderProduct?.orderModifiersSets,
26
+ )
27
+
22
28
  const fullPrice = formatNumber(priceForOneProduct * orderProduct?.quantity, {
23
29
  style: 'currency',
24
30
  currency: Config.Currency.GBP,
25
31
  })
26
32
 
33
+
27
34
  return (
28
35
  <div className='product'>
29
36
  <p className='m-0 name'>{name ?? orderProduct?.name}</p>
@@ -32,9 +39,22 @@ export const ProductSummary = ({
32
39
  {t('shortQuantity')}:&nbsp;{orderProduct?.quantity}
33
40
  </p>
34
41
 
35
- <p className='price'>{fullPrice}</p>
42
+ {modifierSetsPrice && <p className='price'>{fullPrice}</p>}
36
43
  </div>
37
44
 
45
+ {!!orderProduct?.orderModifiersSets?.length && (
46
+ <>
47
+ {orderProduct.orderModifiersSets.map((modifier, index) => (
48
+ <ProductWithModifier
49
+ key={modifier.productQuantity.toString()}
50
+ modifier={modifier}
51
+ modifierKey={index}
52
+ isSummary
53
+ />
54
+ ))}
55
+ </>
56
+ )}
57
+
38
58
  {productQuantityError && (
39
59
  <p className='iframe-event__message-error'>{productQuantityError}</p>
40
60
  )}