diff --git a/server/src/restaurants.ts b/server/src/restaurants.ts index 869f62a..f348cff 100644 --- a/server/src/restaurants.ts +++ b/server/src/restaurants.ts @@ -67,7 +67,7 @@ const parseAllergens = (name: string): { cleanName: string, allergens: number[] if (match) { const allergenString = match[1]; - const allergens = allergenString.split(',').map(num => parseInt(num.trim(), 10)).filter(num => !isNaN(num)); + const allergens = allergenString.split(',').map(num => Number.parseInt(num.trim(), 10)).filter(num => !Number.isNaN(num)); const cleanName = name.replace(regex, '').trim(); return { cleanName, allergens }; } @@ -100,18 +100,42 @@ export const getMenuSladovnicka = async (firstDayOfWeek: Date, mock: boolean = f const html = await getHtml(SLADOVNICKA_URL); const $ = load(html); - const menuContentElements = $('#daily-menu-content-list').children('[id^="daily-menu-content-"]'); - // Prozatím předpokládáme, že budou mít vždy elementy pro všech 5 dní v týdnu, i pokud bude zavřeno - if (menuContentElements.length < 5) { - throw Error("Neočekávaný počet dní v menu Sladovnické: " + menuContentElements.length + ", očekáváno 5 (možná je některý den zavřeno?)"); - } + // Nejdříve zjistíme, které dny jsou k dispozici z tab elementů + const tabElements = $('#daily-menu-tab-list').children('button[id^="daily-menu-tab-"]'); + const availableDays: { [dayIndex: number]: number } = {}; // mapování dayIndex -> contentIndex + + tabElements.each((contentIndex, tabElement) => { + const dayText = $(tabElement).find('.daily-menu-tab__day').text().toLowerCase(); + const dayIndex = DAYS_IN_WEEK.indexOf(dayText); + if (dayIndex !== -1 && dayIndex < 5) { // pouze pracovní dny (0-4) + availableDays[dayIndex] = contentIndex; + } + }); + const menuContentElements = $('#daily-menu-content-list').children('[id^="daily-menu-content-"]'); + const result: Food[][] = []; + + // Inicializujeme všechny pracovní dny (0-4) prázdnými poli for (let dayIndex = 0; dayIndex < 5; dayIndex++) { - const dayChildren = $(menuContentElements[dayIndex]).children(); - // Prozatím předpokládáme, že budou mít vždy polévku a hlavní jídla + result[dayIndex] = []; + } + + // Projdeme pouze dostupné dny + for (const [dayIndex, contentIndex] of Object.entries(availableDays)) { + const dayIndexNum = Number.parseInt(dayIndex); + const contentIndexNum = contentIndex; + + if (contentIndexNum >= menuContentElements.length) { + continue; // Přeskočíme, pokud content element neexistuje + } + + const dayChildren = $(menuContentElements[contentIndexNum]).children(); + + // Ověříme, že má element očekávanou strukturu if (dayChildren.length < 2) { - throw Error("Neočekávaný počet children v menu Sladovnické pro den " + dayIndex + ": " + dayChildren.length + ", očekávány alespoň 2 (polévka a hlavní jídlo)"); + console.warn(`Neočekávaný počet children v menu Sladovnické pro den ${dayIndexNum}: ${dayChildren.length}, očekávány alespoň 2 (polévka a hlavní jídlo)`); + continue; } // Parsování polévky @@ -119,7 +143,8 @@ export const getMenuSladovnicka = async (firstDayOfWeek: Date, mock: boolean = f const soupTable = $(soupElement).find('table tbody tr'); const soupCells = soupTable.children('td'); if (soupCells.length !== 3) { - throw Error("Neočekávaný počet buněk v tabulce polévky: " + soupCells.length + ", ale očekávány byly 3"); + console.warn(`Neočekávaný počet buněk v tabulce polévky pro den ${dayIndexNum}: ${soupCells.length}, ale očekávány byly 3`); + continue; } const soupAmount = sanitizeText($(soupCells.get(0)).text()); @@ -163,8 +188,9 @@ export const getMenuSladovnicka = async (firstDayOfWeek: Date, mock: boolean = f } }); - result[dayIndex] = currentDayFood; + result[dayIndexNum] = currentDayFood; } + return result; } @@ -186,7 +212,7 @@ export const getMenuUMotliku = async (firstDayOfWeek: Date, mock: boolean = fals // Najdeme první tabulku, nad kterou je v H3 datum začínající co nejdřívějším dnem v aktuálním týdnu const tables = $('table.table.table-hover.Xtable-striped'); let usedTable; - let usedDate = new Date(firstDayOfWeek.getTime()); + let usedDate = new Date(firstDayOfWeek); for (let i = 0; i < 4; i++) { const dayOfWeekString = `${usedDate.getDate()}.${usedDate.getMonth() + 1}.`; for (const tableNode of tables) { @@ -206,7 +232,7 @@ export const getMenuUMotliku = async (firstDayOfWeek: Date, mock: boolean = fals if (usedTable == null) { const firstDayOfWeekString = `${firstDayOfWeek.getDate()}.${firstDayOfWeek.getMonth() + 1}.`; - throw Error(`Nepodařilo se najít tabulku pro týden začínající ${firstDayOfWeekString}`); + throw new Error(`Nepodařilo se najít tabulku pro týden začínající ${firstDayOfWeekString}`); } const body = usedTable.children().first(); @@ -239,11 +265,11 @@ export const getMenuUMotliku = async (firstDayOfWeek: Date, mock: boolean = fals } else if (foodType === 'Hlavní jídlo') { isSoup = false; } else { - throw Error("Neočekáváný typ jídla: " + foodType); + throw new Error("Neočekáváný typ jídla: " + foodType); } } else { if (children.length !== 3) { - throw Error("Neočekávaný počet child elementů pro jídlo: " + children.length + ", očekávány 3"); + throw new Error("Neočekávaný počet child elementů pro jídlo: " + children.length + ", očekávány 3"); } const amount = sanitizeText($(children.get(0)).text()); const name = sanitizeText($(children.get(1)).text()); @@ -296,7 +322,7 @@ export const getMenuTechTower = async (firstDayOfWeek: Date, mock: boolean = fal }) } if (!font) { - throw Error('Chyba: nenalezen pro obědy v HTML Techtower.'); + throw new Error('Chyba: nenalezen pro obědy v HTML Techtower.'); } const result: Food[][] = []; @@ -442,7 +468,7 @@ export const getMenuSenkSerikova = async (firstDayOfWeek: Date, mock: boolean = currentDayFood.push({ amount: '-', name: nameWithoutNumber, - price: $(element).children('div.cena').text().replace(/ /g, '\xA0'), + price: $(element).children('div.cena').text().replaceAll(' ', '\xA0'), isSoup: $(element).hasClass('polevka'), }); });