diff --git a/web/dashboard/messages/ar.json b/web/dashboard/messages/ar.json
index b9276b3..b80c392 100644
--- a/web/dashboard/messages/ar.json
+++ b/web/dashboard/messages/ar.json
@@ -329,7 +329,23 @@
"configurePrinters": "فتح إعدادات الطابعة",
"posDeviceSection": "جهاز نقطة البيع (بطاقة)",
"posDeviceHint": "عند الدفع بالبطاقة، يُرسل المبلغ عبر HTTP (POST /pay) إلى الجهاز على الشبكة المحلية.",
- "posDeviceIp": "عنوان IP لجهاز نقطة البيع"
+ "posDeviceIp": "عنوان IP لجهاز نقطة البيع",
+ "testSent": "تم إرسال الاختبار إلى الطابعة.",
+ "stations": {
+ "title": "محطات طباعة المطبخ والبار",
+ "subtitle": "امنح كل قسم تحضير طابعته الخاصة ووجّه فئات القائمة إليها.",
+ "help": "أنشئ محطة (مثل المطبخ أو البار) بطابعتها الخاصة، ثم من «القائمة» اختر محطة الطباعة لكل فئة — الطعام ← المطبخ، المشروبات ← البار. أصناف الفئات بدون محطة تُطبع على طابعة مطبخ الفرع. أما فاتورة العميل فتُطبع دائمًا على طابعة الفواتير.",
+ "add": "إضافة محطة",
+ "name": "اسم المحطة",
+ "namePlaceholder": "مثل المطبخ، البار",
+ "printerIp": "IP الطابعة",
+ "noPrinter": "بدون طابعة — تُستخدم طابعة المطبخ",
+ "categoryCount": "{count} فئات",
+ "test": "اختبار",
+ "empty": "لا توجد محطات بعد. أضف «المطبخ» و«البار» لطباعة أصنافهما بشكل منفصل.",
+ "deleteConfirm": "حذف المحطة «{name}»؟ ستعود فئاتها إلى طابعة المطبخ.",
+ "saveError": "تعذّر حفظ المحطة."
+ }
},
"receipt": {
"table": "الطاولة",
@@ -873,6 +889,8 @@
"newItem": "صنف جديد",
"newCategory": "فئة جديدة",
"editCategoryTitle": "تعديل الفئة",
+ "printStation": "محطة الطباعة",
+ "printStationNone": "طابعة المطبخ (افتراضي)",
"close": "إغلاق",
"saving": "جاري الحفظ…",
"model3d": "نموذج ثلاثي الأبعاد",
@@ -1203,6 +1221,7 @@
"shopNotifications": "الإشعارات والصوت",
"printer": "الطابعة",
"printerSettings": "إعدادات الطابعة",
+ "printerStations": "طابعات المطبخ والبار",
"printTest": "صفحة اختبار الطباعة",
"shopDiscover": "اكتشاف و AI",
"team": "الفريق والموظفون",
diff --git a/web/dashboard/messages/en.json b/web/dashboard/messages/en.json
index 3ccd5aa..aac6b77 100644
--- a/web/dashboard/messages/en.json
+++ b/web/dashboard/messages/en.json
@@ -348,7 +348,23 @@
"configurePrinters": "Open printer settings",
"posDeviceSection": "Card POS terminal",
"posDeviceHint": "On card payment, the amount is sent via HTTP (POST /pay) to the device on your LAN.",
- "posDeviceIp": "POS device IP address"
+ "posDeviceIp": "POS device IP address",
+ "testSent": "Test sent to the printer.",
+ "stations": {
+ "title": "Kitchen & bar print stations",
+ "subtitle": "Give each prep area its own printer and route menu categories to it.",
+ "help": "Create a station (e.g. Kitchen, Bar) with its own printer, then in Menu set each category’s print station — food → Kitchen, drinks → Bar. Items in a category with no station fall back to the branch kitchen printer. The customer receipt always prints to the receipt printer.",
+ "add": "Add station",
+ "name": "Station name",
+ "namePlaceholder": "e.g. Kitchen, Bar",
+ "printerIp": "Printer IP",
+ "noPrinter": "No printer — uses the kitchen printer",
+ "categoryCount": "{count} categories",
+ "test": "Test",
+ "empty": "No stations yet. Add Kitchen and Bar to print their items separately.",
+ "deleteConfirm": "Delete station “{name}”? Its categories will fall back to the kitchen printer.",
+ "saveError": "Failed to save the station."
+ }
},
"receipt": {
"table": "Table",
@@ -907,6 +923,8 @@
"newItem": "New item",
"newCategory": "New category",
"editCategoryTitle": "Edit category",
+ "printStation": "Print station",
+ "printStationNone": "Kitchen printer (default)",
"close": "Close",
"saving": "Saving…",
"model3d": "3D model",
@@ -1275,6 +1293,7 @@
"shopNotifications": "Notifications & sound",
"printer": "Printer",
"printerSettings": "Printer settings",
+ "printerStations": "Kitchen & bar printers",
"printTest": "Print test page",
"shopDiscover": "Discover & AI",
"team": "Team & Staff",
diff --git a/web/dashboard/messages/fa.json b/web/dashboard/messages/fa.json
index aab94db..724a771 100644
--- a/web/dashboard/messages/fa.json
+++ b/web/dashboard/messages/fa.json
@@ -348,7 +348,23 @@
"configurePrinters": "رفتن به تنظیمات پرینتر",
"posDeviceSection": "دستگاه پوز (کارتخوان)",
"posDeviceHint": "هنگام پرداخت کارتی، مبلغ به آدرس HTTP دستگاه ارسال میشود (POST /pay).",
- "posDeviceIp": "آدرس IP دستگاه پوز"
+ "posDeviceIp": "آدرس IP دستگاه پوز",
+ "testSent": "تست به پرینتر ارسال شد.",
+ "stations": {
+ "title": "ایستگاههای چاپ آشپزخانه و بار",
+ "subtitle": "برای هر بخش آمادهسازی یک پرینتر جدا بگذارید و دستههای منو را به آن وصل کنید.",
+ "help": "یک ایستگاه (مثلاً آشپزخانه یا بار) با پرینتر مخصوص خودش بسازید، سپس در «منو» برای هر دسته ایستگاه چاپ را انتخاب کنید — غذا ← آشپزخانه، نوشیدنی ← بار. آیتمهای دستههایی که ایستگاه ندارند روی پرینتر آشپزخانهٔ شعبه چاپ میشوند. فاکتور مشتری همیشه روی پرینتر فاکتور چاپ میشود.",
+ "add": "افزودن ایستگاه",
+ "name": "نام ایستگاه",
+ "namePlaceholder": "مثلاً آشپزخانه، بار",
+ "printerIp": "آیپی پرینتر",
+ "noPrinter": "بدون پرینتر — از پرینتر آشپزخانه استفاده میشود",
+ "categoryCount": "{count} دسته",
+ "test": "تست",
+ "empty": "هنوز ایستگاهی ندارید. «آشپزخانه» و «بار» را اضافه کنید تا آیتمهایشان جدا چاپ شود.",
+ "deleteConfirm": "ایستگاه «{name}» حذف شود؟ دستههای آن به پرینتر آشپزخانه برمیگردند.",
+ "saveError": "ذخیرهٔ ایستگاه ناموفق بود."
+ }
},
"receipt": {
"table": "میز",
@@ -907,6 +923,8 @@
"newItem": "آیتم جدید",
"newCategory": "دسته جدید",
"editCategoryTitle": "ویرایش دسته",
+ "printStation": "ایستگاه چاپ",
+ "printStationNone": "پرینتر آشپزخانه (پیشفرض)",
"close": "بستن",
"saving": "در حال ذخیره…",
"model3d": "مدل سهبعدی",
@@ -1276,6 +1294,7 @@
"shopNotifications": "اعلانها و صدا",
"printer": "پرینتر",
"printerSettings": "تنظیمات پرینتر",
+ "printerStations": "پرینتر آشپزخانه و بار",
"printTest": "صفحه تست چاپ",
"shopDiscover": "کشف و AI",
"team": "تیم و کارمندان",
diff --git a/web/dashboard/src/components/menu/menu-admin-screen.tsx b/web/dashboard/src/components/menu/menu-admin-screen.tsx
index 38f54ef..a5cd4fa 100644
--- a/web/dashboard/src/components/menu/menu-admin-screen.tsx
+++ b/web/dashboard/src/components/menu/menu-admin-screen.tsx
@@ -13,6 +13,7 @@ import { CategoryMediaFields } from "@/components/menu/category-media-fields";
import type { CategoryIconSelection } from "@/components/menu/category-preset-picker";
import { DEFAULT_CATEGORY_ICON_STYLE } from "@/lib/category-icon-presets";
import { apiDelete, apiGet, apiPatch, apiPost } from "@/lib/api/client";
+import { fetchKitchenStations } from "@/lib/api/kitchen-stations";
import {
AlertDialog,
AlertDialogAction,
@@ -57,6 +58,7 @@ interface MenuCategory {
iconStyle?: string;
imageUrl?: string;
isActive: boolean;
+ kitchenStationId?: string | null;
}
interface MenuItem {
@@ -89,6 +91,7 @@ interface CatForm {
icon: string;
iconPreset: CategoryIconSelection;
imageUrl: string;
+ kitchenStationId: string;
}
// ─── Helpers ──────────────────────────────────────────────────────────────────
@@ -118,6 +121,7 @@ const defaultCatForm: CatForm = {
icon: "",
iconPreset: { iconPresetId: null, iconStyle: DEFAULT_CATEGORY_ICON_STYLE },
imageUrl: "",
+ kitchenStationId: "",
};
// ─── Toggle Switch ────────────────────────────────────────────────────────────
@@ -242,6 +246,12 @@ export function MenuAdminScreen() {
enabled: !!cafeId,
});
+ const { data: stations = [] } = useQuery({
+ queryKey: ["kitchen-stations", cafeId],
+ queryFn: () => fetchKitchenStations(cafeId!),
+ enabled: !!cafeId,
+ });
+
const categoryNameById = useMemo(
() => buildCategoryNameMap(categories),
[categories]
@@ -353,6 +363,7 @@ export function MenuAdminScreen() {
iconPresetId: catForm.iconPreset.iconPresetId,
iconStyle: catForm.iconPreset.iconPresetId ? catForm.iconPreset.iconStyle : null,
imageUrl: catForm.imageUrl.trim() || null,
+ kitchenStationId: catForm.kitchenStationId || null,
}),
onSuccess: () => {
setCatModalOpen(false);
@@ -369,6 +380,7 @@ export function MenuAdminScreen() {
iconPresetId: catForm.iconPreset.iconPresetId ?? "",
iconStyle: catForm.iconPreset.iconPresetId ? catForm.iconPreset.iconStyle : "",
imageUrl: mediaField(catForm.imageUrl),
+ kitchenStationId: catForm.kitchenStationId || null,
}),
onSuccess: () => {
setCatModalOpen(false);
@@ -421,6 +433,7 @@ export function MenuAdminScreen() {
DEFAULT_CATEGORY_ICON_STYLE,
},
imageUrl: cat.imageUrl ?? "",
+ kitchenStationId: cat.kitchenStationId ?? "",
});
setCatModalOpen(true);
};
@@ -1012,6 +1025,26 @@ export function MenuAdminScreen() {
}
/>
+ {stations.length > 0 ? (
+
{t("stations.subtitle")}
++ {t("stations.help")} +
+ + {testMsg ? ( ++ {testMsg} +
+ ) : null} + + {editing === "new" ? ( +{tCommon("loading")}
+ ) : stations.length === 0 && editing === null ? ( +{t("stations.empty")}
+ ) : ( +{s.name}
++ {s.printerIp ? `${s.printerIp}:${s.printerPort}` : t("stations.noPrinter")} +
+