Merge pull request #674 from Luca-Timo/feat/workflow-engine

fix: event-reminder, email-language & gallery-publish bugs surfaced during workflow testing
This commit is contained in:
Paul Nothaft
2026-06-27 21:45:07 +02:00
committed by GitHub
9 changed files with 158 additions and 42 deletions
@@ -7,6 +7,8 @@ interface PublishGalleryDialogProps {
eventName: string;
requirePassword: boolean;
customerEmail?: string | null;
/** Assigned customer accounts — notified via the account "your galleries" email when there's no inline email. */
assignedCustomerCount?: number;
isPublishing: boolean;
onConfirm: (password?: string) => void;
onClose: () => void;
@@ -28,24 +30,33 @@ export const PublishGalleryDialog: React.FC<PublishGalleryDialogProps> = ({
eventName,
requirePassword,
customerEmail,
assignedCustomerCount = 0,
isPublishing,
onConfirm,
onClose,
}) => {
const { t } = useTranslation();
// Someone gets notified if there's an inline email OR an assigned account
// (the latter via the account "your galleries" email).
const willNotify = !!customerEmail || assignedCustomerCount > 0;
// The password is only collected (and required) on the inline-email path,
// because the gallery_created email carries it. With no inline email the field
// is hidden and the existing hash is kept — so don't gate submit on it, or a
// password-protected gallery without an email could never be published.
const needsPassword = requirePassword && !!customerEmail;
const [password, setPassword] = useState('');
const [showPassword, setShowPassword] = useState(false);
const [error, setError] = useState<string | undefined>(undefined);
const handleSubmit = () => {
if (requirePassword) {
if (needsPassword) {
if (!password || password.trim().length < 6) {
setError(t('events.publishDialog.errorMinLength', 'Password must be at least 6 characters long.'));
return;
}
}
setError(undefined);
onConfirm(requirePassword ? password : undefined);
onConfirm(needsPassword ? password : undefined);
};
return (
@@ -72,14 +83,21 @@ export const PublishGalleryDialog: React.FC<PublishGalleryDialogProps> = ({
defaultValue:
'Publishing "{{eventName}}" makes the gallery accessible and sends the notification email to {{customerEmail}}.',
})
: t('events.publishDialog.descriptionNoEmail', {
eventName,
defaultValue:
'Publishing "{{eventName}}" makes the gallery accessible. No customer email is set, so no notification will be sent.',
})}
: assignedCustomerCount > 0
? t('events.publishDialog.descriptionAssignedAccount', {
eventName,
count: assignedCustomerCount,
defaultValue:
'Publishing "{{eventName}}" makes the gallery accessible. The assigned customer account(s) will be notified by email (in their language) that it is available.',
})
: t('events.publishDialog.descriptionNoEmail', {
eventName,
defaultValue:
'Publishing "{{eventName}}" makes the gallery accessible. No customer email is set, so no notification will be sent.',
})}
</p>
{requirePassword && customerEmail && (
{needsPassword && (
<div className="space-y-3 mb-4">
<Input
type={showPassword ? 'text' : 'password'}
@@ -133,9 +151,9 @@ export const PublishGalleryDialog: React.FC<PublishGalleryDialogProps> = ({
onClick={handleSubmit}
disabled={isPublishing}
isLoading={isPublishing}
leftIcon={<Send className="w-4 h-4" />}
leftIcon={willNotify ? <Send className="w-4 h-4" /> : undefined}
>
{t('events.publishAndNotify')}
{willNotify ? t('events.publishAndNotify') : t('events.publishDialog.justPublish', 'Publish')}
</Button>
</div>
</Card>
+2
View File
@@ -1125,6 +1125,8 @@
"title": "Galerie veröffentlichen",
"descriptionWithEmail": "Die Galerie \"{{eventName}}\" wird zugänglich gemacht und die Benachrichtigungs-E-Mail an {{customerEmail}} gesendet.",
"descriptionNoEmail": "Die Galerie \"{{eventName}}\" wird zugänglich gemacht. Es ist keine Kunden-E-Mail hinterlegt es wird keine Benachrichtigung gesendet.",
"descriptionAssignedAccount": "Die Galerie \"{{eventName}}\" wird zugänglich gemacht. Die zugewiesenen Kundenkonten werden per E-Mail (in ihrer Sprache) benachrichtigt, dass sie verfügbar ist.",
"justPublish": "Veröffentlichen",
"passwordLabel": "Galerie-Passwort",
"passwordPlaceholder": "Galerie-Passwort eingeben",
"passwordHelp": "Gib das bei der Erstellung gesetzte Passwort erneut ein (oder wähle ein neues). Die E-Mail enthält genau diesen Text; das Backend hasht es erneut, sodass die Galerie-Anmeldung weiterhin funktioniert.",
+2
View File
@@ -670,6 +670,8 @@
"title": "Publish gallery",
"descriptionWithEmail": "Publishing \"{{eventName}}\" makes the gallery accessible and sends the notification email to {{customerEmail}}.",
"descriptionNoEmail": "Publishing \"{{eventName}}\" makes the gallery accessible. No customer email is set, so no notification will be sent.",
"descriptionAssignedAccount": "Publishing \"{{eventName}}\" makes the gallery accessible. The assigned customer account(s) will be notified by email (in their language) that it is available.",
"justPublish": "Publish",
"passwordLabel": "Gallery password",
"passwordPlaceholder": "Enter the gallery password",
"passwordHelp": "Re-type the password set at creation (or pick a new one). The email includes this exact text; the backend re-hashes it so the gallery login still works.",
@@ -2661,6 +2661,7 @@ export const EventDetailsPage: React.FC = () => {
eventName={event.event_name}
requirePassword={isGalleryPublic(event) ? false : true}
customerEmail={event.customer_email}
assignedCustomerCount={((event as { customer_accounts?: Array<{ id: number }> }).customer_accounts || []).length}
isPublishing={publishMutation.isPending}
onConfirm={(password) => publishMutation.mutate(password)}
onClose={() => {