From 22e399a25e2569766aa251bfe75a72f6aaaf55bc Mon Sep 17 00:00:00 2001 From: Dave Earley Date: Wed, 3 Jun 2026 21:30:01 +0100 Subject: [PATCH] Feature: Add ticket date display options --- VERSION | 2 +- backend/VERSION | 0 .../Enums/TicketDateDisplayMode.php | 12 +++ .../UpdateEventSettingsRequest.php | 2 + .../DTO/UpdateEventSettingsDTO.php | 2 + backend/composer.json | 2 +- .../UpdateEventSettingsRequestTest.php | 46 +++++++++++ frontend/package.json | 2 +- .../common/AttendeeTicket/index.tsx | 16 ++-- .../event/TicketDesigner/TicketPreview.tsx | 2 + .../routes/event/TicketDesigner/index.tsx | 21 ++++- frontend/src/locales/de.js | 2 +- frontend/src/locales/de.po | 82 ++++++++++++------- frontend/src/locales/en.js | 2 +- frontend/src/locales/en.po | 82 ++++++++++++------- frontend/src/locales/es.js | 2 +- frontend/src/locales/es.po | 82 ++++++++++++------- frontend/src/locales/fr.js | 2 +- frontend/src/locales/fr.po | 82 ++++++++++++------- frontend/src/locales/hu.js | 2 +- frontend/src/locales/hu.po | 82 ++++++++++++------- frontend/src/locales/it.js | 2 +- frontend/src/locales/it.po | 82 ++++++++++++------- frontend/src/locales/nl.js | 2 +- frontend/src/locales/nl.po | 82 ++++++++++++------- frontend/src/locales/pl.js | 2 +- frontend/src/locales/pl.po | 82 ++++++++++++------- frontend/src/locales/pt-br.js | 2 +- frontend/src/locales/pt-br.po | 82 ++++++++++++------- frontend/src/locales/pt.js | 2 +- frontend/src/locales/pt.po | 82 ++++++++++++------- frontend/src/locales/ru.js | 2 +- frontend/src/locales/ru.po | 82 ++++++++++++------- frontend/src/locales/se.js | 2 +- frontend/src/locales/se.po | 82 ++++++++++++------- frontend/src/locales/tr.js | 2 +- frontend/src/locales/tr.po | 82 ++++++++++++------- frontend/src/locales/vi.js | 2 +- frontend/src/locales/vi.po | 82 ++++++++++++------- frontend/src/locales/zh-cn.js | 2 +- frontend/src/locales/zh-cn.po | 82 ++++++++++++------- frontend/src/locales/zh-hk.js | 2 +- frontend/src/locales/zh-hk.po | 82 ++++++++++++------- frontend/src/types.ts | 1 + 44 files changed, 931 insertions(+), 521 deletions(-) create mode 100644 backend/VERSION create mode 100644 backend/app/DomainObjects/Enums/TicketDateDisplayMode.php create mode 100644 backend/tests/Unit/Http/Request/EventSettings/UpdateEventSettingsRequestTest.php diff --git a/VERSION b/VERSION index 482f3d312c..5bc7cd46d4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.8.0-beta +1.10.0-beta diff --git a/backend/VERSION b/backend/VERSION new file mode 100644 index 0000000000..e69de29bb2 diff --git a/backend/app/DomainObjects/Enums/TicketDateDisplayMode.php b/backend/app/DomainObjects/Enums/TicketDateDisplayMode.php new file mode 100644 index 0000000000..1a777de691 --- /dev/null +++ b/backend/app/DomainObjects/Enums/TicketDateDisplayMode.php @@ -0,0 +1,12 @@ + ['nullable', 'integer'], 'ticket_design_settings.footer_text' => ['nullable', 'string', 'max:500'], 'ticket_design_settings.layout_type' => ['nullable', 'string', Rule::in(['default', 'modern'])], + 'ticket_design_settings.date_display_mode' => ['nullable', 'string', Rule::in(TicketDateDisplayMode::valuesArray())], 'ticket_design_settings.enabled' => ['boolean'], // Marketing settings diff --git a/backend/app/Services/Application/Handlers/EventSettings/DTO/UpdateEventSettingsDTO.php b/backend/app/Services/Application/Handlers/EventSettings/DTO/UpdateEventSettingsDTO.php index 6d3c3864f1..ca73dec5a3 100644 --- a/backend/app/Services/Application/Handlers/EventSettings/DTO/UpdateEventSettingsDTO.php +++ b/backend/app/Services/Application/Handlers/EventSettings/DTO/UpdateEventSettingsDTO.php @@ -8,6 +8,7 @@ use HiEvents\DomainObjects\Enums\HomepageBackgroundType; use HiEvents\DomainObjects\Enums\PaymentProviders; use HiEvents\DomainObjects\Enums\PriceDisplayMode; +use HiEvents\DomainObjects\Enums\TicketDateDisplayMode; use HiEvents\DomainObjects\OrganizerDomainObject; class UpdateEventSettingsDTO extends BaseDTO @@ -150,6 +151,7 @@ public static function createWithDefaults( 'logo_image_id' => null, 'footer_text' => null, 'layout_type' => 'classic', + 'date_display_mode' => TicketDateDisplayMode::START_DATE_TIME->value, 'enabled' => true, ], diff --git a/backend/composer.json b/backend/composer.json index e9768d531c..c12f67d49a 100644 --- a/backend/composer.json +++ b/backend/composer.json @@ -4,7 +4,7 @@ "description": "hi.events - Ticket selling and event management.", "keywords": ["ticketing", "events"], "license": "AGPL-3.0", - "version": "1.8.0-beta", + "version": "1.10.0-beta", "require": { "php": "^8.2", "ext-intl": "*", diff --git a/backend/tests/Unit/Http/Request/EventSettings/UpdateEventSettingsRequestTest.php b/backend/tests/Unit/Http/Request/EventSettings/UpdateEventSettingsRequestTest.php new file mode 100644 index 0000000000..0e66005956 --- /dev/null +++ b/backend/tests/Unit/Http/Request/EventSettings/UpdateEventSettingsRequestTest.php @@ -0,0 +1,46 @@ + ['date_display_mode' => $mode]], + (new UpdateEventSettingsRequest)->rules() + ); + + $this->assertFalse( + $validator->errors()->has('ticket_design_settings.date_display_mode'), + "Expected '{$mode}' to be a valid date display mode" + ); + } + } + + public function test_invalid_date_display_mode_is_rejected(): void + { + $validator = Validator::make( + ['ticket_design_settings' => ['date_display_mode' => 'NOT_A_MODE']], + (new UpdateEventSettingsRequest)->rules() + ); + + $this->assertTrue($validator->errors()->has('ticket_design_settings.date_display_mode')); + } + + public function test_date_display_mode_is_optional(): void + { + $validator = Validator::make( + ['ticket_design_settings' => ['accent_color' => '#333333']], + (new UpdateEventSettingsRequest)->rules() + ); + + $this->assertFalse($validator->errors()->has('ticket_design_settings.date_display_mode')); + } +} diff --git a/frontend/package.json b/frontend/package.json index 09e15f7f65..3e0a2de45d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "hievents-frontend", "private": true, - "version": "1.8.0-beta", + "version": "1.10.0-beta", "type": "module", "scripts": { "dev:csr": "vite --port 5678 --host 0.0.0.0", diff --git a/frontend/src/components/common/AttendeeTicket/index.tsx b/frontend/src/components/common/AttendeeTicket/index.tsx index a30dedcc27..e67ceebe04 100644 --- a/frontend/src/components/common/AttendeeTicket/index.tsx +++ b/frontend/src/components/common/AttendeeTicket/index.tsx @@ -3,6 +3,7 @@ import {Button, CopyButton} from "@mantine/core"; import {formatCurrency} from "../../../utilites/currency.ts"; import {t} from "@lingui/macro"; import {prettyDate} from "../../../utilites/dates.ts"; +import {EventDateRange} from "../EventDateRange"; import QRCode from "react-qr-code"; import {IconCopy, IconPrinter, IconLock, IconX} from "@tabler/icons-react"; import {Address, Attendee, Event, Product} from "../../../types.ts"; @@ -32,6 +33,7 @@ export const AttendeeTicket = ({ const ticketDesignSettings = event?.settings?.ticket_design_settings; const accentColor = ticketDesignSettings?.accent_color || '#6B46C1'; const footerText = ticketDesignSettings?.footer_text; + const dateDisplayMode = ticketDesignSettings?.date_display_mode || 'START_DATE_TIME'; const logoUrl = imageUrl('TICKET_LOGO', event?.images); const ticketStyle = { @@ -71,12 +73,16 @@ export const AttendeeTicket = ({
{/* Event Details */}
-
-
{t`Date & Time`}
-
- {prettyDate(event.start_date, event.timezone, true)} + {dateDisplayMode !== 'HIDDEN' && ( +
+
{t`Date & Time`}
+
+ {dateDisplayMode === 'DATE_RANGE' + ? + : prettyDate(event.start_date, event.timezone, true)} +
-
+ )} {event?.organizer?.name && (
{t`Organizer`}
diff --git a/frontend/src/components/routes/event/TicketDesigner/TicketPreview.tsx b/frontend/src/components/routes/event/TicketDesigner/TicketPreview.tsx index 26da7b28b0..e88adebb5a 100644 --- a/frontend/src/components/routes/event/TicketDesigner/TicketPreview.tsx +++ b/frontend/src/components/routes/event/TicketDesigner/TicketPreview.tsx @@ -10,6 +10,7 @@ interface TicketDesignSettings { accent_color: string; logo_image_id: IdParam | null; footer_text: string | null; + date_display_mode: 'START_DATE_TIME' | 'DATE_RANGE' | 'HIDDEN'; enabled: boolean; } @@ -82,6 +83,7 @@ export const TicketPreview = ({settings, eventId, logoUrl}: TicketPreviewProps) accent_color: settings.accent_color, logo_image_id: settings.logo_image_id, footer_text: settings.footer_text, + date_display_mode: settings.date_display_mode, enabled: settings.enabled }, location_details: eventSettings?.location_details || { diff --git a/frontend/src/components/routes/event/TicketDesigner/index.tsx b/frontend/src/components/routes/event/TicketDesigner/index.tsx index 807feb2c13..250d9439a0 100644 --- a/frontend/src/components/routes/event/TicketDesigner/index.tsx +++ b/frontend/src/components/routes/event/TicketDesigner/index.tsx @@ -8,7 +8,7 @@ import {IdParam} from "../../../../types.ts"; import {showSuccess} from "../../../../utilites/notifications.tsx"; import {t} from "@lingui/macro"; import {useForm} from "@mantine/form"; -import {Button, ColorInput, Textarea, Accordion, Stack, Text, Group} from "@mantine/core"; +import {Button, ColorInput, Textarea, Accordion, Stack, Text, Group, Select} from "@mantine/core"; import {IconColorSwatch, IconHelp, IconPrinter} from "@tabler/icons-react"; import {Tooltip} from "../../../common/Tooltip"; import {ImageUploadDropzone} from "../../../common/ImageUploadDropzone"; @@ -21,6 +21,7 @@ interface TicketDesignSettings { accent_color: string; logo_image_id: IdParam; footer_text: string | null; + date_display_mode: 'START_DATE_TIME' | 'DATE_RANGE' | 'HIDDEN'; enabled: boolean; } @@ -39,6 +40,7 @@ const TicketDesigner = () => { accent_color: '#333333', logo_image_id: undefined, footer_text: '', + date_display_mode: 'START_DATE_TIME', enabled: true, } }); @@ -52,6 +54,7 @@ const TicketDesigner = () => { accent_color: settings.accent_color || '#333333', logo_image_id: settings.logo_image_id || undefined, footer_text: settings.footer_text || '', + date_display_mode: settings.date_display_mode || 'START_DATE_TIME', enabled: settings.enabled !== false, }); } @@ -73,6 +76,7 @@ const TicketDesigner = () => { accent_color: values.accent_color, logo_image_id: values.logo_image_id, footer_text: values.footer_text || undefined, + date_display_mode: values.date_display_mode, enabled: values.enabled } }, @@ -177,6 +181,21 @@ const TicketDesigner = () => { {form.values.footer_text?.length || 0} / 500
+ +
+