@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.
Files changed (91) hide show
  1. package/.claude/settings.local.json +6 -10
  2. package/.env.example +1 -0
  3. package/README.md +18 -16
  4. package/dist/cjs/{index-DvUR1fp8.js → index-CUIxdwQn.js} +3340 -577
  5. package/dist/cjs/index-CUIxdwQn.js.map +1 -0
  6. package/dist/cjs/index-D5rQiSGP.js +38574 -0
  7. package/dist/cjs/index-D5rQiSGP.js.map +1 -0
  8. package/dist/cjs/index.js +2 -2
  9. package/dist/cjs/{index.umd-6SU6nkkJ.js → index.umd-BoFEW91M.js} +9 -19
  10. package/dist/cjs/index.umd-BoFEW91M.js.map +1 -0
  11. package/dist/cjs/index.umd-BzSM62qM.js +13397 -0
  12. package/dist/cjs/index.umd-BzSM62qM.js.map +1 -0
  13. package/dist/esm/index-Cm7V8Zl3.js +38571 -0
  14. package/dist/esm/index-Cm7V8Zl3.js.map +1 -0
  15. package/dist/esm/{index-BlTqx0jm.js → index-fvLIN6eP.js} +3327 -563
  16. package/dist/esm/index-fvLIN6eP.js.map +1 -0
  17. package/dist/esm/index.js +2 -2
  18. package/dist/esm/{index.umd-Dn0hjh7E.js → index.umd-BKBHcCnm.js} +9 -19
  19. package/dist/esm/index.umd-BKBHcCnm.js.map +1 -0
  20. package/dist/esm/index.umd-bIV_YpEF.js +13395 -0
  21. package/dist/esm/index.umd-bIV_YpEF.js.map +1 -0
  22. package/dist/types/components/hook-form/FormProvider.d.ts +2 -1
  23. package/dist/types/form/PaymentOverviewBox.d.ts +2 -0
  24. package/dist/types/form/PaymentOverviewDrawer.d.ts +10 -0
  25. package/dist/types/form/TicketForm.d.ts +1 -0
  26. package/dist/types/form/index.d.ts +2 -1
  27. package/dist/types/form/merchandise/MerchandiseSelection.d.ts +9 -0
  28. package/dist/types/form/merchandise/MerchandiseSlider.d.ts +10 -0
  29. package/dist/types/form/payment/PaymentOverviewCheckbox.d.ts +0 -4
  30. package/dist/types/form/product/ProductVariantsDialog.d.ts +3 -1
  31. package/dist/types/form/services/index.d.ts +7 -0
  32. package/dist/types/form/style.d.ts +1 -0
  33. package/dist/types/form/tickets/ReleaseDescription.d.ts +10 -0
  34. package/dist/types/form/tickets/ReleaseWithMerchandise.d.ts +12 -0
  35. package/dist/types/form/tickets/TicketQuantityControl.d.ts +13 -0
  36. package/dist/types/form/tickets/TicketSelectionMobile.d.ts +16 -0
  37. package/dist/types/hooks/useScrollToFirstError.d.ts +4 -0
  38. package/dist/types/locales/cs.d.ts +22 -0
  39. package/dist/types/locales/en.d.ts +22 -0
  40. package/dist/types/locales/es.d.ts +22 -0
  41. package/dist/types/locales/pl.d.ts +22 -0
  42. package/dist/types/locales/sk.d.ts +22 -0
  43. package/dist/types/locales/uk.d.ts +22 -0
  44. package/dist/types/utils/data/global.d.ts +1 -0
  45. package/dist/types/utils/data/ticket.d.ts +1 -0
  46. package/package.json +10 -4
  47. package/rollup.config.mjs +7 -12
  48. package/src/components/hook-form/FormProvider.tsx +5 -2
  49. package/src/form/ChildEventDialog.tsx +3 -3
  50. package/src/form/ContactPerson.tsx +1 -1
  51. package/src/form/PaymentOverviewBox.tsx +96 -123
  52. package/src/form/PaymentOverviewDrawer.tsx +445 -0
  53. package/src/form/PaymentPending.tsx +19 -4
  54. package/src/form/ReleaseWithMerchandise.tsx +4 -4
  55. package/src/form/Shipping.tsx +48 -33
  56. package/src/form/TicketForm.tsx +146 -41
  57. package/src/form/index.tsx +3 -1
  58. package/src/form/merchandise/MerchandiseSelection.tsx +24 -0
  59. package/src/form/merchandise/MerchandiseSlider.tsx +62 -0
  60. package/src/form/payment/FeeBox.tsx +4 -31
  61. package/src/form/payment/PaymentOverviewCheckbox.tsx +68 -69
  62. package/src/form/product/ProductCard.tsx +258 -59
  63. package/src/form/product/ProductVariantsDialog.tsx +292 -139
  64. package/src/form/services/index.tsx +262 -0
  65. package/src/form/style.ts +16 -4
  66. package/src/form/tickets/ReleaseDescription.tsx +46 -0
  67. package/src/form/tickets/ReleaseWithMerchandise.tsx +267 -0
  68. package/src/form/tickets/TicketQuantityControl.tsx +100 -0
  69. package/src/form/tickets/TicketSelection.tsx +236 -0
  70. package/src/form/{TicketSelectionMap.tsx → tickets/TicketSelectionMap.tsx} +18 -2
  71. package/src/form/tickets/TicketSelectionMobile.tsx +188 -0
  72. package/src/form/{TicketWithMerchandiseSelection.tsx → tickets/TicketWithMerchandiseSelection.tsx} +52 -38
  73. package/src/hooks/useScrollToFirstError.ts +99 -0
  74. package/src/locales/cs.tsx +25 -3
  75. package/src/locales/en.tsx +23 -1
  76. package/src/locales/es.tsx +23 -1
  77. package/src/locales/pl.tsx +23 -1
  78. package/src/locales/sk.tsx +24 -2
  79. package/src/locales/uk.tsx +23 -1
  80. package/src/utils/data/global.ts +1 -0
  81. package/src/utils/data/ticket.ts +1 -0
  82. package/tsconfig.json +1 -1
  83. package/README +0 -1
  84. package/dist/cjs/index-DvUR1fp8.js.map +0 -1
  85. package/dist/cjs/index.umd-6SU6nkkJ.js.map +0 -1
  86. package/dist/esm/index-BlTqx0jm.js.map +0 -1
  87. package/dist/esm/index.umd-Dn0hjh7E.js.map +0 -1
  88. package/src/form/TicketSelection.tsx +0 -307
  89. /package/dist/types/form/{TicketSelection.d.ts → tickets/TicketSelection.d.ts} +0 -0
  90. /package/dist/types/form/{TicketSelectionMap.d.ts → tickets/TicketSelectionMap.d.ts} +0 -0
  91. /package/dist/types/form/{TicketWithMerchandiseSelection.d.ts → tickets/TicketWithMerchandiseSelection.d.ts} +0 -0
