import React from 'react'; import { useTranslation } from 'react-i18next'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Textarea } from '@/components/ui/textarea'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import type { EventQrInviteLayout } from '../../api'; export type QrLayoutCustomization = { layout_id?: string; headline?: string; subtitle?: string; description?: string; badge_label?: string; instructions_heading?: string; instructions?: string[]; link_heading?: string; link_label?: string; cta_label?: string; accent_color?: string; text_color?: string; background_color?: string; secondary_color?: string; badge_color?: string; background_gradient?: { angle?: number; stops?: string[] } | null; logo_data_url?: string | null; logo_url?: string | null; }; const MAX_INSTRUCTIONS = 5; type Props = { open: boolean; onClose: () => void; onSubmit: (customization: QrLayoutCustomization) => Promise; onReset: () => Promise; saving: boolean; inviteUrl: string; eventName: string; layouts: EventQrInviteLayout[]; initialCustomization: QrLayoutCustomization | null; }; export function QrInviteCustomizationDialog({ open, onClose, onSubmit, onReset, saving, inviteUrl, eventName, layouts, initialCustomization, }: Props) { const { t } = useTranslation('management'); const [selectedLayoutId, setSelectedLayoutId] = React.useState(); const [form, setForm] = React.useState({}); const [instructions, setInstructions] = React.useState([]); const [error, setError] = React.useState(null); const defaultInstructions = React.useMemo(() => { const value = t('tasks.customizer.defaults.instructions', { returnObjects: true }) as unknown; return Array.isArray(value) ? (value as string[]) : ['QR-Code scannen', 'Profil anlegen', 'Fotos teilen']; }, [t]); const selectedLayout = React.useMemo(() => { if (layouts.length === 0) { return undefined; } const fallback = layouts[0]; if (!selectedLayoutId) { return fallback; } return layouts.find((layout) => layout.id === selectedLayoutId) ?? fallback; }, [layouts, selectedLayoutId]); React.useEffect(() => { if (!open) { return; } const defaultLayout = initialCustomization?.layout_id ? layouts.find((layout) => layout.id === initialCustomization.layout_id) : undefined; const layout = defaultLayout ?? layouts[0]; setSelectedLayoutId(layout?.id); const nextInstructions = Array.isArray(initialCustomization?.instructions) ? initialCustomization!.instructions! : []; setInstructions(nextInstructions.length > 0 ? nextInstructions : defaultInstructions); setForm({ layout_id: layout?.id, headline: initialCustomization?.headline ?? eventName, subtitle: initialCustomization?.subtitle ?? layout?.subtitle ?? '', description: initialCustomization?.description ?? layout?.description ?? '', badge_label: initialCustomization?.badge_label ?? t('tasks.customizer.defaults.badgeLabel'), instructions_heading: initialCustomization?.instructions_heading ?? t("tasks.customizer.defaults.instructionsHeading"), link_heading: initialCustomization?.link_heading ?? t('tasks.customizer.defaults.linkHeading'), link_label: initialCustomization?.link_label ?? inviteUrl, cta_label: initialCustomization?.cta_label ?? t('tasks.customizer.defaults.ctaLabel'), accent_color: initialCustomization?.accent_color ?? layout?.preview?.accent ?? '#6366F1', text_color: initialCustomization?.text_color ?? layout?.preview?.text ?? '#111827', background_color: initialCustomization?.background_color ?? layout?.preview?.background ?? '#FFFFFF', secondary_color: initialCustomization?.secondary_color ?? 'rgba(15,23,42,0.08)', badge_color: initialCustomization?.badge_color ?? layout?.preview?.accent ?? '#2563EB', background_gradient: initialCustomization?.background_gradient ?? layout?.preview?.background_gradient ?? null, logo_data_url: initialCustomization?.logo_data_url ?? initialCustomization?.logo_url ?? null, }); setError(null); }, [open, layouts, initialCustomization, inviteUrl, eventName, t]); React.useEffect(() => { if (!selectedLayout) { return; } setForm((prev) => ({ ...prev, layout_id: selectedLayout.id, accent_color: prev.accent_color ?? selectedLayout.preview?.accent ?? '#6366F1', text_color: prev.text_color ?? selectedLayout.preview?.text ?? '#111827', background_color: prev.background_color ?? selectedLayout.preview?.background ?? '#FFFFFF', background_gradient: prev.background_gradient ?? selectedLayout.preview?.background_gradient ?? null, })); }, [selectedLayout]); const handleColorChange = (key: keyof QrLayoutCustomization) => (event: React.ChangeEvent) => { setForm((prev) => ({ ...prev, [key]: event.target.value })); }; const handleInputChange = (key: keyof QrLayoutCustomization) => (event: React.ChangeEvent) => { setForm((prev) => ({ ...prev, [key]: event.target.value })); }; const handleInstructionChange = (index: number, value: string) => { setInstructions((prev) => { const next = [...prev]; next[index] = value; return next; }); }; const handleAddInstruction = () => { setInstructions((prev) => (prev.length < MAX_INSTRUCTIONS ? [...prev, ''] : prev)); }; const handleRemoveInstruction = (index: number) => { setInstructions((prev) => prev.filter((_, idx) => idx !== index)); }; const handleLogoUpload = (event: React.ChangeEvent) => { const file = event.target.files?.[0]; if (!file) { return; } if (file.size > 1024 * 1024) { setError(t('tasks.customizer.errors.logoTooLarge', 'Das Logo darf maximal 1 MB groß sein.')); return; } const reader = new FileReader(); reader.onload = () => { setForm((prev) => ({ ...prev, logo_data_url: typeof reader.result === 'string' ? reader.result : null })); setError(null); }; reader.readAsDataURL(file); }; const handleLogoRemove = () => { setForm((prev) => ({ ...prev, logo_data_url: null })); }; const effectiveInstructions = instructions.filter((entry) => entry.trim().length > 0); const preview = React.useMemo(() => { const backgroundStyle = form.background_gradient?.stops && form.background_gradient.stops.length > 0 ? `linear-gradient(${form.background_gradient.angle ?? 180}deg, ${form.background_gradient.stops.join(',')})` : form.background_color ?? selectedLayout?.preview?.background ?? '#FFFFFF'; return { background: backgroundStyle, accent: form.accent_color ?? selectedLayout?.preview?.accent ?? '#6366F1', text: form.text_color ?? selectedLayout?.preview?.text ?? '#111827', secondary: form.secondary_color ?? 'rgba(15,23,42,0.08)', }; }, [form, selectedLayout]); const handleSubmit = async (event: React.FormEvent) => { event.preventDefault(); if (!selectedLayout) { setError(t('tasks.customizer.errors.noLayout', 'Bitte wähle ein Layout aus.')); return; } setError(null); await onSubmit({ ...form, layout_id: selectedLayout.id, instructions: effectiveInstructions, }); }; const handleReset = async () => { setError(null); await onReset(); }; return ( (!value ? onClose() : null)}> {t('tasks.customizer.title', 'QR-Einladung anpassen')} {t('tasks.customizer.description', 'Passe Layout, Texte und Farben deiner QR-Einladung an.')}