"use client"; import { zodResolver } from "@hookform/resolvers/zod"; import { Trash } from "lucide-react"; import { useCallback } from "react"; import type { UseFormReturn } from "react-hook-form"; import { Controller, FormProvider, useFieldArray, useForm, useFormContext, } from "react-hook-form"; import z from "zod"; import QuantityInput from "@/components/shadcnblocks/quantity-input"; import { AspectRatio } from "@/components/ui/aspect-ratio"; import { Button } from "@/components/ui/button"; import { Field, FieldError, FieldLabel } from "@/components/ui/field"; import { Input } from "@/components/ui/input"; import { Separator } from "@/components/ui/separator"; import { cn } from "@/lib/utils"; interface ProductPrice { regular: number; sale?: number; currency: string; } type CartItem = { product_id: string; link: string; name: string; image: string; price: ProductPrice; quantity: number; details: { label: string; value: string; }[]; }; interface CartItemProps extends CartItem { index: number; onRemoveClick: () => void; onQuantityChange: (newQty: number) => void; } interface CartProps { cartItems: CartItem[]; form: UseFormReturn; } interface Checkout4Props { cartItems: CartItem[]; className?: string; } const formatPrice = (price: number, currency = "IRR") => new Intl.NumberFormat("fa-IR", { style: "currency", currency, }).format(price); const PAYMENT_METHODS = { creditCard: "creditCard", paypal: "paypal", onlineBankTransfer: "onlineBankTransfer", }; type PaymentMethod = keyof typeof PAYMENT_METHODS; const CreditCardPayment = z.object({ method: z.literal(PAYMENT_METHODS.creditCard), cardholderName: z.string(), cardNumber: z.string(), expiryDate: z .string() .regex(/^(0[1-9]|1[0-2])\/\d{2}$/, "فرمت نامعتبر (MM/YY)") .refine((value) => { const [mm, yy] = value.split("/").map(Number); const now = new Date(); const currentMonth = now.getMonth() + 1; const currentYear = now.getFullYear() % 100; if (yy < currentYear) return false; if (yy === currentYear && mm < currentMonth) return false; return true; }, "کارت منقضی شده است"), cvc: z.string(), }); const PayPalPayment = z.object({ method: z.literal(PAYMENT_METHODS.paypal), payPalEmail: z.string(), }); const BankTransferPayment = z.object({ method: z.literal(PAYMENT_METHODS.onlineBankTransfer), bankName: z.string(), accountNumber: z.string(), }); const PaymentSchema = z.discriminatedUnion("method", [ CreditCardPayment, PayPalPayment, BankTransferPayment, ]); const checkoutFormSchema = z.object({ email: z.string().email("ایمیل نامعتبر است"), payment: PaymentSchema, products: z .object({ product_id: z.string(), quantity: z.number(), price: z.number(), }) .array(), }); type CheckoutFormType = z.infer; const CART_ITEMS: CartItem[] = [ { product_id: "product-1", link: "#", name: "کفش اسپرت زرشکی", image: "/block-media/shadcnblocks/block/ecommerce/clothes/stylish-maroon-sneaker.png", price: { regular: 354.0, currency: "IRR", }, quantity: 1, details: [ { label: "رنگ", value: "قرمز" }, { label: "سایز", value: "36" }, ], }, { product_id: "product-2", link: "#", name: "سوئیشرت دو رنگ با لوگوی گلدوزی", image: "/block-media/shadcnblocks/block/ecommerce/clothes/bicolor-crewneck-sweatshirt-with-embroidered-logo.png", price: { regular: 499.0, currency: "IRR", }, quantity: 1, details: [ { label: "رنگ", value: "آبی و سفید" }, { label: "سایز", value: "L" }, ], }, { product_id: "product-4", link: "#", name: "کیف چرمی زرشکی", image: "/block-media/shadcnblocks/block/ecommerce/clothes/maroon-leather-handbag.png", price: { regular: 245.0, currency: "IRR", }, quantity: 1, details: [{ label: "رنگ", value: "زرشکی" }], }, ]; const Checkout4 = ({ cartItems = CART_ITEMS, className }: Checkout4Props) => { const defaultProducts = cartItems.map((item) => ({ product_id: item.product_id, quantity: item.quantity, price: item.price.sale ?? item.price.regular, })); const form = useForm({ resolver: zodResolver(checkoutFormSchema), defaultValues: { payment: { method: PAYMENT_METHODS.creditCard, }, products: defaultProducts, }, }); const onSubmit = (data: CheckoutFormType) => { console.log(data); }; return (

خلاصه خرید

پرداخت با کارت بانکی

); }; const Cart = ({ cartItems, form }: CartProps) => { const { fields, remove, update } = useFieldArray({ control: form.control, name: "products", }); const formItems = form.watch("products"); const totalPrice = formItems?.reduce( (sum, p) => sum + p.price * p.quantity, 0, ); const handleRemove = useCallback( (index: number) => () => { remove(index); }, [remove], ); const handleQuantityChange = useCallback( (index: number) => (newQty: number) => update(index, { ...fields[index], quantity: newQty }), [update, fields], ); return (
    {fields.map((field, index) => { const cartItem = cartItems.find( (p) => p.product_id === field.product_id, ); if (!cartItem) return null; return (
  • handleRemove(index)()} onQuantityChange={(newQty: number) => handleQuantityChange(index)(newQty) } index={index} />
  • ); })}
جمع سفارش {formatPrice(totalPrice ?? 0, cartItems[0]?.price.currency)}
هزینه ارسال در مرحله بعد محاسبه می‌شود
مالیات بر ارزش افزوده تقریبی {formatPrice(35.8, cartItems[0]?.price.currency)}
مبلغ قابل پرداخت {formatPrice(totalPrice ?? 0, cartItems[0]?.price.currency)}
); }; const CartItemComponent = ({ image, name, link, details, price, index, onQuantityChange, onRemoveClick, }: CartItemProps) => { const { regular, currency } = price; return (
{name}
{formatPrice(regular, currency)}
); }; const ProductDetails = ({ details, }: { details?: { label: string; value: string }[]; }) => { if (!details) return null; return (

{details.map((item, index) => ( {item.label}: {item.value} {index < details.length - 1 && " · "} ))}

); }; const QuantityField = ({ index, onQuantityChange, }: { index: number; onQuantityChange: (n: number) => void; }) => { const { control } = useFormContext(); return ( ( { field.onChange(newQty); onQuantityChange(newQty); }} className="rounded-none" /> )} /> ); }; const ContactFields = () => { const form = useFormContext(); return ( ( ایمیل {fieldState.invalid && } )} /> ); }; const PaymentFields = () => { const form = useFormContext(); const paymentMethod = form.watch("payment.method") as PaymentMethod; return (

روش پرداخت

); }; const PaymentFieldsByMethod = ({ method }: { method: PaymentMethod }) => { const form = useFormContext(); // Default to credit card if no method selected const paymentMethod = method || PAYMENT_METHODS.creditCard; switch (paymentMethod) { case PAYMENT_METHODS.creditCard: return (
(
اطلاعات کارت بانکی
Visa Mastercard کارت ویژه
{fieldState.invalid && ( )}
)} />
( {fieldState.invalid && ( )} )} />
( نام روی کارت {fieldState.invalid && ( )} )} />
); case PAYMENT_METHODS.paypal: return (
( ایمیل کیف پول دیجیتال {fieldState.invalid && ( )} )} />
); default: return null; } }; const DateInput = () => { const form = useFormContext(); return ( ( تاریخ انقضا { let val = e.target.value; val = val.replace(/[^0-9/]/g, ""); const prev = field.value ?? ""; const isDeleting = val.length < prev.length; if (!isDeleting) { if (val.length === 2 && !val.includes("/")) { val = val + "/"; } } if (val.length > 5) { val = val.slice(0, 5); } field.onChange(val); }} pattern="^(0[1-9]|1[0-2])/[0-9]{2}$" placeholder="MM/YY" dir="rtl" id="checkout-payment-expiryDate" aria-invalid={fieldState.invalid} /> {fieldState.invalid && } )} /> ); }; export { Checkout4 };