@eventlook/sdk 1.4.50 → 1.4.51

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 (119) hide show
  1. package/dist/cjs/_virtual/_commonjsHelpers.js +8 -0
  2. package/dist/cjs/_virtual/_commonjsHelpers.js.map +1 -0
  3. package/dist/cjs/_virtual/index.js +6 -0
  4. package/dist/cjs/_virtual/index.js.map +1 -0
  5. package/dist/cjs/_virtual/index2.js +6 -0
  6. package/dist/cjs/_virtual/index2.js.map +1 -0
  7. package/dist/cjs/_virtual/index3.js +6 -0
  8. package/dist/cjs/_virtual/index3.js.map +1 -0
  9. package/dist/cjs/_virtual/react-is.development.js +6 -0
  10. package/dist/cjs/_virtual/react-is.development.js.map +1 -0
  11. package/dist/cjs/_virtual/react-is.development2.js +6 -0
  12. package/dist/cjs/_virtual/react-is.development2.js.map +1 -0
  13. package/dist/cjs/_virtual/react-is.production.js +6 -0
  14. package/dist/cjs/_virtual/react-is.production.js.map +1 -0
  15. package/dist/cjs/_virtual/react-is.production.min.js +6 -0
  16. package/dist/cjs/_virtual/react-is.production.min.js.map +1 -0
  17. package/dist/cjs/form/ReleaseWithMerchandise.js +57 -48
  18. package/dist/cjs/form/ReleaseWithMerchandise.js.map +1 -1
  19. package/dist/cjs/form/TicketForm.js +1 -1
  20. package/dist/cjs/form/TicketForm.js.map +1 -1
  21. package/dist/cjs/form/TicketQuantityControl.js +51 -0
  22. package/dist/cjs/form/TicketQuantityControl.js.map +1 -0
  23. package/dist/cjs/form/TicketSelection.js +5 -6
  24. package/dist/cjs/form/TicketSelection.js.map +1 -1
  25. package/dist/cjs/form/TicketSelectionMobile.js +98 -0
  26. package/dist/cjs/form/TicketSelectionMobile.js.map +1 -0
  27. package/dist/cjs/form/TicketWithMerchandiseSelection.js +3 -5
  28. package/dist/cjs/form/TicketWithMerchandiseSelection.js.map +1 -1
  29. package/dist/cjs/form/merchendise/MerchandiseSelection.js +19 -0
  30. package/dist/cjs/form/merchendise/MerchandiseSelection.js.map +1 -0
  31. package/dist/cjs/form/merchendise/MerchandiseSlider.js +75 -0
  32. package/dist/cjs/form/merchendise/MerchandiseSlider.js.map +1 -0
  33. package/dist/cjs/form/product/ProductCard.js +3 -2
  34. package/dist/cjs/form/product/ProductCard.js.map +1 -1
  35. package/dist/cjs/form/product/ProductVariantsDialog.js +23 -8
  36. package/dist/cjs/form/product/ProductVariantsDialog.js.map +1 -1
  37. package/dist/cjs/form/tickets/ReleaseWithMerchandise.js +30 -7
  38. package/dist/cjs/form/tickets/ReleaseWithMerchandise.js.map +1 -1
  39. package/dist/cjs/form/tickets/TicketSelection.js +37 -14
  40. package/dist/cjs/form/tickets/TicketSelection.js.map +1 -1
  41. package/dist/cjs/form/tickets/TicketSelectionMap.js +7 -1
  42. package/dist/cjs/form/tickets/TicketSelectionMap.js.map +1 -1
  43. package/dist/cjs/form/tickets/TicketSelectionMobile.js +17 -7
  44. package/dist/cjs/form/tickets/TicketSelectionMobile.js.map +1 -1
  45. package/dist/cjs/form/tickets/TicketWithMerchandiseSelection.js +30 -20
  46. package/dist/cjs/form/tickets/TicketWithMerchandiseSelection.js.map +1 -1
  47. package/dist/cjs/hooks/useConsentScrollOnDrawerOpen.js +59 -0
  48. package/dist/cjs/hooks/useConsentScrollOnDrawerOpen.js.map +1 -0
  49. package/dist/cjs/utils/data/ticket.js +6 -0
  50. package/dist/cjs/utils/data/ticket.js.map +1 -0
  51. package/dist/esm/_virtual/_commonjsHelpers.js +6 -0
  52. package/dist/esm/_virtual/_commonjsHelpers.js.map +1 -0
  53. package/dist/esm/_virtual/index.js +4 -0
  54. package/dist/esm/_virtual/index.js.map +1 -0
  55. package/dist/esm/_virtual/index2.js +4 -0
  56. package/dist/esm/_virtual/index2.js.map +1 -0
  57. package/dist/esm/_virtual/index3.js +4 -0
  58. package/dist/esm/_virtual/index3.js.map +1 -0
  59. package/dist/esm/_virtual/react-is.development.js +4 -0
  60. package/dist/esm/_virtual/react-is.development.js.map +1 -0
  61. package/dist/esm/_virtual/react-is.development2.js +4 -0
  62. package/dist/esm/_virtual/react-is.development2.js.map +1 -0
  63. package/dist/esm/_virtual/react-is.production.js +4 -0
  64. package/dist/esm/_virtual/react-is.production.js.map +1 -0
  65. package/dist/esm/_virtual/react-is.production.min.js +4 -0
  66. package/dist/esm/_virtual/react-is.production.min.js.map +1 -0
  67. package/dist/esm/form/ReleaseWithMerchandise.js +58 -49
  68. package/dist/esm/form/ReleaseWithMerchandise.js.map +1 -1
  69. package/dist/esm/form/TicketForm.js +1 -1
  70. package/dist/esm/form/TicketForm.js.map +1 -1
  71. package/dist/esm/form/TicketQuantityControl.js +47 -0
  72. package/dist/esm/form/TicketQuantityControl.js.map +1 -0
  73. package/dist/esm/form/TicketSelection.js +5 -6
  74. package/dist/esm/form/TicketSelection.js.map +1 -1
  75. package/dist/esm/form/TicketSelectionMobile.js +94 -0
  76. package/dist/esm/form/TicketSelectionMobile.js.map +1 -0
  77. package/dist/esm/form/TicketWithMerchandiseSelection.js +4 -6
  78. package/dist/esm/form/TicketWithMerchandiseSelection.js.map +1 -1
  79. package/dist/esm/form/merchendise/MerchandiseSelection.js +15 -0
  80. package/dist/esm/form/merchendise/MerchandiseSelection.js.map +1 -0
  81. package/dist/esm/form/merchendise/MerchandiseSlider.js +71 -0
  82. package/dist/esm/form/merchendise/MerchandiseSlider.js.map +1 -0
  83. package/dist/esm/form/product/ProductCard.js +3 -2
  84. package/dist/esm/form/product/ProductCard.js.map +1 -1
  85. package/dist/esm/form/product/ProductVariantsDialog.js +23 -8
  86. package/dist/esm/form/product/ProductVariantsDialog.js.map +1 -1
  87. package/dist/esm/form/tickets/ReleaseWithMerchandise.js +30 -7
  88. package/dist/esm/form/tickets/ReleaseWithMerchandise.js.map +1 -1
  89. package/dist/esm/form/tickets/TicketSelection.js +38 -15
  90. package/dist/esm/form/tickets/TicketSelection.js.map +1 -1
  91. package/dist/esm/form/tickets/TicketSelectionMap.js +7 -1
  92. package/dist/esm/form/tickets/TicketSelectionMap.js.map +1 -1
  93. package/dist/esm/form/tickets/TicketSelectionMobile.js +17 -7
  94. package/dist/esm/form/tickets/TicketSelectionMobile.js.map +1 -1
  95. package/dist/esm/form/tickets/TicketWithMerchandiseSelection.js +30 -20
  96. package/dist/esm/form/tickets/TicketWithMerchandiseSelection.js.map +1 -1
  97. package/dist/esm/hooks/useConsentScrollOnDrawerOpen.js +55 -0
  98. package/dist/esm/hooks/useConsentScrollOnDrawerOpen.js.map +1 -0
  99. package/dist/esm/utils/data/ticket.js +4 -0
  100. package/dist/esm/utils/data/ticket.js.map +1 -0
  101. package/dist/types/form/PaymentOverviewDrawer.d.ts +8 -0
  102. package/dist/types/form/merchendise/MerchandiseSelection.d.ts +9 -0
  103. package/dist/types/form/merchendise/MerchandiseSlider.d.ts +10 -0
  104. package/dist/types/form/merchendise/MerchendiseSlider.d.ts +0 -0
  105. package/dist/types/locales/cs.d.ts +1 -5
  106. package/package.json +1 -1
  107. package/src/form/TicketForm.tsx +8 -6
  108. package/src/form/product/ProductCard.tsx +5 -2
  109. package/src/form/product/ProductVariantsDialog.tsx +29 -6
  110. package/src/form/tickets/ReleaseWithMerchandise.tsx +39 -8
  111. package/src/form/tickets/TicketSelection.tsx +50 -17
  112. package/src/form/tickets/TicketSelectionMap.tsx +9 -1
  113. package/src/form/tickets/TicketSelectionMobile.tsx +77 -67
  114. package/src/form/tickets/TicketWithMerchandiseSelection.tsx +49 -31
  115. package/src/utils/data/ticket.ts +1 -0
  116. package/dist/cjs/hooks/useFirstRender.js +0 -14
  117. package/dist/cjs/hooks/useFirstRender.js.map +0 -1
  118. package/dist/esm/hooks/useFirstRender.js +0 -12
  119. package/dist/esm/hooks/useFirstRender.js.map +0 -1