@@ -1,14 +1,6 @@
1
- import React, { JSX, useState } from 'react';
2
- import {
3
- Dialog,
4
- DialogContent,
5
- DialogTitle,
6
- IconButton,
7
- Link,
8
- Stack,
9
- Typography,
10
- } from '@mui/material';
11
- import { RHFCheckbox } from '@components/hook-form';
1
+ import React, { JSX } from 'react';
2
+ import { Box, Button, Stack, Typography } from '@mui/material';
3
+ import { Controller, useFormContext } from 'react-hook-form';
12
4
  import useGlobal from '@hooks/useGlobal';
13
5
  import { Iconify } from '@components';
14
6
 
@@ -16,71 +8,78 @@ interface Props {
16
8
  checkboxName: string;
17
9
  label: string;
18
10
  value: string | JSX.Element;
19
- modal: {
20
- title: string;
21
- description: string | JSX.Element;
22
- };
23
11
  }
24
12
 
25
- const PaymentOverviewCheckbox: React.FC<Props> = ({ checkboxName, label, value, modal }) => {
13
+ const PaymentOverviewCheckbox: React.FC<Props> = ({ checkboxName, label, value }) => {
26
14
  const { t } = useGlobal();
27
- const [open, setOpen] = useState(false);
28
-
29
- const handleOpen = (e: React.MouseEvent<HTMLAnchorElement>) => {
30
- e.preventDefault();
31
- e.stopPropagation();
32
- setOpen(true);
33
- };
34
- const handleClose = () => setOpen(false);
15
+ const { control } = useFormContext();
35
16
 
36
17
  return (
37
- <>
38
- <RHFCheckbox
39
- name={checkboxName}
40
- label={
41
- <Stack
42
- direction="row"
43
- justifyContent="space-between"
44
- alignItems="center"
45
- spacing={1}
46
- sx={{ width: '100%' }}
18
+ <Controller
19
+ name={checkboxName}
20
+ control={control}
21
+ render={({ field }) => (
22
+ <Stack
23
+ direction="row"
24
+ justifyContent="space-between"
25
+ alignItems="center"
26
+ useFlexGap
27
+ spacing={1}
28
+ sx={{ width: '100%', mb: 0.5 }}
29
+ >
30
+ <Typography variant="body2" sx={{ flex: 1 }}>
31
+ {label}
32
+ </Typography>
33
+ <Box
34
+ sx={{
35
+ position: 'relative',
36
+ display: 'flex',
37
+ alignItems: 'center',
38
+ }}
47
39
  >
48
- <Typography variant="caption" sx={{ flex: 1 }}>
49
- {label}
40
+ <Typography
41
+ variant="body2"
42
+ sx={{
43
+ mr: field.value ? 0 : 1,
44
+ ...(field.value
45
+ ? {
46
+ position: 'absolute',
47
+ right: 0,
48
+ }
49
+ : {}),
50
+ }}
51
+ >
52
+ {value}
50
53
  </Typography>
51
- <Stack alignItems="flex-end">
52
- <Typography variant="caption" fontWeight="600">
53
- {value}
54
- </Typography>
55
- <Link variant="caption" onClick={handleOpen}>
56
- {t('more_info')}
57
- </Link>
58
- </Stack>
59
- </Stack>
60
- }
61
- sx={{
62
- width: 'calc(100% + 11px)',
63
- mb: 0.5,
64
- '& > .MuiTypography-root': {
65
- width: '100%',
66
- },
67
- }}
68
- />
69
-
70
- <Dialog open={open} onClose={handleClose} maxWidth="sm" fullWidth>
71
- <DialogTitle
72
- sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}
73
- >
74
- {modal.title}
75
- <IconButton onClick={handleClose} size="small">
76
- <Iconify icon="carbon:close" />
77
- </IconButton>
78
- </DialogTitle>
79
- <DialogContent>
80
- <Typography variant="body2">{modal.description}</Typography>
81
- </DialogContent>
82
- </Dialog>
83
- </>
54
+ <Button
55
+ variant="outlined"
56
+ color="primary"
57
+ size="small"
58
+ startIcon={<Iconify icon="carbon:add" />}
59
+ onClick={(event) => {
60
+ event.preventDefault();
61
+ event.stopPropagation();
62
+ field.onChange(true);
63
+ }}
64
+ sx={{
65
+ borderRadius: 1,
66
+ textTransform: 'none',
67
+ px: 1,
68
+ width: 96,
69
+ minWidth: 96,
70
+ color: 'text.primary',
71
+ visibility: field.value ? 'hidden' : 'visible',
72
+ pointerEvents: field.value ? 'none' : 'auto',
73
+ }}
74
+ tabIndex={field.value ? -1 : 0}
75
+ aria-hidden={field.value}
76
+ >
77
+ {t('add')}
78
+ </Button>
79
+ </Box>
80
+ </Stack>
81
+ )}
82
+ />
84
83
  );
85
84
  };
