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

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 (135) 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/BookingSummary.d.ts +1 -1
  29. package/dist/iframe/order-process/components/BookingSummary/BookingSummary.d.ts.map +1 -1
  30. package/dist/iframe/order-process/components/BookingSummary/BookingSummary.js +2 -1
  31. package/dist/iframe/order-process/components/BookingSummary/components/ProductSummary/ProductSummary.d.ts.map +1 -1
  32. package/dist/iframe/order-process/components/BookingSummary/components/ProductSummary/ProductSummary.js +15 -2
  33. package/dist/iframe/order-process/components/BookingSummary/types/index.d.ts +1 -0
  34. package/dist/iframe/order-process/components/BookingSummary/types/index.d.ts.map +1 -1
  35. package/dist/iframe/order-process/components/BookingSummary/utils/index.d.ts +4 -0
  36. package/dist/iframe/order-process/components/BookingSummary/utils/index.d.ts.map +1 -1
  37. package/dist/iframe/order-process/components/BookingSummary/utils/index.js +29 -2
  38. package/dist/iframe/order-process/components/CategoryProduct/CategoryProduct.d.ts.map +1 -1
  39. package/dist/iframe/order-process/components/CategoryProduct/CategoryProduct.js +106 -2
  40. package/dist/iframe/order-process/components/CategoryProduct/components/ProductQuantityInput/ProductQuantityInput.d.ts +3 -1
  41. package/dist/iframe/order-process/components/CategoryProduct/components/ProductQuantityInput/ProductQuantityInput.d.ts.map +1 -1
  42. package/dist/iframe/order-process/components/CategoryProduct/components/ProductQuantityInput/ProductQuantityInput.js +95 -1
  43. package/dist/iframe/order-process/components/CategoryProduct/components/ProductWithModifier/ProductWithModifier.d.ts +23 -0
  44. package/dist/iframe/order-process/components/CategoryProduct/components/ProductWithModifier/ProductWithModifier.d.ts.map +1 -0
  45. package/dist/iframe/order-process/components/CategoryProduct/components/ProductWithModifier/ProductWithModifier.js +62 -0
  46. package/dist/iframe/order-process/components/CategoryProduct/constants.d.ts +2 -0
  47. package/dist/iframe/order-process/components/CategoryProduct/constants.d.ts.map +1 -0
  48. package/dist/iframe/order-process/components/CategoryProduct/constants.js +4 -0
  49. package/dist/iframe/order-process/components/utils/useOnWindowUnmount.d.ts +6 -0
  50. package/dist/iframe/order-process/components/utils/useOnWindowUnmount.d.ts.map +1 -0
  51. package/dist/iframe/order-process/components/utils/useOnWindowUnmount.js +18 -0
  52. package/dist/iframe/payment/order-items-table/hooks/useTableData.d.ts.map +1 -1
  53. package/dist/iframe/payment/order-items-table/hooks/useTableData.js +83 -10
  54. package/dist/iframe/payment/order-items-table/utils/index.d.ts.map +1 -1
  55. package/dist/iframe/payment/order-items-table/utils/index.js +15 -0
  56. package/dist/iframe/payment/order-items-table/utils/paymentSummary.js +2 -2
  57. package/dist/iframe/payment/payment-page/PaymentPage.d.ts.map +1 -1
  58. package/dist/iframe/payment/payment-page/PaymentPage.js +4 -1
  59. package/dist/index.js +1 -1
  60. package/dist/product-set/form/ProductSetForm.d.ts +3 -1
  61. package/dist/product-set/form/ProductSetForm.d.ts.map +1 -1
  62. package/dist/product-set/form/ProductSetForm.js +6 -4
  63. package/dist/product-set/form/ProductsControl.d.ts.map +1 -1
  64. package/dist/product-set/form/ProductsControl.js +24 -5
  65. package/dist/product-set/form/context.d.ts +3 -1
  66. package/dist/product-set/form/context.d.ts.map +1 -1
  67. package/dist/product-set/form/context.js +2 -1
  68. package/dist/product-set/product/ProductControl.d.ts +8 -0
  69. package/dist/product-set/product/ProductControl.d.ts.map +1 -1
  70. package/dist/product-set/product/ProductControl.js +25 -1
  71. package/dist/product-set/utils/index.d.ts +88 -0
  72. package/dist/product-set/utils/index.d.ts.map +1 -1
  73. package/dist/product-set/utils/index.js +19 -1
  74. package/dist/report/ReportRunnerModal/ReportRunnerModal.d.ts +1 -1
  75. package/dist/report/ReportRunnerModal/ReportRunnerModal.d.ts.map +1 -1
  76. package/dist/sales/coupon/utils/index.d.ts +2 -1
  77. package/dist/sales/coupon/utils/index.d.ts.map +1 -1
  78. package/dist/sales/modals/refund-modal/RefundModal.d.ts +6 -2
  79. package/dist/sales/modals/refund-modal/RefundModal.d.ts.map +1 -1
  80. package/dist/sales/modals/refund-modal/RefundModal.js +8 -4
  81. package/dist/sales/modals/refund-modal/index.d.ts +2 -2
  82. package/dist/sales/modals/refund-modal/index.d.ts.map +1 -1
  83. package/dist/styles/date-time-button/DateTimeButton.scss +8 -1
  84. package/dist/styles/events/EditEventModal.scss +2 -0
  85. package/dist/styles/iframe-page/Page.scss +16 -0
  86. package/dist/styles/iframe-page/PageBody.scss +4 -0
  87. package/dist/styles/modals/Modals.scss +16 -0
  88. package/dist/styles/product-set/EditProductSetElement.scss +1 -0
  89. package/dist/styles/product-set/ProductSetForm.scss +11 -0
  90. package/dist/styles/sales/ManualBooking.scss +6 -0
  91. package/dist/styles/themes/bookedit/index.scss +19 -0
  92. package/package.json +6 -6
  93. package/src/events/event-statistic-modal/utils/index.ts +4 -4
  94. package/src/iframe/ProductWithModifierModal/ModifierSetModal/ProductWithModifierSetForm.tsx +212 -0
  95. package/src/iframe/ProductWithModifierModal/ModifierSetModal/ProductWithModifierSetModal.tsx +75 -0
  96. package/src/iframe/ProductWithModifierModal/ModifierSetModal/controll/ModifierSetControll.tsx +393 -0
  97. package/src/iframe/ProductWithModifierModal/ModifierSetModal/controll/ProductControll.tsx +98 -0
  98. package/src/iframe/ProductWithModifierModal/ModifierSetModal/index.ts +1 -0
  99. package/src/iframe/ProductWithModifierModal/index.ts +1 -0
  100. package/src/iframe/ProductWithModifierModal/utils.ts +29 -0
  101. package/src/iframe/activity-card/ActivityCard.stories.tsx +0 -2
  102. package/src/iframe/activity-card/ActivityCard.tsx +0 -4
  103. package/src/iframe/event/ticket-description/TicketDescription.tsx +5 -3
  104. package/src/iframe/order-process/components/BookingSummary/BookingSummary.tsx +2 -0
  105. package/src/iframe/order-process/components/BookingSummary/components/ProductSummary/ProductSummary.tsx +21 -1
  106. package/src/iframe/order-process/components/BookingSummary/types/index.ts +1 -0
  107. package/src/iframe/order-process/components/BookingSummary/utils/index.ts +42 -1
  108. package/src/iframe/order-process/components/CategoryProduct/CategoryProduct.tsx +155 -75
  109. package/src/iframe/order-process/components/CategoryProduct/components/ProductQuantityInput/ProductQuantityInput.tsx +58 -1
  110. package/src/iframe/order-process/components/CategoryProduct/components/ProductWithModifier/ProductWithModifier.tsx +86 -0
  111. package/src/iframe/order-process/components/CategoryProduct/constants.ts +1 -0
  112. package/src/iframe/order-process/components/utils/useOnWindowUnmount.ts +25 -0
  113. package/src/iframe/payment/order-items-table/hooks/useTableData.tsx +84 -14
  114. package/src/iframe/payment/order-items-table/utils/index.ts +23 -0
  115. package/src/iframe/payment/order-items-table/utils/paymentSummary.tsx +2 -2
  116. package/src/iframe/payment/payment-page/PaymentPage.tsx +8 -10
  117. package/src/product-set/form/ProductSetForm.tsx +11 -3
  118. package/src/product-set/form/ProductsControl.tsx +33 -15
  119. package/src/product-set/form/context.tsx +5 -0
  120. package/src/product-set/product/ProductControl.tsx +37 -1
  121. package/src/product-set/utils/index.ts +19 -0
  122. package/src/report/ReportRunnerModal/ReportRunnerModal.tsx +2 -2
  123. package/src/sales/coupon/utils/index.ts +5 -3
  124. package/src/sales/modals/refund-modal/RefundModal.tsx +15 -6
  125. package/src/sales/modals/refund-modal/index.ts +7 -2
  126. package/src/styles/date-time-button/DateTimeButton.scss +8 -1
  127. package/src/styles/events/EditEventModal.scss +2 -0
  128. package/src/styles/iframe-page/Page.scss +16 -0
  129. package/src/styles/iframe-page/PageBody.scss +4 -0
  130. package/src/styles/modals/Modals.scss +16 -0
  131. package/src/styles/product-set/EditProductSetElement.scss +1 -0
  132. package/src/styles/product-set/ProductSetForm.scss +11 -0
  133. package/src/styles/sales/ManualBooking.scss +6 -0
  134. package/src/styles/themes/bookedit/index.scss +19 -0
  135. package/yarn.lock +334 -333
