Files
ember-market-frontend/components/orders/order-timeline.tsx
g 211cdc71f9
All checks were successful
Build Frontend / build (push) Successful in 1m12s
Enhance dashboard UI and add order timeline
Refactored dashboard pages for improved layout and visual consistency using Card components, motion animations, and updated color schemes. Added an OrderTimeline component to the order details page to visualize order lifecycle. Improved customer management page with better sorting, searching, and a detailed customer dialog. Updated storefront settings page with a modernized layout and clearer sectioning.
2026-01-12 06:53:28 +00:00

87 lines
3.8 KiB
TypeScript

"use client"
import { CheckCircle2, Circle, Clock, Package, Truck, Flag } from "lucide-react"
import { motion } from "framer-motion"
interface OrderTimelineProps {
status: string;
orderDate: Date | string;
paidAt?: Date | string;
completedAt?: Date | string;
}
const steps = [
{ status: "unpaid", label: "Ordered", icon: Clock },
{ status: "paid", label: "Paid", icon: CheckCircle2 },
{ status: "acknowledged", label: "Processing", icon: Package },
{ status: "shipped", label: "Shipped", icon: Truck },
{ status: "completed", label: "Completed", icon: Flag },
]
export default function OrderTimeline({ status, orderDate, paidAt }: OrderTimelineProps) {
const currentStatusIndex = steps.findIndex(step =>
step.status === status ||
(status === "confirming" && step.status === "unpaid") ||
(status === "acknowledged" && step.status === "paid") // Processed is after paid
);
// If status is "confirming", it's basically "unpaid" for the timeline
// If status is "acknowledged", it's "Processing"
const getStepStatus = (index: number) => {
// Basic logic to determine if a step is completed, current, or pending
let effectiveIndex = currentStatusIndex;
if (status === "confirming") effectiveIndex = 0;
if (status === "paid") effectiveIndex = 1;
if (status === "acknowledged") effectiveIndex = 2;
if (status === "shipped") effectiveIndex = 3;
if (status === "completed") effectiveIndex = 4;
if (index < effectiveIndex) return "completed";
if (index === effectiveIndex) return "current";
return "pending";
};
return (
<div className="relative flex justify-between items-center w-full px-4 py-8">
{/* Connector Line */}
<div className="absolute left-10 right-10 top-1/2 h-0.5 bg-muted -translate-y-1/2 z-0">
<motion.div
className="h-full bg-primary"
initial={{ width: "0%" }}
animate={{ width: `${(Math.max(0, steps.findIndex(s => s.status === status)) / (steps.length - 1)) * 100}%` }}
transition={{ duration: 1, ease: "easeInOut" }}
/>
</div>
{steps.map((step, index) => {
const stepStatus = getStepStatus(index);
const Icon = step.icon;
return (
<div key={step.label} className="relative flex flex-col items-center z-10">
<motion.div
initial={{ scale: 0.8, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
transition={{ delay: index * 0.1 }}
className={`flex items-center justify-center w-10 h-10 rounded-full border-2 transition-colors duration-500 ${stepStatus === "completed"
? "bg-primary border-primary text-primary-foreground"
: stepStatus === "current"
? "bg-background border-primary text-primary ring-4 ring-primary/10"
: "bg-background border-muted text-muted-foreground"
}`}
>
<Icon className="h-5 w-5" />
</motion.div>
<div className="absolute top-12 whitespace-nowrap text-xs font-medium tracking-tight">
<p className={stepStatus === "pending" ? "text-muted-foreground" : "text-foreground"}>
{step.label}
</p>
</div>
</div>
);
})}
</div>
)
}