From f02f78a97c67bedca5ddde8b71d8d16df3410ce2 Mon Sep 17 00:00:00 2001 From: "soroush.asadi" Date: Thu, 4 Jun 2026 06:17:37 +0330 Subject: [PATCH] =?UTF-8?q?fix(pos):=20POS=20v2=20menu=20empty=20=E2=80=94?= =?UTF-8?q?=20resolve=20a=20valid=20branch=20like=20classic=20POS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The menu/tables are branch-scoped. v2 used the raw stored branchId, which is null or stale for users who never opened the classic POS (it has no branch picker), so getBranchMenu returned an empty menu. Now v2 fetches /branches, auto-selects the first valid branch (self-healing the stored id), and loads the branch menu + tables + order submission against that resolved branch — matching the classic POS exactly. Also adds a visible "menu failed to load / retry" state instead of a silent empty grid. Co-Authored-By: Claude Opus 4.8 --- .../src/components/pos2/pos2-screen.tsx | 36 ++++++++++++++++--- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/web/dashboard/src/components/pos2/pos2-screen.tsx b/web/dashboard/src/components/pos2/pos2-screen.tsx index 93380e7..762d394 100644 --- a/web/dashboard/src/components/pos2/pos2-screen.tsx +++ b/web/dashboard/src/components/pos2/pos2-screen.tsx @@ -8,7 +8,7 @@ // ───────────────────────────────────────────────────────────────────────────── import { useEffect, useMemo, useState } from "react"; -import { useMutation, useQueryClient } from "@tanstack/react-query"; +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { Search, Plus, Minus, Trash2, Send, CreditCard, Pause, SplitSquareHorizontal, X, WifiOff, ShoppingCart, Users, Coffee, ArrowRight, LayoutGrid, Armchair, @@ -64,10 +64,29 @@ export function Pos2Screen() { const queryClient = useQueryClient(); const cafeId = useAuthStore((s) => s.user?.cafeId); const branchId = useBranchStore((s) => s.branchId); + const setBranchId = useBranchStore((s) => s.setBranchId); + + // Resolve a VALID branch (auto-pick the first) exactly like the classic POS — + // the menu/tables are branch-scoped, so a null or stale stored branchId would + // otherwise load an empty menu. v2 has no branch picker, so it must self-heal. + const { data: branches = [] } = useQuery({ + queryKey: ["branches", cafeId], + queryFn: () => apiGet<{ id: string; name: string }[]>(`/api/cafes/${cafeId}/branches`), + enabled: !!cafeId, + }); + useEffect(() => { + if (branches.length === 0) return; + const valid = branchId && branches.some((b) => b.id === branchId); + if (!valid) setBranchId(branches[0]!.id); + }, [branches, branchId, setBranchId]); + const orderBranchId = useMemo(() => { + if (branchId && branches.some((b) => b.id === branchId)) return branchId; + return branches[0]?.id ?? null; + }, [branchId, branches]); const { data: categories } = usePos2Categories(cafeId); - const { data: menu, isLoading: menuLoading } = usePos2Menu(cafeId, branchId); - const { data: tables, isLoading: tablesLoading, refetch: refetchTables } = usePos2Tables(cafeId, branchId); + const { data: menu, isLoading: menuLoading, isError: menuError, refetch: refetchMenu } = usePos2Menu(cafeId, orderBranchId); + const { data: tables, isLoading: tablesLoading, refetch: refetchTables } = usePos2Tables(cafeId, orderBranchId); const menuById = useMenuById(menu); // cart store slices @@ -175,7 +194,7 @@ export function Pos2Screen() { if (cart.getPendingLines().length === 0) return null; const order = await submitOrderToApi({ cafeId: cafeId as string, - orderBranchId: branchId ?? undefined, + orderBranchId: orderBranchId ?? undefined, cart, reservationId: null, cartItems: cart.items, @@ -249,7 +268,7 @@ export function Pos2Screen() { setBusy(true); try { const cardTotal = payments.filter((p) => p.method === "Card").reduce((s, p) => s + p.amount, 0); - const payBranchId = payTarget.branchId ?? branchId ?? undefined; + const payBranchId = payTarget.branchId ?? orderBranchId ?? undefined; if (cardTotal > 0 && payBranchId) { // push the card amount to the configured terminal (no-op/skip if none) await requestPosPayment(cafeId as string, payBranchId, payTarget.id, cardTotal); @@ -448,6 +467,13 @@ export function Pos2Screen() {
+ ) : menuError ? ( +
+

بارگذاری منو ناموفق بود.

+ +
) : (
{visibleItems.map((it) => (