feat(ui): ev stoğu sayfaları ve dashboard azalan stoklar kartı
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
import { Clock } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { tr } from "@/i18n/tr";
|
||||
import { formatStock } from "@/shared/stock";
|
||||
import { getStock } from "../service";
|
||||
|
||||
const t = tr.stock;
|
||||
const LIMIT = 5;
|
||||
|
||||
/** Dashboard: eşiğin altındaki ürünler ve SKT'si yaklaşan partiler (yoksa görünmez). */
|
||||
export async function LowStockCard({
|
||||
userId,
|
||||
householdId,
|
||||
}: {
|
||||
userId: string;
|
||||
householdId: string;
|
||||
}) {
|
||||
const data = await getStock(userId, householdId);
|
||||
if (!data || (!data.suggestions.length && !data.expiring.length)) return null;
|
||||
const low = data.suggestions.slice(0, LIMIT);
|
||||
const expiring = data.expiring.slice(0, Math.max(0, LIMIT - low.length) || 2);
|
||||
return (
|
||||
<Card size="sm">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-base">{t.dashboard.title}</CardTitle>
|
||||
<CardDescription>
|
||||
{t.dashboard.description(data.suggestions.length, data.expiring.length)}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-3">
|
||||
<ul className="divide-y text-sm">
|
||||
{low.map((i) => (
|
||||
<li key={i.id} className="flex items-center justify-between gap-3 py-1.5">
|
||||
<Link href={`/stok/${i.id}`} className="min-w-0 truncate hover:underline">
|
||||
{i.name}
|
||||
</Link>
|
||||
<span className="shrink-0 text-xs tabular-nums">
|
||||
<span className="text-expense">{formatStock(Math.max(0, i.current), i.unit)}</span>
|
||||
<span className="text-muted-foreground">
|
||||
{" · "}
|
||||
{t.suggestions.suggested(formatStock(i.suggestedQuantity, i.unit))}
|
||||
</span>
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
{expiring.map(({ item, lot }) => (
|
||||
<li
|
||||
key={`${item.id}-${lot.index}`}
|
||||
className="flex items-center justify-between gap-3 py-1.5"
|
||||
>
|
||||
<Link href={`/stok/${item.id}`} className="min-w-0 truncate hover:underline">
|
||||
{item.name}
|
||||
</Link>
|
||||
<span
|
||||
className={
|
||||
lot.status === "expired"
|
||||
? "flex shrink-0 items-center gap-1 text-xs text-expense"
|
||||
: "flex shrink-0 items-center gap-1 text-xs text-amber-700 dark:text-amber-400"
|
||||
}
|
||||
>
|
||||
<Clock className="size-3" />
|
||||
{t.expiring.on(
|
||||
new Intl.DateTimeFormat("tr-TR", { day: "numeric", month: "short" }).format(
|
||||
new Date(`${lot.expiryDate}T12:00:00+03:00`),
|
||||
),
|
||||
)}
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
{data.suggestions.length > low.length ? (
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{t.dashboard.more(data.suggestions.length - low.length)}
|
||||
</p>
|
||||
) : null}
|
||||
<Button size="sm" variant="outline" className="w-fit" asChild>
|
||||
<Link href="/stok">{t.dashboard.open}</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user