@eventlook/sdk 1.5.0-beta.6 → 1.5.0-beta.7

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 (80) hide show
  1. package/.claude/settings.local.json +2 -1
  2. package/.env.example +1 -0
  3. package/README.md +18 -16
  4. package/dist/cjs/{index-DvUR1fp8.js → index-BAfaeq84.js} +3230 -554
  5. package/dist/cjs/index-BAfaeq84.js.map +1 -0
  6. package/dist/cjs/index.js +2 -2
  7. package/dist/cjs/{index.umd-6SU6nkkJ.js → index.umd-Bpwd9vUs.js} +9 -19
  8. package/dist/cjs/index.umd-Bpwd9vUs.js.map +1 -0
  9. package/dist/esm/{index-BlTqx0jm.js → index-CJ_gPli9.js} +3217 -540
  10. package/dist/esm/index-CJ_gPli9.js.map +1 -0
  11. package/dist/esm/index.js +2 -2
  12. package/dist/esm/{index.umd-Dn0hjh7E.js → index.umd-ewNTELOK.js} +9 -19
  13. package/dist/esm/index.umd-ewNTELOK.js.map +1 -0
  14. package/dist/types/components/hook-form/FormProvider.d.ts +2 -1
  15. package/dist/types/form/PaymentOverviewBox.d.ts +2 -0
  16. package/dist/types/form/PaymentOverviewDrawer.d.ts +10 -0
  17. package/dist/types/form/TicketForm.d.ts +1 -0
  18. package/dist/types/form/index.d.ts +2 -1
  19. package/dist/types/form/merchandise/MerchandiseSelection.d.ts +9 -0
  20. package/dist/types/form/merchandise/MerchandiseSlider.d.ts +10 -0
  21. package/dist/types/form/payment/PaymentOverviewCheckbox.d.ts +0 -4
  22. package/dist/types/form/product/ProductVariantsDialog.d.ts +2 -1
  23. package/dist/types/form/services/index.d.ts +7 -0
  24. package/dist/types/form/style.d.ts +1 -0
  25. package/dist/types/form/tickets/ReleaseDescription.d.ts +10 -0
  26. package/dist/types/form/tickets/ReleaseWithMerchandise.d.ts +12 -0
  27. package/dist/types/form/tickets/TicketQuantityControl.d.ts +13 -0
  28. package/dist/types/form/tickets/TicketSelectionMobile.d.ts +17 -0
  29. package/dist/types/hooks/useScrollToFirstError.d.ts +4 -0
  30. package/dist/types/locales/cs.d.ts +22 -0
  31. package/dist/types/locales/en.d.ts +22 -0
  32. package/dist/types/locales/es.d.ts +22 -0
  33. package/dist/types/locales/pl.d.ts +22 -0
  34. package/dist/types/locales/sk.d.ts +22 -0
  35. package/dist/types/locales/uk.d.ts +22 -0
  36. package/dist/types/utils/data/global.d.ts +1 -0
  37. package/package.json +10 -4
  38. package/rollup.config.mjs +7 -12
  39. package/src/components/hook-form/FormProvider.tsx +5 -2
  40. package/src/form/ChildEventDialog.tsx +3 -3
  41. package/src/form/ContactPerson.tsx +1 -1
  42. package/src/form/PaymentOverviewBox.tsx +96 -123
  43. package/src/form/PaymentOverviewDrawer.tsx +446 -0
  44. package/src/form/PaymentPending.tsx +19 -4
  45. package/src/form/ReleaseWithMerchandise.tsx +4 -4
  46. package/src/form/Shipping.tsx +91 -74
  47. package/src/form/TicketForm.tsx +144 -41
  48. package/src/form/index.tsx +3 -1
  49. package/src/form/merchandise/MerchandiseSelection.tsx +24 -0
  50. package/src/form/merchandise/MerchandiseSlider.tsx +62 -0
  51. package/src/form/payment/FeeBox.tsx +4 -31
  52. package/src/form/payment/PaymentOverviewCheckbox.tsx +57 -56
  53. package/src/form/product/ProductCard.tsx +255 -59
  54. package/src/form/product/ProductVariantsDialog.tsx +271 -141
  55. package/src/form/services/index.tsx +263 -0
  56. package/src/form/style.ts +16 -4
  57. package/src/form/tickets/ReleaseDescription.tsx +46 -0
  58. package/src/form/tickets/ReleaseWithMerchandise.tsx +231 -0
  59. package/src/form/tickets/TicketQuantityControl.tsx +100 -0
  60. package/src/form/{TicketSelection.tsx → tickets/TicketSelection.tsx} +24 -128
  61. package/src/form/{TicketSelectionMap.tsx → tickets/TicketSelectionMap.tsx} +9 -1
  62. package/src/form/tickets/TicketSelectionMobile.tsx +177 -0
  63. package/src/form/{TicketWithMerchandiseSelection.tsx → tickets/TicketWithMerchandiseSelection.tsx} +3 -7
  64. package/src/hooks/useScrollToFirstError.ts +99 -0
  65. package/src/locales/cs.tsx +25 -3
  66. package/src/locales/en.tsx +23 -1
  67. package/src/locales/es.tsx +23 -1
  68. package/src/locales/pl.tsx +23 -1
  69. package/src/locales/sk.tsx +24 -2
  70. package/src/locales/uk.tsx +23 -1
  71. package/src/utils/data/global.ts +1 -0
  72. package/tsconfig.json +1 -1
  73. package/README +0 -1
  74. package/dist/cjs/index-DvUR1fp8.js.map +0 -1
  75. package/dist/cjs/index.umd-6SU6nkkJ.js.map +0 -1
  76. package/dist/esm/index-BlTqx0jm.js.map +0 -1
  77. package/dist/esm/index.umd-Dn0hjh7E.js.map +0 -1
  78. /package/dist/types/form/{TicketSelection.d.ts → tickets/TicketSelection.d.ts} +0 -0
  79. /package/dist/types/form/{TicketSelectionMap.d.ts → tickets/TicketSelectionMap.d.ts} +0 -0
  80. /package/dist/types/form/{TicketWithMerchandiseSelection.d.ts → tickets/TicketWithMerchandiseSelection.d.ts} +0 -0
