@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
@@ -1,4 +1,4 @@
1
- import { useEffect, useMemo } from 'react'
1
+ import { useEffect, useMemo, useState } from 'react'
2
2
  import { useFormContext, Controller } from 'react-hook-form'
3
3
  import clsx from 'clsx'
4
4
  import { useTranslation } from 'react-i18next'
@@ -10,8 +10,14 @@ import {
10
10
  Product,
11
11
  ProductCategory,
12
12
  } from '@licklist/plugins/dist/types/context/sale/menuSteps'
13
+ import { Button } from 'react-bootstrap'
14
+ import { FaTrashAlt } from 'react-icons/fa'
15
+ import { ProductWithModifierSetModal } from 'src/iframe/ProductWithModifierModal'
16
+ import { OrderModifierByProduct } from '@licklist/core/dist/DataMapper/Order/OrderModifiierByProduct'
13
17
  import { TicketDescription } from '../../../event/ticket-description'
14
18
  import { ProductQuantityInput } from './components/ProductQuantityInput'
19
+ import { FormOrderItem } from './components/ProductQuantityInput/ProductQuantityInput'
20
+ import { ProductWithModifier } from './components/ProductWithModifier/ProductWithModifier'
15
21
 
16
22
  interface CategoryProductProps {
17
23
  product: Product
@@ -31,7 +37,9 @@ export const CategoryProduct = ({
31
37
  const { formatNumber } = useIntl()
32
38
  const { t } = useTranslation(['Design', 'Validation'])
33
39
  const { control, clearErrors, setError } = useFormContext()
34
-
40
+ const [editOrderModifierIndex, setEditOrderModifierIndex] =
41
+ useState<OrderModifierByProduct>(undefined)
42
+ const [modifierIndex, setModifierIndex] = useState<number>(undefined)
35
43
  const hasDeposits = category.allowDeposits && product?.deposit < product.price
36
44
 
37
45
  const productQuantityError = useMemo(() => {
@@ -118,83 +126,155 @@ export const CategoryProduct = ({
118
126
  render={({
119
127
  field: { onChange, value: productInfo = {}, ref },
120
128
  fieldState: { invalid, error },
121
- }) => (
122
- <div id={String(product.id)} className='iframe-event__category-product'>
123
- <div className={clsx('iframe-event__product', invalid && 'error')}>
124
- <TicketDescription
125
- title={product.name}
126
- description={product.description}
127
- className={clsx('iframe-event__product-description')}
128
- images={product.images}
129
- isRequired={product.isRequired}
130
- canExpand={canExpandDescription}
131
- />
132
- </div>
133
- <div className='iframe-event__product-price-wrapper'>
134
- <span className='product-price'>
135
- {formatNumber(product.price, {
136
- style: 'currency',
137
- currency: Config.Currency.GBP,
138
- })}
139
- </span>
140
- <ProductQuantityInput
141
- onChange={onChange}
142
- productInfo={productInfo}
143
- refCallback={ref}
144
- clearErrors={clearErrors}
145
- product={{
146
- ...product,
147
- isSoldOut: product?.isSoldOut || checkIfSoldOutProduct(),
148
- }}
149
- category={category}
150
- invalid={invalid}
151
- />
152
- </div>
153
- {hasDeposits && !category?.remainderExpireAfter && (
154
- <div className='mt-4'>
155
- {t('Design:payNowAndUponArrival', {
156
- deposit: formatNumber(product?.deposit, {
157
- style: 'currency',
158
- currency: Config.Currency.GBP,
159
- }),
160
- remainder: formatNumber(product.price - product?.deposit, {
161
- style: 'currency',
162
- currency: Config.Currency.GBP,
163
- }),
164
- })}
165
- </div>
166
- )}
129
+ }) => {
130
+ const deleteOrderModifier = (orderModifierIndex: number) => {
131
+ const removedOrderModifierIndex = (
132
+ productInfo as FormOrderItem
133
+ ).orderModifiersSets?.filter(
134
+ (_, index) => index !== orderModifierIndex,
135
+ )
136
+ const productInfoWithRemove = {
137
+ ...productInfo,
138
+ orderModifiersSets: removedOrderModifierIndex,
139
+ quantity: removedOrderModifierIndex.reduce(
140
+ (acc, product) => product.productQuantity + acc,
141
+ 0,
142
+ ),
143
+ }
144
+ onChange(productInfoWithRemove)
145
+ }
167
146
 
168
- {hasDeposits && category?.remainderExpireAfter > 0 && (
169
- <div className='mt-4'>
170
- {t('Design:payNowAndReminderDays', {
171
- deposit: formatNumber(product?.deposit, {
172
- style: 'currency',
173
- currency: Config.Currency.GBP,
174
- }),
175
- remainder: formatNumber(product.price - product?.deposit, {
147
+ const editOrderModifierSet = (orderModifierIndex: number) => {
148
+ const editOrderModifierIndex = (
149
+ productInfo as FormOrderItem
150
+ ).orderModifiersSets.find((_, index) => {
151
+ setModifierIndex(index)
152
+ return index === orderModifierIndex
153
+ })
154
+ setEditOrderModifierIndex(editOrderModifierIndex)
155
+ }
156
+
157
+ const onChangeWithModifierSets = (value: FormOrderItem) => {
158
+ const editedOrderModifiersSets = (
159
+ productInfo as FormOrderItem
160
+ ).orderModifiersSets
161
+ ?.filter((_, index) => index !== modifierIndex)
162
+ .concat(value.orderModifiersSets)
163
+
164
+ onChange({
165
+ ...value,
166
+ orderModifiersSets: editedOrderModifiersSets,
167
+ quantity: editedOrderModifiersSets.reduce(
168
+ (acc, product) => product.productQuantity + acc,
169
+ 0,
170
+ ),
171
+ })
172
+ setEditOrderModifierIndex(undefined)
173
+ }
174
+
175
+ return (
176
+ <div
177
+ id={String(product.id)}
178
+ className='iframe-event__category-product'
179
+ >
180
+ <div className={clsx('iframe-event__product', invalid && 'error')}>
181
+ <TicketDescription
182
+ title={product.name}
183
+ description={product.description}
184
+ className={clsx('iframe-event__product-description')}
185
+ images={product.images}
186
+ isRequired={product.isRequired}
187
+ canExpand={canExpandDescription}
188
+ />
189
+ </div>
190
+ <div className='iframe-event__product-price-wrapper'>
191
+ <span className='product-price'>
192
+ {formatNumber(product.price, {
176
193
  style: 'currency',
177
194
  currency: Config.Currency.GBP,
178
- }),
179
- days: category?.remainderExpireAfter,
180
- })}
195
+ })}
196
+ </span>
197
+ <ProductQuantityInput
198
+ onChange={onChange}
199
+ productInfo={productInfo}
200
+ refCallback={ref}
201
+ clearErrors={clearErrors}
202
+ product={{
203
+ ...product,
204
+ isSoldOut: product?.isSoldOut || checkIfSoldOutProduct(),
205
+ }}
206
+ category={category}
207
+ invalid={invalid}
208
+ />
181
209
  </div>
182
- )}
183
- {invalid && (
184
- <div className='d-flex mt-3 w-100'>
185
- <p className='iframe-event__message-error'>
186
- {HookFormService.hasError(error, 'required') &&
187
- t('Design:pleaseSelectAtLeastFrom', {
188
- min: 1,
189
- type: 'item',
190
- from: 'this category',
191
- })}
192
- {HookFormService.hasError(error, 'validate') && error.message}
193
- </p>
194
- </div>
195
- )}
196
- </div>
197
- )}
210
+ {hasDeposits && !category?.remainderExpireAfter && (
211
+ <div className='mt-4'>
212
+ {t('Design:payNowAndUponArrival', {
213
+ deposit: formatNumber(product?.deposit, {
214
+ style: 'currency',
215
+ currency: Config.Currency.GBP,
216
+ }),
217
+ remainder: formatNumber(product.price - product?.deposit, {
218
+ style: 'currency',
219
+ currency: Config.Currency.GBP,
220
+ }),
221
+ })}
222
+ </div>
223
+ )}
224
+ {(productInfo as FormOrderItem).orderModifiersSets?.length > 0 && (
225
+ <>
226
+ {(productInfo as FormOrderItem).orderModifiersSets.map(
227
+ (modifier, index) => (
228
+ <ProductWithModifier
229
+ key={modifier.productQuantity.toString()}
230
+ modifier={modifier}
231
+ modifierKey={index}
232
+ editOrderModifierSet={editOrderModifierSet}
233
+ deleteOrderModifier={deleteOrderModifier}
234
+ />
235
+ ),
236
+ )}
237
+ </>
238
+ )}
239
+ {hasDeposits && category?.remainderExpireAfter > 0 && (
240
+ <div className='mt-4'>
241
+ {t('Design:payNowAndReminderDays', {
242
+ deposit: formatNumber(product?.deposit, {
243
+ style: 'currency',
244
+ currency: Config.Currency.GBP,
245
+ }),
246
+ remainder: formatNumber(product.price - product?.deposit, {
247
+ style: 'currency',
248
+ currency: Config.Currency.GBP,
249
+ }),
250
+ days: category?.remainderExpireAfter,
251
+ })}
252
+ </div>
253
+ )}
254
+ {invalid && (
255
+ <div className='d-flex mt-3 w-100'>
256
+ <p className='iframe-event__message-error'>
257
+ {HookFormService.hasError(error, 'required') &&
258
+ t('Design:pleaseSelectAtLeastFrom', {
259
+ min: 1,
260
+ type: 'item',
261
+ from: 'this category',
262
+ })}
263
+ {HookFormService.hasError(error, 'validate') && error.message}
264
+ </p>
265
+ </div>
266
+ )}
267
+ <ProductWithModifierSetModal
268
+ show={!!editOrderModifierIndex}
269
+ onHide={() => setEditOrderModifierIndex(undefined)}
270
+ editOrderModifier={editOrderModifierIndex}
271
+ onChange={onChangeWithModifierSets}
272
+ product={product}
273
+ category={category}
274
+ />
275
+ </div>
276
+ )
277
+ }}
198
278
  />
199
279
  )
200
280
  }
@@ -1,14 +1,19 @@
1
+ import { useState } from 'react'
1
2
  import clsx from 'clsx'
2
3
  import { Button } from 'react-bootstrap'
4
+ import { isEmpty } from 'lodash'
3
5
  import { useTranslation } from 'react-i18next'
4
6
  import { FieldValues, RefCallBack, UseFormClearErrors } from 'react-hook-form'
5
7
  import {
6
8
  Product,
7
9
  ProductCategory,
8
10
  } from '@licklist/plugins/dist/types/context/sale/menuSteps'
11
+ import { OrderModifierByProduct } from '@licklist/core/dist/DataMapper/Order/OrderModifiierByProduct'
9
12
  import { NumberInput } from '../NumberInput'
13
+ // eslint-disable-next-line
14
+ import { ProductWithModifierSetModal } from '../../../../../ProductWithModifierModal/ModifierSetModal/ProductWithModifierSetModal'
10
15
 
11
- interface FormOrderItem {
16
+ export interface FormOrderItem {
12
17
  id: number
13
18
  name: string
14
19
  price: number
@@ -17,6 +22,7 @@ interface FormOrderItem {
17
22
  deposit?: number | null
18
23
  quantity: number
19
24
  capacity?: number | null
25
+ orderModifiersSets?: OrderModifierByProduct[] | null
20
26
  }
21
27
 
22
28
  interface ProductQuantityInputProps {
@@ -40,6 +46,7 @@ export const ProductQuantityInput = ({
40
46
  invalid,
41
47
  }: ProductQuantityInputProps) => {
42
48
  const { t } = useTranslation('Design')
49
+ const [open, handleOpenModal] = useState(false)
43
50
 
44
51
  const onChange = (quantity: number | null) => {
45
52
  _onChange({
@@ -48,12 +55,35 @@ export const ProductQuantityInput = ({
48
55
  deposit: product?.deposit,
49
56
  hasDeposit: category.allowDeposits && product?.deposit < product.price,
50
57
  price: product.price,
58
+ orderModifiersSets: [],
51
59
  productCategoryId: category.id,
52
60
  quantity,
53
61
  capacity: product?.capacity,
54
62
  })
55
63
  }
56
64
 
65
+ const onChangeWithModifierSets = (productOrder: FormOrderItem) => {
66
+ if (isEmpty(productInfo)) {
67
+ _onChange(productOrder)
68
+ return handleOpenModal(false)
69
+ }
70
+
71
+ _onChange({
72
+ id: productInfo.id,
73
+ name: productInfo.name,
74
+ deposit: productInfo?.deposit,
75
+ hasDeposit: productInfo.hasDeposit,
76
+ price: productInfo.price,
77
+ orderModifiersSets: productInfo.orderModifiersSets?.concat(
78
+ productOrder.orderModifiersSets,
79
+ ),
80
+ productCategoryId: category.id,
81
+ quantity: productInfo.quantity + productOrder.quantity,
82
+ capacity: productInfo?.capacity,
83
+ })
84
+ return handleOpenModal(false)
85
+ }
86
+
57
87
  if (product.isSoldOut) {
58
88
  return (
59
89
  <div className='iframe-event__sold-out-wrapper'>
@@ -62,6 +92,33 @@ export const ProductQuantityInput = ({
62
92
  )
63
93
  }
64
94
 
95
+ if (product.modifiersSet.length) {
96
+ return (
97
+ <>
98
+ <Button
99
+ ref={refCallback}
100
+ disabled={product.isSoldOut}
101
+ className={clsx(
102
+ `iframe-event__${
103
+ productInfo?.quantity ? 'unselect-product' : 'select-product'
104
+ }`,
105
+ invalid && 'error',
106
+ )}
107
+ onClick={() => handleOpenModal(true)}
108
+ >
109
+ +
110
+ </Button>
111
+ <ProductWithModifierSetModal
112
+ show={open}
113
+ onHide={() => handleOpenModal(false)}
114
+ onChange={onChangeWithModifierSets}
115
+ product={product}
116
+ category={category}
117
+ />
118
+ </>
119
+ )
120
+ }
121
+
65
122
  if (product?.maxAmount === 1) {
66
123
  return (
67
124
  <Button
@@ -0,0 +1,84 @@
1
+ import { Button } from 'react-bootstrap'
2
+ import { useTranslation } from 'react-i18next'
3
+ import { FaTrashAlt } from 'react-icons/fa'
4
+ import { Config } from '@licklist/core'
5
+ import { useIntl } from 'react-intl'
6
+ import { OrderModifierByProduct } from '@licklist/core/dist/DataMapper/Order/OrderModifiierByProduct'
7
+ import {
8
+ getOrderProductModifiersPrice,
9
+ getModifierName,
10
+ } from '../../../BookingSummary/utils'
11
+
12
+ export interface FormOrderItem {
13
+ id: number
14
+ name: string
15
+ price: number
16
+ productCategoryId: number
17
+ hasDeposit?: boolean
18
+ deposit?: number | null
19
+ quantity: number
20
+ capacity?: number | null
21
+ orderModifiersSets?: OrderModifierByProduct[] | null
22
+ }
23
+
24
+ interface ProductQuantityInputProps {
25
+ modifier: OrderModifierByProduct
26
+ modifierKey: number
27
+ isManualBooking?: boolean
28
+ deleteOrderModifier?: (order: number) => void
29
+ editOrderModifierSet?: (order: number) => void
30
+ }
31
+
32
+ export const ProductWithModifier = ({
33
+ modifier,
34
+ modifierKey,
35
+ isManualBooking = false,
36
+ deleteOrderModifier,
37
+ editOrderModifierSet,
38
+ }: ProductQuantityInputProps) => {
39
+ const { t } = useTranslation('Design')
40
+ const { formatNumber } = useIntl()
41
+
42
+ const modifierName = getModifierName(modifier, isManualBooking)
43
+
44
+ const orderModifierDescription = `${modifier.productQuantity}`
45
+
46
+ const modifierPrice = getOrderProductModifiersPrice(modifier)
47
+
48
+ const fullModifiersPrice = formatNumber(modifierPrice, {
49
+ style: 'currency',
50
+ currency: Config.Currency.GBP,
51
+ })
52
+ return (
53
+ <div
54
+ key={modifierKey}
55
+ className='d-flex p-2 justify-content-between align-items-center'
56
+ >
57
+ <div className='d-flex'>
58
+ <p className='font-weight-bold pr-4'>{`${orderModifierDescription} x`}</p>
59
+ <p>{modifierName ? ` ${modifierName}` : t('withoutModifier')}</p>
60
+ </div>
61
+ {isManualBooking ? (
62
+ <p className='price'>{fullModifiersPrice}</p>
63
+ ) : (
64
+ <div>
65
+ <Button
66
+ className='ml-2'
67
+ variant='link'
68
+ onClick={() => editOrderModifierSet(modifierKey)}
69
+ >
70
+ {t('customise')}
71
+ </Button>
72
+
73
+ <Button
74
+ className='ml-2'
75
+ variant='link'
76
+ onClick={() => deleteOrderModifier(modifierKey)}
77
+ >
78
+ <FaTrashAlt />
79
+ </Button>
80
+ </div>
81
+ )}
82
+ </div>
83
+ )
84
+ }
@@ -0,0 +1 @@
1
+ export const MAX_PRODUCT_NUMBER = 100000 // max number
@@ -0,0 +1,25 @@
1
+ import { useEffect } from 'react'
2
+
3
+ export type UseOnWindowUnmountProps = {
4
+ onBeforeUnload: (event: Event) => void
5
+ onPopState: (event: Event) => void
6
+ }
7
+
8
+ export const useOnWindowUnmount = ({
9
+ onBeforeUnload,
10
+ onPopState,
11
+ }: UseOnWindowUnmountProps) => {
12
+ useEffect(() => {
13
+ window.history.pushState(null, '', window.location.pathname)
14
+ window.addEventListener('beforeunload', onBeforeUnload)
15
+ window.addEventListener('popstate', onPopState)
16
+
17
+ return () => {
18
+ window.removeEventListener('beforeunload', onBeforeUnload)
19
+ window.removeEventListener('popstate', onPopState)
20
+ }
21
+ // eslint-disable-next-line react-hooks/exhaustive-deps
22
+ }, [])
23
+
24
+ return null
25
+ }
@@ -1,8 +1,9 @@
1
1
  import { useMemo } from 'react'
2
- import { uniqueId } from 'lodash'
2
+ import { uniqueId, flatMap, flatten, map } from 'lodash'
3
3
  import { useIntl } from 'react-intl'
4
4
  import { useTranslation } from 'react-i18next'
5
5
  import { Product } from '@licklist/core/dist/DataMapper/Product/ProductDataMapper'
6
+ import { OrderModifier } from '@licklist/core/dist/DataMapper/Order/OrderModifierDataMapper'
6
7
  import {
7
8
  PAYMENT_TYPE_VAT,
8
9
  PAYMENT_TYPE_FEE,
@@ -12,6 +13,10 @@ import { StaticTableData } from '../../../../table'
12
13
  import { getProductQuantityAndPrice, getTotalSumByCategory } from '../utils'
13
14
  import { OrderItemsTableProps, SummaryItem } from '../types'
14
15
  import { getOrderSummaryItems } from '../utils/paymentSummary'
16
+ import { Order } from '@licklist/core/dist/DataMapper'
17
+ import { OrderPayment } from '@licklist/core/dist/DataMapper/Order/OrderPaymentDataMapper'
18
+ import { OrderProduct } from '@licklist/core/dist/DataMapper/Order/OrderProductDataMapper'
19
+ import { OrderModifierByProduct } from '@licklist/core/dist/DataMapper/Order/OrderModifiierByProduct'
15
20
 
16
21
  const CURRENCY_DEFAULT = 'GBP'
17
22
  export const PAYMENT_TYPE_TRANSLATE_KEYS = {
@@ -50,19 +55,67 @@ export const useTableData = ({
50
55
  ),
51
56
  })
52
57
 
53
- const renderProductItem = (product: Product) => {
54
- const { quantity, price } = getProductQuantityAndPrice(
55
- order.orderProducts,
56
- product,
57
- )
58
+ const reworkProductStructure = (order: OrderProduct) =>
59
+ order
60
+ ? flatMap(order, (item) => {
61
+ if (!item || !Array.isArray(item)) return []
62
+ return item.map((modGroup, idx) => ({
63
+ deletedAt: order.deletedAt ?? null,
64
+ id: `${order.id}-${idx + 1}`, // Ensuring uniqueness with string concatenation
65
+ orderId: order.orderId ?? null,
66
+ price: order.price ?? 0,
67
+ productId: order.productId ?? '',
68
+ quantity: modGroup.productQuantity ?? 1,
69
+ deposit: order.deposit ?? 0,
70
+ orderProductModifiers: modGroup.modifiers.map((mod) => ({
71
+ modifierId: mod.modifierId ?? '',
72
+ price: mod.price ?? 0,
73
+ productId: mod.productId ?? '',
74
+ quantity: mod.quantity ?? 1,
75
+ modifierSetId: mod.modifierSetId ?? '',
76
+ modifier: mod.modifier ?? null,
77
+ })),
78
+ }))
79
+ })
80
+ : []
81
+
82
+ const renderProductItem = ({
83
+ product,
84
+ productsForCategory,
85
+ }: {
86
+ product: OrderProduct
87
+ productsForCategory: Product[]
88
+ }) => {
89
+ if (product.quantity === 0) {
90
+ return null
91
+ }
92
+
93
+ const name =
94
+ productsForCategory.find((item) => item.id === product.productId)?.name || ''
58
95
 
96
+ return {
97
+ key: product.id,
98
+ name,
99
+ quantity: (
100
+ <div className='quantity'>
101
+ <div className='multiplier'>x</div>
102
+ {product.quantity}
103
+ </div>
104
+ ),
105
+ price: formatPrice(product.price),
106
+ modifier: product?.orderProductModifiers?.map(renderModifierItem) || [],
107
+ }
108
+ }
109
+
110
+ const renderModifierItem = (orderModifier: OrderModifier) => {
111
+ const { quantity, modifier, modifierId, price } = orderModifier
59
112
  if (quantity === 0) {
60
113
  return null
61
114
  }
62
115
 
63
116
  return {
64
- key: product.id,
65
- name: product.name,
117
+ key: modifierId,
118
+ name: ` - ${modifier?.name || ''}`,
66
119
  quantity: (
67
120
  <div className='quantity'>
68
121
  <div className='multiplier'>x</div>
@@ -80,15 +133,33 @@ export const useTableData = ({
80
133
 
81
134
  return productCategories.reduce(
82
135
  (previousValues: StaticTableData[], categoryId) => {
83
- const products = order.products.filter(
136
+ const productsForCategory = order?.products.filter(
84
137
  (product) => product.productCategoryId === categoryId,
85
138
  )
86
139
 
140
+ const products = order.orderProducts.filter((el) =>
141
+ productsForCategory
142
+ .map((product) => product.id)
143
+ .includes(el.productId),
144
+ )
145
+
87
146
  if (!products.length) {
88
147
  return previousValues
89
148
  }
90
-
91
- const filteredProducts = products.map(renderProductItem).filter(Boolean)
149
+ const productsWithReworkedModifier = products.map((product) => {
150
+ if (!product.orderProductModifiers.length) return product
151
+ return reworkProductStructure(product)
152
+ })
153
+
154
+ const filteredProducts = flatten(productsWithReworkedModifier).map(
155
+ (product) =>
156
+ renderProductItem({ product , productsForCategory }),
157
+ )
158
+
159
+ const productWithModifier = flatMap(filteredProducts, (item) => [
160
+ item,
161
+ ...item.modifier,
162
+ ])
92
163
 
93
164
  if (!filteredProducts.length) {
94
165
  return previousValues
@@ -96,8 +167,8 @@ export const useTableData = ({
96
167
 
97
168
  return [
98
169
  ...previousValues,
99
- renderCategoryItem(products),
100
- ...filteredProducts,
170
+ renderCategoryItem(productsForCategory),
171
+ ...productWithModifier,
101
172
  ]
102
173
  },
103
174
  [],
@@ -133,6 +204,5 @@ export const useTableData = ({
133
204
  // eslint-disable-next-line react-hooks/exhaustive-deps
134
205
  [order, externalDiscount, isPaymentProcessed],
135
206
  )
136
-
137
207
  return data
138
208
  }
@@ -6,6 +6,7 @@ import { Product } from '@licklist/core/dist/DataMapper/Product/ProductDataMappe
6
6
  import { PAYMENT_TYPE_DISCOUNT } from '@licklist/core/dist/DataMapper/Order/PaymentDataMapper'
7
7
  import { PaymentDetail } from '@licklist/core/dist/DataMapper/Order/PaymentDetailDataMapper'
8
8
  import { PAYMENT_TYPE_TRANSLATE_KEYS } from '../hooks/useTableData'
9
+ import { OrderModifier } from '@licklist/core/dist/DataMapper/Order/OrderModifierDataMapper'
9
10
 
10
11
  const TRANSLATE_KEYS = {
11
12
  totalAmount: 'totalPaid',
@@ -28,6 +29,7 @@ export const calculateTotalPrice = (
28
29
  order: Order,
29
30
  externalPaymentDetails?: ExternalPaymnetDetail[],
30
31
  ) => {
32
+
31
33
  const totalPrice =
32
34
  order?.orderProducts?.reduce(
33
35
  (total: number, product) =>
@@ -125,5 +127,26 @@ export const getTotalSumByCategory = (
125
127
  product,
126
128
  )
127
129
 
130
+ const modifierFromProduct = orderProducts.find(
131
+ (orderProduct) => orderProduct.productId === product.id,
132
+ )?.orderProductModifiers
133
+ if (modifierFromProduct) {
134
+ const modifierPrice = modifierFromProduct.reduce(
135
+ (prevSum: number, { modifiers }) => {
136
+ const modifiersPrices = modifiers.reduce(
137
+ (prevSumModifier: number, modifier: OrderModifier) =>
138
+ prevSumModifier + modifier.price * modifier.quantity,
139
+ 0,
140
+ )
141
+
142
+ return prevSum + modifiersPrices
143
+ },
144
+ 0,
145
+ )
146
+ const priceWithModifier = price + modifierPrice
147
+
148
+ return prevSum + priceWithModifier * quantity
149
+ }
150
+
128
151
  return prevSum + price * quantity
129
152
  }, 0)