import { useEffect, useState } from 'react'; import { useParams, useNavigate, Link } from 'react-router-dom'; import { supabase } from '@/integrations/supabase/client'; import { AppLayout } from '@/components/AppLayout'; import { Card, CardContent } from '@/components/ui/card'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { useCart } from '@/contexts/CartContext'; import { useAuth } from '@/hooks/useAuth'; import { toast } from '@/hooks/use-toast'; import { Skeleton } from '@/components/ui/skeleton'; import { formatIDR, formatDuration } from '@/lib/format'; import { Video, Calendar, BookOpen, Play, Clock, ChevronDown, ChevronRight, Star, CheckCircle } from 'lucide-react'; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'; import { ReviewModal } from '@/components/reviews/ReviewModal'; import { ProductReviews } from '@/components/reviews/ProductReviews'; interface Product { id: string; title: string; slug: string; type: string; description: string; content: string; price: number; sale_price: number | null; meeting_link: string | null; recording_url: string | null; event_start: string | null; duration_minutes: number | null; created_at: string; } interface Module { id: string; title: string; position: number; lessons: Lesson[]; } interface Lesson { id: string; title: string; duration_seconds: number | null; position: number; } export default function ProductDetail() { const { slug } = useParams<{ slug: string }>(); const navigate = useNavigate(); const [product, setProduct] = useState(null); const [modules, setModules] = useState([]); const [loading, setLoading] = useState(true); const [hasAccess, setHasAccess] = useState(false); const [checkingAccess, setCheckingAccess] = useState(true); const [expandedModules, setExpandedModules] = useState>(new Set()); const [hasReviewed, setHasReviewed] = useState(false); const [reviewModalOpen, setReviewModalOpen] = useState(false); const { addItem, items } = useCart(); const { user } = useAuth(); useEffect(() => { if (slug) fetchProduct(); }, [slug]); useEffect(() => { if (product && user) { checkUserAccess(); checkUserReview(); } else { setCheckingAccess(false); } }, [product, user]); useEffect(() => { if (product?.type === 'bootcamp') { fetchCurriculum(); } }, [product]); const fetchProduct = async () => { const { data, error } = await supabase .from('products') .select('*') .eq('slug', slug) .eq('is_active', true) .maybeSingle(); if (error || !data) { toast({ title: 'Error', description: 'Produk tidak ditemukan', variant: 'destructive' }); } else { setProduct(data); } setLoading(false); }; const fetchCurriculum = async () => { if (!product) return; const { data: modulesData } = await supabase .from('bootcamp_modules') .select(` id, title, position, bootcamp_lessons ( id, title, duration_seconds, position ) `) .eq('product_id', product.id) .order('position'); if (modulesData) { const sorted = modulesData.map(m => ({ ...m, lessons: (m.bootcamp_lessons as Lesson[]).sort((a, b) => a.position - b.position) })); setModules(sorted); // Expand first module by default if (sorted.length > 0) { setExpandedModules(new Set([sorted[0].id])); } } }; const checkUserAccess = async () => { if (!product || !user) return; // Check user_access table first const { data: accessData } = await supabase .from('user_access') .select('id') .eq('user_id', user.id) .eq('product_id', product.id) .maybeSingle(); if (accessData) { setHasAccess(true); setCheckingAccess(false); return; } // Also check for paid orders containing this product const { data: paidOrders } = await supabase .from('orders') .select(` id, order_items!inner (product_id) `) .eq('user_id', user.id) .eq('payment_status', 'paid') .eq('payment_provider', 'pakasir') .eq('order_items.product_id', product.id) .limit(1); setHasAccess(!!(paidOrders && paidOrders.length > 0)); setCheckingAccess(false); }; const checkUserReview = async () => { if (!product || !user) return; const { data } = await supabase .from('reviews') .select('id') .eq('user_id', user.id) .eq('product_id', product.id) .limit(1); setHasReviewed(!!(data && data.length > 0)); }; // Check if webinar has ended (eligible for review) const isWebinarEnded = () => { if (!product || product.type !== 'webinar' || !product.event_start) return false; const eventStart = new Date(product.event_start); const durationMs = (product.duration_minutes || 60) * 60 * 1000; const eventEnd = new Date(eventStart.getTime() + durationMs); return new Date() > eventEnd; }; const handleAddToCart = () => { if (!product) return; addItem({ id: product.id, title: product.title, price: product.price, sale_price: product.sale_price, type: product.type }); toast({ title: 'Ditambahkan', description: `${product.title} sudah ditambahkan ke keranjang` }); }; const isInCart = product ? items.some(item => item.id === product.id) : false; const getVideoEmbed = (url: string) => { const youtubeMatch = url.match(/(?:youtube\.com\/(?:watch\?v=|embed\/)|youtu\.be\/)([^&\s]+)/); if (youtubeMatch) return `https://www.youtube.com/embed/${youtubeMatch[1]}`; const vimeoMatch = url.match(/vimeo\.com\/(\d+)/); if (vimeoMatch) return `https://player.vimeo.com/video/${vimeoMatch[1]}`; return url; }; const totalDuration = modules.reduce((total, m) => total + m.lessons.reduce((sum, l) => sum + (l.duration_seconds || 0), 0), 0 ); const totalLessons = modules.reduce((sum, m) => sum + m.lessons.length, 0); const toggleModule = (id: string) => { const newSet = new Set(expandedModules); if (newSet.has(id)) newSet.delete(id); else newSet.add(id); setExpandedModules(newSet); }; if (loading) { return (
); } if (!product) { return (

Produk tidak ditemukan

); } const renderActionButtons = () => { if (checkingAccess) return ; if (!hasAccess) { return ( ); } switch (product.type) { case 'consulting': return ( ); case 'webinar': if (product.recording_url) { return (