"use client"; import React, { useState, useEffect } from "react"; import { motion } from "motion/react"; import { ChevronRight, ChevronLeft, CreditCard, Truck, ShieldCheck, Wallet, Clock, ArrowRight, Heart, PlusCircle, Copy } from "lucide-react"; import { toPersian, cn } from "../lib/utils"; import { PRODUCTS } from "../lib/data/products"; import { useCartStore } from "../lib/store/cartStore"; import { usePetStore } from "../lib/store/usePetStore"; import { useUserStore } from "../lib/store/userStore"; import { useSettingsStore } from "../lib/store/settingsStore"; import TopUpModal from "./TopUpModal"; import AddressModal from "./AddressModal"; import SearchableSelect from "./SearchableSelect"; import { IRAN_PROVINCES, PROVINCE_CITIES } from "../lib/data/provinces"; import { toast } from "sonner"; import { useRouter } from 'next/navigation'; import api from "../lib/services/api"; export default function CheckoutPage() { const router = useRouter(); const { items, getTotal, getSubtotal, isSubscribed, charityDonation, setCharityDonation, addOrder, clearCart } = useCartStore(); const { getActivePet, updatePet } = usePetStore(); const { profile, isLoggedIn } = useUserStore(); const [loading, setLoading] = useState(false); const [useRoundUp, setUseRoundUp] = useState(false); const [paymentMethod, setPaymentMethod] = useState('card'); const [showTopUpModal, setShowTopUpModal] = useState(false); const [showAddressModal, setShowAddressModal] = useState(false); const [selectedAddressId, setSelectedAddressId] = useState(''); // Custom manual address state if guest or not using stored addresses const [manualName, setManualName] = useState(''); const [manualPhone, setManualPhone] = useState(''); const [manualProvince, setManualProvince] = useState(''); const [manualCity, setManualCity] = useState(''); const [manualZipCode, setManualZipCode] = useState(''); const [manualAddress, setManualAddress] = useState(''); const handleCopy = (text: string, title: string) => { navigator.clipboard.writeText(text); toast.success(`${title} با موفقیت کپی شد!`); }; useEffect(() => { Promise.resolve().then(() => { // Set default selected address if logged in if (isLoggedIn && profile.addresses && profile.addresses.length > 0) { const def = profile.addresses.find(a => a.isDefault) || profile.addresses[0]; setSelectedAddressId(def.id); } else if (isLoggedIn && profile.firstName) { // Pre-fill profile info for manual fields setManualName(`${profile.firstName} ${profile.lastName}`.trim()); setManualPhone(profile.mobile || ''); } }); }, [isLoggedIn, profile]); const roundStep = Number(useSettingsStore((state) => state.getText('CHARITY_ROUND_STEP', '10000'))) || 10000; const shippingFeeSetting = useSettingsStore((state) => state.getText('shipping_fee', '0')); const shippingFee = Number(shippingFeeSetting) || 0; const isCardToCardEnabled = useSettingsStore((state) => state.getBoolean('PAY_GATEWAY_CARD_ENABLE', true) && state.getBoolean('cardToCardEnabled', true) && state.getBoolean('payment_card_to_card_enabled', true) ); const subtotal = getSubtotal(); const remainder = subtotal % roundStep; const roundUpDiff = remainder === 0 ? roundStep : roundStep - remainder; const handleCharityToggle = () => { if (!useRoundUp) { setCharityDonation(roundUpDiff); setUseRoundUp(true); } else { setCharityDonation(0); setUseRoundUp(false); } }; const handleFinalize = async () => { const totalAmount = getTotal() + shippingFee; const activePet = getActivePet(); // 1. Validate shipping address const selectedAddr = profile.addresses?.find(a => a.id === selectedAddressId); let shippingAddressStr = ''; if (selectedAddr) { shippingAddressStr = `${selectedAddr.province}، ${selectedAddr.city}، ${selectedAddr.detail}${selectedAddr.zipCode ? ` (کد پستی: ${selectedAddr.zipCode})` : ''} (گیرنده: ${selectedAddr.receptorName} - ${toPersian(selectedAddr.phone)})`; } else if (manualAddress) { const provCity = [manualProvince, manualCity].filter(Boolean).join('، '); shippingAddressStr = `${provCity ? provCity + '، ' : ''}${manualAddress}${manualZipCode ? ` (کد پستی: ${manualZipCode})` : ''}${manualName ? ` (گیرنده: ${manualName}${manualPhone ? ` - ${toPersian(manualPhone)}` : ''})` : ''}`; } if (!selectedAddressId && !manualAddress) { toast.error("لطفاً یک آدرس برای ارسال سفارش انتخاب کرده یا آدرس جدید وارد کنید."); return; } // 2. Validate wallet balance if payment method is wallet if (paymentMethod === 'wallet' && (profile.walletBalance || 0) < totalAmount) { toast.error(`موجودی کیف پول شما (${(profile.walletBalance || 0).toLocaleString('fa-IR')} تومان) کمتر از مبلغ نهایی سفارش (${totalAmount.toLocaleString('fa-IR')} تومان) است. لطفاً ابتدا کیف پول خود را شارژ کنید.`); return; } setLoading(true); try { // 3. Register the order in the backend const orderId = await addOrder({ items: [...items], total: totalAmount, charityDonation: charityDonation, paymentMethod: paymentMethod, isRefill: isSubscribed, petId: activePet?.id, shippingAddress: shippingAddressStr }); // 4. Handle Online Payment via Zibal IPG if (paymentMethod === 'online') { try { const res = await api.post('/payment/zibal/initiate', { orderId }); if (res.data?.paymentUrl) { toast.success("در حال انتقال به درگاه پرداخت زیبال..."); window.location.href = res.data.paymentUrl; return; } else { toast.error("خطا در ایجاد تراکنش پرداخت زیبال"); } } catch (gatewayErr: unknown) { const gErr = gatewayErr as { response?: { data?: { message?: string } }; message?: string }; const errMsg = gErr.response?.data?.message || gErr.message || "خطا در اتصال به درگاه پرداخت زیبال"; toast.error(errMsg); router.push(`/checkout/success/${orderId}`); return; } } // 5. Re-fetch user profile from backend to sync PostgreSQL wallet balance and charity donation total const { fetchProfile } = useUserStore.getState(); await fetchProfile(); // 6. Update pet consumptions and charity contributions for active pet const targetPet = activePet || usePetStore.getState().pets[0]; if (targetPet) { const newConsumptions = [...(targetPet.consumptions || [])]; items.forEach(item => { const existing = newConsumptions.find(c => c.productId === item.product.id); if (existing) { existing.remaining += item.product.packageSize * item.quantity; existing.packageSize = item.product.packageSize; } else { newConsumptions.push({ productId: item.product.id, packageSize: item.product.packageSize, remaining: item.product.packageSize * item.quantity }); } }); updatePet(targetPet.id, { consumptions: newConsumptions }); } clearCart(); toast.success("سفارش شما با موفقیت ثبت شد!"); router.push(`/checkout/success/${orderId}`); } catch (err: unknown) { // Re-fetch profile to guarantee local state is always identical to PostgreSQL useUserStore.getState().fetchProfile().catch(() => {}); const errorObj = err as { response?: { data?: { message?: string; details?: Array<{ message?: string }> } }; message?: string }; const backendMessage = errorObj.response?.data?.message || errorObj.response?.data?.details?.[0]?.message || errorObj.message; // Only toast if message exists and is not a generic duplicate if (backendMessage && !backendMessage.includes("Request failed") && !backendMessage.includes("خطای غیرمنتظره")) { toast.error(`خطا در ثبت سفارش: ${backendMessage}`); } } finally { setLoading(false); } }; if (items.length === 0) { return (

سبد خرید شما خالی است

); } return (
{/* Mobile Navigation & Breadcrumbs */}
router.push('/shop')}>سبد خرید نهایی‌سازی سفارش
{/* Desktop Breadcrumbs (Hidden on Mobile) */}
router.push('/')}>خانه درگاه پرداخت امن و نهایی‌سازی
{/* Main Form */}
{/* Step 1: Shipping */}
۱

