import { useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { useAuth } from '@/hooks/useAuth'; import { supabase } from '@/integrations/supabase/client'; 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 } from '@/components/ui/card'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Switch } from '@/components/ui/switch'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { toast } from '@/hooks/use-toast'; import { Skeleton } from '@/components/ui/skeleton'; import { Plus, Pencil, Trash2 } from 'lucide-react'; import { CurriculumEditor } from '@/components/admin/CurriculumEditor'; import { RichTextEditor } from '@/components/RichTextEditor'; import { formatIDR } from '@/lib/format'; interface Product { id: string; title: string; slug: string; type: string; description: string; content: string; meeting_link: string | null; recording_url: string | null; event_start: string | null; duration_minutes: number | null; price: number; sale_price: number | null; is_active: boolean; } const emptyProduct = { title: '', slug: '', type: 'webinar', description: '', content: '', meeting_link: '', recording_url: '', event_start: null as string | null, duration_minutes: null as number | null, price: 0, sale_price: null as number | null, is_active: true, }; export default function AdminProducts() { const { user, isAdmin, loading: authLoading } = useAuth(); const navigate = useNavigate(); const [products, setProducts] = useState([]); const [loading, setLoading] = useState(true); const [dialogOpen, setDialogOpen] = useState(false); const [editingProduct, setEditingProduct] = useState(null); const [form, setForm] = useState(emptyProduct); const [saving, setSaving] = useState(false); const [activeTab, setActiveTab] = useState('details'); useEffect(() => { if (!authLoading) { if (!user) navigate('/auth'); else if (!isAdmin) navigate('/dashboard'); else fetchProducts(); } }, [user, isAdmin, authLoading]); const fetchProducts = async () => { const { data, error } = await supabase.from('products').select('*').order('created_at', { ascending: false }); if (!error && data) setProducts(data); setLoading(false); }; const generateSlug = (title: string) => title.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, ''); const handleEdit = (product: Product) => { setEditingProduct(product); setForm({ title: product.title, slug: product.slug, type: product.type, description: product.description, content: product.content || '', meeting_link: product.meeting_link || '', recording_url: product.recording_url || '', event_start: product.event_start, duration_minutes: product.duration_minutes, price: product.price, sale_price: product.sale_price, is_active: product.is_active, }); setActiveTab('details'); setDialogOpen(true); }; const handleNew = () => { setEditingProduct(null); setForm(emptyProduct); setActiveTab('details'); setDialogOpen(true); }; const handleSave = async () => { if (!form.title || !form.slug || form.price <= 0) { toast({ title: 'Validasi error', description: 'Lengkapi semua field wajib', variant: 'destructive' }); return; } setSaving(true); const productData = { title: form.title, slug: form.slug, type: form.type, description: form.description, content: form.content, meeting_link: form.meeting_link || null, recording_url: form.recording_url || null, event_start: form.event_start || null, duration_minutes: form.duration_minutes || null, price: form.price, sale_price: form.sale_price || null, is_active: form.is_active, }; if (editingProduct) { const { error } = await supabase.from('products').update(productData).eq('id', editingProduct.id); if (error) toast({ title: 'Error', description: 'Gagal mengupdate produk', variant: 'destructive' }); else { toast({ title: 'Berhasil', description: 'Produk diupdate' }); setDialogOpen(false); fetchProducts(); } } else { const { error } = await supabase.from('products').insert(productData); if (error) toast({ title: 'Error', description: error.message, variant: 'destructive' }); else { toast({ title: 'Berhasil', description: 'Produk dibuat' }); setDialogOpen(false); fetchProducts(); } } setSaving(false); }; const handleDelete = async (id: string) => { if (!confirm('Hapus produk ini?')) return; const { error } = await supabase.from('products').delete().eq('id', id); if (error) toast({ title: 'Error', description: 'Gagal menghapus produk', variant: 'destructive' }); else { toast({ title: 'Berhasil', description: 'Produk dihapus' }); fetchProducts(); } }; if (authLoading || loading) { return (
); } return (

Manajemen Produk

Kelola semua produk

{/* Desktop Table */}
Judul Tipe Harga Status Aksi {products.map((product) => ( {product.title} {product.type} {product.sale_price ? ( {formatIDR(product.sale_price)} {formatIDR(product.price)} ) : ( {formatIDR(product.price)} )} {product.is_active ? 'Aktif' : 'Nonaktif'} ))} {products.length === 0 && ( Belum ada produk )}
{/* Mobile Card Layout */}
{products.map((product) => (

{product.title}

{product.type}

Harga:
{product.sale_price ? (
{formatIDR(product.sale_price)} {formatIDR(product.price)}
) : ( {formatIDR(product.price)} )}
Status: {product.is_active ? 'Aktif' : 'Nonaktif'}
))} {products.length === 0 && (
Belum ada produk
)}
{ if (!open) { const confirmed = window.confirm('Tutup dialog? Data yang belum disimpan akan hilang.'); if (!confirmed) return; } setDialogOpen(open); }}> {editingProduct ? 'Edit Produk' : 'Produk Baru'} Detail {editingProduct && form.type === 'bootcamp' && Kurikulum}
setForm({ ...form, title: e.target.value, slug: generateSlug(e.target.value) })} className="border-2" />
setForm({ ...form, slug: e.target.value })} className="border-2" />
setForm({ ...form, description: v })} />
setForm({ ...form, content: v })} />
setForm({ ...form, meeting_link: e.target.value })} placeholder="https://meet.google.com/..." className="border-2" />
setForm({ ...form, recording_url: e.target.value })} placeholder="https://youtube.com/..." className="border-2" />
{form.type === 'webinar' && (
setForm({ ...form, event_start: e.target.value || null })} className="border-2" />
setForm({ ...form, duration_minutes: e.target.value ? parseInt(e.target.value) : null })} placeholder="60" className="border-2" />
)}
setForm({ ...form, price: parseFloat(e.target.value) || 0 })} className="border-2" />
setForm({ ...form, sale_price: e.target.value ? parseFloat(e.target.value) : null })} placeholder="Kosongkan jika tidak promo" className="border-2" />
setForm({ ...form, is_active: checked })} />
{editingProduct && form.type === 'bootcamp' && ( )}
); }