"use client"; import { zodResolver } from "@hookform/resolvers/zod"; import { useForm, Controller } from "react-hook-form"; import { Button } from "@/components/ui/button"; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from "@/components/ui/form"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; import { CoinPurchaseSchema, type CoinPurchaseInput, CoinPurchasePackageEnum, PaymentGatewayEnum, SupportedCurrencyEnum } from "@/lib/schemas"; import type { CoinPackageDetails, CurrencyInfo } from "@/lib/types"; import { useToast } from "@/hooks/use-toast"; import { useRouter } from "next/navigation"; import { useState, useEffect } from "react"; import { Loader2, Coins, CreditCard, ShoppingCart, Lock } from "lucide-react"; import { usePaystackPayment, PaystackButton, PaystackConsumer } from 'react-paystack'; import { useFlutterwave, closePaymentModal } from 'flutterwave-react-v3'; import { initiateCoinPurchase, verifyPaymentAndAwardCoins } from "@/lib/actions/billing"; import { getLoggedInUser, type LoggedInUser } from "@/lib/actions/auth"; const paystackPublicKey = process.env.NEXT_PUBLIC_PAYSTACK_PUBLIC_KEY || ''; const flutterwavePublicKey = process.env.NEXT_PUBLIC_FLUTTERWAVE_PUBLIC_KEY || ''; const COIN_BASE_PRICE_NGN = 10; // 1 Coin = 10 NGN const coinPackages: CoinPackageDetails[] = [ { id: 'small_50', name: "Small Pack", coins: 50, priceNGN: 50 * COIN_BASE_PRICE_NGN, description: "Get started with 50 coins." }, { id: 'medium_150', name: "Medium Pack", coins: 150, priceNGN: 150 * COIN_BASE_PRICE_NGN, description: "Most popular: 150 coins." }, { id: 'large_300', name: "Large Pack", coins: 300, priceNGN: 300 * COIN_BASE_PRICE_NGN, description: "Best value: 300 coins." }, ]; const currencyRatesList: CurrencyInfo[] = [ { code: 'NGN', symbol: '₦', rate: 1, name: 'Nigerian Naira' }, { code: 'USD', symbol: '$', rate: 0.00063, name: 'US Dollar' }, { code: 'GBP', symbol: '£', rate: 0.00050, name: 'British Pound' }, { code: 'EUR', symbol: '€', rate: 0.00058, name: 'Euro' }, { code: 'GHS', symbol: 'GH₵', rate: 0.0094, name: 'Ghanaian Cedi' }, { code: 'KES', symbol: 'KSh', rate: 0.093, name: 'Kenyan Shilling' }, { code: 'ZAR', symbol: 'R', rate: 0.012, name: 'South African Rand' }, { code: 'UGX', symbol: 'USh', rate: 2.5, name: 'Ugandan Shilling' }, { code: 'TZS', symbol: 'TSh', rate: 1.6, name: 'Tanzanian Shilling' }, { code: 'RWF', symbol: 'RF', rate: 0.82, name: 'Rwandan Franc' }, { code: 'XOF', symbol: 'CFA', rate: 0.38, name: 'West African CFA franc' }, { code: 'XAF', symbol: 'FCFA', rate: 0.38, name: 'Central African CFA franc' }, { code: 'CAD', symbol: 'CA$', rate: 0.00086, name: 'Canadian Dollar' }, { code: 'EGP', symbol: 'E£', rate: 0.030, name: 'Egyptian Pound' }, { code: 'GNF', symbol: 'FG', rate: 5.4, name: 'Guinean Franc' }, { code: 'MAD', symbol: 'MAD', rate: 0.0063, name: 'Moroccan Dirham' }, { code: 'MWK', symbol: 'MK', rate: 1.1, name: 'Malawian Kwacha' }, { code: 'SLL', symbol: 'Le', rate: 14.0, name: 'Sierra Leonean Leone (New)'}, { code: 'STD', symbol: 'Db', rate: 14.0, name: 'São Tomé & Príncipe Dobra (New)' }, { code: 'ZMW', symbol: 'ZK', rate: 0.017, name: 'Zambian Kwacha' }, { code: 'CLP', symbol: 'CLP$', rate: 0.58, name: 'Chilean Peso' }, { code: 'COP', symbol: 'COL$', rate: 2.5, name: 'Colombian Peso' }, ]; export function CoinPurchaseForm() { const { toast } = useToast(); const router = useRouter(); const [isLoading, setIsLoading] = useState(false); const [currentUser, setCurrentUser] = useState(null); useEffect(() => { getLoggedInUser().then(setCurrentUser); }, []); const form = useForm({ resolver: zodResolver(CoinPurchaseSchema), defaultValues: { package: "medium_150", currency: "NGN", paymentGateway: "paystack", email: currentUser?.email || "", name: currentUser?.name || "", }, }); const selectedPackageId = form.watch("package"); const selectedCurrencyCode = form.watch("currency"); const selectedPkg = coinPackages.find(p => p.id === selectedPackageId) || coinPackages[0]; const selectedCurrInfo = currencyRatesList.find(c => c.code === selectedCurrencyCode) || currencyRatesList[0]; const priceInSelectedCurrency = parseFloat((selectedPkg.priceNGN * selectedCurrInfo.rate).toFixed(2)); useEffect(() => { form.setValue("amountInSelectedCurrency", priceInSelectedCurrency); form.setValue("amountInNGN", selectedPkg.priceNGN); form.setValue("coinsToCredit", selectedPkg.coins); if (currentUser) { form.setValue("email", currentUser.email); form.setValue("name", currentUser.name); } }, [selectedPkg, priceInSelectedCurrency, form, currentUser]); const handlePaymentSuccess = async (response: any, gateway: 'paystack' | 'flutterwave') => { console.log(`${gateway} success response:`, response); toast({ title: `${gateway} Payment Submitted (Simulation)`, description: `Ref: ${response.reference || response.transaction_id}. Verifying...` }); setIsLoading(true); // SIMULATE webhook verification for now const verificationResult = await verifyPaymentAndAwardCoins(gateway, response.reference || response.transaction_id, response); toast({ title: verificationResult.success ? "Purchase Complete!" : "Verification Issue", description: verificationResult.message, variant: verificationResult.success ? "default" : "destructive", }); if (verificationResult.success) { router.refresh(); } setIsLoading(false); }; const handlePaymentClose = (gateway: 'paystack' | 'flutterwave') => { console.log(`${gateway} payment modal closed.`); toast({ title: "Payment Cancelled", description: "The payment process was cancelled.", variant: "default" }); setIsLoading(false); }; // Paystack Config const paystackConfig = { reference: new Date().getTime().toString(), email: form.getValues("email"), amount: priceInSelectedCurrency * 100, // Amount in kobo currency: selectedCurrencyCode, publicKey: paystackPublicKey, metadata: { userId: currentUser?._id, packageName: selectedPkg.name, coins: selectedPkg.coins, custom_fields: [ { display_name: "Package", variable_name: "package", value: selectedPkg.name }, { display_name: "Coins", variable_name: "coins", value: selectedPkg.coins } ] } }; // Flutterwave Config const flutterwaveConfig = { public_key: flutterwavePublicKey, tx_ref: new Date().getTime().toString(), amount: priceInSelectedCurrency, currency: selectedCurrencyCode, payment_options: "card,mobilemoney,ussd", customer: { email: form.getValues("email"), name: form.getValues("name") || "Anita Deploy User", }, customizations: { title: "Anita Deploy - Coin Purchase", description: `Payment for ${selectedPkg.coins} coins`, logo: "https://placehold.co/100x100.png?text=AD", }, }; const initializePaystackPayment = usePaystackPayment(paystackConfig); const handleFlutterwavePayment = useFlutterwave(flutterwaveConfig); async function onSubmit(values: CoinPurchaseInput) { setIsLoading(true); if (!paystackPublicKey || !flutterwavePublicKey) { toast({title: "Configuration Error", description: "Payment gateway keys are not set. Please contact support.", variant: "destructive"}); setIsLoading(false); return; } if (!currentUser) { toast({title: "Error", description: "User not loaded. Please refresh.", variant: "destructive"}); setIsLoading(false); return; } const currentPaystackConfig = { ...paystackConfig, reference: `anitad_${currentUser._id}_${new Date().getTime()}`, email: values.email, amount: values.amountInSelectedCurrency * 100, currency: values.currency, metadata: { userId: currentUser._id, packageName: selectedPkg.name, coins: selectedPkg.coins, transactionType: "coin_purchase", custom_fields: [ { display_name: "Package", variable_name: "package", value: selectedPkg.name }, { display_name: "Coins", variable_name: "coins", value: selectedPkg.coins } ] } }; const currentFlutterwaveConfig = { ...flutterwaveConfig, tx_ref: `anitad_${currentUser._id}_${new Date().getTime()}`, amount: values.amountInSelectedCurrency, currency: values.currency, customer: { email: values.email, name: values.name || "Anita Deploy User", }, meta: { userId: currentUser._id, packageName: selectedPkg.name, coins: selectedPkg.coins, transactionType: "coin_purchase" } }; const initResult = await initiateCoinPurchase({ ...values, }); if (!initResult.success || !initResult.transactionReference) { toast({ title: "Initiation Failed", description: initResult.message, variant: "destructive" }); setIsLoading(false); return; } currentPaystackConfig.reference = initResult.transactionReference; currentFlutterwaveConfig.tx_ref = initResult.transactionReference; if (values.paymentGateway === "paystack") { initializePaystackPayment({ onSuccess: (response) => handlePaymentSuccess(response, 'paystack'), onClose: () => handlePaymentClose('paystack'), config: currentPaystackConfig, }); } else if (values.paymentGateway === "flutterwave") { handleFlutterwavePayment({ callback: (response) => { handlePaymentSuccess(response, 'flutterwave'); closePaymentModal(); }, onClose: () => handlePaymentClose('flutterwave'), }); } } return (
( 1. Select Coin Package {coinPackages.map((pkg) => ( ))} )} /> ( 2. Select Currency The price will be converted to your selected currency. )} /> Order Summary

Package: {selectedPkg.name} ({selectedPkg.coins} Coins)

Total: {selectedCurrInfo.symbol} {priceInSelectedCurrency.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} ({selectedCurrencyCode})

{selectedCurrencyCode !== 'NGN' && (

(Approx. {currencyRatesList.find(c => c.code === 'NGN')?.symbol} {selectedPkg.priceNGN.toLocaleString()} NGN)

)}
( 3. Select Payment Gateway )} />

Secure payment processing by Paystack & Flutterwave.

); }