import { useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; import { AppLayout } from "@/components/AppLayout"; import { useAuth } from "@/hooks/useAuth"; import { supabase } from "@/integrations/supabase/client"; 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 { formatIDR } from "@/lib/format"; import { Video, Calendar, BookOpen, ArrowRight, Package, Receipt, ShoppingBag } from "lucide-react"; import { WhatsAppBanner } from "@/components/WhatsAppBanner"; import { ConsultingHistory } from "@/components/reviews/ConsultingHistory"; import { UnpaidOrderAlert } from "@/components/UnpaidOrderAlert"; interface UserAccess { id: string; product: { id: string; title: string; slug: string; type: string; meeting_link: string | null; recording_url: string | null; }; } interface Order { id: string; total_amount: number; payment_status: string | null; created_at: string; } interface UnpaidConsultingOrder { order_id: string; qr_expires_at: string; } export default function MemberDashboard() { const { user, loading: authLoading } = useAuth(); const navigate = useNavigate(); const [access, setAccess] = useState([]); const [recentOrders, setRecentOrders] = useState([]); const [unpaidConsultingOrders, setUnpaidConsultingOrders] = useState([]); const [loading, setLoading] = useState(true); const [hasWhatsApp, setHasWhatsApp] = useState(true); useEffect(() => { if (!authLoading && !user) navigate("/auth"); else if (user) fetchData(); }, [user, authLoading]); // Fetch unpaid consulting orders useEffect(() => { if (!user) return; const fetchUnpaidOrders = async () => { const { data, error } = await supabase .from('consulting_slots') .select(` order_id, orders ( id, payment_status, qr_expires_at ) `) .eq('status', 'pending_payment') .order('created_at', { ascending: false }); if (!error && data) { // Filter in JavaScript: only include slots where order is pending AND not expired const now = new Date().toISOString(); const validSlots = data.filter((item: any) => item.orders?.payment_status === 'pending' && item.orders?.qr_expires_at && item.orders.qr_expires_at > now ); // Get unique order IDs const uniqueOrders = Array.from( new Set(validSlots.map((item: any) => item.order_id)) ).map((orderId) => { // Find the corresponding order data const orderData = validSlots.find((item: any) => item.order_id === orderId); return { order_id: orderId, qr_expires_at: (orderData as any)?.orders?.qr_expires_at || '' }; }); setUnpaidConsultingOrders(uniqueOrders); } }; fetchUnpaidOrders(); }, [user]); // Auto-hide expired orders every 30 seconds useEffect(() => { const checkExpiry = () => { setUnpaidConsultingOrders(prev => prev.filter(order => new Date(order.qr_expires_at) > new Date()) ); }; const interval = setInterval(checkExpiry, 30000); // Check every 30s return () => clearInterval(interval); }, []); const fetchData = async () => { const [accessRes, ordersRes, paidOrdersRes, profileRes] = await Promise.all([ supabase .from("user_access") .select(`id, product:products (id, title, slug, type, meeting_link, recording_url)`) .eq("user_id", user!.id), supabase.from("orders").select("*").eq("user_id", user!.id).order("created_at", { ascending: false }).limit(3), // Also get products from paid orders (via order_items) supabase .from("orders") .select( ` order_items ( product:products (id, title, slug, type, meeting_link, recording_url) ) `, ) .eq("user_id", user!.id) .eq("payment_status", "paid") .eq("payment_provider", "pakasir"), supabase.from("profiles").select("whatsapp_number").eq("id", user!.id).single(), ]); // Combine access from user_access and paid orders const directAccess = (accessRes.data as unknown as UserAccess[]) || []; const paidProductAccess: UserAccess[] = []; if (paidOrdersRes.data) { const existingIds = new Set(directAccess.map((a) => a.product.id)); paidOrdersRes.data.forEach((order: any) => { order.order_items?.forEach((item: any) => { if (item.product && !existingIds.has(item.product.id)) { existingIds.add(item.product.id); paidProductAccess.push({ id: `paid-${item.product.id}`, product: item.product }); } }); }); } setAccess([...directAccess, ...paidProductAccess]); if (ordersRes.data) setRecentOrders(ordersRes.data); if (profileRes.data) setHasWhatsApp(!!profileRes.data.whatsapp_number); setLoading(false); }; const getQuickAction = (item: UserAccess) => { switch (item.product.type) { case "consulting": return { label: "Jadwalkan", icon: Calendar, href: item.product.meeting_link }; case "webinar": return { label: "Tonton", icon: Video, href: item.product.recording_url || item.product.meeting_link }; case "bootcamp": return { label: "Lanjutkan", icon: BookOpen, route: `/bootcamp/${item.product.slug}` }; default: return null; } }; if (authLoading || loading) { return (
{[...Array(4)].map((_, i) => ( ))}
); } return (

Dashboard

Selamat datang kembali!

{/* Unpaid Order Alert - shown when user has unpaid consulting orders */} {unpaidConsultingOrders.length > 0 && (
)} {!hasWhatsApp && }

{access.length}

Produk Diakses

{recentOrders.length}

Order Terbaru

Jelajahi lebih banyak

Lihat semua produk

{access.length > 0 && (

Akses Cepat

{access.slice(0, 3).map((item) => { const action = getQuickAction(item); return ( {item.product.title} {item.product.type} {action && (action.route ? ( ) : action.href ? ( ) : null)} ); })}
)} {recentOrders.length > 0 && (

Order Terbaru

{recentOrders.map((order) => (

{order.id.slice(0, 8)}

{new Date(order.created_at).toLocaleDateString("id-ID")}

{order.payment_status === "paid" ? "Lunas" : "Pending"} {formatIDR(order.total_amount)}
))}
)} {/* Consulting History with Review Prompts */}
); }