86
85
 
@@ -1,6 +1,18 @@
1
- import { Button, Card, Stack, Typography } from '@mui/material';
2
- import { Iconify } from '@components/iconify';
1
+ import {
2
+ Box,
3
+ Button,
4
+ Card,
5
+ Dialog,
6
+ DialogActions,
7
+ DialogContent,
8
+ DialogTitle,
9
+ IconButton,
10
+ Link,
11
+ Stack,
12
+ Typography,
13
+ } from '@mui/material';
3
14
  import Image from '@components/Image';
15
+ import { Iconify } from '@components/iconify';
4
16
  import { IEventProduct } from '@utils/types/event-product.type';
5
17
  import React, { useMemo, useState } from 'react';
6
18
  import ProductVariantsDialog from '@form/product/ProductVariantsDialog';
@@ -9,6 +21,8 @@ import { useFormContext, useWatch } from 'react-hook-form';
9
21
  import { ITicketForm, ITicketFormTicket } from '@utils/types/ticket.type';
10
22
  import { getSelectedQuantityByVariant } from '@utils/product';
11
23
  import useGlobal from '@hooks/useGlobal';
24
+ import { fCurrency } from '@utils/formatNumber';
25
+ import { MAX_TICKETS_PER_ORDER } from '@utils/data/ticket';
12
26
 
