@eventlook/sdk 1.5.0-beta.6 → 1.5.0-beta.8
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.
- package/.claude/settings.local.json +6 -10
- package/.env.example +1 -0
- package/README.md +18 -16
- package/dist/cjs/{index-DvUR1fp8.js → index-CUIxdwQn.js} +3340 -577
- package/dist/cjs/index-CUIxdwQn.js.map +1 -0
- package/dist/cjs/index-D5rQiSGP.js +38574 -0
- package/dist/cjs/index-D5rQiSGP.js.map +1 -0
- package/dist/cjs/index.js +2 -2
- package/dist/cjs/{index.umd-6SU6nkkJ.js → index.umd-BoFEW91M.js} +9 -19
- package/dist/cjs/index.umd-BoFEW91M.js.map +1 -0
- package/dist/cjs/index.umd-BzSM62qM.js +13397 -0
- package/dist/cjs/index.umd-BzSM62qM.js.map +1 -0
- package/dist/esm/index-Cm7V8Zl3.js +38571 -0
- package/dist/esm/index-Cm7V8Zl3.js.map +1 -0
- package/dist/esm/{index-BlTqx0jm.js → index-fvLIN6eP.js} +3327 -563
- package/dist/esm/index-fvLIN6eP.js.map +1 -0
- package/dist/esm/index.js +2 -2
- package/dist/esm/{index.umd-Dn0hjh7E.js → index.umd-BKBHcCnm.js} +9 -19
- package/dist/esm/index.umd-BKBHcCnm.js.map +1 -0
- package/dist/esm/index.umd-bIV_YpEF.js +13395 -0
- package/dist/esm/index.umd-bIV_YpEF.js.map +1 -0
- package/dist/types/components/hook-form/FormProvider.d.ts +2 -1
- package/dist/types/form/PaymentOverviewBox.d.ts +2 -0
- package/dist/types/form/PaymentOverviewDrawer.d.ts +10 -0
- package/dist/types/form/TicketForm.d.ts +1 -0
- package/dist/types/form/index.d.ts +2 -1
- package/dist/types/form/merchandise/MerchandiseSelection.d.ts +9 -0
- package/dist/types/form/merchandise/MerchandiseSlider.d.ts +10 -0
- package/dist/types/form/payment/PaymentOverviewCheckbox.d.ts +0 -4
- package/dist/types/form/product/ProductVariantsDialog.d.ts +3 -1
- package/dist/types/form/services/index.d.ts +7 -0
- package/dist/types/form/style.d.ts +1 -0
- package/dist/types/form/tickets/ReleaseDescription.d.ts +10 -0
- package/dist/types/form/tickets/ReleaseWithMerchandise.d.ts +12 -0
- package/dist/types/form/tickets/TicketQuantityControl.d.ts +13 -0
- package/dist/types/form/tickets/TicketSelectionMobile.d.ts +16 -0
- package/dist/types/hooks/useScrollToFirstError.d.ts +4 -0
- package/dist/types/locales/cs.d.ts +22 -0
- package/dist/types/locales/en.d.ts +22 -0
- package/dist/types/locales/es.d.ts +22 -0
- package/dist/types/locales/pl.d.ts +22 -0
- package/dist/types/locales/sk.d.ts +22 -0
- package/dist/types/locales/uk.d.ts +22 -0
- package/dist/types/utils/data/global.d.ts +1 -0
- package/dist/types/utils/data/ticket.d.ts +1 -0
- package/package.json +10 -4
- package/rollup.config.mjs +7 -12
- package/src/components/hook-form/FormProvider.tsx +5 -2
- package/src/form/ChildEventDialog.tsx +3 -3
- package/src/form/ContactPerson.tsx +1 -1
- package/src/form/PaymentOverviewBox.tsx +96 -123
- package/src/form/PaymentOverviewDrawer.tsx +445 -0
- package/src/form/PaymentPending.tsx +19 -4
- package/src/form/ReleaseWithMerchandise.tsx +4 -4
- package/src/form/Shipping.tsx +48 -33
- package/src/form/TicketForm.tsx +146 -41
- package/src/form/index.tsx +3 -1
- package/src/form/merchandise/MerchandiseSelection.tsx +24 -0
- package/src/form/merchandise/MerchandiseSlider.tsx +62 -0
- package/src/form/payment/FeeBox.tsx +4 -31
- package/src/form/payment/PaymentOverviewCheckbox.tsx +68 -69
- package/src/form/product/ProductCard.tsx +258 -59
- package/src/form/product/ProductVariantsDialog.tsx +292 -139
- package/src/form/services/index.tsx +262 -0
- package/src/form/style.ts +16 -4
- package/src/form/tickets/ReleaseDescription.tsx +46 -0
- package/src/form/tickets/ReleaseWithMerchandise.tsx +267 -0
- package/src/form/tickets/TicketQuantityControl.tsx +100 -0
- package/src/form/tickets/TicketSelection.tsx +236 -0
- package/src/form/{TicketSelectionMap.tsx → tickets/TicketSelectionMap.tsx} +18 -2
- package/src/form/tickets/TicketSelectionMobile.tsx +188 -0
- package/src/form/{TicketWithMerchandiseSelection.tsx → tickets/TicketWithMerchandiseSelection.tsx} +52 -38
- package/src/hooks/useScrollToFirstError.ts +99 -0
- package/src/locales/cs.tsx +25 -3
- package/src/locales/en.tsx +23 -1
- package/src/locales/es.tsx +23 -1
- package/src/locales/pl.tsx +23 -1
- package/src/locales/sk.tsx +24 -2
- package/src/locales/uk.tsx +23 -1
- package/src/utils/data/global.ts +1 -0
- package/src/utils/data/ticket.ts +1 -0
- package/tsconfig.json +1 -1
- package/README +0 -1
- package/dist/cjs/index-DvUR1fp8.js.map +0 -1
- package/dist/cjs/index.umd-6SU6nkkJ.js.map +0 -1
- package/dist/esm/index-BlTqx0jm.js.map +0 -1
- package/dist/esm/index.umd-Dn0hjh7E.js.map +0 -1
- package/src/form/TicketSelection.tsx +0 -307
- /package/dist/types/form/{TicketSelection.d.ts → tickets/TicketSelection.d.ts} +0 -0
- /package/dist/types/form/{TicketSelectionMap.d.ts → tickets/TicketSelectionMap.d.ts} +0 -0
- /package/dist/types/form/{TicketWithMerchandiseSelection.d.ts → tickets/TicketWithMerchandiseSelection.d.ts} +0 -0
|
@@ -1,307 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useRef, useState } from 'react';
|
|
2
|
-
import { useFormContext, useWatch } from 'react-hook-form';
|
|
3
|
-
import {
|
|
4
|
-
Box,
|
|
5
|
-
Button,
|
|
6
|
-
Divider,
|
|
7
|
-
Grid,
|
|
8
|
-
IconButton,
|
|
9
|
-
MenuItem,
|
|
10
|
-
Skeleton,
|
|
11
|
-
Stack,
|
|
12
|
-
Typography,
|
|
13
|
-
} from '@mui/material';
|
|
14
|
-
import { RHFSelect } from '@components/hook-form';
|
|
15
|
-
import { ITicketForm, ITicketFormTicket } from '@utils/types/ticket.type';
|
|
16
|
-
import useEventActiveReleases from '@hooks/data/useEventActiveReleases';
|
|
17
|
-
import { fCurrency } from '@utils/formatNumber';
|
|
18
|
-
import { Iconify } from '@components/iconify';
|
|
19
|
-
import { groupBy } from '@utils/global';
|
|
20
|
-
import { IReleaseShort } from '@utils/types/release.type';
|
|
21
|
-
import FeeBox from '@form/payment/FeeBox';
|
|
22
|
-
import { IEvent } from '@utils/types/event.type';
|
|
23
|
-
import useResponsive from '@hooks/useResponsive';
|
|
24
|
-
import ReleaseExtraFields from '@form/extra-field/ReleaseExtraFields';
|
|
25
|
-
import { EventType } from '@utils/data/event';
|
|
26
|
-
import useGlobal from '@hooks/useGlobal';
|
|
27
|
-
|
|
28
|
-
interface Props {
|
|
29
|
-
event: IEvent;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const TicketSelection: React.FC<Props> = ({ event }) => {
|
|
33
|
-
const { t, lang } = useGlobal();
|
|
34
|
-
const isMobile = useResponsive('down', 'md');
|
|
35
|
-
const { setValue, watch } = useFormContext<ITicketForm>();
|
|
36
|
-
const tickets = useWatch({
|
|
37
|
-
name: `tickets.${event.id}`,
|
|
38
|
-
defaultValue: [],
|
|
39
|
-
}) as ITicketFormTicket[];
|
|
40
|
-
const eventTimeslotId = watch('eventTimeslotId');
|
|
41
|
-
const [soldOutReleaseCategoryNames, setSoldOutReleaseCategoryNames] = useState<string[]>([]);
|
|
42
|
-
const isProcessingRef = useRef(false);
|
|
43
|
-
const { data: activeReleases, mutate } = useEventActiveReleases(
|
|
44
|
-
event.id,
|
|
45
|
-
false,
|
|
46
|
-
event.type === EventType.RECURRING ? eventTimeslotId : undefined
|
|
47
|
-
);
|
|
48
|
-
|
|
49
|
-
const showLoading = !activeReleases && event.type !== EventType.RECURRING;
|
|
50
|
-
|
|
51
|
-
useEffect(() => {
|
|
52
|
-
if (!isProcessingRef.current) selectedTickets();
|
|
53
|
-
}, [tickets, activeReleases]);
|
|
54
|
-
|
|
55
|
-
const isReleaseSelected = (id: number) => !!tickets.find((ticket) => ticket.releaseId === id);
|
|
56
|
-
|
|
57
|
-
const getRelease = (releaseId: number) => {
|
|
58
|
-
const release = activeReleases?.find((activeRelease) => activeRelease.id === releaseId);
|
|
59
|
-
return release ? release : null;
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
const getExtraFields = (releaseId: number | '', index: number) => {
|
|
63
|
-
if (!releaseId) return null;
|
|
64
|
-
|
|
65
|
-
const release = getRelease(releaseId);
|
|
66
|
-
|
|
67
|
-
if (!release || !release?.extraFields || release?.extraFields.length <= 0) return null;
|
|
68
|
-
|
|
69
|
-
const addedRelease = tickets.find((ticket) => ticket.releaseId === release.id);
|
|
70
|
-
const countTickets = addedRelease?.quantity || 0;
|
|
71
|
-
return (
|
|
72
|
-
<ReleaseExtraFields
|
|
73
|
-
release={release}
|
|
74
|
-
eventId={event.id}
|
|
75
|
-
releaseIndex={index}
|
|
76
|
-
quantity={countTickets}
|
|
77
|
-
/>
|
|
78
|
-
);
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
const getAvailableTicketsForRelease = (release: ITicketFormTicket): number => {
|
|
82
|
-
const selectedRelease = activeReleases?.find((item) => item.id === release.releaseId);
|
|
83
|
-
const availableQuantity = selectedRelease ? selectedRelease.availableTickets : 0;
|
|
84
|
-
return availableQuantity > 10 ? 10 : availableQuantity;
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
const countReleaseCategories = (): number => {
|
|
88
|
-
const grouped = groupBy(activeReleases || [], 'releaseCategoryName');
|
|
89
|
-
return Object.keys(grouped).length;
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
const selectedReleaseIsSoldOut = (releases: IReleaseShort[] | undefined) => {
|
|
93
|
-
const lockedSelectedReleases: boolean[] | undefined = releases?.map((item, index) => {
|
|
94
|
-
const nextRelease = releases?.find(
|
|
95
|
-
(item2) =>
|
|
96
|
-
item2.releaseCategoryName === item.releaseCategoryName && item2.order === item.order + 1
|
|
97
|
-
);
|
|
98
|
-
const selected = tickets.find((ticket) => ticket.releaseId === item.id);
|
|
99
|
-
return !!nextRelease && item.locked && !!selected && index + 1 == tickets.length;
|
|
100
|
-
});
|
|
101
|
-
return lockedSelectedReleases && lockedSelectedReleases.includes(true);
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
const countUnlockedReleases = () => activeReleases?.filter((item) => !item.locked).length || 0;
|
|
105
|
-
|
|
106
|
-
const countSelectedTickets = () => {
|
|
107
|
-
let count = 0;
|
|
108
|
-
for (const ticket of tickets) {
|
|
109
|
-
count += +ticket.quantity;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return count;
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
const isQuantityDisabled = (value: number, releaseId: number | '') => {
|
|
116
|
-
const releaseSelected = tickets.find((item) => item.releaseId === releaseId);
|
|
117
|
-
return releaseSelected && releaseSelected.quantity
|
|
118
|
-
? countSelectedTickets() + value - releaseSelected.quantity > 10
|
|
119
|
-
: countSelectedTickets() + value > 10;
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
const removeTicket = (indexToRemove: number) => {
|
|
123
|
-
const activeReleases = tickets.filter((_ticket, index) => index !== indexToRemove);
|
|
124
|
-
setValue(`tickets.${event.id}`, activeReleases);
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
const selectedTickets = async () => {
|
|
128
|
-
const releases = await mutate();
|
|
129
|
-
const allFilled = tickets.filter((item) => !item.releaseId || !item.quantity);
|
|
130
|
-
|
|
131
|
-
const soldOutReleaseCategories = activeReleases?.filter((release) =>
|
|
132
|
-
tickets.find(
|
|
133
|
-
(ticket) =>
|
|
134
|
-
release.id === ticket.releaseId &&
|
|
135
|
-
ticket.quantity === release.availableTickets &&
|
|
136
|
-
release.availableTickets !== 10
|
|
137
|
-
)
|
|
138
|
-
);
|
|
139
|
-
setSoldOutReleaseCategoryNames(
|
|
140
|
-
soldOutReleaseCategories?.map((item) => item.releaseCategoryName) || []
|
|
141
|
-
);
|
|
142
|
-
|
|
143
|
-
const hasSelectableRelease = activeReleases?.some(
|
|
144
|
-
(release) => !isReleaseSelected(release.id) && !release.locked
|
|
145
|
-
);
|
|
146
|
-
|
|
147
|
-
const shouldAddRow =
|
|
148
|
-
(soldOutReleaseCategories &&
|
|
149
|
-
selectedReleaseIsSoldOut(releases) &&
|
|
150
|
-
tickets.length < soldOutReleaseCategories.length + countUnlockedReleases() &&
|
|
151
|
-
!allFilled.length) ||
|
|
152
|
-
(activeReleases &&
|
|
153
|
-
soldOutReleaseCategories?.length &&
|
|
154
|
-
activeReleases?.length > tickets.length &&
|
|
155
|
-
tickets.length < soldOutReleaseCategories.length + countUnlockedReleases() &&
|
|
156
|
-
!allFilled.length) ||
|
|
157
|
-
(tickets.length < countReleaseCategories() && !allFilled.length);
|
|
158
|
-
|
|
159
|
-
const shouldRemoveEmptyRows =
|
|
160
|
-
allFilled.length > 0 &&
|
|
161
|
-
tickets.length > 1 &&
|
|
162
|
-
!hasSelectableRelease &&
|
|
163
|
-
(!soldOutReleaseCategories?.length || !selectedReleaseIsSoldOut(releases));
|
|
164
|
-
|
|
165
|
-
if (shouldAddRow) {
|
|
166
|
-
isProcessingRef.current = true;
|
|
167
|
-
setValue(`tickets.${event.id}`, [
|
|
168
|
-
...tickets,
|
|
169
|
-
{
|
|
170
|
-
releaseId: '',
|
|
171
|
-
quantity: '',
|
|
172
|
-
itemName: '',
|
|
173
|
-
price: 0,
|
|
174
|
-
products: [],
|
|
175
|
-
extraFields: [],
|
|
176
|
-
},
|
|
177
|
-
]);
|
|
178
|
-
setTimeout(() => (isProcessingRef.current = false), 0);
|
|
179
|
-
} else if (shouldRemoveEmptyRows) {
|
|
180
|
-
// Only remove completely empty rows (no releaseId), keep rows where user started selecting
|
|
181
|
-
const nonEmptyTickets = tickets.filter((item) => item.releaseId);
|
|
182
|
-
if (nonEmptyTickets.length < tickets.length) {
|
|
183
|
-
isProcessingRef.current = true;
|
|
184
|
-
setValue(`tickets.${event.id}`, nonEmptyTickets);
|
|
185
|
-
setTimeout(() => (isProcessingRef.current = false), 0);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
return (
|
|
191
|
-
<Stack spacing={3} direction="column" divider={<Divider sx={{ borderStyle: 'dashed' }} />}>
|
|
192
|
-
{tickets.map((item, index) => (
|
|
193
|
-
<Box key={index}>
|
|
194
|
-
<Grid container spacing={3}>
|
|
195
|
-
<Grid size={{ xs: 12, md: 6 }}>
|
|
196
|
-
{showLoading ? (
|
|
197
|
-
<Skeleton
|
|
198
|
-
variant="rounded"
|
|
199
|
-
sx={{
|
|
200
|
-
width: '100%',
|
|
201
|
-
height: (theme) => theme.spacing(7.5),
|
|
202
|
-
}}
|
|
203
|
-
/>
|
|
204
|
-
) : (
|
|
205
|
-
<RHFSelect
|
|
206
|
-
name={`tickets.${event.id}.${index}.releaseId`}
|
|
207
|
-
value={item.releaseId}
|
|
208
|
-
label={
|
|
209
|
-
index > 0
|
|
210
|
-
? t('form.labels.add_another_release')
|
|
211
|
-
: t('form.labels.release_category_price')
|
|
212
|
-
}
|
|
213
|
-
maxHeight="calc(100vh - 2rem)"
|
|
214
|
-
onChange={(e) => {
|
|
215
|
-
setValue(`tickets.${event.id}.${index}.releaseId`, Number(e.target.value));
|
|
216
|
-
setValue(`tickets.${event.id}.${index}.extraFields`, []);
|
|
217
|
-
}}
|
|
218
|
-
>
|
|
219
|
-
<MenuItem key={0} value="">
|
|
220
|
-
{t('choose')}
|
|
221
|
-
</MenuItem>
|
|
222
|
-
{activeReleases?.map((activeRelease) => (
|
|
223
|
-
<MenuItem
|
|
224
|
-
key={activeRelease.id}
|
|
225
|
-
value={activeRelease.id}
|
|
226
|
-
disabled={
|
|
227
|
-
isReleaseSelected(activeRelease.id) ||
|
|
228
|
-
(activeRelease.locked &&
|
|
229
|
-
!soldOutReleaseCategoryNames.includes(activeRelease.releaseCategoryName))
|
|
230
|
-
}
|
|
231
|
-
>
|
|
232
|
-
{activeRelease.releaseCategoryName} - {activeRelease.name}:{' '}
|
|
233
|
-
{activeRelease.price === 0
|
|
234
|
-
? t('free')
|
|
235
|
-
: fCurrency(activeRelease.price, lang, event.currency)}
|
|
236
|
-
</MenuItem>
|
|
237
|
-
))}
|
|
238
|
-
</RHFSelect>
|
|
239
|
-
)}
|
|
240
|
-
</Grid>
|
|
241
|
-
<Grid key={index} size={{ xs: 12, md: 6 }}>
|
|
242
|
-
{showLoading ? (
|
|
243
|
-
<Skeleton
|
|
244
|
-
variant="rounded"
|
|
245
|
-
sx={{
|
|
246
|
-
width: '100%',
|
|
247
|
-
height: (theme) => theme.spacing(7.5),
|
|
248
|
-
}}
|
|
249
|
-
/>
|
|
250
|
-
) : (
|
|
251
|
-
<Stack direction="row" alignItems="center" spacing={1}>
|
|
252
|
-
<RHFSelect
|
|
253
|
-
name={`tickets.${event.id}.${index}.quantity`}
|
|
254
|
-
value={item.quantity}
|
|
255
|
-
label={t('form.labels.quantity')}
|
|
256
|
-
>
|
|
257
|
-
{[...Array(getAvailableTicketsForRelease(item))].map((_, index2) => (
|
|
258
|
-
<MenuItem
|
|
259
|
-
key={index2}
|
|
260
|
-
value={index2 + 1}
|
|
261
|
-
disabled={isQuantityDisabled(index2 + 1, item.releaseId)}
|
|
262
|
-
>
|
|
263
|
-
{index2 + 1}
|
|
264
|
-
</MenuItem>
|
|
265
|
-
))}
|
|
266
|
-
{!item.releaseId && (
|
|
267
|
-
<MenuItem disabled sx={{ textTransform: 'unset!important' }}>
|
|
268
|
-
{t('event.tickets.stepper.1.quantity_select')}
|
|
269
|
-
</MenuItem>
|
|
270
|
-
)}
|
|
271
|
-
</RHFSelect>
|
|
272
|
-
{item.releaseId && item.quantity && (
|
|
273
|
-
<Box>
|
|
274
|
-
<IconButton color="primary" onClick={() => removeTicket(index)}>
|
|
275
|
-
<Iconify icon="carbon:trash-can" />
|
|
276
|
-
</IconButton>
|
|
277
|
-
</Box>
|
|
278
|
-
)}
|
|
279
|
-
</Stack>
|
|
280
|
-
)}
|
|
281
|
-
</Grid>
|
|
282
|
-
</Grid>
|
|
283
|
-
{activeReleases && item.releaseId && (
|
|
284
|
-
<Typography
|
|
285
|
-
variant="caption"
|
|
286
|
-
content="div"
|
|
287
|
-
mt={2}
|
|
288
|
-
mb={getRelease(item.releaseId)?.extraFields?.length ? 2 : 0}
|
|
289
|
-
display="block"
|
|
290
|
-
>
|
|
291
|
-
{getRelease(item.releaseId)?.description ?? ''}
|
|
292
|
-
</Typography>
|
|
293
|
-
)}
|
|
294
|
-
{getExtraFields(item.releaseId, index)}
|
|
295
|
-
</Box>
|
|
296
|
-
))}
|
|
297
|
-
<Box>
|
|
298
|
-
<Typography variant="caption" component="div" fontStyle="italic" mb={2}>
|
|
299
|
-
*{t('event.tickets.stepper.1.max_ticket_quantity')}
|
|
300
|
-
</Typography>
|
|
301
|
-
{isMobile && <FeeBox event={event} align="right" />}
|
|
302
|
-
</Box>
|
|
303
|
-
</Stack>
|
|
304
|
-
);
|
|
305
|
-
};
|
|
306
|
-
|
|
307
|
-
export default TicketSelection;
|
|
File without changes
|
|
File without changes
|
|
File without changes
|