import { useState, useEffect } from "react"; import { useNavigate, useSearchParams } from "react-router-dom"; import { AppLayout } from "@/components/AppLayout"; import { useCart } from "@/contexts/CartContext"; import { useAuth } from "@/hooks/useAuth"; import { supabase } from "@/integrations/supabase/client"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import { Label } from "@/components/ui/label"; import { toast } from "@/hooks/use-toast"; import { formatIDR } from "@/lib/format"; import { Trash2, CreditCard, Loader2, QrCode, Wallet } from "lucide-react"; import { QRCodeSVG } from "qrcode.react"; // Pakasir configuration const PAKASIR_PROJECT_SLUG = import.meta.env.VITE_PAKASIR_PROJECT_SLUG || "dewengoding"; 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; }; // Edge function base URL - configurable via env with sensible default const getEdgeFunctionBaseUrl = (): string => { return import.meta.env.VITE_SUPABASE_EDGE_URL || "https://lovable.backoffice.biz.id/functions/v1"; }; const PAKASIR_CALLBACK_URL = `${getEdgeFunctionBaseUrl()}/pakasir-webhook`; type PaymentMethod = "qris" | "paypal"; type CheckoutStep = "cart" | "payment" | "waiting"; interface PaymentData { qr_string?: string; payment_url?: string; expired_at?: string; order_id?: string; } export default function Checkout() { const { items, removeItem, clearCart, total } = useCart(); const { user } = useAuth(); const navigate = useNavigate(); const [searchParams] = useSearchParams(); const [loading, setLoading] = useState(false); const [step, setStep] = useState("cart"); const [paymentMethod, setPaymentMethod] = useState("qris"); const [paymentData, setPaymentData] = useState(null); const [orderId, setOrderId] = useState(null); const [checkingStatus, setCheckingStatus] = useState(false); // Check for returning from PayPal useEffect(() => { const returnedOrderId = searchParams.get("order_id"); if (returnedOrderId) { setOrderId(returnedOrderId); checkPaymentStatus(returnedOrderId); } }, [searchParams]); const checkPaymentStatus = async (oid: string) => { setCheckingStatus(true); const { data: order } = await supabase.from("orders").select("payment_status").eq("id", oid).single(); if (order?.payment_status === "paid") { toast({ title: "Pembayaran berhasil!", description: "Akses produk sudah aktif" }); navigate("/access"); } else { toast({ title: "Pembayaran pending", description: "Menunggu konfirmasi pembayaran" }); } setCheckingStatus(false); }; const handleCheckout = async () => { if (!user) { toast({ title: "Login diperlukan", description: "Silakan login untuk melanjutkan pembayaran" }); navigate("/auth"); return; } if (items.length === 0) { toast({ title: "Keranjang kosong", description: "Tambahkan produk ke keranjang terlebih dahulu", variant: "destructive", }); return; } setLoading(true); try { // Generate a unique order reference const orderRef = `ORD${Date.now().toString(36).toUpperCase()}${Math.random().toString(36).substring(2, 6).toUpperCase()}`; const amountInRupiah = Math.round(total); // Create order with pending payment status const { data: order, error: orderError } = await supabase .from("orders") .insert({ user_id: user.id, total_amount: amountInRupiah, status: "pending", payment_provider: "pakasir", payment_reference: orderRef, payment_status: "pending", payment_method: paymentMethod, }) .select() .single(); if (orderError || !order) { throw new Error("Gagal membuat order"); } // Create order items const orderItems = items.map((item) => ({ order_id: order.id, product_id: item.id, unit_price: item.sale_price ?? item.price, quantity: 1, })); const { error: itemsError } = await supabase.from("order_items").insert(orderItems); if (itemsError) throw new Error("Gagal menambahkan item order"); setOrderId(order.id); // 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`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ project: PAKASIR_PROJECT_SLUG, order_id: order.id, amount: amountInRupiah, api_key: getPakasirApiKey(), description: productTitles, callback_url: PAKASIR_CALLBACK_URL, }), }); const result = await response.json(); if (result.qr_string || result.qr) { setPaymentData({ qr_string: result.qr_string || result.qr, expired_at: result.expired_at, order_id: order.id, }); setStep("waiting"); clearCart(); } else { // Fallback to redirect if API doesn't return QR const pakasirUrl = `https://app.pakasir.com/pay/${PAKASIR_PROJECT_SLUG}/${amountInRupiah}?order_id=${order.id}`; clearCart(); window.location.href = pakasirUrl; } } catch { // Fallback to redirect const pakasirUrl = `https://app.pakasir.com/pay/${PAKASIR_PROJECT_SLUG}/${amountInRupiah}?order_id=${order.id}`; clearCart(); window.location.href = pakasirUrl; } } else { // PayPal - redirect to Pakasir PayPal URL clearCart(); const paypalUrl = `https://app.pakasir.com/paypal/${PAKASIR_PROJECT_SLUG}/${amountInRupiah}?order_id=${order.id}`; window.location.href = paypalUrl; } } catch (error) { console.error("Checkout error:", error); toast({ title: "Error", description: error instanceof Error ? error.message : "Terjadi kesalahan saat checkout", variant: "destructive", }); } finally { setLoading(false); } }; const refreshPaymentStatus = async () => { if (!orderId) return; setCheckingStatus(true); const { data: order } = await supabase.from("orders").select("payment_status").eq("id", orderId).single(); if (order?.payment_status === "paid") { toast({ title: "Pembayaran berhasil!", description: "Akses produk sudah aktif" }); navigate("/access"); } else { toast({ title: "Belum ada pembayaran", description: "Silakan selesaikan pembayaran" }); } setCheckingStatus(false); }; // Waiting for QRIS payment if (step === "waiting" && paymentData) { return (
Scan QR Code untuk Bayar

{formatIDR(total)}

{paymentData.expired_at && (

Berlaku hingga: {new Date(paymentData.expired_at).toLocaleString("id-ID")}

)}

Pembayaran diproses melalui Pakasir dan akan dikonfirmasi otomatis setelah berhasil.

); } return (

Checkout

{items.length === 0 ? (

Keranjang belanja Anda kosong

) : (
{items.map((item) => (

{item.title}

{item.type}

{formatIDR(item.sale_price ?? item.price)}
))} Metode Pembayaran setPaymentMethod(v as PaymentMethod)} className="space-y-3" >
Ringkasan Order
Total {formatIDR(total)}

Pembayaran diproses melalui Pakasir

)}
); }