events werden nun erfolgreich gespeichert, branding wird nun erfolgreich gespeichert, emotionen können nun angelegt werden. Task Ansicht im Event admin verbessert, Buttons in FAB umgewandelt und vereinheitlicht. Teilen-Link Guest PWA schicker gemacht, SynGoogleFonts ausgebaut (mit Einzel-Family-Download).
This commit is contained in:
@@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||||
import { AlertTriangle, ArrowLeft, Loader2, Save, Sparkles } from 'lucide-react';
|
||||
import toast from 'react-hot-toast';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
|
||||
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
@@ -16,6 +16,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@
|
||||
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion';
|
||||
|
||||
import { AdminLayout } from '../components/AdminLayout';
|
||||
import { FloatingActionBar } from '../components/FloatingActionBar';
|
||||
import {
|
||||
createEvent,
|
||||
getEvent,
|
||||
@@ -67,6 +68,7 @@ export default function EventFormPage() {
|
||||
const slugParam = params.slug ?? searchParams.get('slug') ?? undefined;
|
||||
const isEdit = Boolean(slugParam);
|
||||
const navigate = useNavigate();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const { t: tErrors } = useTranslation('common', { keyPrefix: 'errors' });
|
||||
const { t: tForm } = useTranslation('management', { keyPrefix: 'eventForm' });
|
||||
@@ -88,6 +90,7 @@ export default function EventFormPage() {
|
||||
const [showUpgradeHint, setShowUpgradeHint] = React.useState(false);
|
||||
const [readOnlyPackageName, setReadOnlyPackageName] = React.useState<string | null>(null);
|
||||
const [eventPackageMeta, setEventPackageMeta] = React.useState<EventPackageMeta | null>(null);
|
||||
const formRef = React.useRef<HTMLFormElement | null>(null);
|
||||
|
||||
const { data: packages, isLoading: packagesLoading } = useQuery({
|
||||
queryKey: ['packages', 'endcustomer'],
|
||||
@@ -143,7 +146,7 @@ export default function EventFormPage() {
|
||||
queryKey: ['tenant', 'events', slugParam],
|
||||
queryFn: () => getEvent(slugParam!),
|
||||
enabled: Boolean(isEdit && slugParam),
|
||||
staleTime: 60_000,
|
||||
staleTime: 0,
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
@@ -277,6 +280,16 @@ export default function EventFormPage() {
|
||||
}
|
||||
}
|
||||
|
||||
const handleSubmitClick = React.useCallback(() => {
|
||||
if (formRef.current) {
|
||||
if (typeof formRef.current.requestSubmit === 'function') {
|
||||
formRef.current.requestSubmit();
|
||||
} else {
|
||||
formRef.current.submit();
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
|
||||
async function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
|
||||
event.preventDefault();
|
||||
const trimmedName = form.name.trim();
|
||||
@@ -320,14 +333,20 @@ export default function EventFormPage() {
|
||||
if (isEdit) {
|
||||
const targetSlug = originalSlug ?? slugParam!;
|
||||
const updated = await updateEvent(targetSlug, payload);
|
||||
queryClient.invalidateQueries({ queryKey: ['tenant', 'events'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['tenant', 'events', targetSlug] });
|
||||
queryClient.invalidateQueries({ queryKey: ['tenant', 'dashboard'] });
|
||||
setOriginalSlug(updated.slug);
|
||||
setShowUpgradeHint(false);
|
||||
setError(null);
|
||||
toast.success(tForm('actions.saved', 'Event gespeichert'));
|
||||
navigate(ADMIN_EVENT_VIEW_PATH(updated.slug));
|
||||
} else {
|
||||
const { event: created } = await createEvent(payload);
|
||||
queryClient.invalidateQueries({ queryKey: ['tenant', 'events'] });
|
||||
setShowUpgradeHint(false);
|
||||
setError(null);
|
||||
toast.success(tForm('actions.saved', 'Event gespeichert'));
|
||||
navigate(ADMIN_EVENT_VIEW_PATH(created.slug));
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -456,6 +475,26 @@ export default function EventFormPage() {
|
||||
</Button>
|
||||
);
|
||||
|
||||
const fabActions = [
|
||||
{
|
||||
key: 'save',
|
||||
label: saving ? tForm('actions.saving', 'Speichert') : tForm('actions.save', 'Speichern'),
|
||||
icon: Save,
|
||||
onClick: handleSubmitClick,
|
||||
loading: saving,
|
||||
disabled: loading || !form.name.trim() || !form.slug.trim() || !form.eventTypeId,
|
||||
tone: 'primary' as const,
|
||||
},
|
||||
{
|
||||
key: 'cancel',
|
||||
label: tForm('actions.cancel', 'Abbrechen'),
|
||||
icon: ArrowLeft,
|
||||
onClick: () => navigate(-1),
|
||||
disabled: saving,
|
||||
tone: 'secondary' as const,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<AdminLayout
|
||||
title={isEdit ? tForm('titles.edit', 'Event bearbeiten') : tForm('titles.create', 'Neues Event erstellen')}
|
||||
@@ -500,7 +539,7 @@ export default function EventFormPage() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Card className="border-0 bg-white/85 shadow-xl shadow-fuchsia-100/60">
|
||||
<Card className="border-0 bg-white/85 shadow-xl shadow-fuchsia-100/60 pb-28">
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2 text-xl text-slate-900">
|
||||
<Sparkles className="h-5 w-5 text-pink-500" /> {tForm('sections.details.title', 'Eventdetails')}
|
||||
@@ -513,7 +552,7 @@ export default function EventFormPage() {
|
||||
{loading ? (
|
||||
<FormSkeleton />
|
||||
) : (
|
||||
<form className="space-y-6" onSubmit={handleSubmit}>
|
||||
<form className="space-y-6" onSubmit={handleSubmit} ref={formRef}>
|
||||
<div className="grid gap-4 sm:grid-cols-2">
|
||||
<div className="space-y-2 sm:col-span-2">
|
||||
<Label htmlFor="event-name">{tForm('fields.name.label', 'Eventname')}</Label>
|
||||
@@ -585,26 +624,6 @@ export default function EventFormPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap gap-3">
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={saving || !form.name.trim() || !form.slug.trim() || !form.eventTypeId}
|
||||
className="bg-gradient-to-r from-pink-500 via-fuchsia-500 to-purple-500 text-white shadow-lg shadow-pink-500/20"
|
||||
>
|
||||
{saving ? (
|
||||
<>
|
||||
<Loader2 className="h-4 w-4 animate-spin" /> {tForm('actions.saving', 'Speichert')}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Save className="h-4 w-4" /> {tForm('actions.save', 'Speichern')}
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
<Button variant="ghost" type="button" onClick={() => navigate(-1)}>
|
||||
{tForm('actions.cancel', 'Abbrechen')}
|
||||
</Button>
|
||||
</div>
|
||||
<div className="sm:col-span-2 mt-6">
|
||||
<Accordion type="single" collapsible defaultValue="package">
|
||||
<AccordionItem value="package" className="border-0">
|
||||
@@ -695,6 +714,7 @@ export default function EventFormPage() {
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
<FloatingActionBar actions={fabActions} />
|
||||
</AdminLayout>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user