import { useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { supabase } from '@/integrations/supabase/client'; import { useAuth } from '@/hooks/useAuth'; import { AppLayout } from '@/components/AppLayout'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Textarea } from '@/components/ui/textarea'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'; import { Badge } from '@/components/ui/badge'; import { toast } from '@/hooks/use-toast'; import { Skeleton } from '@/components/ui/skeleton'; import { Plus, Pencil, Trash2, Calendar, Clock } from 'lucide-react'; import { formatDateTime } from '@/lib/format'; interface Event { id: string; type: string; product_id: string | null; title: string; starts_at: string; ends_at: string; status: string; } interface AvailabilityBlock { id: string; kind: string; starts_at: string; ends_at: string; note: string | null; } interface Product { id: string; title: string; } const emptyEvent = { type: 'webinar', product_id: '' as string, title: '', starts_at: '', ends_at: '', status: 'confirmed', }; const emptyBlock = { kind: 'blocked', starts_at: '', ends_at: '', note: '', }; export default function AdminEvents() { const { user, isAdmin, loading: authLoading } = useAuth(); const navigate = useNavigate(); const [events, setEvents] = useState([]); const [blocks, setBlocks] = useState([]); const [products, setProducts] = useState([]); const [loading, setLoading] = useState(true); const [eventDialogOpen, setEventDialogOpen] = useState(false); const [editingEvent, setEditingEvent] = useState(null); const [eventForm, setEventForm] = useState(emptyEvent); const [blockDialogOpen, setBlockDialogOpen] = useState(false); const [editingBlock, setEditingBlock] = useState(null); const [blockForm, setBlockForm] = useState(emptyBlock); useEffect(() => { if (!authLoading) { if (!user) navigate('/auth'); else if (!isAdmin) navigate('/dashboard'); else fetchData(); } }, [user, isAdmin, authLoading]); const fetchData = async () => { const [eventsRes, blocksRes, productsRes] = await Promise.all([ supabase.from('events').select('*').order('starts_at', { ascending: false }), supabase.from('availability_blocks').select('*').order('starts_at', { ascending: false }), supabase.from('products').select('id, title').eq('is_active', true), ]); if (eventsRes.data) setEvents(eventsRes.data); if (blocksRes.data) setBlocks(blocksRes.data); if (productsRes.data) setProducts(productsRes.data); setLoading(false); }; // Event handlers const handleNewEvent = () => { setEditingEvent(null); setEventForm(emptyEvent); setEventDialogOpen(true); }; const handleEditEvent = (event: Event) => { setEditingEvent(event); setEventForm({ type: event.type, product_id: event.product_id || '', title: event.title, starts_at: event.starts_at.slice(0, 16), ends_at: event.ends_at.slice(0, 16), status: event.status, }); setEventDialogOpen(true); }; const handleSaveEvent = async () => { if (!eventForm.title || !eventForm.starts_at || !eventForm.ends_at) { toast({ title: 'Error', description: 'Lengkapi semua field yang wajib diisi', variant: 'destructive' }); return; } const eventData = { type: eventForm.type, product_id: eventForm.product_id || null, title: eventForm.title, starts_at: new Date(eventForm.starts_at).toISOString(), ends_at: new Date(eventForm.ends_at).toISOString(), status: eventForm.status, }; if (editingEvent) { const { error } = await supabase.from('events').update(eventData).eq('id', editingEvent.id); if (error) toast({ title: 'Error', description: 'Gagal mengupdate event', variant: 'destructive' }); else { toast({ title: 'Berhasil', description: 'Event diupdate' }); setEventDialogOpen(false); fetchData(); } } else { const { error } = await supabase.from('events').insert(eventData); if (error) toast({ title: 'Error', description: error.message, variant: 'destructive' }); else { toast({ title: 'Berhasil', description: 'Event dibuat' }); setEventDialogOpen(false); fetchData(); } } }; const handleDeleteEvent = async (id: string) => { if (!confirm('Hapus event ini?')) return; const { error } = await supabase.from('events').delete().eq('id', id); if (error) toast({ title: 'Error', description: 'Gagal menghapus event', variant: 'destructive' }); else { toast({ title: 'Berhasil', description: 'Event dihapus' }); fetchData(); } }; // Block handlers const handleNewBlock = () => { setEditingBlock(null); setBlockForm(emptyBlock); setBlockDialogOpen(true); }; const handleEditBlock = (block: AvailabilityBlock) => { setEditingBlock(block); setBlockForm({ kind: block.kind, starts_at: block.starts_at.slice(0, 16), ends_at: block.ends_at.slice(0, 16), note: block.note || '', }); setBlockDialogOpen(true); }; const handleSaveBlock = async () => { if (!blockForm.starts_at || !blockForm.ends_at) { toast({ title: 'Error', description: 'Lengkapi waktu mulai dan selesai', variant: 'destructive' }); return; } const blockData = { kind: blockForm.kind, starts_at: new Date(blockForm.starts_at).toISOString(), ends_at: new Date(blockForm.ends_at).toISOString(), note: blockForm.note || null, }; if (editingBlock) { const { error } = await supabase.from('availability_blocks').update(blockData).eq('id', editingBlock.id); if (error) toast({ title: 'Error', description: 'Gagal mengupdate', variant: 'destructive' }); else { toast({ title: 'Berhasil', description: 'Blok diupdate' }); setBlockDialogOpen(false); fetchData(); } } else { const { error } = await supabase.from('availability_blocks').insert(blockData); if (error) toast({ title: 'Error', description: error.message, variant: 'destructive' }); else { toast({ title: 'Berhasil', description: 'Blok dibuat' }); setBlockDialogOpen(false); fetchData(); } } }; const handleDeleteBlock = async (id: string) => { if (!confirm('Hapus blok waktu ini?')) return; const { error } = await supabase.from('availability_blocks').delete().eq('id', id); if (error) toast({ title: 'Error', description: 'Gagal menghapus', variant: 'destructive' }); else { toast({ title: 'Berhasil', description: 'Blok dihapus' }); fetchData(); } }; if (authLoading || loading) { return (
); } return (

Kalender & Jadwal

Kelola event dan blok ketersediaan

Event Ketersediaan Daftar Event {/* Desktop Table */}
Judul Tipe Mulai Status Aksi {events.map((event) => ( {event.title} {event.type} {formatDateTime(event.starts_at)} {event.status} ))} {events.length === 0 && ( Belum ada event )}
{/* Mobile Card Layout */}
{events.map((event) => (

{event.title}

{event.type}

{event.status}
Mulai: {formatDateTime(event.starts_at)}
))} {events.length === 0 && (
Belum ada event
)}
Blok Ketersediaan {/* Desktop Table */}
Tipe Mulai Selesai Catatan Aksi {blocks.map((block) => ( {block.kind === 'available' ? 'Tersedia' : 'Tidak Tersedia'} {formatDateTime(block.starts_at)} {formatDateTime(block.ends_at)} {block.note || '-'} ))} {blocks.length === 0 && ( Belum ada blok ketersediaan )}
{/* Mobile Card Layout */}
{blocks.map((block) => (

{block.kind === 'available' ? 'Tersedia' : 'Tidak Tersedia'}

{block.kind === 'available' ? 'Tersedia' : 'Tidak'}
Mulai: {formatDateTime(block.starts_at)}
Selesai: {formatDateTime(block.ends_at)}
{block.note && (
Catatan: {block.note}
)}
))} {blocks.length === 0 && (
Belum ada blok ketersediaan
)}
{/* Event Dialog */} {editingEvent ? 'Edit Event' : 'Buat Event Baru'}
setEventForm({ ...eventForm, title: e.target.value })} className="border-2" />
setEventForm({ ...eventForm, starts_at: e.target.value })} className="border-2" />
setEventForm({ ...eventForm, ends_at: e.target.value })} className="border-2" />
{/* Block Dialog */} {editingBlock ? 'Edit Blok' : 'Tambah Blok Ketersediaan'}
setBlockForm({ ...blockForm, starts_at: e.target.value })} className="border-2" />
setBlockForm({ ...blockForm, ends_at: e.target.value })} className="border-2" />