@@ -8,6 +8,7 @@ import { useFormContext, useWatch } from 'react-hook-form';
8
8
  import { IEventProductForm } from '@utils/types/product.type';
9
9
  import { fCurrency } from '@utils/formatNumber';
10
10
  import { Currencies } from '@utils/data/currency';
11
+ import { MAX_TICKETS_PER_ORDER } from '@utils/data/ticket';
11
12
  import { getSelectedQuantityByVariant } from '@utils/product';
12
13
  import ReleaseExtraFields from '@form/extra-field/ReleaseExtraFields';
13
14
  import ReleaseDescription from '@form/tickets/ReleaseDescription';
@@ -43,10 +44,19 @@ const ReleaseWithMerchandise: React.FC<Props> = ({
43
44
  const getSelectedQuantity = (id: number) =>
44
45
  tickets.find((ticket) => ticket.releaseId === id)?.quantity || 0;
45
46
 
47
+ const countSelectedTickets = () => {
48
+ let count = 0;
49
+ for (const ticket of tickets) {
50
+ count += Number(ticket.quantity || 0);
51
+ }
52
+
53
+ return count;
54
+ };
55
+
46
56
  const getAvailableTicketsForRelease = (release: ITicketFormTicket): number => {
47
57
  const selectedRelease = activeReleases?.find((item) => item.id === release.releaseId);
48
58
  const availableQuantity = selectedRelease ? selectedRelease.availableTickets : 0;
49
- return availableQuantity > 10 ? 10 : availableQuantity;
59
+ return availableQuantity > MAX_TICKETS_PER_ORDER ? MAX_TICKETS_PER_ORDER : availableQuantity;
50
60
  };
51
61
 
52
62
  const isMaxQuantity = (releaseId: number) => {
@@ -61,7 +71,17 @@ const ReleaseWithMerchandise: React.FC<Props> = ({
61
71
  : productsToAdd
62
72
  ? [productsToAdd]
63
73
  : [];
64
- const quantity = normalizedProducts.length ? normalizedProducts.length : 1;
74
+ const requestedQuantity = normalizedProducts.length ? normalizedProducts.length : 1;
75
+ const releaseMaxQuantity = Math.min(release.availableTickets || 0, MAX_TICKETS_PER_ORDER);
76
+ const remainingOrderCapacity = Math.max(0, MAX_TICKETS_PER_ORDER - countSelectedTickets());
77
+ const quantity = Math.min(requestedQuantity, releaseMaxQuantity, remainingOrderCapacity);
78
+
79
+ if (quantity <= 0) {
80
+ setOpenVariantDialog(null);
81
+ return;
82
+ }
83
+
84
+ const selectedProducts = normalizedProducts.slice(0, quantity);
65
85
  const extraFields = release.extraFields?.length
66
86
  ? Array.from({ length: quantity }, () =>
67
87
  release.extraFields!.map((field) => ({
@@ -78,7 +98,7 @@ const ReleaseWithMerchandise: React.FC<Props> = ({
78
98
  quantity,
79
99
  itemName: '',
80
100
  price: 0,
81
- products: normalizedProducts,
101
+ products: selectedProducts,
82
102
  extraFields,
83
103
  },
84
104
  ]);
@@ -95,9 +115,10 @@ const ReleaseWithMerchandise: React.FC<Props> = ({
95
115
  if (addedRelease) {
96
116
  const increment = normalizedProducts.length ? normalizedProducts.length : 1;
97
117
  const maxQuantity = getAvailableTicketsForRelease(addedRelease);
118
+ const remainingOrderCapacity = Math.max(0, MAX_TICKETS_PER_ORDER - countSelectedTickets());
98
119
  const availableIncrement = Math.max(
99
120
  0,
100
- Math.min(increment, maxQuantity - Number(addedRelease.quantity))
121
+ Math.min(increment, maxQuantity - Number(addedRelease.quantity), remainingOrderCapacity)
101
122
  );
102
123
  if (availableIncrement === 0) return;
103
124
 
@@ -158,6 +179,13 @@ const ReleaseWithMerchandise: React.FC<Props> = ({
158
179
  }
159
180
  }, [tickets, release.id, setValue]);
160
181
 
182
+ const remainingOrderCapacity = Math.max(0, MAX_TICKETS_PER_ORDER - countSelectedTickets());
183
+ const nextRelease = activeReleases?.find(
184
+ (item) =>
185
+ item.releaseCategoryName === release.releaseCategoryName && item.order === release.order + 1
186
+ );
187
+ const hasSelectedNextRelease = !!nextRelease && getSelectedQuantity(nextRelease.id) > 0;
188
+
161
189
  return (
162
190
  <Box
163
191
  sx={{
@@ -173,7 +201,7 @@ const ReleaseWithMerchandise: React.FC<Props> = ({
173
201
  <Stack spacing={0}>
174
202
  <Box>
175
203
  <Typography variant="subtitle2" fontWeight={700}>
176
- {getReleaseTitle(release)}
204
+ {getReleaseTitle(release)} - {release.name}
177
205
  </Typography>
178
206
  </Box>
179
207
 
@@ -193,9 +221,11 @@ const ReleaseWithMerchandise: React.FC<Props> = ({
193
221
 
194
222
  <TicketQuantityControl
195
223
  quantity={getSelectedQuantity(release.id)}
196
- isDisabled={release.locked}
197
- canAddFirst={!release.locked}
198
- canAddMore={!isMaxQuantity(release.id)}
224
+ isDisabled={release.locked || hasSelectedNextRelease}
225
+ canAddFirst={!release.locked && !hasSelectedNextRelease && remainingOrderCapacity > 0}
226
+ canAddMore={
227
+ !isMaxQuantity(release.id) && !hasSelectedNextRelease && remainingOrderCapacity > 0
228
+ }
199
229
  addLabel={t('add')}
200
230
  onDecrement={() => decreaseQuantity()}
201
231
  onIncrement={() =>
@@ -229,6 +259,7 @@ const ReleaseWithMerchandise: React.FC<Props> = ({
229
259
  selectedQuantityByVariant={getSelectedQuantityByVariant(products, tickets)}
230
260
  eventId={eventId}
231
261
  canAddOnlyOneAtATime
262
+ maxSelectableQuantity={remainingOrderCapacity}
232
263
  />
233
264
  )}
234
265
  </Stack>
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useRef, useState } from 'react';
1
+ import React, { useEffect, useRef } from 'react';
2
2
  import { useFormContext, useWatch } from 'react-hook-form';
3
3
  import { Box, Divider, Stack, Typography } from '@mui/material';
4
4
  import { ITicketForm, ITicketFormTicket } from '@utils/types/ticket.type';
@@ -9,6 +9,7 @@ import { IEvent } from '@utils/types/event.type';
9
9
  import useResponsive from '@hooks/useResponsive';
10
10
  import ReleaseExtraFields from '@form/extra-field/ReleaseExtraFields';
11
11
  import { EventType } from '@utils/data/event';
12
+ import { MAX_TICKETS_PER_ORDER } from '@utils/data/ticket';
12
13
  import useGlobal from '@hooks/useGlobal.ts';
13
14
  import TicketSelectionMobile from './TicketSelectionMobile';
14
15
 
@@ -25,7 +26,6 @@ const TicketSelection: React.FC<Props> = ({ event }) => {
25
26
  defaultValue: [],
26
27
  }) as ITicketFormTicket[];
27
28
  const eventTimeslotId = watch('eventTimeslotId');
28
- const [soldOutReleaseCategoryNames, setSoldOutReleaseCategoryNames] = useState<string[]>([]);
29
29
  const isProcessingRef = useRef(false);
30
30
  const { data: activeReleases, mutate } = useEventActiveReleases(
31
31
  event.id,
@@ -68,7 +68,7 @@ const TicketSelection: React.FC<Props> = ({ event }) => {
68
68
  // const getAvailableTicketsForRelease = (release: ITicketFormTicket): number => {
69
69
  // const selectedRelease = activeReleases?.find((item) => item.id === release.releaseId);
70
70
  // const availableQuantity = selectedRelease ? selectedRelease.availableTickets : 0;
71
- // return availableQuantity > 10 ? 10 : availableQuantity;
71
+ // return availableQuantity > MAX_TICKETS_PER_ORDER ? MAX_TICKETS_PER_ORDER : availableQuantity;
72
72
  // };
73
73
 
74
74
  const countReleaseCategories = (): number => {
@@ -83,7 +83,15 @@ const TicketSelection: React.FC<Props> = ({ event }) => {
83
83
  item2.releaseCategoryName === item.releaseCategoryName && item2.order === item.order + 1
84
84
  );
85
85
  const selected = tickets.find((ticket) => ticket.releaseId === item.id);
86
- return !!nextRelease && item.locked && !!selected && index + 1 == tickets.length;
86
+ const maxSelectable = Math.min(item.availableTickets || 0, MAX_TICKETS_PER_ORDER);
87
+
88
+ return (
89
+ !!nextRelease &&
90
+ item.locked &&
91
+ !!selected &&
92
+ Number(selected.quantity) >= maxSelectable &&
93
+ index + 1 == tickets.length
94
+ );
87
95
  });
88
96
  return lockedSelectedReleases && lockedSelectedReleases.includes(true);
89
97
  };
@@ -102,8 +110,8 @@ const TicketSelection: React.FC<Props> = ({ event }) => {
102
110
  const isQuantityDisabled = (value: number, releaseId: number | '') => {
103
111
  const releaseSelected = tickets.find((item) => item.releaseId === releaseId);
104
112
  return releaseSelected && releaseSelected.quantity
105
- ? countSelectedTickets() + value - releaseSelected.quantity > 10
106
- : countSelectedTickets() + value > 10;
113
+ ? countSelectedTickets() + value - releaseSelected.quantity > MAX_TICKETS_PER_ORDER
114
+ : countSelectedTickets() + value > MAX_TICKETS_PER_ORDER;
107
115
  };
108
116
 
109
117
  const removeTicket = (indexToRemove: number) => {
@@ -113,21 +121,47 @@ const TicketSelection: React.FC<Props> = ({ event }) => {
113
121
 
114
122
  const selectedTickets = async () => {
115
123
  const releases = await mutate();
124
+ const currentReleases = releases || activeReleases || [];
116
125
  const allFilled = tickets.filter((item) => !item.releaseId || !item.quantity);
117
126
 
118
- const soldOutReleaseCategories = activeReleases?.filter((release) =>
127
+ const soldOutReleaseCategories = currentReleases.filter((release) =>
119
128
  tickets.find(
120
129
  (ticket) =>
121
130
  release.id === ticket.releaseId &&
122
- ticket.quantity === release.availableTickets &&
123
- release.availableTickets !== 10
131
+ Number(ticket.quantity) >= Math.min(release.availableTickets || 0, MAX_TICKETS_PER_ORDER)
124
132
  )
125
133
  );
126
- setSoldOutReleaseCategoryNames(
127
- soldOutReleaseCategories?.map((item) => item.releaseCategoryName) || []
128
- );
129
134
 
130
- const hasSelectableRelease = activeReleases?.some(
135
+ if (currentReleases.length) {
136
+ let hasChanges = false;
137
+ const updatedReleases = currentReleases.map((release) => {
138
+ const previousRelease = currentReleases.find(
139
+ (item) =>
140
+ item.releaseCategoryName === release.releaseCategoryName &&
141
+ item.order === release.order - 1
142
+ );
143
+
144
+ if (!release.locked || !previousRelease) return release;
145
+
146
+ const previousTicket = tickets.find((ticket) => ticket.releaseId === previousRelease.id);
147
+ const previousMaxSelectable = Math.min(
148
+ previousRelease.availableTickets || 0,
149
+ MAX_TICKETS_PER_ORDER
150
+ );
151
+ const shouldUnlock = Number(previousTicket?.quantity || 0) >= previousMaxSelectable;
152
+
153
+ if (!shouldUnlock) return release;
154
+
155
+ hasChanges = true;
156
+ return { ...release, locked: false };
157
+ });
158
+
159
+ if (hasChanges) {
160
+ await mutate(updatedReleases, false);
161
+ }
162
+ }
163
+
164
+ const hasSelectableRelease = currentReleases.some(
131
165
  (release) => !isReleaseSelected(release.id) && !release.locked
132
166
  );
133
167
 
@@ -136,9 +170,9 @@ const TicketSelection: React.FC<Props> = ({ event }) => {
136
170
  selectedReleaseIsSoldOut(releases) &&
137
171
  tickets.length < soldOutReleaseCategories.length + countUnlockedReleases() &&
138
172
  !allFilled.length) ||
139
- (activeReleases &&
140
- soldOutReleaseCategories?.length &&
141
- activeReleases?.length > tickets.length &&
173
+ (currentReleases.length &&
174
+ soldOutReleaseCategories.length &&
175
+ currentReleases.length > tickets.length &&
142
176
  tickets.length < soldOutReleaseCategories.length + countUnlockedReleases() &&
143
177
  !allFilled.length) ||
144
178
  (tickets.length < countReleaseCategories() && !allFilled.length);
@@ -184,7 +218,6 @@ const TicketSelection: React.FC<Props> = ({ event }) => {
184
218
  event={event}
185
219
  activeReleases={activeReleases}
186
220
  showLoading={showLoading}
187
- soldOutReleaseCategoryNames={soldOutReleaseCategoryNames}
188
221
  tickets={tickets}
189
222
  isQuantityDisabled={isQuantityDisabled}
190
223
  setValue={setValue as (name: string, value: any) => void}
@@ -5,6 +5,7 @@ import { Button } from '@mui/material';
5
5
  import { iframe, TicketSelection } from '@seat-picker/seat-picker-sdk';
6
6
  import { useFormContext } from 'react-hook-form';
7
7
  import { ITicketForm, ITicketFormTicket, ITicketLocation } from '@utils/types/ticket.type.ts';
8
+ import { MAX_TICKETS_PER_ORDER } from '@utils/data/ticket';
8
9
  import Iconify from '@components/iconify/Iconify';
9
10
 
10
11
  interface Props {
@@ -43,11 +44,18 @@ const TicketSelectionMap: React.FC<Props> = ({ event }) => {
43
44
  [] as { quantity: number; seat: ITicketLocation; ticket: any }[]
44
45
  );
45
46
 
47
+ let remainingTicketCapacity = MAX_TICKETS_PER_ORDER;
48
+
46
49
  for (const groupedSeat of groupedSeatsByZone) {
50
+ if (remainingTicketCapacity <= 0) break;
51
+
52
+ const quantity = Math.min(groupedSeat.quantity, remainingTicketCapacity);
53
+ remainingTicketCapacity -= quantity;
54
+
47
55
  tickets.push({
48
56
  releaseId: groupedSeat.ticket.id,
49
57
  price: groupedSeat.ticket.price,
50
- quantity: groupedSeat.quantity,
58
+ quantity,
51
59
  itemName: `${groupedSeat.ticket.releaseCategoryName} - ${groupedSeat.ticket.name}`,
52
60
  products: [],
53
61
  extraFields: [],
@@ -4,6 +4,7 @@ import { fCurrency } from '@utils/formatNumber';
4
4
  import { IEvent } from '@utils/types/event.type';
5
5
  import { IReleaseShort } from '@utils/types/release.type';
6
6
  import { ITicketFormTicket } from '@utils/types/ticket.type';
7
+ import { MAX_TICKETS_PER_ORDER } from '@utils/data/ticket';
7
8
  import useGlobal from '@hooks/useGlobal';
8
9
  import ReleaseDescription from './ReleaseDescription';
9
10
  import TicketQuantityControl from './TicketQuantityControl';
@@ -12,7 +13,6 @@ interface Props {
12
13
  event: IEvent;
13
14
  activeReleases?: IReleaseShort[];
14
15
  showLoading: boolean;
15
- soldOutReleaseCategoryNames: string[];
16
16
  tickets: ITicketFormTicket[];
17
17
  isQuantityDisabled: (value: number, releaseId: number | '') => boolean;
18
18
  setValue: (name: string, value: any) => void;
@@ -24,7 +24,6 @@ const TicketSelectionMobile: React.FC<Props> = ({
24
24
  event,
25
25
  activeReleases,
26
26
  showLoading,
27
- soldOutReleaseCategoryNames,
28
27
  tickets,
29
28
  isQuantityDisabled,
30
29
  setValue,
@@ -47,8 +46,11 @@ const TicketSelectionMobile: React.FC<Props> = ({
47
46
  return Number(ticket?.quantity || 0);
48
47
  };
49
48
 
49
+ const isReleaseVisible = (release: IReleaseShort) =>
50
+ !release.locked || getReleaseQuantity(release.id) > 0;
51
+
50
52
  const updateReleaseQuantity = (release: IReleaseShort, nextQuantity: number) => {
51
- const maxAvailable = Math.min(release.availableTickets || 0, 10);
53
+ const maxAvailable = Math.min(release.availableTickets || 0, MAX_TICKETS_PER_ORDER);
52
54
  const clampedQuantity = Math.max(0, Math.min(nextQuantity, maxAvailable));
53
55
  const ticketIndex = getTicketIndexByRelease(release.id);
54
56
 
@@ -100,76 +102,84 @@ const TicketSelectionMobile: React.FC<Props> = ({
100
102
 
101
103
  return (
102
104
  <Stack spacing={2}>
103
- {activeReleases?.map((release) => {
104
- const quantity = getReleaseQuantity(release.id);
105
- const ticketIndex = getTicketIndexByRelease(release.id);
106
- const maxAvailable = Math.min(release.availableTickets || 0, 10);
107
- const isLocked =
108
- release.locked && !soldOutReleaseCategoryNames.includes(release.releaseCategoryName);
109
- const isDisabled = isLocked && quantity === 0;
110
- const canAddFirst = maxAvailable > 0 && !isQuantityDisabled(1, release.id);
111
- const canAddMore = quantity < maxAvailable && !isQuantityDisabled(quantity + 1, release.id);
112
-
113
- return (
114
- <Box
115
- key={release.id}
116
- sx={{
117
- pt: 1,
118
- pr: 0.5,
119
- pb: 0.5,
120
- pl: 2,
121
- borderRadius: 1,
122
- bgcolor: (theme) => (isLight ? theme.palette.grey[100] : theme.palette.grey[800]),
123
- }}
124
- >
125
- <Stack spacing={0}>
126
- <Box>
127
- <Typography variant="subtitle2" fontWeight={700}>
128
- {getReleaseTitle(release)}
129
- </Typography>
130
- </Box>
131
-
132
- <Stack direction="row" alignItems="center" justifyContent="space-between">
133
- <Stack>
134
- <Typography variant="body2">
135
- {release.price === 0
136
- ? t('free')
137
- : fCurrency(release.price, lang, event.currency)}
105
+ {activeReleases
106
+ ?.filter((release) => isReleaseVisible(release))
107
+ .map((release) => {
108
+ const quantity = getReleaseQuantity(release.id);
109
+ const ticketIndex = getTicketIndexByRelease(release.id);
110
+ const maxAvailable = Math.min(release.availableTickets || 0, MAX_TICKETS_PER_ORDER);
111
+ const isLocked = release.locked;
112
+ const nextRelease = activeReleases?.find(
113
+ (item) =>
114
+ item.releaseCategoryName === release.releaseCategoryName &&
115
+ item.order === release.order + 1
116
+ );
117
+ const hasSelectedNextRelease = !!nextRelease && getReleaseQuantity(nextRelease.id) > 0;
118
+ const isDisabled = hasSelectedNextRelease || (isLocked && quantity === 0);
119
+ const canAddFirst = maxAvailable > 0 && !isQuantityDisabled(1, release.id);
120
+ const canAddMore =
121
+ quantity < maxAvailable && !isQuantityDisabled(quantity + 1, release.id);
122
+
123
+ return (
124
+ <Box
125
+ key={release.id}
126
+ sx={{
127
+ pt: 1,
128
+ pr: 0.5,
129
+ pb: 0.5,
130
+ pl: 2,
131
+ borderRadius: 1,
132
+ bgcolor: (theme) => (isLight ? theme.palette.grey[100] : theme.palette.grey[800]),
133
+ }}
134
+ >
135
+ <Stack spacing={0}>
136
+ <Box>
137
+ <Typography variant="subtitle2" fontWeight={700}>
138
+ {getReleaseTitle(release)} - {release.name}
138
139
  </Typography>
139
-
140
- <ReleaseDescription
141
- description={release.description}
142
- isExpanded={Boolean(expandedReleaseIds[release.id])}
143
- onToggle={() => toggleReleaseDescription(release.id)}
144
- moreInfoLabel={t('more_info')}
140
+ </Box>
141
+
142
+ <Stack direction="row" alignItems="center" justifyContent="space-between">
143
+ <Stack>
144
+ <Typography variant="body2">
145
+ {release.price === 0
146
+ ? t('free')
147
+ : fCurrency(release.price, lang, event.currency)}
148
+ </Typography>
149
+
150
+ <ReleaseDescription
151
+ description={release.description}
152
+ isExpanded={Boolean(expandedReleaseIds[release.id])}
153
+ onToggle={() => toggleReleaseDescription(release.id)}
154
+ moreInfoLabel={t('more_info')}
155
+ />
156
+ </Stack>
157
+
158
+ <TicketQuantityControl
159
+ quantity={quantity}
160
+ isDisabled={isDisabled}
161
+ canAddFirst={canAddFirst}
162
+ canAddMore={canAddMore}
163
+ addLabel={t('add')}
164
+ onDecrement={() => updateReleaseQuantity(release, quantity - 1)}
165
+ onIncrement={() => updateReleaseQuantity(release, quantity + 1)}
166
+ onAddFirst={() => updateReleaseQuantity(release, 1)}
145
167
  />
146
168
  </Stack>
147
169
 
148
- <TicketQuantityControl
149
- quantity={quantity}
150
- isDisabled={isDisabled}
151
- canAddFirst={canAddFirst}
152
- canAddMore={canAddMore}
153
- addLabel={t('add')}
154
- onDecrement={() => updateReleaseQuantity(release, quantity - 1)}
155
- onIncrement={() => updateReleaseQuantity(release, quantity + 1)}
156
- onAddFirst={() => updateReleaseQuantity(release, 1)}
170
+ <ReleaseDescription
171
+ description={release.description}
172
+ isExpanded={Boolean(expandedReleaseIds[release.id])}
173
+ onToggle={() => toggleReleaseDescription(release.id)}
174
+ moreInfoLabel={t('more_info')}
175
+ showCollapse
157
176
  />
158
- </Stack>
159
177
 
160
- <ReleaseDescription
161
- description={release.description}
162
- isExpanded={Boolean(expandedReleaseIds[release.id])}
163
- onToggle={() => toggleReleaseDescription(release.id)}
164
- moreInfoLabel={t('more_info')}
165
- showCollapse
166
- />
167
-
168
- {ticketIndex >= 0 && getExtraFields(release.id, ticketIndex)}
169
- </Stack>
170
- </Box>
171
- );
172
- })}
178
+ {ticketIndex >= 0 && getExtraFields(release.id, ticketIndex)}
179
+ </Stack>
180
+ </Box>
181
+ );
182
+ })}
173
183
  </Stack>
174
184
  );
175
185
  };
@@ -8,6 +8,7 @@ import { IReleaseShort } from '@utils/types/release.type';
8
8
  import { IEvent } from '@utils/types/event.type';
9
9
  import ReleaseWithMerchandise from '@form/tickets/ReleaseWithMerchandise';
10
10
  import { EventType } from '@utils/data/event';
11
+ import { MAX_TICKETS_PER_ORDER } from '@utils/data/ticket';
11
12
  import useGlobal from '@hooks/useGlobal.ts';
12
13
 
13
14
  interface Props {
@@ -42,7 +43,15 @@ const TicketWithMerchandiseSelection: React.FC<Props> = ({ event }) => {
42
43
  item2.releaseCategoryName === item.releaseCategoryName && item2.order === item.order + 1
43
44
  );
44
45
  const selected = tickets.find((ticket) => ticket.releaseId === item.id);
45
- return !!nextRelease && item.locked && !!selected && index + 1 == tickets.length;
46
+ const maxSelectable = Math.min(item.availableTickets || 0, MAX_TICKETS_PER_ORDER);
47
+
48
+ return (
49
+ !!nextRelease &&
50
+ item.locked &&
51
+ !!selected &&
52
+ Number(selected.quantity) >= maxSelectable &&
53
+ index + 1 == tickets.length
54
+ );
46
55
  });
47
56
  return lockedSelectedReleases && lockedSelectedReleases.includes(true);
48
57
  };
@@ -53,33 +62,40 @@ const TicketWithMerchandiseSelection: React.FC<Props> = ({ event }) => {
53
62
 
54
63
  const selectedTickets = async () => {
55
64
  const releases = await mutate();
65
+ const currentReleases = releases || activeReleases || [];
56
66
  const allFilled = tickets.filter((item) => !item.releaseId || !item.quantity);
57
67
 
58
- const soldOutReleaseCategories = activeReleases?.filter((release) =>
68
+ const soldOutReleaseCategories = currentReleases.filter((release) =>
59
69
  tickets.find(
60
70
  (ticket) =>
61
71
  release.id === ticket.releaseId &&
62
- ticket.quantity === release.availableTickets &&
63
- release.availableTickets !== 10
72
+ Number(ticket.quantity) >= Math.min(release.availableTickets || 0, MAX_TICKETS_PER_ORDER)
64
73
  )
65
74
  );
66
75
 
67
76
  // Unlock next releases when current release is sold out
68
- if (soldOutReleaseCategories?.length && activeReleases) {
77
+ if (currentReleases.length) {
69
78
  let hasChanges = false;
70
- const updatedReleases = activeReleases.map((release) => {
71
- // For each sold-out release, find and unlock the next one
72
- const soldOutRelease = soldOutReleaseCategories.find(
73
- (soldOut) =>
74
- soldOut.releaseCategoryName === release.releaseCategoryName &&
75
- soldOut.order === release.order - 1 &&
76
- release.locked
79
+ const updatedReleases = currentReleases.map((release) => {
80
+ const previousRelease = currentReleases.find(
81
+ (item) =>
82
+ item.releaseCategoryName === release.releaseCategoryName &&
83
+ item.order === release.order - 1
84
+ );
85
+
86
+ if (!release.locked || !previousRelease) return release;
87
+
88
+ const previousTicket = tickets.find((ticket) => ticket.releaseId === previousRelease.id);
89
+ const previousMaxSelectable = Math.min(
90
+ previousRelease.availableTickets || 0,
91
+ MAX_TICKETS_PER_ORDER
77
92
  );
78
- if (soldOutRelease) {
79
- hasChanges = true;
80
- return { ...release, locked: false };
81
- }
82
- return release;
93
+ const shouldUnlock = Number(previousTicket?.quantity || 0) >= previousMaxSelectable;
94
+
95
+ if (!shouldUnlock) return release;
96
+
97
+ hasChanges = true;
98
+ return { ...release, locked: false };
83
99
  });
84
100
 
85
101
  if (hasChanges) {
@@ -87,7 +103,7 @@ const TicketWithMerchandiseSelection: React.FC<Props> = ({ event }) => {
87
103
  }
88
104
  }
89
105
 
90
- const hasSelectableRelease = activeReleases?.some(
106
+ const hasSelectableRelease = currentReleases.some(
91
107
  (release) => !isReleaseSelected(release.id) && !release.locked
92
108
  );
93
109
 
@@ -96,9 +112,9 @@ const TicketWithMerchandiseSelection: React.FC<Props> = ({ event }) => {
96
112
  selectedReleaseIsSoldOut(releases) &&
97
113
  tickets.length < soldOutReleaseCategories.length + countUnlockedReleases() &&
98
114
  !allFilled.length) ||
99
- (activeReleases &&
100
- soldOutReleaseCategories?.length &&
101
- activeReleases?.length > tickets.length &&
115
+ (currentReleases.length &&
116
+ soldOutReleaseCategories.length &&
117
+ currentReleases.length > tickets.length &&
102
118
  tickets.length < soldOutReleaseCategories.length + countUnlockedReleases() &&
103
119
  !allFilled.length) ||
104
120
  (tickets.length < countReleaseCategories() && !allFilled.length);
@@ -145,16 +161,18 @@ const TicketWithMerchandiseSelection: React.FC<Props> = ({ event }) => {
145
161
  }}
146
162
  />
147
163
  ) : (
148
- activeReleases?.map((release, index) => (
149
- <ReleaseWithMerchandise
150
- key={release.id}
151
- eventId={event.id}
152
- release={release}
153
- activeReleases={activeReleases}
154
- currency={event.currency}
155
- index={index}
156
- />
157
- ))
164
+ activeReleases
165
+ ?.filter((release) => !release.locked || isReleaseSelected(release.id))
166
+ .map((release, index) => (
167
+ <ReleaseWithMerchandise
168
+ key={release.id}
169
+ eventId={event.id}
170
+ release={release}
171
+ activeReleases={activeReleases}
172
+ currency={event.currency}
173
+ index={index}
174
+ />
175
+ ))
158
176
  )}
159
177
  {!activeReleases && event.type === EventType.RECURRING && (
160
178
  <Typography variant="h5">{t('event.tickets.stepper.1.select_timeslot')}</Typography>
@@ -0,0 +1 @@
1
+ export const MAX_TICKETS_PER_ORDER = 10;
@@ -1,14 +0,0 @@
1
- 'use strict';
2
-
3
- var React = require('react');
4
-
5
- function useFirstRender() {
6
- const firstRender = React.useRef(true);
7
- React.useEffect(() => {
8
- firstRender.current = false;
9
- }, []);
10
- return firstRender.current;
11
- }
12
-
13
- exports.useFirstRender = useFirstRender;
14
- //# sourceMappingURL=useFirstRender.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useFirstRender.js","sources":["../../../src/hooks/useFirstRender.ts"],"sourcesContent":["import { useRef, useEffect } from 'react';\n\nexport function useFirstRender(): boolean {\n const firstRender = useRef(true);\n\n useEffect(() => {\n firstRender.current = false;\n }, []);\n\n return firstRender.current;\n}\n"],"names":["useRef","useEffect"],"mappings":";;;;SAEgB,cAAc,GAAA;AAC5B,IAAA,MAAM,WAAW,GAAGA,YAAM,CAAC,IAAI,CAAC;IAEhCC,eAAS,CAAC,MAAK;AACb,QAAA,WAAW,CAAC,OAAO,GAAG,KAAK;KAC5B,EAAE,EAAE,CAAC;IAEN,OAAO,WAAW,CAAC,OAAO;AAC5B;;;;"}
@@ -1,12 +0,0 @@
1
- import { useRef, useEffect } from 'react';
2
-
3
- function useFirstRender() {
4
- const firstRender = useRef(true);
5
- useEffect(() => {
6
- firstRender.current = false;
7
- }, []);
8
- return firstRender.current;
9
- }
10
-
11
- export { useFirstRender };
12
- //# sourceMappingURL=useFirstRender.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useFirstRender.js","sources":["../../../src/hooks/useFirstRender.ts"],"sourcesContent":["import { useRef, useEffect } from 'react';\n\nexport function useFirstRender(): boolean {\n const firstRender = useRef(true);\n\n useEffect(() => {\n firstRender.current = false;\n }, []);\n\n return firstRender.current;\n}\n"],"names":[],"mappings":";;SAEgB,cAAc,GAAA;AAC5B,IAAA,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC;IAEhC,SAAS,CAAC,MAAK;AACb,QAAA,WAAW,CAAC,OAAO,GAAG,KAAK;KAC5B,EAAE,EAAE,CAAC;IAEN,OAAO,WAAW,CAAC,OAAO;AAC5B;;;;"}