implement fe with backend

This commit is contained in:
2026-08-02 01:25:17 +05:30
parent 3c5b476635
commit 266a2a2c14
38 changed files with 5229 additions and 32 deletions
@@ -0,0 +1,65 @@
"use client"
import Link from "next/link"
import { Lightbulb, PackageCheck } from "lucide-react"
import { buttonVariants } from "@/components/ui/button"
import { cn } from "@/lib/utils"
import { SalesFreeIssueSuggestion } from "@/types/sales"
export function FreeIssuePromotionSuggestions({ suggestion }: { suggestion: SalesFreeIssueSuggestion | null }) {
if (!suggestion || suggestion.lines.length === 0) {
return (
<div className="rounded-2xl border border-dashed p-6 text-sm text-muted-foreground">
No free-issue promotion suggestions were generated for this slip yet.
</div>
)
}
return (
<div className="rounded-2xl border p-4">
<div className="mb-4 flex items-center justify-between gap-3">
<div>
<div className="inline-flex items-center gap-2 rounded-full bg-amber-500/10 px-3 py-1 text-xs font-semibold uppercase tracking-wide text-amber-700">
<Lightbulb className="size-3.5" />
Backend suggestion
</div>
<h2 className="mt-2 text-lg font-semibold text-foreground">Free-issue promotions</h2>
<p className="text-sm text-muted-foreground">The server suggests reward quantities and alternate products for this slip.</p>
</div>
<Link href="/dashboard/sales/free-issues/new" className={cn(buttonVariants({ variant: "outline", size: "sm" }))}>
Create free issue
</Link>
</div>
<div className="grid gap-4 lg:grid-cols-2">
{suggestion.lines.map((line) => (
<div key={line.salesSlipLineId} className="rounded-xl border bg-muted/20 p-4">
<div className="flex items-start justify-between gap-3">
<div>
<div className="font-medium text-foreground">{line.itemName}</div>
<div className="text-sm text-muted-foreground">{line.itemSku} Qty {line.qty}</div>
</div>
<div className="rounded-full bg-primary/10 px-3 py-1 text-xs font-semibold text-primary">
Buy {line.triggerQty} get {line.suggestedFreeQty} free
</div>
</div>
<div className="mt-3 flex flex-wrap gap-2 text-sm">
{line.rewardOptions.map((option, index) => (
<span key={option.itemId} className={cn("inline-flex items-center gap-1 rounded-full border px-3 py-1", index === 0 && "border-primary bg-primary/5 text-primary") }>
{index === 0 ? <PackageCheck className="size-3.5" /> : null}
{option.name}
</span>
))}
</div>
<div className="mt-3 text-sm text-muted-foreground">
Suggested free qty: <span className="font-medium text-foreground">{line.suggestedFreeQty.toFixed(2)}</span>
</div>
</div>
))}
</div>
</div>
)
}
@@ -0,0 +1,42 @@
"use client"
import Link from "next/link"
import { buttonVariants } from "@/components/ui/button"
import { cn } from "@/lib/utils"
import { SalesSlipSummary } from "@/types/sales"
export function FreeIssueSuggestions({ rows }: { rows: SalesSlipSummary[] }) {
if (rows.length === 0) return null
return (
<div className="rounded-2xl border p-4">
<div className="mb-3 flex items-center justify-between gap-3">
<div>
<h2 className="text-lg font-semibold text-foreground">Free issue suggestions</h2>
<p className="text-sm text-muted-foreground">Recent free-issue slips created from the free-issues page.</p>
</div>
<Link href="/dashboard/sales/free-issues" className={cn(buttonVariants({ variant: "outline", size: "sm" }))}>
Open free issues
</Link>
</div>
<div className="grid gap-3 md:grid-cols-2 xl:grid-cols-3">
{rows.map((row) => (
<Link
key={row.salesSlipId}
href={`/dashboard/sales/free-issues/${row.salesSlipId}`}
className="rounded-xl border bg-muted/20 p-3 transition-colors hover:bg-muted/40"
>
<div className="flex items-center justify-between gap-2">
<div className="font-medium text-foreground">{row.slipNo}</div>
<div className="text-xs uppercase tracking-wide text-muted-foreground">{row.status}</div>
</div>
<div className="mt-1 text-sm text-muted-foreground">{row.customerSnapshotName}</div>
<div className="mt-2 text-sm text-foreground">Free qty total: {row.totals.freeQtyTotal.toFixed(2)}</div>
</Link>
))}
</div>
</div>
)
}