import { useEffect, useState, useRef, useCallback } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import { supabase } from '@/integrations/supabase/client'; import { useAuth } from '@/hooks/useAuth'; import { useVideoProgress } from '@/hooks/useVideoProgress'; import { AppLayout } from '@/components/AppLayout'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Skeleton } from '@/components/ui/skeleton'; import { toast } from '@/hooks/use-toast'; import { ChevronLeft, Play, Star, Clock, CheckCircle } from 'lucide-react'; import { VideoPlayerWithChapters, VideoPlayerRef } from '@/components/VideoPlayerWithChapters'; import { TimelineChapters } from '@/components/TimelineChapters'; import { ReviewModal } from '@/components/reviews/ReviewModal'; import { Badge } from '@/components/ui/badge'; interface VideoChapter { time: number; title: string; } interface Product { id: string; title: string; slug: string; recording_url: string | null; m3u8_url?: string | null; mp4_url?: string | null; video_host?: 'youtube' | 'adilo' | 'unknown'; description: string | null; chapters?: VideoChapter[]; } interface UserReview { id: string; rating: number; title?: string; body?: string; is_approved: boolean; created_at: string; } export default function WebinarRecording() { const { slug } = useParams<{ slug: string }>(); const navigate = useNavigate(); const { user, loading: authLoading } = useAuth(); const [product, setProduct] = useState(null); const [loading, setLoading] = useState(true); const [currentTime, setCurrentTime] = useState(0); const [accentColor, setAccentColor] = useState(''); const [userReview, setUserReview] = useState(null); const [reviewModalOpen, setReviewModalOpen] = useState(false); const playerRef = useRef(null); useEffect(() => { if (!authLoading && !user) { navigate('/auth'); } else if (user && slug) { checkAccessAndFetch(); } }, [user, authLoading, slug]); const checkAccessAndFetch = async () => { const { data: productData, error: productError } = await supabase .from('products') .select('id, title, slug, recording_url, m3u8_url, mp4_url, video_host, description, chapters') .eq('slug', slug) .eq('type', 'webinar') .maybeSingle(); if (productError || !productData) { toast({ title: 'Error', description: 'Webinar tidak ditemukan', variant: 'destructive' }); navigate('/dashboard'); return; } setProduct(productData); if (!productData.recording_url) { toast({ title: 'Info', description: 'Rekaman webinar belum tersedia', variant: 'destructive' }); navigate('/dashboard'); return; } // Fetch accent color from settings const { data: settings } = await supabase .from('platform_settings') .select('brand_accent_color') .single(); if (settings?.brand_accent_color) { setAccentColor(settings.brand_accent_color); } // Check access via user_access or paid orders const [accessRes, paidOrdersRes] = await Promise.all([ supabase .from('user_access') .select('id') .eq('user_id', user!.id) .eq('product_id', productData.id) .maybeSingle(), supabase .from('orders') .select('order_items!inner(product_id)') .eq('user_id', user!.id) .eq('payment_status', 'paid') ]); const hasDirectAccess = !!accessRes.data; const hasPaidOrderAccess = paidOrdersRes.data?.some((order: any) => order.order_items?.some((item: any) => item.product_id === productData.id) ); if (!hasDirectAccess && !hasPaidOrderAccess) { toast({ title: 'Akses ditolak', description: 'Anda tidak memiliki akses ke webinar ini', variant: 'destructive' }); navigate('/dashboard'); return; } setLoading(false); // Check if user has already reviewed this webinar checkUserReview(); }; const checkUserReview = async () => { if (!product || !user) return; const { data } = await supabase .from('reviews') .select('id, rating, title, body, is_approved, created_at') .eq('user_id', user.id) .eq('product_id', product.id) .order('created_at', { ascending: false }) .limit(1); if (data && data.length > 0) { setUserReview(data[0] as UserReview); } else { setUserReview(null); } }; // Check if user has submitted a review (regardless of approval status) const hasSubmittedReview = userReview !== null; // Determine video host (prioritize Adilo over YouTube) const detectedVideoHost = product?.video_host || ( product?.m3u8_url ? 'adilo' : product?.recording_url?.includes('adilo.bigcommand.com') ? 'adilo' : product?.recording_url?.includes('youtube.com') || product?.recording_url?.includes('youtu.be') ? 'youtube' : 'unknown' ); const handleChapterClick = useCallback((time: number) => { // VideoPlayerWithChapters will handle the jump if (playerRef.current && playerRef.current.jumpToTime) { playerRef.current.jumpToTime(time); } }, []); const handleTimeUpdate = useCallback((time: number) => { setCurrentTime(time); }, []); // Fetch progress data for review trigger const { progress, hasProgress: hasWatchProgress } = useVideoProgress({ videoId: product?.id || '', videoType: 'webinar', }); // Show review prompt if user has watched more than 5 seconds (any engagement) const shouldShowReviewPrompt = hasWatchProgress; if (authLoading || loading) { return (
); } if (!product) return null; const hasChapters = product.chapters && product.chapters.length > 0; return (

{product.title}

{/* Video Player */}
{(product.recording_url || product.m3u8_url) && ( )}
{/* Timeline Chapters - video track for navigation */} {hasChapters && (
)} {/* Description */} {product.description && (
)} {/* Instructions */}

Panduan Menonton

  • Gunakan tombol fullscreen di pojok kanan bawah video untuk tampilan terbaik
  • Anda dapat memutar ulang video kapan saja
  • Pastikan koneksi internet stabil untuk pengalaman menonton yang lancar
{/* Review Section - Show after any engagement, but only if user hasn't submitted a review yet */} {shouldShowReviewPrompt && !hasSubmittedReview && (

Bagaimana webinar ini?

Berikan ulasan Anda untuk membantu peserta lain memilih webinar yang tepat.

)} {/* User's Existing Review */} {userReview && ( Ulasan Anda{!userReview.is_approved && ' (Menunggu Persetujuan)'}
{[1, 2, 3, 4, 5].map((star) => ( ))} {new Date(userReview.created_at).toLocaleDateString('id-ID', { year: 'numeric', month: 'long', day: 'numeric', })} {!userReview.is_approved && ( Menunggu persetujuan admin )}
{userReview.title && (

{userReview.title}

)} {userReview.body && (

{userReview.body}

)} {!userReview.is_approved && (

Ulasan Anda sedang ditinjau oleh admin dan akan segera ditampilkan setelah disetujui.

)}
)}
{/* Review Modal */} {product && user && ( { checkUserReview(); toast({ title: 'Terima kasih!', description: userReview ? 'Ulasan Anda berhasil diperbarui.' : 'Ulasan Anda berhasil disimpan.', }); }} /> )} ); }