diff --git a/web/dashboard/messages/ar.json b/web/dashboard/messages/ar.json index 23205c1..b206a9a 100644 --- a/web/dashboard/messages/ar.json +++ b/web/dashboard/messages/ar.json @@ -270,6 +270,7 @@ "void": "إلغاء", "voidItem": "إلغاء الصنف", "voided": "ملغى", + "itemNotePlaceholder": "ملاحظة للمطبخ/البار (اختياري)", "confirmVoid": "هل أنت متأكد أنك تريد إلغاء هذا الصنف؟", "voidError": "تعذر إلغاء الصنف", "transferTable": "نقل الطاولة", @@ -883,6 +884,7 @@ "orderHint": "سيقوم الموظفون بتحضير طلبك قريباً", "guestName": "اسمك (اختياري)", "guestPhone": "الجوال (اختياري)", + "itemNote": "ملاحظة (مثلاً بدون طماطم، سكر أقل)", "addMoreItems": "إضافة المزيد", "orderError": "تعذر تسجيل الطلب. حاول مرة أخرى.", "rateLimited": "طلبات كثيرة — انتظر بضع دقائق", diff --git a/web/dashboard/messages/en.json b/web/dashboard/messages/en.json index 751f725..f4e79bd 100644 --- a/web/dashboard/messages/en.json +++ b/web/dashboard/messages/en.json @@ -289,6 +289,7 @@ "void": "Void", "voidItem": "Void item", "voided": "Voided", + "itemNotePlaceholder": "Note for kitchen/bar (optional)", "confirmVoid": "Are you sure you want to void this item?", "voidError": "Could not void item", "transferTable": "Transfer table", @@ -952,6 +953,7 @@ "orderHint": "Staff will prepare your order shortly", "guestName": "Your name (optional)", "guestPhone": "Mobile (optional)", + "itemNote": "Note (e.g. no tomato, less sugar)", "addMoreItems": "Add more items", "orderError": "Could not place order. Try again.", "rateLimited": "Too many requests — please wait a few minutes", diff --git a/web/dashboard/messages/fa.json b/web/dashboard/messages/fa.json index ce456cd..2d3d7a3 100644 --- a/web/dashboard/messages/fa.json +++ b/web/dashboard/messages/fa.json @@ -289,6 +289,7 @@ "void": "ابطال", "voidItem": "ابطال آیتم", "voided": "ابطال شده", + "itemNotePlaceholder": "یادداشت برای آشپزخانه/بار (اختیاری)", "confirmVoid": "آیا مطمئن هستید که می‌خواهید این آیتم را ابطال کنید؟", "voidError": "خطا در ابطال آیتم", "transferTable": "انتقال میز", @@ -952,6 +953,7 @@ "orderHint": "کارکنان به زودی سفارش شما را آماده می‌کنند", "guestName": "نام شما (اختیاری)", "guestPhone": "شماره موبایل (اختیاری)", + "itemNote": "یادداشت (مثلاً بدون گوجه، کم‌شکر)", "addMoreItems": "افزودن آیتم دیگر", "orderError": "خطا در ثبت سفارش. دوباره امتحان کنید", "orderSaveError": "سفارش ثبت شد اما ذخیره محلی ناموفق بود. صفحه را رفرش نکنید.", diff --git a/web/dashboard/src/components/kds/kds-screen.tsx b/web/dashboard/src/components/kds/kds-screen.tsx index 437b514..aae1f4b 100644 --- a/web/dashboard/src/components/kds/kds-screen.tsx +++ b/web/dashboard/src/components/kds/kds-screen.tsx @@ -178,6 +178,11 @@ export function KdsScreen() {
  • {formatNumber(item.quantity, numberLocale)}×{" "} {item.menuItemName} + {item.notes ? ( + + ✍️ {item.notes} + + ) : null}
  • ))} diff --git a/web/dashboard/src/components/pos/pos-screen.tsx b/web/dashboard/src/components/pos/pos-screen.tsx index eaac0ed..25ebe0e 100644 --- a/web/dashboard/src/components/pos/pos-screen.tsx +++ b/web/dashboard/src/components/pos/pos-screen.tsx @@ -255,6 +255,7 @@ export function PosScreen() { addItem, removeItem, updateQty, + setNotes, couponCode, appliedCoupon, setCouponCode, @@ -1210,10 +1211,11 @@ export function PosScreen() {
    +
    ) : null}
    +
    + {!line.isVoided && ( + setNotes(line.menuItem.id, e.target.value)} + onClick={(e) => e.stopPropagation()} + onKeyDown={(e) => e.stopPropagation()} + placeholder={t("itemNotePlaceholder")} + className="w-full rounded-md border border-border/70 bg-background px-2 py-1 text-[11px] placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-primary/40" + /> + )}
    )) )} diff --git a/web/dashboard/src/components/qr/qr-guest-menu.tsx b/web/dashboard/src/components/qr/qr-guest-menu.tsx index ee3a5b6..559d8ab 100644 --- a/web/dashboard/src/components/qr/qr-guest-menu.tsx +++ b/web/dashboard/src/components/qr/qr-guest-menu.tsx @@ -407,29 +407,44 @@ export function QrGuestMenu({ code }: QrGuestMenuProps) { {cart.map((c) => (
    -
    - -

    - {formatCurrency(effectiveLinePrice(c.item), "fa-IR")} -

    -
    -
    - removeFromCart(c.item.id)} - variant="outline" - color={primary} - /> - {c.qty} - addToCart(c.item)} - variant="filled" - color={primary} - /> +
    +
    + +

    + {formatCurrency(effectiveLinePrice(c.item), "fa-IR")} +

    +
    +
    + removeFromCart(c.item.id)} + variant="outline" + color={primary} + /> + {c.qty} + addToCart(c.item)} + variant="filled" + color={primary} + /> +
    + + setCart((prev) => + prev.map((l) => + l.item.id === c.item.id ? { ...l, note: e.target.value } : l + ) + ) + } + placeholder={t("itemNote")} + className="w-full rounded-md border qr-border bg-transparent px-2 py-1.5 text-xs placeholder:opacity-60 focus:outline-none" + />
    ))}
    diff --git a/web/dashboard/src/lib/stores/cart.store.ts b/web/dashboard/src/lib/stores/cart.store.ts index ac871db..4bf168a 100644 --- a/web/dashboard/src/lib/stores/cart.store.ts +++ b/web/dashboard/src/lib/stores/cart.store.ts @@ -34,6 +34,7 @@ interface CartState { addItem: (item: MenuItem) => void; removeItem: (menuItemId: string) => void; updateQty: (menuItemId: string, quantity: number) => void; + setNotes: (menuItemId: string, notes: string) => void; setCouponCode: (code: string) => void; setAppliedCoupon: (coupon: AppliedCoupon | null) => void; clearCoupon: () => void; @@ -135,6 +136,13 @@ export const useCartStore = create((set, get) => ({ }); }, + setNotes: (menuItemId, notes) => + set({ + items: get().items.map((i) => + i.menuItem.id === menuItemId ? { ...i, notes: notes.trim() || undefined } : i + ), + }), + setCouponCode: (code) => set({ couponCode: code }), setAppliedCoupon: (coupon) => set({ appliedCoupon: coupon }), clearCoupon: () => set(clearCouponState),