109 lines
3.7 KiB
TypeScript
109 lines
3.7 KiB
TypeScript
import React, { useCallback, useState } from 'react';
|
|
import { Card, CardHeader, CardTitle, CardDescription } from "@/components/ui/card";
|
|
import { type Event } from '@/features/event/api/eventService';
|
|
import { type DashboardModule, type DashboardModuleContext } from '@/components/dashboard/dashboardModuleTypes';
|
|
import { eventDashboardModule } from '@/features/event/dashboardModule';
|
|
import { quickPostDashboardModule } from '@/features/photopost/dashboardModule';
|
|
|
|
interface DashboardCardProps {
|
|
title: string;
|
|
description: string;
|
|
onClick: () => void;
|
|
illustration?: string;
|
|
}
|
|
|
|
const DashboardCard: React.FC<DashboardCardProps> = ({ title, description, onClick, illustration }) => (
|
|
<Card className="hover:shadow-md transition-shadow cursor-pointer h-full relative overflow-hidden" onClick={onClick}>
|
|
<div className="pointer-events-none absolute -left-20 -top-20 h-56 w-56 rounded-full bg-gradient-to-br from-primary/25 via-primary/10 to-transparent blur-3xl" />
|
|
{illustration && (
|
|
<div
|
|
className="hidden md:block pointer-events-none absolute inset-0"
|
|
style={{
|
|
backgroundImage: `url(${illustration})`,
|
|
backgroundRepeat: 'no-repeat',
|
|
backgroundPosition: 'right bottom',
|
|
backgroundSize: 'auto 80%',
|
|
opacity: 0.9,
|
|
filter: 'drop-shadow(0 8px 16px rgba(0,0,0,0.15))',
|
|
}}
|
|
/>
|
|
)}
|
|
<CardHeader className="pb-2 pr-6 relative z-10">
|
|
<div className="flex items-center">
|
|
<CardTitle className="text-lg">{title}</CardTitle>
|
|
</div>
|
|
<CardDescription className="text-sm">{description}</CardDescription>
|
|
</CardHeader>
|
|
{illustration && (
|
|
<div className="md:hidden px-6 pb-4 relative z-10">
|
|
<img src={illustration} alt="" className="mt-2 w-full h-auto object-contain" />
|
|
</div>
|
|
)}
|
|
</Card>
|
|
);
|
|
|
|
interface DashboardProps {
|
|
onActionClick: (action: string) => void;
|
|
hasActiveEvent: boolean;
|
|
currentEvent: Event | null;
|
|
}
|
|
|
|
const Dashboard: React.FC<DashboardProps> = ({ onActionClick, hasActiveEvent, currentEvent }) => {
|
|
const [activeModuleId, setActiveModuleId] = useState<string | null>(null);
|
|
|
|
const ctx: DashboardModuleContext = {
|
|
currentEvent,
|
|
};
|
|
|
|
const allModules: DashboardModule[] = [
|
|
eventDashboardModule,
|
|
quickPostDashboardModule,
|
|
];
|
|
|
|
const visibleModules = allModules.filter((m) => m.isVisible ? m.isVisible(ctx) : true);
|
|
|
|
const activeModule = activeModuleId
|
|
? visibleModules.find((m) => m.id === activeModuleId) || null
|
|
: null;
|
|
|
|
const handleBackToOverview = useCallback(() => {
|
|
setActiveModuleId(null);
|
|
}, []);
|
|
|
|
const renderContent = () => {
|
|
if (activeModule) {
|
|
return activeModule.renderWizard(ctx, handleBackToOverview);
|
|
}
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<h1 className="text-2xl font-bold tracking-tight">Willkommen zurück</h1>
|
|
<p className="text-muted-foreground">Was möchtest du heute tun?</p>
|
|
</div>
|
|
</div>
|
|
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-2">
|
|
{visibleModules.map((module) => (
|
|
<DashboardCard
|
|
key={module.id}
|
|
title={module.getTitle(ctx)}
|
|
description={module.getDescription(ctx)}
|
|
onClick={() => setActiveModuleId(module.id)}
|
|
illustration={module.getIllustration?.(ctx)}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
return <div className="p-[2px] sm:p-6">{renderContent()}</div>;
|
|
};
|
|
|
|
const DashboardComponent: React.FC<DashboardProps> = Dashboard;
|
|
export default DashboardComponent;
|
|
|
|
// removed modal-based EventTimelineOverlay in favor of inline EventWizard
|
|
|