@licklist/design 0.71.18-dev.3 → 0.71.18-dev.4

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 (97) hide show
  1. package/dist/events/edit-event-modal/component/SelectEventProductSet/component/EditEventProductSet.js +1 -0
  2. package/dist/iframe/ProductWithModifierModal/ModifierSetModal/ProductWithModifierSetForm.d.ts +18 -0
  3. package/dist/iframe/ProductWithModifierModal/ModifierSetModal/ProductWithModifierSetForm.d.ts.map +1 -0
  4. package/dist/iframe/ProductWithModifierModal/ModifierSetModal/ProductWithModifierSetForm.js +281 -0
  5. package/dist/iframe/ProductWithModifierModal/ModifierSetModal/ProductWithModifierSetModal.d.ts +15 -0
  6. package/dist/iframe/ProductWithModifierModal/ModifierSetModal/ProductWithModifierSetModal.d.ts.map +1 -0
  7. package/dist/iframe/ProductWithModifierModal/ModifierSetModal/ProductWithModifierSetModal.js +89 -0
  8. package/dist/iframe/ProductWithModifierModal/ModifierSetModal/controll/ModifierSetControll.d.ts +16 -0
  9. package/dist/iframe/ProductWithModifierModal/ModifierSetModal/controll/ModifierSetControll.d.ts.map +1 -0
  10. package/dist/iframe/ProductWithModifierModal/ModifierSetModal/controll/ModifierSetControll.js +447 -0
  11. package/dist/iframe/ProductWithModifierModal/ModifierSetModal/controll/ProductControll.d.ts +12 -0
  12. package/dist/iframe/ProductWithModifierModal/ModifierSetModal/controll/ProductControll.d.ts.map +1 -0
  13. package/dist/iframe/ProductWithModifierModal/ModifierSetModal/controll/ProductControll.js +45 -0
  14. package/dist/iframe/ProductWithModifierModal/ModifierSetModal/index.d.ts +2 -0
  15. package/dist/iframe/ProductWithModifierModal/ModifierSetModal/index.d.ts.map +1 -0
  16. package/dist/iframe/ProductWithModifierModal/index.d.ts +2 -0
  17. package/dist/iframe/ProductWithModifierModal/index.d.ts.map +1 -0
  18. package/dist/iframe/event/ticket-description/TicketDescription.d.ts +2 -1
  19. package/dist/iframe/event/ticket-description/TicketDescription.d.ts.map +1 -1
  20. package/dist/iframe/event/ticket-description/TicketDescription.js +4 -3
  21. package/dist/iframe/order-process/components/BookingSummary/components/ProductSummary/ProductSummary.d.ts.map +1 -1
  22. package/dist/iframe/order-process/components/BookingSummary/components/ProductSummary/ProductSummary.js +29 -2
  23. package/dist/iframe/order-process/components/BookingSummary/utils/index.d.ts +4 -0
  24. package/dist/iframe/order-process/components/BookingSummary/utils/index.d.ts.map +1 -1
  25. package/dist/iframe/order-process/components/BookingSummary/utils/index.js +27 -2
  26. package/dist/iframe/order-process/components/CategoryProduct/CategoryProduct.d.ts.map +1 -1
  27. package/dist/iframe/order-process/components/CategoryProduct/CategoryProduct.js +106 -2
  28. package/dist/iframe/order-process/components/CategoryProduct/components/ProductQuantityInput/ProductQuantityInput.d.ts +3 -1
  29. package/dist/iframe/order-process/components/CategoryProduct/components/ProductQuantityInput/ProductQuantityInput.d.ts.map +1 -1
  30. package/dist/iframe/order-process/components/CategoryProduct/components/ProductQuantityInput/ProductQuantityInput.js +95 -1
  31. package/dist/iframe/order-process/components/CategoryProduct/components/ProductWithModifier/ProductWithModifier.d.ts +22 -0
  32. package/dist/iframe/order-process/components/CategoryProduct/components/ProductWithModifier/ProductWithModifier.d.ts.map +1 -0
  33. package/dist/iframe/order-process/components/CategoryProduct/components/ProductWithModifier/ProductWithModifier.js +62 -0
  34. package/dist/iframe/order-process/components/CategoryProduct/constants.d.ts +2 -0
  35. package/dist/iframe/order-process/components/CategoryProduct/constants.d.ts.map +1 -0
  36. package/dist/iframe/order-process/components/CategoryProduct/constants.js +4 -0
  37. package/dist/iframe/order-process/components/utils/useOnWindowUnmount.d.ts +6 -0
  38. package/dist/iframe/order-process/components/utils/useOnWindowUnmount.d.ts.map +1 -0
  39. package/dist/iframe/order-process/components/utils/useOnWindowUnmount.js +18 -0
  40. package/dist/iframe/payment/order-items-table/hooks/useTableData.d.ts.map +1 -1
  41. package/dist/iframe/payment/order-items-table/hooks/useTableData.js +83 -10
  42. package/dist/iframe/payment/order-items-table/utils/index.d.ts.map +1 -1
  43. package/dist/iframe/payment/order-items-table/utils/index.js +15 -0
  44. package/dist/iframe/payment/order-items-table/utils/paymentSummary.js +2 -2
  45. package/dist/product-set/form/ProductSetForm.d.ts +3 -1
  46. package/dist/product-set/form/ProductSetForm.d.ts.map +1 -1
  47. package/dist/product-set/form/ProductSetForm.js +6 -4
  48. package/dist/product-set/form/ProductsControl.d.ts.map +1 -1
  49. package/dist/product-set/form/ProductsControl.js +17 -5
  50. package/dist/product-set/form/context.d.ts +3 -1
  51. package/dist/product-set/form/context.d.ts.map +1 -1
  52. package/dist/product-set/form/context.js +2 -1
  53. package/dist/product-set/product/ProductControl.d.ts +8 -0
  54. package/dist/product-set/product/ProductControl.d.ts.map +1 -1
  55. package/dist/product-set/product/ProductControl.js +25 -1
  56. package/dist/product-set/utils/index.d.ts +88 -0
  57. package/dist/product-set/utils/index.d.ts.map +1 -1
  58. package/dist/product-set/utils/index.js +19 -1
  59. package/dist/sales/coupon/utils/index.d.ts +2 -1
  60. package/dist/sales/coupon/utils/index.d.ts.map +1 -1
  61. package/dist/styles/iframe-page/Page.scss +16 -0
  62. package/dist/styles/iframe-page/PageBody.scss +4 -0
  63. package/dist/styles/modals/Modals.scss +16 -0
  64. package/dist/styles/product-set/ProductSetForm.scss +10 -0
  65. package/dist/styles/sales/ManualBooking.scss +6 -0
  66. package/dist/styles/themes/bookedit/index.scss +14 -0
  67. package/package.json +6 -6
  68. package/src/iframe/ProductWithModifierModal/ModifierSetModal/ProductWithModifierSetForm.tsx +205 -0
  69. package/src/iframe/ProductWithModifierModal/ModifierSetModal/ProductWithModifierSetModal.tsx +75 -0
  70. package/src/iframe/ProductWithModifierModal/ModifierSetModal/controll/ModifierSetControll.tsx +471 -0
  71. package/src/iframe/ProductWithModifierModal/ModifierSetModal/controll/ProductControll.tsx +55 -0
  72. package/src/iframe/ProductWithModifierModal/ModifierSetModal/index.ts +1 -0
  73. package/src/iframe/ProductWithModifierModal/index.ts +1 -0
  74. package/src/iframe/event/ticket-description/TicketDescription.tsx +5 -3
  75. package/src/iframe/order-process/components/BookingSummary/components/ProductSummary/ProductSummary.tsx +32 -1
  76. package/src/iframe/order-process/components/BookingSummary/utils/index.ts +45 -1
  77. package/src/iframe/order-process/components/CategoryProduct/CategoryProduct.tsx +155 -75
  78. package/src/iframe/order-process/components/CategoryProduct/components/ProductQuantityInput/ProductQuantityInput.tsx +58 -1
  79. package/src/iframe/order-process/components/CategoryProduct/components/ProductWithModifier/ProductWithModifier.tsx +84 -0
  80. package/src/iframe/order-process/components/CategoryProduct/constants.ts +1 -0
  81. package/src/iframe/order-process/components/utils/useOnWindowUnmount.ts +25 -0
  82. package/src/iframe/payment/order-items-table/hooks/useTableData.tsx +84 -14
  83. package/src/iframe/payment/order-items-table/utils/index.ts +23 -0
  84. package/src/iframe/payment/order-items-table/utils/paymentSummary.tsx +2 -2
  85. package/src/product-set/form/ProductSetForm.tsx +11 -3
  86. package/src/product-set/form/ProductsControl.tsx +24 -15
  87. package/src/product-set/form/context.tsx +5 -0
  88. package/src/product-set/product/ProductControl.tsx +37 -1
  89. package/src/product-set/utils/index.ts +19 -0
  90. package/src/sales/coupon/utils/index.ts +5 -3
  91. package/src/styles/iframe-page/Page.scss +16 -0
  92. package/src/styles/iframe-page/PageBody.scss +4 -0
  93. package/src/styles/modals/Modals.scss +16 -0
  94. package/src/styles/product-set/ProductSetForm.scss +10 -0
  95. package/src/styles/sales/ManualBooking.scss +6 -0
  96. package/src/styles/themes/bookedit/index.scss +14 -0
  97. package/yarn.lock +171 -199