@@ -0,0 +1,446 @@
1
+ import { Box, Button, SwipeableDrawer, Typography } from '@mui/material';
2
+ import React, { useEffect } from 'react';
3
+ import { useRef, useState } from 'react';
4
+ import PaymentOverviewBox from './PaymentOverviewBox';
5
+ import { IEvent } from '@utils/types/event.type';
6
+ import useGlobal from '@hooks/useGlobal';
7
+ import { fCurrency } from '@utils/formatNumber';
8
+ import { EVENTLOOK_ORDER_FORM_ID } from '@utils/data/global';
9
+
10
+ interface Props {
11
+ event: IEvent;
12
+ totalPrice: number;
13
+ termsAndConditionsRef?: React.RefObject<HTMLElement | null>;
14
+ onOpenChange?: (open: boolean) => void;
15
+ }
16
+
17
+ const swipeAreaWidth = 120;
18
+
19
+ const clearResetPulledPastTimeout = (timeoutRef: { current: number | null }) => {
20
+ if (timeoutRef.current !== null) {
21
+ window.clearTimeout(timeoutRef.current);
22
+ timeoutRef.current = null;
23
+ }
24
+ };
25
+
26
+ const PaymentOverviewDrawer: React.FC<Props> = ({
27
+ event,
28
+ totalPrice,
29
+ termsAndConditionsRef,
30
+ onOpenChange,
31
+ }) => {
32
+ const { t, lang } = useGlobal();
33
+ const [isDrawerOpened, setIsDrawerOpened] = useState(false);
34
+ const [isOpeningGesture, setIsOpeningGesture] = useState(false);
35
+ const [hasPulledPastClosedTabHeight, setHasPulledPastClosedTabHeight] = useState(false);
36
+ const [isDrawerHidden, setIsDrawerHidden] = useState(false);
37
+ const [closedTabHeight, setClosedTabHeight] = useState(0);
38
+ const openingTouchStartYRef = useRef<number | null>(null);
39
+ const openDrawerRef = useRef(false);
40
+ const isOpeningGestureRef = useRef(false);
41
+ const shouldReopenOnScrollUpRef = useRef(false);
42
+ const lastScrollYRef = useRef(0);
43
+ const isScrollingDownRef = useRef(false);
44
+ const wasAtPageBottomRef = useRef(false);
45
+ const resetPulledPastTimeoutRef = useRef<number | null>(null);
46
+ const closedTabRef = useRef<HTMLDivElement>(null);
47
+
48
+ useEffect(() => {
49
+ openDrawerRef.current = isDrawerOpened;
50
+ }, [isDrawerOpened]);
51
+
52
+ useEffect(() => {
53
+ isOpeningGestureRef.current = isOpeningGesture;
54
+ }, [isOpeningGesture]);
55
+
56
+ // reopens the drawer when user scrolls up and the drawer was closed by scrolling down to the bottom of the page
57
+ useEffect(() => {
58
+ if (typeof window === 'undefined') {
59
+ return;
60
+ }
61
+
62
+ const atBottomThreshold = 8;
63
+ lastScrollYRef.current = window.scrollY;
64
+ isScrollingDownRef.current = false;
65
+ wasAtPageBottomRef.current =
66
+ window.innerHeight + window.scrollY >=
67
+ document.documentElement.scrollHeight - atBottomThreshold;
68
+
69
+ const handleScroll = () => {
70
+ const currentY = window.scrollY;
71
+ const isScrollingUp = currentY < lastScrollYRef.current;
72
+ const isScrollingDown = currentY > lastScrollYRef.current;
73
+ const isAtPageBottom =
74
+ window.innerHeight + currentY >= document.documentElement.scrollHeight - atBottomThreshold;
75
+
76
+ isScrollingDownRef.current = isScrollingDown;
77
+
78
+ if (
79
+ isScrollingUp &&
80
+ wasAtPageBottomRef.current &&
81
+ shouldReopenOnScrollUpRef.current &&
82
+ !openDrawerRef.current
83
+ ) {
84
+ shouldReopenOnScrollUpRef.current = false;
85
+ setIsDrawerHidden(false);
86
+ openDrawerHandler();
87
+ }
88
+
89
+ wasAtPageBottomRef.current = isAtPageBottom;
90
+ lastScrollYRef.current = currentY;
91
+ };
92
+
93
+ window.addEventListener('scroll', handleScroll, { passive: true });
94
+
95
+ return () => {
96
+ window.removeEventListener('scroll', handleScroll);
97
+ };
98
+ }, []);
99
+
100
+ useEffect(() => {
101
+ const closedTab = closedTabRef.current;
102
+ if (!closedTab) return;
103
+
104
+ const updateClosedTabHeight = () => {
105
+ setClosedTabHeight(closedTab.offsetHeight);
106
+ };
107
+
108
+ updateClosedTabHeight();
109
+
110
+ const resizeObserver = new ResizeObserver(() => {
111
+ updateClosedTabHeight();
112
+ });
113
+
114
+ resizeObserver.observe(closedTab);
115
+
116
+ return () => {
117
+ resizeObserver.disconnect();
118
+ };
119
+ }, []);
120
+
121
+ useEffect(
122
+ () => () => {
123
+ clearResetPulledPastTimeout(resetPulledPastTimeoutRef);
124
+ },
125
+ []
126
+ );
127
+
128
+ useEffect(() => {
129
+ const termsAndConditionsElement = termsAndConditionsRef?.current;
130
+ if (!termsAndConditionsElement) {
131
+ return;
132
+ }
133
+
134
+ if (!('IntersectionObserver' in window)) {
135
+ return;
136
+ }
137
+
138
+ const observer = new IntersectionObserver(
139
+ (entries) => {
140
+ const entry = entries[0];
141
+ const hasReachedTermsSection = entry?.isIntersecting ?? false;
142
+ const shouldAutoCloseDrawer = hasReachedTermsSection;
143
+ const shouldHideDrawerTab =
144
+ hasReachedTermsSection && !openDrawerRef.current && !isOpeningGestureRef.current;
145
+ setIsDrawerHidden(shouldHideDrawerTab);
146
+
147
+ if (shouldAutoCloseDrawer && openDrawerRef.current && isScrollingDownRef.current) {
148
+ closeDrawerHandler({ shouldReopenOnScrollUp: true });
149
+ setIsDrawerHidden(true);
150
+ }
151
+ },
152
+ {
153
+ root: null,
154
+ threshold: 0,
155
+ rootMargin: '0px 0px -40% 0px',
156
+ }
157
+ );
158
+
159
+ observer.observe(termsAndConditionsElement);
160
+
161
+ return () => {
162
+ observer.disconnect();
163
+ };
164
+ }, [termsAndConditionsRef]);
165
+
166
+ const toggleDrawer = () => {
167
+ if (openDrawerRef.current) {
168
+ closeDrawerHandler();
169
+ return;
170
+ }
171
+
172
+ openDrawerHandler();
173
+ };
174
+
175
+ const openDrawerHandler = () => {
176
+ clearResetPulledPastTimeout(resetPulledPastTimeoutRef);
177
+ setIsOpeningGesture(false);
178
+ setHasPulledPastClosedTabHeight(false);
179
+ openingTouchStartYRef.current = null;
180
+ shouldReopenOnScrollUpRef.current = false;
181
+ setIsDrawerOpened(true);
182
+ onOpenChange?.(true);
183
+ };
184
+
185
+ const closeDrawerHandler = ({
186
+ shouldReopenOnScrollUp = false,
187
+ }: { shouldReopenOnScrollUp?: boolean } = {}) => {
188
+ clearResetPulledPastTimeout(resetPulledPastTimeoutRef);
189
+ setIsOpeningGesture(false);
190
+ setHasPulledPastClosedTabHeight(false);
191
+ openingTouchStartYRef.current = null;
192
+ shouldReopenOnScrollUpRef.current = shouldReopenOnScrollUp;
193
+ setIsDrawerOpened(false);
194
+ onOpenChange?.(false);
195
+ };
196
+
197
+ const scheduleResetPulledPastTimeout = () => {
198
+ clearResetPulledPastTimeout(resetPulledPastTimeoutRef);
199
+ resetPulledPastTimeoutRef.current = window.setTimeout(() => {
200
+ if (!openDrawerRef.current) {
201
+ setHasPulledPastClosedTabHeight(false);
202
+ }
203
+ }, 180);
204
+ };
205
+
206
+ const handleGestureStart = (startY: number | null) => {
207
+ openingTouchStartYRef.current = startY;
208
+ setIsOpeningGesture(true);
209
+ setHasPulledPastClosedTabHeight(false);
210
+ };
211
+
212
+ const handleGestureMove = (currentY?: number) => {
213
+ if (!isOpeningGestureRef.current) return;
214
+
215
+ const startY = openingTouchStartYRef.current;
216
+ if (startY === null || typeof currentY !== 'number') return;
217
+
218
+ const pullDistance = startY - currentY;
219
+ const currentClosedTabHeight = closedTabRef.current?.offsetHeight ?? 0;
220
+ setHasPulledPastClosedTabHeight(
221
+ currentClosedTabHeight > 0 && pullDistance >= currentClosedTabHeight
222
+ );
223
+ };
224
+
225
+ const handleGestureCancel = () => {
226
+ openingTouchStartYRef.current = null;
227
+ setIsOpeningGesture(false);
228
+ setHasPulledPastClosedTabHeight(false);
229
+ };
230
+
231
+ const handleGestureEnd = ({
232
+ shouldResetTouchStart = false,
233
+ }: { shouldResetTouchStart?: boolean } = {}) => {
234
+ if (shouldResetTouchStart) {
235
+ openingTouchStartYRef.current = null;
236
+ }
237
+
238
+ if (!isDrawerOpened) {
239
+ setIsOpeningGesture(false);
240
+ scheduleResetPulledPastTimeout();
241
+ }
242
+ };
243
+
244
+ return (
245
+ <Box sx={{ display: { md: 'none' } }}>
246
+ {/* Drawer Tab */}
247
+ <Box
248
+ ref={closedTabRef}
249
+ sx={{
250
+ position: 'fixed',
251
+ bottom: 0,
252
+ left: 0,
253
+ right: 0,
254
+ backgroundColor: (theme) => theme.palette.background.paper,
255
+ borderTopLeftRadius: isOpeningGesture || isDrawerOpened ? 0 : 16,
256
+ borderTopRightRadius: isOpeningGesture || isDrawerOpened ? 0 : 16,
257
+ boxShadow:
258
+ isOpeningGesture || isDrawerOpened ? 'none' : '0 -8px 10px 2px rgba(0,0,0,0.2)',
259
+ zIndex: (theme) => theme.zIndex.drawer + 1,
260
+ opacity: isDrawerHidden ? 0 : 1,
261
+ transform: isDrawerHidden ? 'translateY(calc(100% + 12px))' : 'translateY(0)',
262
+ transition:
263
+ 'opacity 180ms ease, transform 180ms ease, border-radius 120ms ease, box-shadow 120ms ease',
264
+ pointerEvents: 'none',
265
+ }}
266
+ >
267
+ {!isDrawerOpened && (
268
+ <Box
269
+ sx={{
270
+ display: 'flex',
271
+ justifyContent: 'center',
272
+ alignItems: 'center',
273
+ width: '100%',
274
+ py: 1,
275
+ }}
276
+ >
277
+ <Box
278
+ sx={{
279
+ width: 80,
280
+ height: 6,
281
+ backgroundColor: (theme) => theme.palette.grey[300],
282
+ borderRadius: 3,
283
+ opacity: isOpeningGesture ? 0 : 1,
284
+ transition: 'opacity 120ms ease',
285
+ }}
286
+ />
287
+ </Box>
288
+ )}
289
+ <Box
290
+ role="button"
291
+ aria-label={t('form.labels.payment_overview_open')}
292
+ onClick={toggleDrawer}
293
+ onTouchStart={(event: React.TouchEvent<HTMLDivElement>) => {
294
+ handleGestureStart(event.touches[0]?.clientY ?? null);
295
+ }}
296
+ onMouseDown={() => {
297
+ handleGestureStart(null);
298
+ }}
299
+ onTouchMove={(event: React.TouchEvent<HTMLDivElement>) => {
300
+ handleGestureMove(event.touches[0]?.clientY);
301
+ }}
302
+ onTouchCancel={handleGestureCancel}
303
+ onTouchEnd={() => {
304
+ handleGestureEnd({ shouldResetTouchStart: true });
305
+ }}
306
+ onMouseUp={() => {
307
+ handleGestureEnd();
308
+ }}
309
+ sx={{
310
+ width: '100%',
311
+ px: 2,
312
+ pb: 2,
313
+ pointerEvents: isDrawerOpened || isDrawerHidden ? 'none' : 'auto',
314
+ cursor: 'pointer',
315
+ }}
316
+ >
317
+ <Typography
318
+ sx={{
319
+ fontWeight: 'bold',
320
+ display: 'flex',
321
+ justifyContent: 'space-between',
322
+ alignItems: 'center',
323
+ }}
324
+ >
325
+ <span>{t('form.labels.total')}:</span>
326
+ <span>{fCurrency(totalPrice, lang, event.currency)}</span>
327
+ </Typography>
328
+
329
+ <Button
330
+ type="submit"
331
+ form={EVENTLOOK_ORDER_FORM_ID}
332
+ onClick={(event) => {
333
+ event.stopPropagation();
334
+ }}
335
+ variant="contained"
336
+ size="large"
337
+ fullWidth
338
+ sx={{ mt: 1, height: { xs: 36, md: 40 } }}
339
+ >
340
+ {t('buy')}
341
+ </Button>
342
+ </Box>
343
+ </Box>
344
+
345
+ {/* Drawer Content */}
346
+ <SwipeableDrawer
347
+ anchor="bottom"
348
+ open={isDrawerOpened}
349
+ onClose={() => closeDrawerHandler()}
350
+ onOpen={() => openDrawerHandler()}
351
+ swipeAreaWidth={swipeAreaWidth}
352
+ allowSwipeInChildren
353
+ disableSwipeToOpen={isDrawerHidden}
354
+ keepMounted
355
+ SwipeAreaProps={{
356
+ onTouchStart: (event: React.TouchEvent<HTMLDivElement>) => {
357
+ handleGestureStart(event.touches[0]?.clientY ?? null);
358
+ },
359
+ onMouseDown: () => {
360
+ handleGestureStart(null);
361
+ },
362
+ onTouchMove: (event: React.TouchEvent<HTMLDivElement>) => {
363
+ handleGestureMove(event.touches[0]?.clientY);
364
+ },
365
+ onTouchCancel: handleGestureCancel,
366
+ onTouchEnd: () => {
367
+ handleGestureEnd({ shouldResetTouchStart: true });
368
+ },
369
+ onMouseUp: () => {
370
+ handleGestureEnd();
371
+ },
372
+ }}
373
+ sx={{
374
+ display: { md: 'none' },
375
+ pointerEvents: isDrawerOpened ? 'none' : 'auto',
376
+ '& .MuiDrawer-paper': {
377
+ pointerEvents: 'auto',
378
+ },
379
+ '& .MuiSwipeArea-root': {
380
+ pointerEvents: 'auto',
381
+ },
382
+ }}
383
+ ModalProps={{
384
+ disableScrollLock: true,
385
+ keepMounted: false,
386
+ disableAutoFocus: true,
387
+ disableRestoreFocus: true,
388
+ disableEnforceFocus: true,
389
+ BackdropProps: {
390
+ sx: {
391
+ background: 'none',
392
+ pointerEvents: 'none',
393
+ },
394
+ },
395
+ }}
396
+ PaperProps={{
397
+ sx: {
398
+ borderTopLeftRadius: 16,
399
+ borderTopRightRadius: 16,
400
+ boxShadow: '0 -8px 10px 2px rgba(0,0,0,0.2)',
401
+ overflow: 'hidden',
402
+ mb:
403
+ isDrawerOpened ||
404
+ (!isDrawerOpened && (isOpeningGesture || hasPulledPastClosedTabHeight))
405
+ ? `${closedTabHeight}px`
406
+ : 0,
407
+ transition: 'none',
408
+ },
409
+ }}
410
+ >
411
+ <Box
412
+ role="button"
413
+ aria-label={t('form.labels.payment_overview_close')}
414
+ onClick={toggleDrawer}
415
+ sx={{
416
+ display: 'flex',
417
+ justifyContent: 'center',
418
+ alignItems: 'center',
419
+ backgroundColor: (theme) => theme.palette.background.paper,
420
+ cursor: 'pointer',
421
+ py: 1,
422
+ }}
423
+ >
424
+ <Box
425
+ sx={{
426
+ width: 80,
427
+ height: 6,
428
+ backgroundColor: (theme) => theme.palette.grey[300],
429
+ borderRadius: 3,
430
+ }}
431
+ />
432
+ </Box>
433
+ <Box
434
+ sx={{
435
+ height: '100%',
436
+ overflow: 'auto',
437
+ }}
438
+ >
439
+ <PaymentOverviewBox event={event} hideBuyButton />
440
+ </Box>
441
+ </SwipeableDrawer>
442
+ </Box>
443
+ );
444
+ };
445
+
446
+ export default PaymentOverviewDrawer;
@@ -1,4 +1,4 @@
1
- import React, { lazy, Suspense } from 'react';
1
+ import React, { lazy, useEffect, useState } from 'react';
2
2
  import { Box, Typography } from '@mui/material';
