This commit is contained in:
2026-06-02 10:23:09 +03:00
parent e08d555b23
commit 0c87eaef46
136 changed files with 16069 additions and 94 deletions

131
components/OrderTable.tsx Normal file
View File

@@ -0,0 +1,131 @@
'use client';
import { useState } from "react";
import Link from "next/link";
import type { OrderWithDetails, OrderStatus } from "@/lib/types";
import { StatusBadge } from "./StatusBadge";
export function OrderTable({ orders }: { orders: OrderWithDetails[] }) {
const [search, setSearch] = useState("");
const [statusFilter, setStatusFilter] = useState<OrderStatus | "">("");
const filtered = orders.filter((order) => {
const matchesSearch =
!search ||
order.title.toLowerCase().includes(search.toLowerCase()) ||
order.customers.some((oc) =>
oc.customer.name.toLowerCase().includes(search.toLowerCase())
);
const matchesStatus = !statusFilter || order.status === statusFilter;
return matchesSearch && matchesStatus;
});
const getTotal = (order: OrderWithDetails) =>
order.items.reduce((sum, item) => sum + item.finalPrice, 0);
return (
<div>
{/* Filters */}
<div className="flex flex-col sm:flex-row gap-3 mb-4">
<input
type="text"
placeholder="Search orders..."
value={search}
onChange={(e) => setSearch(e.target.value)}
className="flex-1 border-2 border-border rounded-xl px-4 py-2.5 text-sm bg-white focus:border-accent focus:ring-2 focus:ring-accent/20 outline-none"
/>
<select
value={statusFilter}
onChange={(e) => setStatusFilter(e.target.value as OrderStatus | "")}
className="border-2 border-border rounded-xl px-4 py-2.5 text-sm bg-white focus:border-accent outline-none"
>
<option value="">All Statuses</option>
<option value="pending">Pending</option>
<option value="purchased">Purchased</option>
<option value="delivered">Delivered</option>
<option value="closed">Closed</option>
</select>
</div>
{/* Mobile cards */}
<div className="sm:hidden flex flex-col gap-3">
{filtered.length === 0 ? (
<div className="px-4 py-8 text-center text-muted border-2 border-border rounded-2xl">
No orders found
</div>
) : (
filtered.map((order) => (
<Link
key={order.id}
href={`/orders/${order.id}`}
className="block border-2 border-border rounded-2xl p-4 hover:bg-surface/50 transition-colors"
>
<div className="flex items-start justify-between gap-2 mb-2">
<h3 className="font-bold text-fg text-sm truncate flex-1">{order.title}</h3>
<StatusBadge status={order.status} />
</div>
<div className="flex items-center justify-between text-xs text-muted">
<span>{order.items.length} item{order.items.length !== 1 ? "s" : ""}</span>
<span className="font-mono font-bold text-fg">${getTotal(order).toFixed(2)}</span>
</div>
{order.customers.length > 0 && (
<p className="text-xs text-muted mt-1 truncate">
{order.customers.map((oc) => oc.customer.name).join(", ")}
</p>
)}
</Link>
))
)}
</div>
{/* Desktop table */}
<div className="hidden sm:block border-2 border-border rounded-2xl overflow-hidden">
<table className="w-full">
<thead>
<tr className="bg-surface border-b-2 border-border">
<th className="text-left px-4 py-3 text-sm font-medium text-muted">Title</th>
<th className="text-left px-4 py-3 text-sm font-medium text-muted">Status</th>
<th className="text-left px-4 py-3 text-sm font-medium text-muted hidden md:table-cell">Customers</th>
<th className="text-right px-4 py-3 text-sm font-medium text-muted">Items</th>
<th className="text-right px-4 py-3 text-sm font-medium text-muted">Total</th>
<th className="text-right px-4 py-3 text-sm font-medium text-muted hidden lg:table-cell">Updated</th>
</tr>
</thead>
<tbody>
{filtered.length === 0 ? (
<tr>
<td colSpan={6} className="px-4 py-8 text-center text-muted">
No orders found
</td>
</tr>
) : (
filtered.map((order) => (
<tr
key={order.id}
className="border-b border-border last:border-b-0 hover:bg-surface/50 transition-colors"
>
<td className="px-4 py-3">
<Link href={`/orders/${order.id}`} className="font-medium text-fg hover:text-accent transition-colors">
{order.title}
</Link>
</td>
<td className="px-4 py-3">
<StatusBadge status={order.status} />
</td>
<td className="px-4 py-3 text-sm text-muted hidden md:table-cell">
{order.customers.map((oc) => oc.customer.name).join(", ") || "\u2014"}
</td>
<td className="px-4 py-3 text-right font-mono text-sm">{order.items.length}</td>
<td className="px-4 py-3 text-right font-mono text-sm font-medium">${getTotal(order).toFixed(2)}</td>
<td className="px-4 py-3 text-right text-sm text-muted hidden lg:table-cell font-mono">
{new Date(order.updatedAt).toLocaleDateString()}
</td>
</tr>
))
)}
</tbody>
</table>
</div>
</div>
);
}