Files
fotospiel-app/resources/js/admin/pages/EngagementPage.tsx

140 lines
5.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React from 'react';
import { useSearchParams } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { Button } from '@/components/ui/button';
import { AdminLayout } from '../components/AdminLayout';
import { CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import {
TenantHeroCard,
FrostedCard,
FrostedSurface,
tenantHeroPrimaryButtonClass,
tenantHeroSecondaryButtonClass,
} from '../components/tenant';
import { TasksSection } from './TasksPage';
import { TaskCollectionsSection } from './TaskCollectionsPage';
import { EmotionsSection } from './EmotionsPage';
const TAB_KEYS = ['tasks', 'collections', 'emotions'] as const;
type EngagementTab = (typeof TAB_KEYS)[number];
function ensureValidTab(value: string | null): EngagementTab {
if (value && (TAB_KEYS as readonly string[]).includes(value)) {
return value as EngagementTab;
}
return 'tasks';
}
export default function EngagementPage() {
const { t } = useTranslation('management');
const { t: tc } = useTranslation('common');
const [searchParams, setSearchParams] = useSearchParams();
const initialTab = React.useMemo(() => ensureValidTab(searchParams.get('tab')), [searchParams]);
const [activeTab, setActiveTab] = React.useState<EngagementTab>(initialTab);
const handleTabChange = React.useCallback(
(next: string) => {
const valid = ensureValidTab(next);
setActiveTab(valid);
setSearchParams((prev) => {
const params = new URLSearchParams(prev);
params.set('tab', valid);
return params;
});
},
[setSearchParams]
);
const heading = tc('navigation.engagement');
const heroDescription = t('engagement.hero.description', {
defaultValue: 'Kuratiere Aufgaben, Moderationskollektionen und Emotionen als kreative Toolbox für jedes Event.'
});
const heroSupporting = [
t('engagement.hero.summary.tasks', { defaultValue: 'Plane Aufgaben, die Gäste motivieren von Upload-Regeln bis zu Story-Prompts.' }),
t('engagement.hero.summary.collections', { defaultValue: 'Sammle Vorlagen und kollektive Inhalte, um Events im Handumdrehen neu zu starten.' })
];
const heroPrimaryAction = (
<Button
size="sm"
className={tenantHeroPrimaryButtonClass}
onClick={() => handleTabChange('tasks')}
>
{t('engagement.hero.actions.tasks', 'Zu Aufgaben wechseln')}
</Button>
);
const heroSecondaryAction = (
<Button
size="sm"
className={tenantHeroSecondaryButtonClass}
onClick={() => handleTabChange('collections')}
>
{t('engagement.hero.actions.collections', 'Kollektionen ansehen')}
</Button>
);
const heroAside = (
<FrostedSurface className="space-y-4 border-white/20 p-5 text-slate-900 shadow-md shadow-rose-300/20 dark:border-slate-800/70 dark:bg-slate-950/80">
<div>
<p className="text-xs uppercase tracking-[0.3em] text-slate-500 dark:text-slate-400">{t('engagement.hero.activeTab', { defaultValue: 'Aktiver Bereich' })}</p>
<p className="mt-2 text-lg font-semibold text-slate-900 dark:text-slate-100">{t(`engagement.tabs.${activeTab}.title`, { defaultValue: tc(`navigation.${activeTab}`) })}</p>
</div>
<p className="text-xs text-slate-600 dark:text-slate-400">
{t('engagement.hero.tip', 'Wechsle Tabs, um Aufgaben, Kollektionen oder Emotionen zu bearbeiten und direkt in Events einzubinden.')}
</p>
</FrostedSurface>
);
return (
<AdminLayout
title={heading}
subtitle={t('engagement.subtitle', 'Bündle Aufgaben, Vorlagen und Emotionen für deine Events.')}
>
<TenantHeroCard
badge={t('engagement.hero.badge', 'Engagement')}
title={heading}
description={heroDescription}
supporting={heroSupporting}
primaryAction={heroPrimaryAction}
secondaryAction={heroSecondaryAction}
aside={heroAside}
/>
<FrostedCard className="mt-6 border border-white/20">
<CardHeader className="px-0 pt-0">
<CardTitle className="sr-only">{heading}</CardTitle>
</CardHeader>
<CardContent className="space-y-6">
<Tabs value={activeTab} onValueChange={handleTabChange} className="space-y-6">
<TabsList className="grid w-full grid-cols-3 rounded-2xl border border-white/25 bg-white/80 p-1 shadow-inner shadow-rose-200/20 dark:border-slate-800/70 dark:bg-slate-900/70">
{(['tasks', 'collections', 'emotions'] as const).map((tab) => (
<TabsTrigger
key={tab}
value={tab}
className="rounded-xl text-sm font-medium transition data-[state=active]:bg-gradient-to-r data-[state=active]:from-[#ff5f87] data-[state=active]:via-[#ec4899] data-[state=active]:to-[#6366f1] data-[state=active]:text-white"
>
{tc(`navigation.${tab}`)}
</TabsTrigger>
))}
</TabsList>
<TabsContent value="tasks" className="space-y-6">
<TasksSection embedded onNavigateToCollections={() => handleTabChange('collections')} />
</TabsContent>
<TabsContent value="collections" className="space-y-6">
<TaskCollectionsSection embedded onNavigateToTasks={() => handleTabChange('tasks')} />
</TabsContent>
<TabsContent value="emotions" className="space-y-6">
<EmotionsSection embedded />
</TabsContent>
</Tabs>
</CardContent>
</FrostedCard>
</AdminLayout>
);
}