Changes
This commit is contained in:
130
src/pages/Events.tsx
Normal file
130
src/pages/Events.tsx
Normal file
@@ -0,0 +1,130 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user