diff --git a/src/pages/Checkout.tsx b/src/pages/Checkout.tsx index 869938c..41d850a 100644 --- a/src/pages/Checkout.tsx +++ b/src/pages/Checkout.tsx @@ -15,7 +15,15 @@ import { QRCodeSVG } from "qrcode.react"; // Pakasir configuration const PAKASIR_PROJECT_SLUG = "dewengoding"; -const PAKASIR_API_KEY = "iP13osgh7lAzWWIPsj7TbW5M3iGEAQMo"; +const SANDBOX_API_KEY = "iP13osgh7lAzWWIPsj7TbW5M3iGEAQMo"; + +// Centralized API key retrieval - uses env var with sandbox fallback +const getPakasirApiKey = (): string => { + return import.meta.env.VITE_PAKASIR_API_KEY || SANDBOX_API_KEY; +}; + +// TODO: Replace with actual Supabase Edge Function URL after creation +const PAKASIR_CALLBACK_URL = "https://lovable.backoffice.biz.id/functions/v1/pakasir-webhook"; type PaymentMethod = "qris" | "paypal"; type CheckoutStep = "cart" | "payment" | "waiting"; @@ -117,7 +125,10 @@ export default function Checkout() { setOrderId(order.id); - if (paymentMethod === "qris") { + // Build description from product titles + const productTitles = items.map(item => item.title).join(", "); + + if (paymentMethod === "qris") { // Call Pakasir API for QRIS try { const response = await fetch(`https://app.pakasir.com/api/transactioncreate/qris`, { @@ -127,7 +138,9 @@ export default function Checkout() { project: PAKASIR_PROJECT_SLUG, order_id: order.id, amount: amountInRupiah, - api_key: PAKASIR_API_KEY, + api_key: getPakasirApiKey(), + description: productTitles, + callback_url: PAKASIR_CALLBACK_URL, }), }); @@ -222,7 +235,7 @@ export default function Checkout() {
- Pembayaran akan otomatis terkonfirmasi setelah Anda scan dan bayar QR code di atas + Pembayaran diproses melalui Pakasir dan akan dikonfirmasi otomatis setelah berhasil.
diff --git a/src/pages/ProductDetail.tsx b/src/pages/ProductDetail.tsx index 7f71d54..655bb0b 100644 --- a/src/pages/ProductDetail.tsx +++ b/src/pages/ProductDetail.tsx @@ -121,13 +121,35 @@ export default function ProductDetail() { const checkUserAccess = async () => { if (!product || !user) return; - const { data } = await supabase + + // 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(); - setHasAccess(!!data); + + 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); }; diff --git a/src/pages/member/MemberDashboard.tsx b/src/pages/member/MemberDashboard.tsx index e0d48cf..f46c83e 100644 --- a/src/pages/member/MemberDashboard.tsx +++ b/src/pages/member/MemberDashboard.tsx @@ -42,11 +42,38 @@ export default function MemberDashboard() { }, [user, authLoading]); const fetchData = async () => { - const [accessRes, ordersRes] = await Promise.all([ + const [accessRes, ordersRes, paidOrdersRes] = 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) + 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') ]); - if (accessRes.data) setAccess(accessRes.data as unknown as UserAccess[]); + + // 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); setLoading(false); };