13
27
  interface Props {
14
28
  eventProduct: IEventProduct;
@@ -17,85 +31,270 @@ interface Props {
17
31
  }
18
32
 
19
33
  const ProductCard: React.FC<Props> = ({ eventProduct, eventId, isOnlyMerchandise }) => {
20
- const { t } = useGlobal();
34
+ const { t, lang } = useGlobal();
21
35
  const [openVariantDialog, setOpenVariantDialog] = useState<boolean>(false);
22
- const { setValue } = useFormContext<ITicketForm>();
36
+ const [openSimpleProductDialog, setOpenSimpleProductDialog] = useState<boolean>(false);
37
+ const { setValue, getValues } = useFormContext<ITicketForm>();
23
38
  const tickets: ITicketFormTicket[] = useWatch({ name: `tickets.${eventId}`, defaultValue: [] });
24
39
  const products: IEventProductForm[] = useWatch({ name: `products.${eventId}`, defaultValue: [] });
40
+ const isSimpleProduct = eventProduct.eventProductVariants.length === 1;
41
+ const simpleVariant = isSimpleProduct ? eventProduct.eventProductVariants[0] : undefined;
25
42
 
26
- const onSelectVariant = (selectedVariant: IEventProductForm) => {
27
- const variant = products.find(
28
- (product) => product.eventProductVariantId === selectedVariant.eventProductVariantId
29
- );
43
+ const onSelectVariant = (selectedVariants: IEventProductForm[] | IEventProductForm) => {
44
+ const normalized = Array.isArray(selectedVariants) ? selectedVariants : [selectedVariants];
45
+ const currentProducts =
46
+ (getValues(`products.${eventId}`) as IEventProductForm[] | undefined) ?? [];
47
+ const nextProducts = [...currentProducts];
48
+
49
+ normalized.forEach((selectedVariant) => {
50
+ const index = nextProducts.findIndex(
51
+ (product) => product.eventProductVariantId === selectedVariant.eventProductVariantId
52
+ );
30
53
 
31
- if (variant) {
32
- if (selectedVariant.quantity === 0) {
33
- setValue(
34
- `products.${eventId}`,
35
- products.filter(
36
- (product) => product.eventProductVariantId !== variant.eventProductVariantId
37
- )
38
- );
54
+ if (index >= 0) {
55
+ if (selectedVariant.quantity <= 0) {
56
+ nextProducts.splice(index, 1);
57
+ } else {
58
+ nextProducts[index] = {
59
+ ...nextProducts[index],
60
+ quantity: selectedVariant.quantity,
61
+ };
62
+ }
39
63
  } else {
40
- setValue(
41
- `products.${eventId}`,
42
- products.map((product) => {
43
- if (product.eventProductVariantId === selectedVariant.eventProductVariantId) {
44
- return {
45
- ...product,
46
- quantity: selectedVariant.quantity,
47
- };
48
- }
49
- return product;
50
- })
51
- );
64
+ if (selectedVariant.quantity > 0) {
65
+ nextProducts.push(selectedVariant);
66
+ }
52
67
  }
53
- } else if (selectedVariant.quantity !== 0) {
54
- setValue(`products.${eventId}`, [...products, selectedVariant]);
55
- }
68
+ });
69
+
70
+ setValue(`products.${eventId}`, nextProducts, {
71
+ shouldDirty: true,
72
+ shouldValidate: true,
73
+ });
56
74
  };
57
75
 
58
- const eventNotEmpty = useMemo(() => products.some((product) => product?.quantity), [products]);
76
+ const eventNotEmpty = useMemo(() => {
77
+ const variantIds = new Set(eventProduct.eventProductVariants.map((variant) => variant.id));
78
+ return products.some(
79
+ (product) => product?.quantity && variantIds.has(product.eventProductVariantId)
80
+ );
81
+ }, [products, eventProduct.eventProductVariants]);
82
+
83
+ const selectedQuantityByVariant = useMemo(
84
+ () => getSelectedQuantityByVariant(products, tickets),
85
+ [products, tickets]
86
+ );
87
+
88
+ const simpleProductQuantity = useMemo(() => {
89
+ if (!simpleVariant) return 0;
90
+ const matched = products.find((product) => product.eventProductVariantId === simpleVariant.id);
91
+ return matched?.quantity ?? 0;
92
+ }, [products, simpleVariant]);
93
+
94
+ const simpleProductMaxAvailable = useMemo(() => {
95
+ if (!simpleVariant) return 0;
96
+ const { quantity, sold } = simpleVariant.productVariant;
97
+ if (!quantity) return Number.POSITIVE_INFINITY;
98
+ const used = selectedQuantityByVariant[simpleVariant.id] ?? 0;
99
+ return quantity - sold - used;
100
+ }, [simpleVariant, selectedQuantityByVariant]);
101
+
102
+ const onChangeSimpleProductQuantity = (nextQuantity: number) => {
103
+ if (!simpleVariant) return;
104
+ if (nextQuantity < 0 || nextQuantity > MAX_TICKETS_PER_ORDER) return;
105
+ if (
106
+ nextQuantity > simpleProductQuantity &&
107
+ nextQuantity - simpleProductQuantity > simpleProductMaxAvailable
108
+ )
109
+ return;
110
+
111
+ onSelectVariant({
112
+ eventProductVariantId: simpleVariant.id,
113
+ productVariantId: simpleVariant.productVariant.id,
114
+ quantity: nextQuantity,
115
+ price: simpleVariant.priceWithVat,
116
+ excludedShippingMethodIds: eventProduct.excludedShippingMethods.map((method) => method.id),
117
+ });
118
+ };
119
+
120
+ const simpleProductQuantityControl =
121
+ simpleProductQuantity > 0 ? (
122
+ <Stack direction="row" spacing={1} alignItems="center" width="100%">
123
+ <IconButton
124
+ onClick={() => onChangeSimpleProductQuantity(simpleProductQuantity - 1)}
125
+ disabled={simpleProductQuantity <= 0}
126
+ sx={{
127
+ flex: '1 1 0',
128
+ height: 36,
129
+ p: 0,
130
+ borderRadius: 1,
131
+ border: '1px solid',
132
+ borderColor: 'grey.300',
133
+ display: 'flex',
134
+ alignItems: 'center',
135
+ justifyContent: 'center',
136
+ }}
137
+ >
138
+ <Iconify icon="eva:minus-fill" width={18} height={18} />
139
+ </IconButton>
140
+ <Box
141
+ sx={{
142
+ flex: '1 1 0',
143
+ height: 36,
144
+ borderRadius: 1,
145
+ border: '1px solid',
146
+ borderColor: 'grey.300',
147
+ display: 'flex',
148
+ alignItems: 'center',
149
+ justifyContent: 'center',
150
+ fontWeight: 700,
151
+ }}
152
+ >
153
+ {simpleProductQuantity}
154
+ </Box>
155
+ <IconButton
156
+ onClick={() => onChangeSimpleProductQuantity(simpleProductQuantity + 1)}
157
+ disabled={
158
+ simpleProductQuantity >= MAX_TICKETS_PER_ORDER || simpleProductMaxAvailable <= 0
159
+ }
160
+ sx={{
161
+ flex: '1 1 0',
162
+ height: 36,
163
+ p: 0,
164
+ borderRadius: 1,
165
+ bgcolor: 'primary.main',
166
+ color: 'primary.contrastText',
167
+ '&:hover': { bgcolor: 'primary.dark' },
168
+ '&.Mui-disabled': {
169
+ bgcolor: 'action.disabledBackground',
170
+ color: 'action.disabled',
171
+ },
172
+ }}
173
+ >
174
+ <Iconify icon="eva:plus-fill" width={18} height={18} />
175
+ </IconButton>
176
+ </Stack>
177
+ ) : (
178
+ <Button
179
+ variant="contained"
180
+ onClick={() => onChangeSimpleProductQuantity(1)}
181
+ disabled={simpleProductMaxAvailable <= 0}
182
+ fullWidth
183
+ >
184
+ {t('add')}
185
+ </Button>
186
+ );
59
187
 
60
188
  return (
61
189
  <>
62
- <Card sx={{ p: 2 }}>
63
- <Stack spacing={1}>
64
- <Image src={eventProduct.product.previewImage.url} ratio="1/1" sx={{ borderRadius: 2 }} />
65
- <Typography variant="h5">{eventProduct.product.name}</Typography>
66
- <Typography
67
- variant="caption"
68
- dangerouslySetInnerHTML={{ __html: eventProduct.product.description }}
69
- sx={{
70
- height: 44,
71
- textOverflow: 'ellipsis',
72
- overflow: 'hidden',
73
- display: '-webkit-box',
74
- WebkitLineClamp: 2,
75
- WebkitBoxOrient: 'vertical',
76
- }}
190
+ <Card
191
+ sx={{
192
+ p: 0,
193
+ borderRadius: 0,
194
+ boxShadow: 'none',
195
+ background: 'none',
196
+ }}
197
+ >
198
+ <Stack spacing={0}>
199
+ <Image
200
+ src={eventProduct.product.previewImage.url}
201
+ ratio="21/9"
202
+ sx={{ borderRadius: 1, maxHeight: 96 }}
77
203
  />
78
- <Button
79
- variant="contained"
80
- onClick={() => setOpenVariantDialog(true)}
81
- fullWidth
82
- startIcon={
83
- eventNotEmpty ? <Iconify icon="eva:edit-fill" /> : <Iconify icon="eva:plus-fill" />
84
- }
85
- >
86
- {eventNotEmpty ? t('change') : t('add')}
87
- </Button>
204
+ <Typography variant="h5" sx={{ fontSize: '14px', fontWeight: 700 }}>
205
+ {eventProduct.product.name}
206
+ </Typography>
207
+ <Stack direction="row" alignItems="center" justifyContent="space-between" spacing={1}>
208
+ <Typography variant="body2" color="text.primary">
209
+ {eventProduct.product.priceWithVat > 0
210
+ ? fCurrency(eventProduct.product.priceWithVat, lang, eventProduct.product.currency)
211
+ : t('free')}
212
+ </Typography>
213
+ {isSimpleProduct && (
214
+ <Link
215
+ onClick={() => setOpenSimpleProductDialog(true)}
216
+ color="inherit"
217
+ underline="always"
218
+ fontSize={12}
219
+ >
220
+ {t('more_info')}
221
+ </Link>
222
+ )}
223
+ </Stack>
224
+ {isSimpleProduct ? (
225
+ simpleProductQuantityControl
226
+ ) : (
227
+ <Button
228
+ variant={eventNotEmpty ? 'contained' : 'outlined'}
229
+ onClick={() => setOpenVariantDialog(true)}
230
+ fullWidth
231
+ sx={{
232
+ color: eventNotEmpty ? (theme) => theme.palette.common.white : 'inherit',
233
+ borderColor: (theme) => theme.palette.grey[300],
234
+ }}
235
+ >
236
+ {eventNotEmpty
237
+ ? t('event.tickets.merchandise.show_added')
238
+ : t('event.tickets.merchandise.show_sizes')}
239
+ </Button>
240
+ )}
88
241
  </Stack>
89
242
  </Card>
90
243
  <ProductVariantsDialog
91
244
  eventProduct={eventProduct}
92
245
  eventId={eventId}
93
- openDialog={openVariantDialog}
246
+ openDialog={openVariantDialog && !isSimpleProduct}
94
247
  onClose={() => setOpenVariantDialog(false)}
95
248
  callback={onSelectVariant}
96
- selectedQuantityByVariant={getSelectedQuantityByVariant(products, tickets)}
249
+ selectedQuantityByVariant={selectedQuantityByVariant}
97
250
  isOnlyMerchandise={isOnlyMerchandise}
98
251
  />
252
+ <Dialog
253
+ open={openSimpleProductDialog && isSimpleProduct}
254
+ onClose={() => setOpenSimpleProductDialog(false)}
255
+ fullWidth
256
+ maxWidth="sm"
257
+ >
258
+ <DialogTitle
259
+ sx={{
260
+ textAlign: 'center',
261
+ fontWeight: 700,
262
+ fontSize: { xs: '1.5rem', sm: '2rem' },
263
+ mb: 2,
264
+ }}
265
+ >
266
+ {eventProduct.product.name}
267
+ </DialogTitle>
268
+ <DialogContent sx={{ pb: 0 }}>
269
+ <Stack spacing={2}>
270
+ <Typography
271
+ variant="body2"
272
+ dangerouslySetInnerHTML={{ __html: eventProduct.product.description }}
273
+ />
274
+ <Typography variant="body1" color="text.primary">
275
+ {eventProduct.product.priceWithVat > 0
276
+ ? fCurrency(eventProduct.product.priceWithVat, lang, eventProduct.product.currency)
277
+ : t('free')}
278
+ </Typography>
279
+ </Stack>
280
+ </DialogContent>
281
+ <DialogActions sx={{ px: 3, pb: 3 }}>
282
+ <Stack spacing={1} width="100%">
283
+ {simpleProductQuantityControl}
284
+ <Button
285
+ variant="outlined"
286
+ onClick={() => setOpenSimpleProductDialog(false)}
287
+ fullWidth
288
+ sx={{
289
+ color: 'inherit',
290
+ borderColor: (theme) => theme.palette.grey[300],
291
+ }}
292
+ >
293
+ {t('close')}
294
+ </Button>
295
+ </Stack>
296
+ </DialogActions>
297
+ </Dialog>
99
298
  </>
100
299
  );
101
300
  };