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() {
+
+ {!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),