@@ -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 ? (
@@ -17,6 +17,7 @@ export const BookingSummary = ({
17
17
  formValues = {},
18
18
  shouldHidePeopleAmount,
19
19
  eventName,
20
+ headerTitle,
20
21
  transactionFee = 0,
21
22
  productsWithErrors = [],
22
23
  isLoading,
@@ -43,6 +44,7 @@ export const BookingSummary = ({
43
44
  <BookingSummaryAccordion
44
45
  isPaymentPage={isPaymentPage}
45
46
  hasPeopleInput={hasPeopleInput}
47
+ title={headerTitle}
46
48
  headerComponent={headerComponent}
47
49
  >
48
50
  <div className='event-info'>
@@ -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
  )}
@@ -24,4 +24,5 @@ export type BookingSummaryProps = {
24
24
  isPaymentPage?: boolean
25
25
  headerComponent?: ReactElement
26
26
  footer?: ReactElement
27
+ headerTitle?: string
27
28
  }
@@ -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
 
@@ -13,6 +17,9 @@ export const cartSumByOrderProducts = ({
13
17
  }
14
18
  return orderProducts.reduce((prevSumValue: number, product) => {
15
19
  if (!product) return 0
20
+ const modifiersPrice = calculateTotalModifiersPrice(
21
+ product?.orderModifiersSets,
22
+ )
16
23
 
17
24
  const price = isTotalSum
18
25
  ? product?.price
@@ -20,10 +27,44 @@ export const cartSumByOrderProducts = ({
20
27
  ? product?.deposit
21
28
  : product?.price
22
29
 
23
- return prevSumValue + price * product.quantity
30
+ return prevSumValue + price * product.quantity + modifiersPrice
24
31
  }, 0)
25
32
  }
26
33
 
34
+ export const getModifierName = (
35
+ modifier: OrderModifierByProduct,
36
+ ) => {
37
+ const modifierName = (orderModifier: OrderModifier) => orderModifier?.modifier?.name ?? orderModifier?.name
38
+ return `${modifier.modifiers.map((item) => (
39
+ item?.quantity > 1 ? `${item?.quantity}x - ${modifierName(item)}` : modifierName(item))).join(', ')}`
40
+ }
41
+
42
+ export const calculateTotalModifiersPrice = (
43
+ orderModifiersSets: OrderModifierByProduct[],
44
+ ) =>
45
+ orderModifiersSets
46
+ ?.map((set) =>
47
+ set.modifiers.reduce(
48
+ (sum, modifier) =>
49
+ sum + modifier.price * modifier.quantity * set.productQuantity,
50
+ 0,
51
+ ),
52
+ )
53
+ .reduce((total, setTotal) => total + setTotal, 0)
54
+
55
+ export const getOrderProductModifiersPrice = (
56
+ modifierFromProduct: OrderModifierByProduct,
57
+ ) => {
58
+ const { modifiers, productQuantity } = modifierFromProduct
59
+ const modifiersPrices = modifiers.reduce(
60
+ (prevSumModifier: number, modifier: OrderModifier) =>
61
+ prevSumModifier + modifier.price * modifier.quantity,
62
+ 0,
63
+ )
64
+
65
+ return modifiersPrices * productQuantity
66
+ }
67
+
27
68
  export const getProductError = (
28
69
  productsWithErrors: QuantityCheckProductInfo[],
29
70
  productId: OrderItem['id'],
@@ -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
  }