doAddClickFoodChoice(location)}>
@@ -684,7 +684,7 @@ function App() {
}
-
+
{Object.keys(Restaurant).map(key => {
const locationKey = key as Restaurant;
return food[locationKey] && renderFoodTable(locationKey, food[locationKey]);
@@ -699,7 +699,11 @@ function App() {
{Object.entries(LunchChoice)
.filter(entry => {
const locationKey = entry[0] as Restaurant;
- return !food[locationKey]?.closed;
+ // Podniky, pro které server nevrátil menu (dočasně uzavřené), nenabízíme
+ if (Object.keys(Restaurant).includes(locationKey) && !food?.[locationKey]) {
+ return false;
+ }
+ return !food?.[locationKey]?.closed;
})
.map(entry => )}
diff --git a/server/changelogs/2026-10-09.json b/server/changelogs/2026-10-09.json
index b0d6eba..c8c8269 100644
--- a/server/changelogs/2026-10-09.json
+++ b/server/changelogs/2026-10-09.json
@@ -1,3 +1,4 @@
[
- "Opraveno načítání jídelního lístku TechTower po změně jejich webu"
+ "Opraveno načítání jídelního lístku TechTower po změně jejich webu",
+ "Šenk Šeříková je dočasně skryt, protože je podnik uzavřen"
]
diff --git a/server/src/routes/devRoutes.ts b/server/src/routes/devRoutes.ts
index 8df7a2f..905011b 100644
--- a/server/src/routes/devRoutes.ts
+++ b/server/src/routes/devRoutes.ts
@@ -1,12 +1,12 @@
import express, { Request } from "express";
-import { getDateForWeekIndex, getData, getRestaurantMenu, getToday, initIfNeeded } from "../service";
+import { getDateForWeekIndex, getData, isRestaurantDisabled, getActiveRestaurants, getRestaurantMenu, getToday, initIfNeeded } from "../service";
import { formatDate, getDayOfWeekIndex } from "../utils";
import getStorage from "../storage";
import { getWebsocket } from "../websocket";
import { getLogin } from "../auth";
import { parseToken } from "../utils";
import webpush from 'web-push';
-import { ClientData, GroupState, MealSlot, OrderGroupMember, TrackingProvider } from "../../../types/gen/types.gen";
+import { ClientData, GroupState, MealSlot, OrderGroupMember, Restaurant, TrackingProvider } from "../../../types/gen/types.gen";
import { getStores } from "../stores";
import { createGroup } from "../groups";
import {
@@ -36,7 +36,7 @@ const LUNCH_CHOICES = [
'OBJEDNAVAM',
'NEOBEDVAM',
'ROZHODUJI',
-];
+].filter(choice => !isRestaurantDisabled(choice as Restaurant));
// Náhodné názvy jídel do poznámek mock objednávek
const MOCK_ORDER_FOODS = [
@@ -72,12 +72,7 @@ const MAX_ORDER_MEMBER_COUNT = 50;
const MAX_ORDER_AMOUNT = 100000;
// Restaurace s menu
-const RESTAURANTS_WITH_MENU = [
- 'SLADOVNICKA',
- 'TECHTOWER',
- 'ZASTAVKAUMICHALA',
- 'SENKSERIKOVA',
-];
+const RESTAURANTS_WITH_MENU = getActiveRestaurants();
/**
* Middleware pro kontrolu DEV režimu
@@ -138,7 +133,7 @@ async function generateMockDataForDay(dayIndex: number, requestedCount?: number)
};
// Pokud má restaurace menu, vybereme náhodné jídlo
- if (RESTAURANTS_WITH_MENU.includes(choice) && menus[choice]?.length) {
+ if (RESTAURANTS_WITH_MENU.includes(choice as Restaurant) && menus[choice]?.length) {
const foods = menus[choice];
// Vybereme náhodné jídlo (ne polévku)
const mainFoods = foods.filter((f: any) => !f.isSoup);
diff --git a/server/src/routes/foodRoutes.ts b/server/src/routes/foodRoutes.ts
index ba0c810..3a48f90 100644
--- a/server/src/routes/foodRoutes.ts
+++ b/server/src/routes/foodRoutes.ts
@@ -1,6 +1,6 @@
import express, { Request, Response } from "express";
import { getLogin, getTrusted } from "../auth";
-import { addChoice, getDateForWeekIndex, getToday, removeChoice, removeChoices, updateDepartureTime, updateNote, fetchRestaurantWeekMenuData, saveRestaurantWeekMenu, updateBuyer } from "../service";
+import { addChoice, getActiveRestaurants, getDateForWeekIndex, getToday, removeChoice, removeChoices, updateDepartureTime, updateNote, fetchRestaurantWeekMenuData, saveRestaurantWeekMenu, updateBuyer } from "../service";
import { getDayOfWeekIndex, parseToken, getFirstWorkDayOfWeek } from "../utils";
import { getWebsocket } from "../websocket";
import { callNotifikace } from "../notifikace";
@@ -232,8 +232,8 @@ export const refreshMetoda = async (req: Request, res: Response) => {
return res.status(400).json({ error: "ještě neumim TODO..." });
}
try {
- // Pro všechny restaurace refreshni menu na aktuální týden
- const restaurants = ["SLADOVNICKA", "TECHTOWER", "ZASTAVKAUMICHALA", "SENKSERIKOVA"] as const;
+ // Pro všechny aktivní restaurace refreshni menu na aktuální týden
+ const restaurants = getActiveRestaurants();
const firstDay = getFirstWorkDayOfWeek(getToday());
const results: Record = {};
const successfulRestaurants: string[] = [];
diff --git a/server/src/service.ts b/server/src/service.ts
index bb75048..b91c78e 100644
--- a/server/src/service.ts
+++ b/server/src/service.ts
@@ -9,6 +9,24 @@ import { ClientData, DepartureTime, LunchChoice, LunchChoices, MealSlot, PizzaDa
const storage = getStorage();
const MENU_PREFIX = 'menu';
+/**
+ * Dočasně uzavřené podniky – nezobrazují se na hlavní stránce, nelze je zvolit
+ * a neprovádí se pro ně načítání menu z jejich webu.
+ */
+export const DISABLED_RESTAURANTS: readonly Restaurant[] = [
+ Restaurant.SENKSERIKOVA, // dočasně uzavřen
+];
+
+/** Vrátí true, pokud je podnik dočasně vyřazen z nabídky. */
+export function isRestaurantDisabled(restaurant: Restaurant | LunchChoice): boolean {
+ return DISABLED_RESTAURANTS.includes(restaurant as Restaurant);
+}
+
+/** Vrátí podniky s menu, které nejsou dočasně vyřazeny. */
+export function getActiveRestaurants(): Restaurant[] {
+ return (Object.values(Restaurant) as Restaurant[]).filter(r => !isRestaurantDisabled(r));
+}
+
function getDataKey(date: Date, slot?: MealSlot): string {
const base = formatDate(date);
return slot === MealSlot.EXTRA ? `${base}_extra` : base;
@@ -55,13 +73,12 @@ export async function getData(date?: Date, slot?: MealSlot): Promise
if (slot === MealSlot.EXTRA) {
clientData.stores = await getStores();
} else {
- clientData.menus = {
- SLADOVNICKA: await getRestaurantMenu('SLADOVNICKA', date),
- // UMOTLIKU: await getRestaurantMenu('UMOTLIKU', date),
- TECHTOWER: await getRestaurantMenu('TECHTOWER', date),
- ZASTAVKAUMICHALA: await getRestaurantMenu('ZASTAVKAUMICHALA', date),
- SENKSERIKOVA: await getRestaurantMenu('SENKSERIKOVA', date),
+ // Dočasně vyřazené podniky se do odpovědi vůbec nezahrnují (klient je pak nezobrazí)
+ const menus: RestaurantDayMenuMap = {};
+ for (const restaurant of getActiveRestaurants()) {
+ menus[restaurant] = await getRestaurantMenu(restaurant, date);
}
+ clientData.menus = menus;
// Očistí volby jídel odkazující na indexy, které v aktuálním menu již neexistují.
// Pokud se v odpovědi něco změnilo, promítne očistu i do uložených dat (self-heal).
if (pruneStaleFoodChoices(clientData.choices, clientData.menus)) {
@@ -236,7 +253,8 @@ export async function getRestaurantMenu(restaurant: Restaurant, date?: Date, for
const usedDate = date ?? getToday();
const dayOfWeekIndex = getDayOfWeekIndex(usedDate);
const now = new Date().getTime();
- if (getIsWeekend(usedDate)) {
+ // O víkendu a u dočasně vyřazených podniků menu vůbec nenačítáme
+ if (getIsWeekend(usedDate) || isRestaurantDisabled(restaurant)) {
return {
lastUpdate: now,
closed: true,
@@ -468,6 +486,9 @@ export async function addChoice(login: string, trusted: boolean, locationKey: Lu
await initIfNeeded(usedDate, slot);
let data = await getClientData(usedDate, slot);
validateTrusted(data, login, trusted);
+ if (isRestaurantDisabled(locationKey)) {
+ throw new Error(`Podnik ${locationKey} je dočasně uzavřen`);
+ }
await validateFoodIndex(locationKey, foodIndex, date);
if (!slot || slot === MealSlot.OBED) {