@@ -0,0 +1,471 @@
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 {
9
+ Controller,
10
+ FieldErrors,
11
+ FieldValues,
12
+ useFormContext,
13
+ } from 'react-hook-form'
14
+ import { xor, uniqBy } from 'lodash'
15
+ import clsx from 'clsx'
16
+ import { Currency } from '@licklist/core/dist/Config'
17
+ import { useIntl } from 'react-intl'
18
+ import { MAX_PRODUCT_NUMBER } from 'src/iframe/order-process/components/CategoryProduct/constants'
19
+ import { NumberInputHorizontal } from 'src/sales'
20
+
21
+ interface ModifiersSetControllProps {
22
+ modifiers?: Modifier[]
23
+ modifierSet: ModifierSet
24
+ modifiersSetWithErrors?: FieldErrors<FieldValues>
25
+ isLoading?: boolean
26
+ isEditMode?: boolean
27
+ productId: number
28
+ orderProductModifierSets?: OrderModifier[]
29
+ }
30
+
31
+ type selectModifierType = 'radio' | 'checkbox' | 'selector'
32
+
33
+ export const ModifiersSetControl = ({
34
+ modifierSet,
35
+ modifiers,
36
+ modifiersSetWithErrors,
37
+ productId,
38
+ isLoading = false,
39
+ isEditMode = false,
40
+ orderProductModifierSets,
41
+ }: ModifiersSetControllProps) => {
42
+ const { control, watch, setValue, trigger } = useFormContext()
43
+ const { t } = useTranslation('App')
44
+
45
+ const filteredOrderModifierSets = (
46
+ modifiersSet: OrderModifier[],
47
+ ): OrderModifier[] => {
48
+ if (!modifiersSet) return []
49
+ const orderModifier = modifiersSet
50
+ .flat()
51
+ .filter((modifier) => !!modifier?.quantity)
52
+
53
+ return uniqBy(
54
+ orderModifier,
55
+ (item) => `${item.modifierId}-${item.modifierSetId}`,
56
+ )
57
+ }
58
+
59
+ const orderModifiersSets = watch(`${productId}.orderProductModifiers`)
60
+ const { formatNumber } = useIntl()
61
+ const formatToCurrency = (value: number) =>
62
+ formatNumber(value, { style: 'currency', currency: Currency.GBP })
63
+
64
+ const orderProductModifiersQuantity = (orderModifiersSets) => {
65
+ const filteredOrderModifier = filteredOrderModifierSets(orderModifiersSets)
66
+ return filteredOrderModifier
67
+ .flat()
68
+ .filter((item) => item && item.modifierSetId === modifierSet.id).length
69
+ }
70
+
71
+ const orderProductModifiersMaxQuantity =
72
+ orderProductModifiersQuantity(orderModifiersSets)
73
+
74
+ const currentOrderModifiersSets = useMemo(
75
+ () =>
76
+ orderProductModifierSets?.filter(
77
+ (modifier) => modifier.modifierSetId === modifierSet.id,
78
+ ) || [],
79
+ [orderProductModifierSets, modifierSet.id],
80
+ )
81
+
82
+ const onChangeModifiers = (
83
+ e: ChangeEvent<HTMLInputElement>,
84
+ type: selectModifierType,
85
+ quantity?: number,
86
+ ) => {
87
+ if (!modifiers) return
88
+
89
+ const selectedModifier = modifiers?.find(
90
+ (item) => item.id === Number(e.target.defaultValue || e.target.id),
91
+ )
92
+ const checkSelectedModifier =
93
+ orderModifiersSets?.find(
94
+ (modifier) => modifier?.modifierId === selectedModifier?.id,
95
+ )?.quantity === 1
96
+
97
+ if (selectedModifier && type === 'radio') {
98
+ modifiers.forEach((modifier) => {
99
+ const isSelected = modifier.id === selectedModifier.id
100
+ const orderModifiers: OrderModifier = {
101
+ modifierId: modifier.id,
102
+ price: modifier.price,
103
+ productId,
104
+ name: modifier.name,
105
+ quantity: isSelected ? 1 : 0,
106
+ modifierSetId: modifierSet.id,
107
+ }
108
+ setValue(
109
+ `${productId}.orderProductModifiers.${modifierSet.id}`,
110
+ orderModifiers,
111
+ )
112
+ })
113
+ }
114
+
115
+ if (selectedModifier && type === 'checkbox') {
116
+ const orderModifiers: OrderModifier = {
117
+ modifierId: selectedModifier.id,
118
+ price: selectedModifier.price,
119
+ productId,
120
+ name: selectedModifier.name,
121
+ quantity: checkSelectedModifier ? 0 : 1,
122
+ modifierSetId: modifierSet.id,
123
+ }
124
+ setValue(
125
+ `${productId}.orderProductModifiers.${modifierSet.id}.${selectedModifier.id}`,
126
+ orderModifiers,
127
+ )
128
+ }
129
+
130
+ if (selectedModifier && type === 'selector' && quantity) {
131
+ const orderModifiers: OrderModifier = {
132
+ modifierId: selectedModifier.id,
133
+ price: selectedModifier.price,
134
+ productId,
135
+ quantity,
136
+ name: selectedModifier.name,
137
+ modifierSetId: modifierSet.id,
138
+ }
139
+ setValue(
140
+ `${productId}.orderProductModifiers.${modifierSet.id}.${selectedModifier.id}`,
141
+ orderModifiers,
142
+ )
143
+ }
144
+ }
145
+
146
+ useEffect(() => {
147
+ if (!orderProductModifierSets?.length) return
148
+ orderProductModifierSets.forEach((orderModifier) =>
149
+ setValue(
150
+ `${productId}.orderProductModifiers.${orderModifier.modifierSetId}.${orderModifier.modifierId}`,
151
+ orderModifier,
152
+ ),
153
+ )
154
+ }, [isEditMode])
155
+
156
+ const modifiersErrors = modifiersSetWithErrors?.modifiers
157
+
158
+ return (
159
+ <>
160
+ {modifierSet?.maxItems === 1 &&
161
+ modifiers.every((modifier) => modifier.maxItems === 1) &&
162
+ !currentOrderModifiersSets?.find((modifier) => !!modifier?.quantity) ? (
163
+ <>
164
+ <Controller
165
+ name={`${modifierSet.id}`}
166
+ data-testid='modifierSet-values-select'
167
+ control={control}
168
+ rules={{
169
+ required: !!modifierSet.minItems
170
+ }}
171
+ render={({ field }) => {
172
+ const onChange = (e: ChangeEvent<HTMLInputElement>) => {
173
+ onChangeModifiers(e, 'radio')
174
+ field.onChange(e.target.id)
175
+ }
176
+ return (
177
+ <>
178
+ {modifiers?.map((modifier) => {
179
+ const selectedOrderModifierId = currentOrderModifiersSets
180
+ ?.find(
181
+ (orderModifier) =>
182
+ orderModifier.modifierId === modifier.id,
183
+ )
184
+ ?.modifierId?.toString()
185
+
186
+ return (
187
+ <Col key={modifier.id.toString()}>
188
+ <>
189
+ <div className='modifier-container d-flex justify-content-between align-items-center p-2'>
190
+ <Form.Check
191
+ className='custom-radio'
192
+ inline
193
+ id={modifier.id.toString()}
194
+ defaultChecked={!!selectedOrderModifierId}
195
+ defaultValue={modifier.id.toString()}
196
+ checked={field.value === modifier.id.toString()}
197
+ onChange={onChange}
198
+ type='radio'
199
+ label={modifier.name}
200
+ name={modifier.name}
201
+ />
202
+ </div>
203
+ <div className='mt-3 w-100 pl-2'>
204
+ <p>{modifier.description}</p>
205
+ <div className='price'>
206
+ + {formatToCurrency(modifier.price)}
207
+ </div>
208
+ </div>
209
+ </>
210
+ </Col>
211
+ )
212
+ })}
213
+ </>
214
+ )
215
+ }}
216
+ />
217
+
218
+ {modifiersErrors?.message && (
219
+ <Col>
220
+ <div className='invalid-feedback field-values-error'>
221
+ {modifiersSetWithErrors.message || 'test'}
222
+ </div>
223
+ </Col>
224
+ )}
225
+ </>
226
+ ) : (
227
+ <>
228
+ {modifiers?.map((modifier, index) => {
229
+ const selectedOrderModifier = currentOrderModifiersSets?.find(
230
+ (orderModifier) => orderModifier.modifierId === modifier.id,
231
+ )?.quantity
232
+ const requiredModifierSet = modifierSet?.minItems > currentOrderModifiersSets.length
233
+ const errorMessage = (modifiersErrors as FieldError[])?.find(
234
+ (modifier) =>
235
+ modifier.ref && modifier.ref.name === `modifiers[${index}]`,
236
+ )?.message
237
+
238
+ return (
239
+ <>
240
+ {modifier.maxItems === 1 ? (
241
+ <>
242
+ <Controller
243
+ name={`modifiers[${index}]`}
244
+ control={control}
245
+ rules={{
246
+ required: !!modifier.minItems || requiredModifierSet,
247
+ validate: (value) => {
248
+ if (!value) return true
249
+ const {
250
+ maxItems: maxModifierSet,
251
+ minItems: minModifierSet,
252
+ } = modifierSet
253
+
254
+ if (
255
+ orderProductModifiersMaxQuantity < minModifierSet
256
+ ) {
257
+ return t('Validation:quantityMinNumberModifier', {
258
+ min: minModifierSet,
259
+ }) as string
260
+ }
261
+
262
+ if (
263
+ orderProductModifiersMaxQuantity > maxModifierSet
264
+ ) {
265
+ return t('Validation:quantityMaxNumberModifier', {
266
+ max: maxModifierSet,
267
+ }) as string
268
+ }
269
+
270
+ const { maxItems, minItems } = modifier
271
+ if (value?.length > maxItems) {
272
+ return t('Validation:quantityMaxNumberModifier', {
273
+ max: maxItems,
274
+ }) as string
275
+ }
276
+
277
+ if (value?.length < minItems) {
278
+ return t('Validation:quantityMinNumberModifier', {
279
+ min: minItems,
280
+ }) as string
281
+ }
282
+
283
+ return true
284
+ },
285
+ }}
286
+ render={({ field }) => {
287
+ const onChange = (e: ChangeEvent<HTMLInputElement>) => {
288
+ onChangeModifiers(e, 'checkbox')
289
+ field.onChange(
290
+ xor(field.value, [Number(e.target.value)]),
291
+ )
292
+ }
293
+
294
+ return (
295
+ <Col
296
+ className='modifier-container pl-6'
297
+ key={modifier.id.toString()}
298
+ >
299
+ <div className='d-flex justify-content-between align-items-center'>
300
+ <Checkbox
301
+ value={modifier.id}
302
+ onChange={onChange}
303
+ label={modifier.name}
304
+ defaultChecked={!!selectedOrderModifier}
305
+ />
306
+ </div>
307
+ <div className='mt-3 w-100 pl-2'>
308
+ <p>{modifier.description}</p>
309
+ <div className='price'>
310
+ + {formatToCurrency(modifier.price)}
311
+ </div>
312
+ </div>
313
+ {errorMessage && (
314
+ <div className='invalid-feedback d-flex'>
315
+ {errorMessage}
316
+ </div>
317
+ )}
318
+ </Col>
319
+ )
320
+ }}
321
+ />
322
+ </>
323
+ ) : (
324
+ <>
325
+ <div className='modifier-header m-0'>
326
+ <div className='title'>{modifier.name}</div>
327
+ </div>
328
+ <Controller
329
+ control={control}
330
+ name={`${productId}.${modifierSet.id}.modifiers[${index}].quantity`}
331
+ rules={{
332
+ required: !!modifier.minItems || requiredModifierSet,
333
+ validate: (value) => {
334
+ // if (!value) return true
335
+ const {
336
+ maxItems: maxModifierSet,
337
+ minItems: minModifierSet,
338
+ } = modifierSet
339
+ if (
340
+ orderProductModifiersMaxQuantity < minModifierSet
341
+ ) {
342
+ return t('Validation:quantityMinNumberModifier', {
343
+ min: minModifierSet,
344
+ }) as string
345
+ }
346
+
347
+ if (
348
+ orderProductModifiersMaxQuantity > maxModifierSet
349
+ ) {
350
+
351
+ return t('Validation:quantityMaxNumberModifier', {
352
+ max: maxModifierSet,
353
+ }) as string
354
+ }
355
+
356
+ const { maxItems, minItems } = modifier
357
+ if (value > maxItems) {
358
+ return t('Validation:quantityMaxNumberModifier', {
359
+ max: maxItems,
360
+ }) as string
361
+ }
362
+
363
+ if (value < minItems) {
364
+ return t('Validation:quantityMinNumberModifier', {
365
+ min: minItems,
366
+ }) as string
367
+ }
368
+
369
+ return true
370
+ },
371
+ }}
372
+ render={({
373
+ field: { onChange, value, ref },
374
+ fieldState: { invalid, error },
375
+ }) => {
376
+ const onChangeProductQuantity = (val: number) => {
377
+ const quantity = Math.min(
378
+ MAX_PRODUCT_NUMBER,
379
+ Math.max(0, Math.ceil(val)),
380
+ )
381
+ onChange(quantity)
382
+ trigger(
383
+ `${productId}.${modifierSet.id}.modifiers[${index}].quantity`,
384
+ )
385
+ onChangeModifiers(
386
+ { target: { id: modifier.id.toString() } },
387
+ 'selector',
388
+ quantity,
389
+ )
390
+ }
391
+
392
+ return (
393
+ <div className='modifier-container'>
394
+ <div className='d-flex align-items-center column mb-8 pl-6 pt-2'>
395
+ <div className='quantity-container mb-0'>
396
+ <NumberInputHorizontal
397
+ ref={ref}
398
+ size='big'
399
+ onChange={onChangeProductQuantity}
400
+ onMinusClick={onChangeProductQuantity}
401
+ onPlusClick={onChangeProductQuantity}
402
+ min={0}
403
+ max={MAX_PRODUCT_NUMBER}
404
+ value={value ?? selectedOrderModifier ?? 0}
405
+ className={clsx(invalid && 'error')}
406
+ isLoading={isLoading}
407
+ />
408
+ </div>
409
+ </div>
410
+ <div className='p-2 mt-3 w-100 pl-4'>
411
+ <p className='pl-2'>{modifier.description}</p>
412
+ <div className='pl-2 price'>
413
+ + {formatToCurrency(modifier.price)}
414
+ </div>
415
+ {error?.message && (
416
+ <div className='d-flex mt-3 w-100'>
417
+ <p className='iframe-event__message-error'>
418
+ {error.message}
419
+ </p>
420
+ </div>
421
+ )}
422
+ </div>
423
+ </div>
424
+ )
425
+ }}
426
+ />
427
+ </>
428
+ )}
429
+ {modifiersErrors?.message && (
430
+ <Col>
431
+ <div className='invalid-feedback field-values-error'>
432
+ {modifiersSetWithErrors.message || 'test'}
433
+ </div>
434
+ </Col>
435
+ )}
436
+ </>
437
+ )
438
+ })}
439
+ </>
440
+ )}
441
+ </>
442
+ )
443
+ }
444
+
445
+ type CheckboxProps = {
446
+ onChange: (e: ChangeEvent<HTMLInputElement>) => void
447
+ value: number
448
+ label: string
449
+ defaultChecked: boolean
450
+ }
451
+
452
+ const Checkbox = ({
453
+ onChange,
454
+ value,
455
+ label,
456
+ defaultChecked,
457
+ }: CheckboxProps) => {
458
+ const checkboxId = useId()
459
+
460
+ return (
461
+ <Form.Group controlId={checkboxId} className='custom-checkbox mt-0'>
462
+ <Form.Check
463
+ label={label}
464
+ value={value}
465
+ defaultChecked={defaultChecked}
466
+ onChange={onChange}
467
+ type='checkbox'
468
+ />
469
+ </Form.Group>
470
+ )
471
+ }
@@ -0,0 +1,55 @@
1
+ import {
2
+ useFormContext,
3
+ Controller,
4
+ FieldErrors,
5
+ FieldValues,
6
+ } from 'react-hook-form'
7
+ import { OrderModifierByProduct } from '@licklist/core/dist/DataMapper/Order/OrderModifiierByProduct'
8
+ import { Product } from '@licklist/plugins/dist/types/context/sale/menuSteps'
9
+ import { ModifiersSetControl } from './ModifierSetControll'
10
+
11
+ interface ProductControlProps {
12
+ product: Product
13
+ isLoading?: boolean
14
+ editOrderModifier?: OrderModifierByProduct
15
+ errors?: FieldErrors<FieldValues>
16
+ }
17
+
18
+ export const ProductControl = ({
19
+ product,
20
+ isLoading = false,
21
+ editOrderModifier,
22
+ errors,
23
+ }: ProductControlProps) => {
24
+ const { control } = useFormContext()
25
+ const modifiersSet = product?.modifiersSet || []
26
+
27
+ return (
28
+ <Controller
29
+ control={control}
30
+ name='product'
31
+ render={() => (
32
+ <div className='mb-8 pt-4'>
33
+ <div className=' d-flex flex-column'>
34
+ {modifiersSet.map((modifierSet) => (
35
+ <>
36
+ <div className='modifier-header'>
37
+ <div className='title'>{modifierSet.name}</div>
38
+ </div>
39
+ <ModifiersSetControl
40
+ modifierSet={modifierSet}
41
+ productId={product.id}
42
+ modifiers={modifierSet.modifiers}
43
+ isEditMode={!!editOrderModifier?.modifiers}
44
+ orderProductModifierSets={editOrderModifier?.modifiers}
45
+ modifiersSetWithErrors={errors}
46
+ isLoading={isLoading}
47
+ />
48
+ </>
49
+ ))}
50
+ </div>
51
+ </div>
52
+ )}
53
+ />
54
+ )
55
+ }
@@ -0,0 +1 @@
1
+ import './ProductWithModifierSetModal.js'
@@ -0,0 +1 @@
1
+ export { ProductWithModifierSetModal } from './ModifierSetModal/ProductWithModifierSetModal'
@@ -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,7 @@ 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'
5
6
 
