131 lines
4.2 KiB
TypeScript
131 lines
4.2 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
import { Link } from 'react-router-dom';
|
|
import { supabase } from '@/integrations/supabase/client';
|
|
import { AppLayout } from '@/components/AppLayout';
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
|
import { Badge } from '@/components/ui/badge';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Skeleton } from '@/components/ui/skeleton';
|
|
import { formatDateTime } from '@/lib/format';
|
|
import { Calendar, Video, Users, BookOpen } from 'lucide-react';
|
|
|
|
interface Event {
|
|
id: string;
|
|
type: string;
|
|
product_id: string | null;
|
|
title: string;
|
|
starts_at: string;
|
|
ends_at: string;
|
|
status: string;
|
|
product?: {
|
|
slug: string;
|
|
title: string;
|
|
} | null;
|
|
}
|
|
|
|
export default function Events() {
|
|
const [events, setEvents] = useState<Event[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
useEffect(() => {
|
|
fetchEvents();
|
|
}, []);
|
|
|
|
const fetchEvents = async () => {
|
|
const { data, error } = await supabase
|
|
.from('events')
|
|
.select(`
|
|
*,
|
|
product:products (slug, title)
|
|
`)
|
|
.eq('status', 'confirmed')
|
|
.gte('ends_at', new Date().toISOString())
|
|
.order('starts_at', { ascending: true });
|
|
|
|
if (!error && data) {
|
|
setEvents(data as unknown as Event[]);
|
|
}
|
|
setLoading(false);
|
|
};
|
|
|
|
const getTypeIcon = (type: string) => {
|
|
switch (type) {
|
|
case 'bootcamp': return BookOpen;
|
|
case 'webinar': return Video;
|
|
case 'consulting': return Users;
|
|
default: return Calendar;
|
|
}
|
|
};
|
|
|
|
const getTypeLabel = (type: string) => {
|
|
switch (type) {
|
|
case 'bootcamp': return 'Bootcamp';
|
|
case 'webinar': return 'Webinar';
|
|
case 'consulting': return 'Konsultasi';
|
|
default: return type;
|
|
}
|
|
};
|
|
|
|
return (
|
|
<AppLayout>
|
|
<div className="container mx-auto px-4 py-8">
|
|
<div className="flex items-center gap-3 mb-8">
|
|
<Calendar className="w-8 h-8" />
|
|
<div>
|
|
<h1 className="text-4xl font-bold">Kalender Acara</h1>
|
|
<p className="text-muted-foreground">Jadwal webinar, bootcamp, dan sesi konsultasi</p>
|
|
</div>
|
|
</div>
|
|
|
|
{loading ? (
|
|
<div className="space-y-4">
|
|
{[...Array(3)].map((_, i) => (
|
|
<Skeleton key={i} className="h-32 w-full" />
|
|
))}
|
|
</div>
|
|
) : events.length === 0 ? (
|
|
<Card className="border-2 border-border">
|
|
<CardContent className="py-12 text-center">
|
|
<Calendar className="w-12 h-12 mx-auto mb-4 text-muted-foreground" />
|
|
<p className="text-muted-foreground">Belum ada acara terjadwal</p>
|
|
</CardContent>
|
|
</Card>
|
|
) : (
|
|
<div className="space-y-4">
|
|
{events.map((event) => {
|
|
const Icon = getTypeIcon(event.type);
|
|
return (
|
|
<Card key={event.id} className="border-2 border-border">
|
|
<CardHeader className="pb-2">
|
|
<div className="flex items-start justify-between">
|
|
<div className="flex items-center gap-3">
|
|
<div className="p-2 bg-muted rounded-none">
|
|
<Icon className="w-5 h-5" />
|
|
</div>
|
|
<div>
|
|
<CardTitle className="text-lg">{event.title}</CardTitle>
|
|
<CardDescription>{formatDateTime(event.starts_at)}</CardDescription>
|
|
</div>
|
|
</div>
|
|
<Badge className="bg-secondary">{getTypeLabel(event.type)}</Badge>
|
|
</div>
|
|
</CardHeader>
|
|
<CardContent>
|
|
{event.product && (
|
|
<Link to={`/products/${event.product.slug}`}>
|
|
<Button variant="outline" size="sm" className="border-2">
|
|
Lihat Produk
|
|
</Button>
|
|
</Link>
|
|
)}
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
})}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</AppLayout>
|
|
);
|
|
}
|