3
3
  import bankTransferAnimation from '../utils/data/lottie/bank-transfer.json';
4
4
  import { varBounce } from '@components/animate';
@@ -9,6 +9,23 @@ const Lottie = lazy(() => import('lottie-react'));
9
9
 
10
10
  const PaymentPending: React.FC = () => {
11
11
  const { t } = useGlobal();
12
+ const [LottieComponent, setLottieComponent] = useState<React.ComponentType<any> | null>(null);
13
+
14
+ useEffect(() => {
15
+ if (typeof window === 'undefined') return;
16
+
17
+ let isMounted = true;
18
+
19
+ import('lottie-react').then((module) => {
20
+ if (isMounted) {
21
+ setLottieComponent(() => module.default);
22
+ }
23
+ });
24
+
25
+ return () => {
26
+ isMounted = false;
27
+ };
28
+ }, []);
12
29
 
13
30
  return (
14
31
  <Box textAlign="center">
@@ -18,9 +35,7 @@ const PaymentPending: React.FC = () => {
18
35
  </Typography>
19
36
  </m.div>
20
37
  <Box maxWidth={600} mx="auto">
21
- <Suspense fallback={null}>
22
- <Lottie animationData={bankTransferAnimation} />
23
- </Suspense>
38
+ {LottieComponent ? <LottieComponent animationData={bankTransferAnimation} /> : null}
24
39
  </Box>
25
40
  </Box>
26
41
  );
@@ -52,7 +52,7 @@ const ReleaseWithMerchandise: React.FC<Props> = ({
52
52
  return getSelectedQuantity(releaseId) >= getAvailableTicketsForRelease(release);
53
53
  };
54
54
 
55
- const addRelease = (product?: IEventProductForm) => {
55
+ const addRelease = (variants?: IEventProductForm[]) => {
56
56
  setValue(`tickets.${eventId}`, [
57
57
  ...tickets,
58
58
  {
@@ -60,7 +60,7 @@ const ReleaseWithMerchandise: React.FC<Props> = ({
60
60
  quantity: 1,
61
61
  itemName: '',
62
62
  price: 0,
63
- products: product ? [product] : [],
63
+ products: variants?.length ? variants : [],
64
64
  extraFields: release.extraFields?.length
65
65
  ? [
66
66
  release.extraFields.map((field) => ({
@@ -74,7 +74,7 @@ const ReleaseWithMerchandise: React.FC<Props> = ({
74
74
  setOpenVariantDialog(null);
75
75
  };
76
76
 
77
- const increaseQuantity = (product?: IEventProductForm) => {
77
+ const increaseQuantity = (variants?: IEventProductForm[]) => {
78
78
  const addedRelease = tickets.find((ticket) => ticket.releaseId === release.id);
79
79
  if (addedRelease) {
80
80
  const newQuantity = Number(addedRelease.quantity) + 1;
@@ -86,7 +86,7 @@ const ReleaseWithMerchandise: React.FC<Props> = ({
86
86
  ? {
87
87
  ...ticket,
88
88
  quantity: newQuantity > maxQuantity ? maxQuantity : newQuantity,
89
- products: product ? [...ticket.products, product] : ticket.products,
89
+ products: variants?.length ? [...ticket.products, ...variants] : ticket.products,
90
90
  extraFields: release.extraFields?.length
91
91
  ? [
92
92
  ...ticket.extraFields,