"use client"; import { zodResolver } from "@hookform/resolvers/zod"; import { useState } from "react"; import type { SubmitHandler, UseFormReturn } from "react-hook-form"; import { Controller, FormProvider, useFieldArray, useForm, useFormContext, } from "react-hook-form"; import z from "zod"; import type { PriceType } from "@/components/shadcnblocks/price"; import { Price, PriceValue } from "@/components/shadcnblocks/price"; import { Accordion, AccordionContent, AccordionItem, AccordionTrigger, } from "@/components/ui/accordion"; import { AspectRatio } from "@/components/ui/aspect-ratio"; import { Button } from "@/components/ui/button"; import { Checkbox } from "@/components/ui/checkbox"; import { Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldTitle, } from "@/components/ui/field"; import { Input } from "@/components/ui/input"; import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, } from "@/components/ui/input-group"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import { Separator } from "@/components/ui/separator"; import { cn } from "@/lib/utils"; type CartItem = { product_id: string; link: string; name: string; image: string; price: PriceType; details: { label: string; value: string; }[]; }; 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({ contactInfo: z.object({ email: z.string(), subscribe: z.boolean().optional(), }), address: z.object({ country: z.string(), firstName: z.string(), lastName: z.string(), address: z.string(), postalCode: z.string(), city: z.string(), phone: z.string(), }), payment: PaymentSchema, products: z .object({ product_id: z.string(), quantity: z.number(), price: z.number(), }) .array(), }); type CheckoutFormType = z.infer; type CartItemProps = CartItem; type CartType = { items: CartItem[]; shippingCost: { price: number; currency: string; }; discount: { price: number; currency: string; }; }; interface CartProps { cartData: CartType; form: UseFormReturn; } interface Checkout8Props { cart: CartType; className?: string; } interface CheckoutFormProps { onSubmit: SubmitHandler; } const CART = { items: [ { product_id: "product-1", link: "#", name: "کفش اسپرت زرشکی", image: "/block-media/shadcnblocks/block/ecommerce/clothes/stylish-maroon-sneaker.png", price: { regular: 354000.0, currency: "ریال", }, details: [ { label: "رنگ", value: "قرمز", }, { label: "سایز", value: "۳۶", }, ], }, { product_id: "product-2", link: "#", name: "سویشرت دو‌رنگ با لوگوی گلدوزی", image: "/block-media/shadcnblocks/block/ecommerce/clothes/bicolor-crewneck-sweatshirt-with-embroidered-logo.png", price: { regular: 499000.0, currency: "ریال", }, 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: 245000.0, currency: "ریال", }, details: [ { label: "رنگ", value: "زرشکی", }, ], }, ], shippingCost: { price: 20000.0, currency: "ریال", }, discount: { price: 50000.0, currency: "ریال", }, }; const Checkout8 = ({ cart = CART, className }: Checkout8Props) => { const defaultProducts = cart.items.map((item) => ({ product_id: item.product_id, price: item.price.sale ?? item.price.regular, })); const form = useForm({ resolver: zodResolver(checkoutFormSchema), defaultValues: { payment: { method: PAYMENT_METHODS.creditCard, }, products: defaultProducts, }, }); const onSubmit: SubmitHandler = ( data: CheckoutFormType, ) => { console.log(data); }; return (
); }; const Cart = ({ cartData, form }: CartProps) => { const { fields } = useFieldArray({ control: form.control, name: "products", }); const formItems = form.watch("products"); const subTotalPrice = formItems?.reduce((sum, p) => sum + p.price, 0); const totalPrice = subTotalPrice + cartData.shippingCost.price - cartData.discount.price; return (

سبد خرید

{formItems.length.toLocaleString("fa-IR")} محصول در سبد خرید شما قرار دارد.

    {fields.map((field) => { return (
  • p.product_id === field.product_id, ) as CartItem)} />
  • ); })}
جمع سفارش
هزینه ارسال
تخفیف
مبلغ قابل پرداخت
); }; const CartItem = ({ image, name, link, details, price }: CartItemProps) => { const { regular, currency } = price; return (
{name}

{name}

); }; const ProductDetails = ({ details, }: { details?: { label: string; value: string; }[]; }) => { if (!details) return; return (
    {details?.map((item, index) => { const isLast = index === details.length - 1; return (
  • {item.label}:
    {item.value}
    {!isLast && /}
  • ); })}
); }; const promoCodeFormSchema = z.object({ promoCode: z.string().trim().min(3), }); type promoCodeFormType = z.infer; const PromoCode = () => { const promoForm = useForm({ resolver: zodResolver(promoCodeFormSchema), defaultValues: { promoCode: "", }, }); const onSubmit = (data: promoCodeFormType) => { console.log(data); }; return (
(
کد تخفیف کد تخفیف خود را وارد کنید تا مبلغ سفارش به‌صورت خودکار به‌روزرسانی شود.
اعمال تخفیف {fieldState.invalid && }
)} />
); }; const CheckoutForm = ({ onSubmit }: CheckoutFormProps) => { const [activeAccordion, setActiveAccordion] = useState("item-1"); const { handleSubmit } = useFormContext(); const handleOnValueChange = (value: string) => { setActiveAccordion(value); }; const onContinue = (value: string) => { setActiveAccordion(value); }; const accordionTriggerClasses = "px-5 py-3.5 text-base font-semibold hover:no-underline"; const accordionContentClasses = ""; return (
اطلاعات تماس
روش ارسال
پرداخت
); }; const ContactFields = () => { const form = useFormContext(); return ( ( کشور {fieldState.invalid && } )} />
( نام {fieldState.invalid && } )} /> ( نام خانوادگی {fieldState.invalid && } )} />
( آدرس {fieldState.invalid && } )} />
( کد پستی {fieldState.invalid && } )} /> ( شهر {fieldState.invalid && } )} />
( تلفن {fieldState.invalid && } )} /> ( ایمیل {fieldState.invalid && } )} /> ( مایلم از تخفیف‌ها و پیشنهادهای ویژه مطلع شوم. )} />
); }; const ShippingMethodFields = () => { const form = useFormContext(); return ( ( پست اکسپرس تحویل در اولین روز کاری
پیک سریع تحویل طی ۳ تا ۵ روز کاری
{fieldState.invalid && }
)} /> ); }; const PaymentFields = () => { const form = useFormContext(); const paymentMethod = form.watch("payment.method") as PaymentMethod; return (
( کارت بانکی کارت بانکی پی‌پال پی‌پال پرداخت از طریق انتقال بانکی {fieldState.invalid && } )} />
); }; const PaymentFieldsByMethod = ({ method }: { method: PaymentMethod }) => { const form = useFormContext(); if (!method) return; switch (method) { case PAYMENT_METHODS.creditCard: return (
( نام روی کارت {fieldState.invalid && ( )} )} /> ( شماره کارت {fieldState.invalid && ( )} )} />
( کد امنیتی (CVC) {fieldState.invalid && ( )} )} />
); case PAYMENT_METHODS.paypal: return ( ( ایمیل پی‌پال {fieldState.invalid && } )} /> ); case PAYMENT_METHODS.onlineBankTransfer: return (
( نام بانک {fieldState.invalid && ( )} )} /> ( شماره حساب {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" id="checkout-payment-expiryDate" aria-invalid={fieldState.invalid} /> {fieldState.invalid && } )} /> ); }; export { Checkout8 };