Files
reui-blocks/blocks/order-summary3.tsx
T

360 lines
12 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.
import { CheckCircle, MapPin, Package, Receipt, Truck } from "lucide-react";
import { AspectRatio } from "@/components/ui/aspect-ratio";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import { Separator } from "@/components/ui/separator";
import { cn } from "@/lib/utils";
interface OrderItem {
id: string;
name: string;
image: string;
price: number;
quantity: number;
details?: { label: string; value: string }[];
}
interface ShippingAddress {
name: string;
street: string;
city: string;
state: string;
zipCode: string;
country: string;
}
interface PaymentMethod {
type: "card" | "paypal" | "bank";
lastFour?: string;
cardBrand?: string;
email?: string;
}
interface OrderSummaryData {
orderNumber: string;
/** ISO 8601 date (YYYY-MM-DD) */
orderDate: string;
status: "confirmed" | "processing" | "shipped" | "delivered";
email: string;
items: OrderItem[];
subtotal: number;
shipping: number;
tax: number;
discount?: number;
total: number;
shippingAddress: ShippingAddress;
shippingMethod: string;
/** ISO 8601 date range for estimated delivery */
estimatedDeliveryFrom: string;
estimatedDeliveryTo?: string;
paymentMethod: PaymentMethod;
}
const currencyFormatter = new Intl.NumberFormat("fa-IR", {
style: "currency",
currency: "IRR",
});
const dateFormatter = new Intl.DateTimeFormat("fa-IR", {
year: "numeric",
month: "long",
day: "numeric",
});
const formatOrderDate = (isoDate: string) =>
dateFormatter.format(new Date(isoDate + "T12:00:00"));
const formatDeliveryEstimate = (from: string, to?: string) => {
if (to && to !== from) {
return `${formatOrderDate(from)} تا ${formatOrderDate(to)}`;
}
return formatOrderDate(from);
};
const DEFAULT_ORDER: OrderSummaryData = {
orderNumber: "ORD-2024-78432",
orderDate: "2024-12-14",
status: "confirmed",
email: "customer@example.com",
items: [
{
id: "1",
name: "کفش بژ مینیمال",
image:
"/block-media/shadcnblocks/block/ecommerce/clothes/Minimalist-Beige-Sneakers-2.png",
price: 120.0,
quantity: 1,
details: [
{ label: "سایز", value: "42" },
{ label: "رنگ", value: "بژ" },
],
},
{
id: "2",
name: "تاپ آبی گلدوزی",
image:
"/block-media/shadcnblocks/block/ecommerce/clothes/Woman-in-Embroidered-Blue-Top-2.png",
price: 140.0,
quantity: 2,
details: [
{ label: "سایز", value: "M" },
{ label: "رنگ", value: "آبی" },
],
},
{
id: "3",
name: "کلاه فدورا کلاسیک",
image:
"/block-media/shadcnblocks/block/ecommerce/accessories/Classic-Fedora-Hat-2.png",
price: 84.0,
quantity: 1,
details: [{ label: "سایز", value: "یک سایز" }],
},
],
subtotal: 484.0,
shipping: 12.0,
tax: 38.72,
discount: 50.0,
total: 484.72,
shippingAddress: {
name: "علی محمدی",
street: "خیابان ولیعصر، پلاک ۱۲۳۴، واحد ۵",
city: "تهران",
state: "تهران",
zipCode: "1415783114",
country: "ایران",
},
shippingMethod: "ارسال سریع",
estimatedDeliveryFrom: "2024-12-18",
estimatedDeliveryTo: "2024-12-20",
paymentMethod: {
type: "card",
lastFour: "4242",
cardBrand: "Visa",
},
};
interface OrderSummary3Props {
order?: OrderSummaryData;
className?: string;
}
const OrderSummary3 = ({
order = DEFAULT_ORDER,
className,
}: OrderSummary3Props) => {
return (
<section
dir="rtl"
lang="fa"
className={cn("py-16 md:py-24", className)}
>
<div className="container">
<div className="mb-12 text-center">
<div className="mx-auto mb-6 flex size-20 items-center justify-center rounded-full bg-emerald-500">
<CheckCircle
className="size-10 text-white"
strokeWidth={2.5}
aria-hidden="true"
/>
</div>
<h1 className="mb-3 text-xl font-bold tracking-tight md:text-2xll">
سفارش تأیید شد
</h1>
<p className="text-lg text-muted-foreground">
تأییدیه به{" "}
<span className="font-semibold text-foreground" dir="rtl">
{order.email}
</span>{" "}
ارسال شد.
</p>
</div>
<Card className="mb-10 border-2 shadow-none">
<CardContent className="grid grid-cols-2 divide-x divide-y p-0 md:grid-cols-4 md:divide-y-0">
<div className="p-5">
<p className="text-xs font-medium tracking-wider text-muted-foreground">
شناسه سفارش
</p>
<p className="mt-1 text-lg font-bold" dir="rtl">
{order.orderNumber}
</p>
</div>
<div className="p-5">
<p className="text-xs font-medium tracking-wider text-muted-foreground">
تاریخ سفارش
</p>
<p className="mt-1 text-lg font-bold">
{formatOrderDate(order.orderDate)}
</p>
</div>
<div className="p-5">
<p className="text-xs font-medium tracking-wider text-muted-foreground">
تحویل
</p>
<p className="mt-1 text-lg font-bold">
{formatDeliveryEstimate(
order.estimatedDeliveryFrom,
order.estimatedDeliveryTo,
)}
</p>
</div>
<div className="p-5">
<p className="text-xs font-medium tracking-wider text-muted-foreground">
پرداخت
</p>
<p className="mt-1 text-lg font-bold" dir="rtl">
{order.paymentMethod.cardBrand} ****
{order.paymentMethod.lastFour}
</p>
</div>
</CardContent>
</Card>
<div className="mb-10">
<h2 className="mb-6 text-xl font-bold">اقلام شما</h2>
<div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
{order.items.map((item) => (
<Card
key={item.id}
className="overflow-hidden border-2 p-0 shadow-none"
>
<AspectRatio ratio={1} className="bg-muted">
<img
src={item.image}
alt={item.name}
className="size-full object-cover"
/>
</AspectRatio>
<CardContent className="p-5">
<h3 className="text-lg font-bold">{item.name}</h3>
{item.details && (
<p className="mt-1 text-sm text-muted-foreground">
{item.details.map((d, i) => (
<span key={d.label}>
{d.label}: {d.value}
{i < item.details!.length - 1 && " · "}
</span>
))}
</p>
)}
<div className="mt-3 flex items-center justify-between">
<span className="text-sm text-muted-foreground">
تعداد: {item.quantity.toLocaleString("fa-IR")}
</span>
<span className="text-xl font-bold tabular-nums">
{currencyFormatter.format(item.price * item.quantity)}
</span>
</div>
</CardContent>
</Card>
))}
</div>
</div>
<div className="grid gap-6 md:grid-cols-2">
<Card className="border-2 shadow-none">
<CardContent className="p-6">
<div className="mb-4 flex items-center gap-3">
<div className="flex size-12 items-center justify-center rounded-xl bg-primary/10">
<MapPin className="size-6 text-primary" aria-hidden="true" />
</div>
<h3 className="text-xl font-bold">آدرس ارسال</h3>
</div>
<div className="space-y-1 text-muted-foreground">
<p className="font-semibold text-foreground">
{order.shippingAddress.name}
</p>
<p>{order.shippingAddress.street}</p>
<p>
{order.shippingAddress.city}،{" "}
{order.shippingAddress.state} کد پستی{" "}
<span dir="rtl" className="tabular-nums">
{order.shippingAddress.zipCode}
</span>
</p>
<p>{order.shippingAddress.country}</p>
</div>
<Separator className="my-4" />
<div className="flex items-center gap-2 text-sm">
<Package
className="size-4 text-muted-foreground"
aria-hidden="true"
/>
<span className="font-medium">{order.shippingMethod}</span>
</div>
</CardContent>
</Card>
<Card className="border-2 shadow-none">
<CardContent className="p-6">
<div className="mb-4 flex items-center gap-3">
<div className="flex size-12 items-center justify-center rounded-xl bg-primary/10">
<Receipt
className="size-6 text-primary"
aria-hidden="true"
/>
</div>
<h3 className="text-xl font-bold">خلاصه سفارش</h3>
</div>
<div className="space-y-3">
<div className="flex justify-between">
<span className="text-muted-foreground">جمع جزء</span>
<span className="font-medium tabular-nums">
{currencyFormatter.format(order.subtotal)}
</span>
</div>
<div className="flex justify-between">
<span className="text-muted-foreground">هزینه ارسال</span>
<span className="font-medium tabular-nums">
{order.shipping === 0
? "رایگان"
: currencyFormatter.format(order.shipping)}
</span>
</div>
<div className="flex justify-between">
<span className="text-muted-foreground">مالیات</span>
<span className="font-medium tabular-nums">
{currencyFormatter.format(order.tax)}
</span>
</div>
{order.discount && order.discount > 0 && (
<div className="flex justify-between text-emerald-600">
<span>تخفیف</span>
<span className="font-medium tabular-nums">
−{currencyFormatter.format(order.discount)}
</span>
</div>
)}
<Separator />
<div className="flex items-center justify-between pt-2">
<span className="text-xl font-bold">مبلغ پرداخت‌شده</span>
<span className="text-xl font-bold tabular-nums">
{currencyFormatter.format(order.total)}
</span>
</div>
</div>
</CardContent>
</Card>
</div>
<div className="mt-10 flex flex-col items-center gap-4 sm:flex-row sm:justify-center">
<Button size="lg" className="w-full px-8 sm:w-auto">
<Truck className="me-2 size-5" aria-hidden="true" />
پیگیری سفارش
</Button>
<Button size="lg" variant="outline" className="w-full px-8 sm:w-auto">
ادامه خرید
</Button>
</div>
</div>
</section>
);
};
export { OrderSummary3 };