feat(frontend): fulfillment split, API-driven topics, hub-and-spoke nav, stock-count modal, FOUND ceiling, semantic colors
- bug1: quote header fulfillment counter («رسید: X از Y قلم» amber / «تکمیل شد» green / «در راه»); expanded line items visually split into the received part (رسید شده ✓ + date + target warehouse from the receipt allocations) and the in-transit remainder — quantities always sum to the original line (invariant D holds, display-only split) - bug2: 8-topic grids (suppliers/wizard/units) now come from /material-categories via the store (new lib/topics.ts; fixed the mismatched «ابزار و تجهیزات ساخت» label); suppliers topic->category resolution no longer falls back to an arbitrary category; duplicate month/status lists reuse the shared dictionaries; TopicGrid gained a loading EmptyState - bug3: hub-and-spoke — the tab strip renders only on the warehouse dashboard; sub-views hide it and navigate back via «بازگشت به داشبورد»; «افزایش موجود» became the «تغییر موجودی» entry button - bug4: stock count goes through a confirmation modal (current vs counted vs variance with کسری/مازاد badges) before posting STOCK_COUNT; numbers parsed defensively - bug5: found qty is capped client-side (red input + inline warning, submit disabled) and backend returns 422 when exceeding the missing balance; fully-recovered losses drop off the pending list - bug6+7: quantities render as absolute values with semantic color coding (emerald inflow / rose outflow / blue neutral) across dashboard timeline, daily control and the change-inventory form
This commit is contained in:
@@ -1,20 +1,25 @@
|
||||
import { TOPICS } from "../lib/constants";
|
||||
import { EmptyState } from "./EmptyState";
|
||||
import type { Topic } from "../lib/types";
|
||||
import { normalize } from "../lib/normalize";
|
||||
import { faNum } from "../lib/formatters";
|
||||
import { cn } from "../lib/utils";
|
||||
|
||||
export interface TopicGridProps {
|
||||
topics: Topic[]; // از store (API) میآید
|
||||
selectedTopic?: string;
|
||||
onSelect: (topicKey: string) => void;
|
||||
onSelect: (topicName: string) => void;
|
||||
showCounts?: boolean; // تعداد تأمینکنندههای هر تاپیک
|
||||
counts?: Record<string, number>; // topic name → count
|
||||
}
|
||||
|
||||
// گرید ۴ ستونهی ۸ تاپیک
|
||||
export function TopicGrid({ selectedTopic, onSelect, showCounts = false, counts }: TopicGridProps) {
|
||||
// گرید تاپیکها (از /material-categories — نه لیست ثابت)
|
||||
export function TopicGrid({ topics, selectedTopic, onSelect, showCounts = false, counts }: TopicGridProps) {
|
||||
if (!topics.length) {
|
||||
return <EmptyState emoji="🗂️" text="در حال بارگذاری دستهبندیها…" />;
|
||||
}
|
||||
return (
|
||||
<div className="grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-4">
|
||||
{TOPICS.map((t) => {
|
||||
{topics.map((t) => {
|
||||
const selected = selectedTopic != null && normalize(selectedTopic) === normalize(t.name);
|
||||
const count = counts?.[t.name] ?? 0;
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user