Files
reui-blocks/blocks/checkout8.tsx
T

1093 lines
32 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"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<typeof checkoutFormSchema>;
type CartItemProps = CartItem;
type CartType = {
items: CartItem[];
shippingCost: {
price: number;
currency: string;
};
discount: {
price: number;
currency: string;
};
};
interface CartProps {
cartData: CartType;
form: UseFormReturn<CheckoutFormType>;
}
interface Checkout8Props {
cart: CartType;
className?: string;
}
interface CheckoutFormProps {
onSubmit: SubmitHandler<CheckoutFormType>;
}
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<CheckoutFormType> = (
data: CheckoutFormType,
) => {
console.log(data);
};
return (
<section
dir="rtl"
lang="fa"
className={cn("bg-muted py-32", className)}
>
<div className="container">
<FormProvider {...form}>
<div className="grid grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3">
<div className="col-span-1">
<div className="space-y-6">
<Cart form={form} cartData={cart} />
<PromoCode />
</div>
</div>
<div className="xl:col-span-2">
<CheckoutForm onSubmit={onSubmit} />
</div>
</div>
</FormProvider>
</div>
</section>
);
};
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 (
<div className="space-y-6 rounded-lg border-border bg-background p-7 shadow-lg">
<div>
<h2 className="text-xl leading-relaxed font-semibold">سبد خرید</h2>
<p className="text-sm font-medium text-muted-foreground">
{formItems.length.toLocaleString("fa-IR")} محصول در سبد خرید شما قرار دارد.
</p>
</div>
<Separator />
<ul className="space-y-5">
{fields.map((field) => {
return (
<li key={field.id}>
<CartItem
{...(cartData.items.find(
(p) => p.product_id === field.product_id,
) as CartItem)}
/>
</li>
);
})}
</ul>
<Separator />
<div className="space-y-4">
<div className="flex items-center justify-between">
<div>جمع سفارش</div>
<Price>
<PriceValue
price={subTotalPrice}
currency={cartData.items[0].price.currency}
/>
</Price>
</div>
<div className="flex items-center justify-between">
<div>هزینه ارسال</div>
<Price>
<PriceValue
price={cartData.shippingCost.price}
currency={cartData.shippingCost.currency}
/>
</Price>
</div>
<div className="flex items-center justify-between">
<div>تخفیف</div>
<Price>
<PriceValue
price={cartData.discount.price}
currency={cartData.discount.currency}
/>
</Price>
</div>
</div>
<Separator />
<div className="flex items-center justify-between">
<div>مبلغ قابل پرداخت</div>
<Price>
<PriceValue
price={totalPrice}
currency={cartData.discount.currency}
/>
</Price>
</div>
<Button className="w-full">ثبت و پرداخت سفارش</Button>
</div>
);
};
const CartItem = ({ image, name, link, details, price }: CartItemProps) => {
const { regular, currency } = price;
return (
<a href={link} className="flex items-center gap-4">
<div className="shrink-0 basis-15">
<AspectRatio ratio={1} className="overflow-hidden">
<img
src={image}
alt={name}
className="block size-full object-cover object-center"
/>
</AspectRatio>
</div>
<div className="flex flex-1 gap-4 max-sm:flex-col sm:items-center">
<div className="flex-1">
<h2 className="font-medium">{name}</h2>
<ProductDetails details={details} />
</div>
<Price className="text-sm font-semibold">
<PriceValue price={regular} currency={currency} variant="regular" />
</Price>
</div>
</a>
);
};
const ProductDetails = ({
details,
}: {
details?: {
label: string;
value: string;
}[];
}) => {
if (!details) return;
return (
<ul>
{details?.map((item, index) => {
const isLast = index === details.length - 1;
return (
<li className="inline" key={index}>
<dl className="inline text-xs text-muted-foreground">
<dt className="inline">{item.label}: </dt>
<dd className="inline">{item.value}</dd>
{!isLast && <span className="mx-1 text-muted-foreground">/</span>}
</dl>
</li>
);
})}
</ul>
);
};
const promoCodeFormSchema = z.object({
promoCode: z.string().trim().min(3),
});
type promoCodeFormType = z.infer<typeof promoCodeFormSchema>;
const PromoCode = () => {
const promoForm = useForm<promoCodeFormType>({
resolver: zodResolver(promoCodeFormSchema),
defaultValues: {
promoCode: "",
},
});
const onSubmit = (data: promoCodeFormType) => {
console.log(data);
};
return (
<div className="rounded-lg border-border bg-background p-7 shadow-lg">
<form onSubmit={promoForm.handleSubmit(onSubmit)}>
<Controller
name="promoCode"
control={promoForm.control}
render={({ field, fieldState }) => (
<Field data-invalid={fieldState.invalid}>
<div>
<FieldLabel
htmlFor="promo-code"
className="text-lg font-semibold"
>
کد تخفیف
</FieldLabel>
<FieldDescription>
کد تخفیف خود را وارد کنید تا مبلغ سفارش به‌صورت خودکار به‌روزرسانی شود.
</FieldDescription>
</div>
<InputGroup>
<InputGroupInput
{...field}
id="promo-code"
placeholder="کد تخفیف"
aria-invalid={fieldState.invalid}
/>
<InputGroupAddon align="inline-end">
<InputGroupButton variant="default" className="text-xs">
اعمال تخفیف
</InputGroupButton>
</InputGroupAddon>
</InputGroup>
{fieldState.invalid && <FieldError errors={[fieldState.error]} />}
</Field>
)}
/>
</form>
</div>
);
};
const CheckoutForm = ({ onSubmit }: CheckoutFormProps) => {
const [activeAccordion, setActiveAccordion] = useState("item-1");
const { handleSubmit } = useFormContext<CheckoutFormType>();
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 (
<div className="space-y-6 rounded-lg border-border bg-background p-7 shadow-lg">
<form onSubmit={handleSubmit(onSubmit)}>
<Accordion
type="single"
collapsible
className="w-full border"
value={activeAccordion}
onValueChange={handleOnValueChange}
>
<AccordionItem value="مرحله ۱">
<AccordionTrigger className={accordionTriggerClasses}>
اطلاعات تماس
</AccordionTrigger>
<AccordionContent className={accordionContentClasses}>
<div className="space-y-7">
<ContactFields />
<Button
type="button"
className="w-full"
variant="secondary"
onClick={() => onContinue("item-2")}
>
ادامه مرحله
</Button>
</div>
</AccordionContent>
</AccordionItem>
<AccordionItem value="مرحله ۲">
<AccordionTrigger className={accordionTriggerClasses}>
روش ارسال
</AccordionTrigger>
<AccordionContent className={accordionContentClasses}>
<div className="space-y-7">
<ShippingMethodFields />
<Button
type="button"
className="w-full"
variant="secondary"
onClick={() => onContinue("item-3")}
>
ادامه مرحله
</Button>
</div>
</AccordionContent>
</AccordionItem>
<AccordionItem value="مرحله ۳">
<AccordionTrigger className={accordionTriggerClasses}>
پرداخت
</AccordionTrigger>
<AccordionContent className={accordionContentClasses}>
<div className="space-y-7">
<PaymentFields />
<Button type="submit" className="w-full">
ثبت و پرداخت سفارش
</Button>
</div>
</AccordionContent>
</AccordionItem>
</Accordion>
</form>
</div>
);
};
const ContactFields = () => {
const form = useFormContext();
return (
<FieldGroup className="gap-3.5">
<Controller
name="address.country"
control={form.control}
render={({ field, fieldState }) => (
<Field data-invalid={fieldState.invalid}>
<FieldLabel
className="text-sm font-normal"
htmlFor="checkout-country"
>
کشور
</FieldLabel>
<Input
{...field}
id="checkout-country"
aria-invalid={fieldState.invalid}
/>
{fieldState.invalid && <FieldError errors={[fieldState.error]} />}
</Field>
)}
/>
<div className="flex gap-3.5 max-sm:flex-col">
<Controller
name="address.firstName"
control={form.control}
render={({ field, fieldState }) => (
<Field data-invalid={fieldState.invalid}>
<FieldLabel
className="text-sm font-normal"
htmlFor="checkout-firstName"
>
نام
</FieldLabel>
<Input
{...field}
id="checkout-firstName"
aria-invalid={fieldState.invalid}
/>
{fieldState.invalid && <FieldError errors={[fieldState.error]} />}
</Field>
)}
/>
<Controller
name="address.lastName"
control={form.control}
render={({ field, fieldState }) => (
<Field data-invalid={fieldState.invalid}>
<FieldLabel
className="text-sm font-normal"
htmlFor="checkout-lastName"
>
نام خانوادگی
</FieldLabel>
<Input
{...field}
id="checkout-lastName"
aria-invalid={fieldState.invalid}
/>
{fieldState.invalid && <FieldError errors={[fieldState.error]} />}
</Field>
)}
/>
</div>
<Controller
name="address.address"
control={form.control}
render={({ field, fieldState }) => (
<Field data-invalid={fieldState.invalid}>
<FieldLabel
className="text-sm font-normal"
htmlFor="checkout-address"
>
آدرس
</FieldLabel>
<Input
{...field}
id="checkout-address"
aria-invalid={fieldState.invalid}
/>
{fieldState.invalid && <FieldError errors={[fieldState.error]} />}
</Field>
)}
/>
<div className="flex gap-3.5 max-sm:flex-col">
<Controller
name="address.postalCode"
control={form.control}
render={({ field, fieldState }) => (
<Field data-invalid={fieldState.invalid}>
<FieldLabel
className="text-sm font-normal"
htmlFor="checkout-postalCode"
>
کد پستی
</FieldLabel>
<Input
{...field}
id="checkout-postalCode"
aria-invalid={fieldState.invalid}
/>
{fieldState.invalid && <FieldError errors={[fieldState.error]} />}
</Field>
)}
/>
<Controller
name="address.city"
control={form.control}
render={({ field, fieldState }) => (
<Field data-invalid={fieldState.invalid}>
<FieldLabel
className="text-sm font-normal"
htmlFor="checkout-city"
>
شهر
</FieldLabel>
<Input
{...field}
id="checkout-city"
aria-invalid={fieldState.invalid}
/>
{fieldState.invalid && <FieldError errors={[fieldState.error]} />}
</Field>
)}
/>
</div>
<Controller
name="address.phone"
control={form.control}
render={({ field, fieldState }) => (
<Field data-invalid={fieldState.invalid}>
<FieldLabel
className="text-sm font-normal"
htmlFor="checkout-phone"
>
تلفن
</FieldLabel>
<Input
{...field}
id="checkout-phone"
aria-invalid={fieldState.invalid}
/>
{fieldState.invalid && <FieldError errors={[fieldState.error]} />}
</Field>
)}
/>
<Controller
name="contactInfo.email"
control={form.control}
render={({ field, fieldState }) => (
<Field data-invalid={fieldState.invalid}>
<FieldLabel
className="text-sm font-normal"
htmlFor="checkout-email"
>
ایمیل
</FieldLabel>
<Input
{...field}
id="checkout-email"
aria-invalid={fieldState.invalid}
/>
{fieldState.invalid && <FieldError errors={[fieldState.error]} />}
</Field>
)}
/>
<Controller
name="contactInfo.subscribe"
control={form.control}
render={({ field }) => (
<Field orientation="horizontal">
<Checkbox
id="checkout-subscribe"
name={field.name}
// @ts-ignore
checked={field.value}
onCheckedChange={field.onChange}
/>
<FieldLabel htmlFor="checkout-subscribe" className="font-normal">
مایلم از تخفیف‌ها و پیشنهادهای ویژه مطلع شوم.
</FieldLabel>
</Field>
)}
/>
</FieldGroup>
);
};
const ShippingMethodFields = () => {
const form = useFormContext();
return (
<Controller
name="shippingMethod"
control={form.control}
render={({ field, fieldState }) => (
<Field>
<RadioGroup
name={field.name}
value={field.value}
onValueChange={field.onChange}
className="flex max-sm:flex-col"
>
<FieldLabel htmlFor="checkout-shippingMethod-1">
<Field orientation="horizontal" data-invalid={fieldState.invalid}>
<FieldContent>
<FieldTitle>پست اکسپرس</FieldTitle>
<FieldDescription>تحویل در اولین روز کاری</FieldDescription>
</FieldContent>
<div className="flex gap-3.5">
<Price className="text-sm">
<PriceValue price={10000} currency="ریال" />
</Price>
<RadioGroupItem
value="UPS"
id="checkout-shippingMethod-1"
aria-invalid={fieldState.invalid}
/>
</div>
</Field>
</FieldLabel>
<FieldLabel htmlFor="checkout-shippingMethod-2">
<Field orientation="horizontal" data-invalid={fieldState.invalid}>
<FieldContent>
<FieldTitle>پیک سریع</FieldTitle>
<FieldDescription>تحویل طی ۳ تا ۵ روز کاری</FieldDescription>
</FieldContent>
<div className="flex gap-3.5">
<Price className="text-sm">
<PriceValue price={2990} currency="ریال" />
</Price>
<RadioGroupItem
value="FedEx"
id="checkout-shippingMethod-2"
aria-invalid={fieldState.invalid}
/>
</div>
</Field>
</FieldLabel>
</RadioGroup>
{fieldState.invalid && <FieldError errors={[fieldState.error]} />}
</Field>
)}
/>
);
};
const PaymentFields = () => {
const form = useFormContext();
const paymentMethod = form.watch("payment.method") as PaymentMethod;
return (
<div className="space-y-7">
<Controller
name="payment.method"
control={form.control}
render={({ field, fieldState }) => (
<Field>
<RadioGroup
name={field.name}
value={field.value}
onValueChange={field.onChange}
>
<FieldLabel htmlFor="checkout-payment-method-1">
<Field
orientation="horizontal"
data-invalid={fieldState.invalid}
>
<FieldContent className="flex-1">
<FieldTitle>کارت بانکی</FieldTitle>
</FieldContent>
<img
src="/block-media/shadcnblocks/block/logos/visa-icon.svg"
alt="کارت بانکی"
className="size-5"
/>
<RadioGroupItem
value="creditCard"
id="checkout-payment-method-1"
aria-invalid={fieldState.invalid}
/>
</Field>
</FieldLabel>
<FieldLabel htmlFor="checkout-payment-method-2">
<Field
orientation="horizontal"
data-invalid={fieldState.invalid}
>
<FieldContent className="flex-1">
<FieldTitle>پی‌پال</FieldTitle>
</FieldContent>
<img
src="/block-media/shadcnblocks/block/logos/paypal-icon.svg"
alt="پی‌پال"
className="size-5"
/>
<RadioGroupItem
value="paypal"
id="checkout-payment-method-2"
aria-invalid={fieldState.invalid}
/>
</Field>
</FieldLabel>
<FieldLabel htmlFor="checkout-payment-method-3">
<Field
orientation="horizontal"
data-invalid={fieldState.invalid}
>
<FieldContent>
<FieldTitle>پرداخت از طریق انتقال بانکی</FieldTitle>
</FieldContent>
<RadioGroupItem
value="onlineBankTransfer"
id="checkout-payment-method-3"
aria-invalid={fieldState.invalid}
/>
</Field>
</FieldLabel>
</RadioGroup>
{fieldState.invalid && <FieldError errors={[fieldState.error]} />}
</Field>
)}
/>
<PaymentFieldsByMethod method={paymentMethod} />
</div>
);
};
const PaymentFieldsByMethod = ({ method }: { method: PaymentMethod }) => {
const form = useFormContext();
if (!method) return;
switch (method) {
case PAYMENT_METHODS.creditCard:
return (
<div className="space-y-3.5">
<Controller
name="payment.cardholderName"
control={form.control}
render={({ field, fieldState }) => (
<Field data-invalid={fieldState.invalid}>
<FieldLabel
className="text-sm font-normal"
htmlFor="checkout-payment-cardholderName"
>
نام روی کارت
</FieldLabel>
<Input
{...field}
id="checkout-payment-cardholderName"
aria-invalid={fieldState.invalid}
/>
{fieldState.invalid && (
<FieldError errors={[fieldState.error]} />
)}
</Field>
)}
/>
<Controller
name="payment.cardNumber"
control={form.control}
render={({ field, fieldState }) => (
<Field data-invalid={fieldState.invalid}>
<FieldLabel
className="text-sm font-normal"
htmlFor="checkout-payment-cardNumber"
>
شماره کارت
</FieldLabel>
<Input
{...field}
id="checkout-payment-cardNumber"
aria-invalid={fieldState.invalid}
/>
{fieldState.invalid && (
<FieldError errors={[fieldState.error]} />
)}
</Field>
)}
/>
<div className="flex gap-3.5 max-sm:flex-col">
<DateInput />
<Controller
name="payment.cvc"
control={form.control}
render={({ field, fieldState }) => (
<Field data-invalid={fieldState.invalid}>
<FieldLabel
className="text-sm font-normal"
htmlFor="checkout-payment-cvc"
>
کد امنیتی (CVC)
</FieldLabel>
<Input
{...field}
id="checkout-payment-cvc"
aria-invalid={fieldState.invalid}
/>
{fieldState.invalid && (
<FieldError errors={[fieldState.error]} />
)}
</Field>
)}
/>
</div>
</div>
);
case PAYMENT_METHODS.paypal:
return (
<Controller
name="payment.payPalEmail"
control={form.control}
render={({ field, fieldState }) => (
<Field data-invalid={fieldState.invalid}>
<FieldLabel
className="text-sm font-normal"
htmlFor="checkout-payment-payPalEmail"
>
ایمیل پی‌پال
</FieldLabel>
<Input
{...field}
type="email"
placeholder="example@email.com"
id="checkout-payment-payPalEmail"
aria-invalid={fieldState.invalid}
/>
{fieldState.invalid && <FieldError errors={[fieldState.error]} />}
</Field>
)}
/>
);
case PAYMENT_METHODS.onlineBankTransfer:
return (
<div className="space-y-3.5">
<Controller
name="payment.bankName"
control={form.control}
render={({ field, fieldState }) => (
<Field data-invalid={fieldState.invalid}>
<FieldLabel
className="text-sm font-normal"
htmlFor="checkout-payment-bankName"
>
نام بانک
</FieldLabel>
<Input
{...field}
placeholder="نام بانک"
id="checkout-payment-bankName"
aria-invalid={fieldState.invalid}
/>
{fieldState.invalid && (
<FieldError errors={[fieldState.error]} />
)}
</Field>
)}
/>
<Controller
name="payment.accountNumber"
control={form.control}
render={({ field, fieldState }) => (
<Field data-invalid={fieldState.invalid}>
<FieldLabel
className="text-sm font-normal"
htmlFor="checkout-payment-accountNumber"
>
شماره حساب
</FieldLabel>
<Input
{...field}
id="checkout-payment-accountNumber"
aria-invalid={fieldState.invalid}
/>
{fieldState.invalid && (
<FieldError errors={[fieldState.error]} />
)}
</Field>
)}
/>
</div>
);
default:
return null;
}
};
const DateInput = () => {
const form = useFormContext();
return (
<Controller
name="payment.expiryDate"
control={form.control}
render={({ field, fieldState }) => (
<Field data-invalid={fieldState.invalid}>
<FieldLabel
className="text-sm font-normal"
htmlFor="checkout-payment-expiryDate"
>
تاریخ انقضا
</FieldLabel>
<Input
{...field}
onChange={(e) => {
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 && <FieldError errors={[fieldState.error]} />}
</Field>
)}
/>
);
};
export { Checkout8 };