feat(menu): per-item print station (cold bar / kitchen / barista)
CI/CD / CI · API (dotnet build + test) (push) Successful in 41s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 29s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m6s
CI/CD / CI · Admin Web (tsc) (push) Successful in 38s
CI/CD / CI · Website (tsc) (push) Successful in 45s
CI/CD / CI · Koja (tsc) (push) Successful in 49s
CI/CD / Deploy · all services (push) Successful in 3m28s
CI/CD / CI · API (dotnet build + test) (push) Successful in 41s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 29s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m6s
CI/CD / CI · Admin Web (tsc) (push) Successful in 38s
CI/CD / CI · Website (tsc) (push) Successful in 45s
CI/CD / CI · Koja (tsc) (push) Successful in 49s
CI/CD / Deploy · all services (push) Successful in 3m28s
Each menu item can now pick its own print station, overriding the category's — so a category can fan out to different printers (e.g. a drink → cold bar, a food → kitchen). Adds MenuItem.KitchenStationId (+ migration, FK SetNull), wires create/update/DTO, and updates kitchen-ticket routing to group by the item's station ?? the category's station ?? the branch kitchen printer. Deleting a station now also clears item assignments. Menu item editor gains a "Print station" dropdown (default = "same as category"). fa/en/ar added. Backend built clean via the Nexus mirror; migration applies on deploy (MigrateAsync). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -917,7 +917,8 @@
|
||||
"deleteItemSuccess": "تم حذف الصنف",
|
||||
"deleteCategoryConfirmTitle": "حذف الفئة",
|
||||
"deleteCategoryConfirmDesc": "هل أنت متأكد من حذف الفئة «{name}»؟",
|
||||
"deleteCategorySuccess": "تم حذف الفئة"
|
||||
"deleteCategorySuccess": "تم حذف الفئة",
|
||||
"printStationInherit": "نفس الفئة"
|
||||
},
|
||||
"branchMenu": {
|
||||
"title": "قائمة الفرع",
|
||||
|
||||
@@ -951,7 +951,8 @@
|
||||
"deleteItemSuccess": "Item deleted",
|
||||
"deleteCategoryConfirmTitle": "Delete category",
|
||||
"deleteCategoryConfirmDesc": "Are you sure you want to delete the “{name}” category?",
|
||||
"deleteCategorySuccess": "Category deleted"
|
||||
"deleteCategorySuccess": "Category deleted",
|
||||
"printStationInherit": "Same as category"
|
||||
},
|
||||
"branchMenu": {
|
||||
"title": "Branch Menu",
|
||||
|
||||
@@ -951,7 +951,8 @@
|
||||
"deleteItemSuccess": "آیتم حذف شد",
|
||||
"deleteCategoryConfirmTitle": "حذف دستهبندی",
|
||||
"deleteCategoryConfirmDesc": "آیا از حذف دسته «{name}» مطمئن هستید؟",
|
||||
"deleteCategorySuccess": "دسته حذف شد"
|
||||
"deleteCategorySuccess": "دسته حذف شد",
|
||||
"printStationInherit": "مثل دستهٔ منو"
|
||||
},
|
||||
"branchMenu": {
|
||||
"title": "منوی شعبه",
|
||||
|
||||
@@ -73,6 +73,7 @@ interface MenuItem {
|
||||
videoUrl?: string;
|
||||
model3dUrl?: string;
|
||||
isAvailable: boolean;
|
||||
kitchenStationId?: string | null;
|
||||
}
|
||||
|
||||
interface ItemForm {
|
||||
@@ -84,6 +85,7 @@ interface ItemForm {
|
||||
imageUrl: string;
|
||||
videoUrl: string;
|
||||
model3dUrl: string;
|
||||
kitchenStationId: string;
|
||||
}
|
||||
|
||||
interface CatForm {
|
||||
@@ -114,6 +116,7 @@ const defaultItemForm: ItemForm = {
|
||||
imageUrl: "",
|
||||
videoUrl: "",
|
||||
model3dUrl: "",
|
||||
kitchenStationId: "",
|
||||
};
|
||||
|
||||
const defaultCatForm: CatForm = {
|
||||
@@ -296,6 +299,7 @@ export function MenuAdminScreen() {
|
||||
imageUrl: itemForm.imageUrl || null,
|
||||
videoUrl: itemForm.videoUrl || null,
|
||||
model3dUrl: itemForm.model3dUrl || null,
|
||||
kitchenStationId: itemForm.kitchenStationId || null,
|
||||
}),
|
||||
onSuccess: () => {
|
||||
setItemModalOpen(false);
|
||||
@@ -314,6 +318,7 @@ export function MenuAdminScreen() {
|
||||
imageUrl: mediaField(itemForm.imageUrl),
|
||||
videoUrl: mediaField(itemForm.videoUrl),
|
||||
model3dUrl: mediaField(itemForm.model3dUrl),
|
||||
kitchenStationId: itemForm.kitchenStationId || null,
|
||||
}),
|
||||
onSuccess: () => {
|
||||
setItemModalOpen(false);
|
||||
@@ -411,6 +416,7 @@ export function MenuAdminScreen() {
|
||||
imageUrl: item.imageUrl ?? "",
|
||||
videoUrl: item.videoUrl ?? "",
|
||||
model3dUrl: item.model3dUrl ?? "",
|
||||
kitchenStationId: item.kitchenStationId ?? "",
|
||||
});
|
||||
setItemModalOpen(true);
|
||||
};
|
||||
@@ -956,6 +962,26 @@ export function MenuAdminScreen() {
|
||||
) : null}
|
||||
</LabeledField>
|
||||
|
||||
{stations.length > 0 ? (
|
||||
<LabeledField label={t("printStation")} htmlFor="modal-item-station">
|
||||
<select
|
||||
id="modal-item-station"
|
||||
className="h-10 w-full rounded-md border border-input bg-background px-3 text-sm"
|
||||
value={itemForm.kitchenStationId}
|
||||
onChange={(e) =>
|
||||
setItemForm((f) => ({ ...f, kitchenStationId: e.target.value }))
|
||||
}
|
||||
>
|
||||
<option value="">{t("printStationInherit")}</option>
|
||||
{stations.map((s) => (
|
||||
<option key={s.id} value={s.id}>
|
||||
{s.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</LabeledField>
|
||||
) : null}
|
||||
|
||||
{/* Actions */}
|
||||
<div className="flex items-center justify-between gap-2 border-t border-border pt-4">
|
||||
{editingItem ? (
|
||||
|
||||
Reference in New Issue
Block a user