6
7
  type ProductSummaryProps = {
7
8
  name?: string
@@ -19,11 +20,32 @@ export const ProductSummary = ({
19
20
 
20
21
  const priceForOneProduct = orderProduct?.price
21
22
 
23
+ const modifierSetsPrice = calculateTotalModifiersPrice(
24
+ orderProduct?.orderModifiersSets,
25
+ )
26
+
22
27
  const fullPrice = formatNumber(priceForOneProduct * orderProduct?.quantity, {
23
28
  style: 'currency',
24
29
  currency: Config.Currency.GBP,
25
30
  })
26
31
 
32
+ const modifiersName = `${orderProduct.orderModifiersSets
33
+ ?.map((modifierProduct) =>
34
+ modifierProduct?.modifiers
35
+ .map((item) =>
36
+ item?.quantity > 1
37
+ ? `${item?.quantity}x - ${item?.name}`
38
+ : item?.name,
39
+ )
40
+ .join(', '),
41
+ )
42
+ .join(', ')}`
43
+
44
+ const fullModifiersPrice = formatNumber(modifierSetsPrice, {
45
+ style: 'currency',
46
+ currency: Config.Currency.GBP,
47
+ })
48
+
27
49
  return (
28
50
  <div className='product'>
29
51
  <p className='m-0 name'>{name ?? orderProduct?.name}</p>
@@ -32,9 +54,18 @@ export const ProductSummary = ({
32
54
  {t('shortQuantity')}:&nbsp;{orderProduct?.quantity}
33
55
  </p>
34
56
 
35
- <p className='price'>{fullPrice}</p>
57
+ {modifierSetsPrice && <p className='price'>{fullPrice}</p>}
36
58
  </div>
37
59
 
60
+ {fullModifiersPrice && (
61
+ <>
62
+ <p className='mt-2'>{modifiersName}</p>
63
+ <div className='d-flex justify-content-end'>
64
+ <p className='price'>{fullModifiersPrice}</p>
65
+ </div>
66
+ </>
67
+ )}
68
+
38
69
  {productQuantityError && (
39
70
  <p className='iframe-event__message-error'>{productQuantityError}</p>
40
71
  )}
@@ -1,3 +1,7 @@
1
+ import { OrderModifier } from '@licklist/core/dist/DataMapper/Order/OrderModifierDataMapper'
2
+ import {
3
+ OrderModifierByProduct
4
+ } from '@licklist/core/dist/DataMapper/Order/OrderModifiierByProduct'
1
5
  import { QuantityCheckProductInfo } from '@licklist/plugins/dist/types/Api/verifyStock'
2
6
  import { OrderItem } from '@licklist/plugins/dist/types/context/Iframe/orderItems'
3
7
 
@@ -14,16 +18,56 @@ export const cartSumByOrderProducts = ({
14
18
  return orderProducts.reduce((prevSumValue: number, product) => {
15
19
  if (!product) return 0
16
20
 
21
+ const modifiersPrice = calculateTotalModifiersPrice(
22
+ product?.orderModifiersSets,
23
+ )
24
+
17
25
  const price = isTotalSum
18
26
  ? product?.price
19
27
  : product.hasDeposit
20
28
  ? product?.deposit
21
29
  : product?.price
22
30
 
23
- return prevSumValue + price * product.quantity
31
+ return prevSumValue + price * product.quantity + modifiersPrice
24
32
  }, 0)
25
33
  }
26
34
 
35
+ export const getModifierName = (
36
+ modifier: OrderModifierByProduct,
37
+ isManualBooking: boolean,
38
+ ) => {
39
+ const modifierName = (orderModifier: OrderModifier) =>
40
+ !isManualBooking ? orderModifier?.name : orderModifier.modifier.name
41
+ return `${modifier.modifiers.map((item) => (
42
+ item?.quantity > 1 ? `${item?.quantity}x - ${modifierName(item)}` : modifierName(item))).join(', ')}`
43
+ }
44
+
45
+ export const calculateTotalModifiersPrice = (
46
+ orderModifiersSets: OrderModifierByProduct[],
47
+ ) =>
48
+ orderModifiersSets
49
+ ?.map((set) =>
50
+ set.modifiers.reduce(
51
+ (sum, modifier) =>
52
+ sum + modifier.price * modifier.quantity * set.productQuantity,
53
+ 0,
54
+ ),
55
+ )
56
+ .reduce((total, setTotal) => total + setTotal, 0)
57
+
58
+ export const getOrderProductModifiersPrice = (
59
+ modifierFromProduct: OrderModifierByProduct,
60
+ ) => {
61
+ const { modifiers, productQuantity } = modifierFromProduct
62
+ const modifiersPrices = modifiers.reduce(
63
+ (prevSumModifier: number, modifier: OrderModifier) =>
64
+ prevSumModifier + modifier.price * modifier.quantity,
65
+ 0,
66
+ )
67
+
68
+ return modifiersPrices * productQuantity
69
+ }
70
+
27
71
  export const getProductError = (
28
72
  productsWithErrors: QuantityCheckProductInfo[],
29
73
  productId: OrderItem['id'],