اطلاعات ارسال

{isLoggedIn && profile.addresses && profile.addresses.length > 0 ? (

انتخاب آدرس جهت تحویل سفارش:

{profile.addresses.map((addr) => (
setSelectedAddressId(addr.id)} className={cn( "p-4 rounded-2xl border-2 cursor-pointer transition-all flex items-start gap-3", selectedAddressId === addr.id ? "border-canina-blue bg-canina-blue/5" : "border-medical-gray-100 hover:border-medical-gray-200" )} > setSelectedAddressId(addr.id)} className="mt-1" />
{addr.title} {addr.isDefault && ( پیش‌فرض )}

{addr.province}، {addr.city}، {addr.detail}

گیرنده: {addr.receptorName} | همراه: {toPersian(addr.phone)}

))}
) : (
{isLoggedIn && (
)}
setManualName(e.target.value)} className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-3 sm:py-4 px-4 sm:px-6 text-xs sm:text-sm focus:outline-none focus:ring-2 focus:ring-canina-blue/20" placeholder="مثلاً: پارسا آقایی" />
setManualPhone(e.target.value.replace(/[^0-9]/g, ''))} className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-3 sm:py-4 px-4 sm:px-6 text-xs sm:text-sm focus:outline-none focus:ring-2 focus:ring-canina-blue/20 dir-ltr text-right" placeholder="۰۹۱۲XXXXXXX" />
{ const cities = PROVINCE_CITIES[prov] || []; setManualProvince(prov); setManualCity(cities[0] || ''); }} />
{manualProvince && PROVINCE_CITIES[manualProvince] ? ( setManualCity(c)} /> ) : ( setManualCity(e.target.value)} className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-3 sm:py-4 px-4 sm:px-6 text-xs sm:text-sm focus:outline-none focus:ring-2 focus:ring-canina-blue/20" placeholder="نام شهر..." /> )}