diff --git a/client/src/App.tsx b/client/src/App.tsx index c5cd8db..7e5baab 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -351,7 +351,7 @@ function App() { } else { content =

Chyba načtení dat

} - return + return

{name}

{menu?.lastUpdate && Poslední aktualizace: {getHumanDateTime(new Date(menu.lastUpdate))}} {content} @@ -402,8 +402,8 @@ function App() { Poslední změny: {dayIndex != null && @@ -418,6 +418,7 @@ function App() { {/* {food[Restaurants.UMOTLIKU] && renderFoodTable('U Motlíků', food[Restaurants.UMOTLIKU])} */} {food[Restaurants.TECHTOWER] && renderFoodTable('TechTower', food[Restaurants.TECHTOWER])} {food[Restaurants.ZASTAVKAUMICHALA] && renderFoodTable('Zastávka u Michala', food[Restaurants.ZASTAVKAUMICHALA])} + {food[Restaurants.SENKSERIKOVA] && renderFoodTable('Pivovarský šenk Šeříková', food[Restaurants.SENKSERIKOVA])}
diff --git a/server/src/mock.ts b/server/src/mock.ts index 961f724..e94fbea 100644 --- a/server/src/mock.ts +++ b/server/src/mock.ts @@ -517,7 +517,91 @@ const MOCK_DATA = { isSoup: false, } ], - ] + ], + 'senkSerikova': [ + [ + { + amount: "-", + name: "Drůbeží vývar s masem a nudlemi", + price: "45\xA0Kč", + isSoup: true, + }, + { + amount: "-", + name: "Vepřová pečeně se zelím a houskovým knedlíkem", + price: "155\xA0Kč", + isSoup: false, + }, + { + amount: "-", + name: "Špagety s kuřecím masem, špenátem a smetanou", + price: "145\xA0Kč", + isSoup: false, + }, + { + amount: "-", + name: "Medailonky z vepřové panenky s fazolkami se slaninou, šťouchané brambory", + price: "185\xA0Kč", + isSoup: false, + } + ], + [ + { + amount: "-", + name: "Mrkvová polévka se zázvorem a kokosovým mlékem", + price: "45\xA0Kč", + isSoup: true, + }, + { + amount: "-", + name: "Hovězí po Burgundsku, bramborová kaše", + price: "155\xA0Kč", + isSoup: false, + } + ], + [ + { + amount: "-", + name: "Hovězí vývar s játrovými knedlíčky", + price: "45\xA0Kč", + isSoup: true, + }, + { + amount: "-", + name: "Kuřecí plátky na sušených rajčatech, bylinkách a česneku, bramborová kaše", + price: "155\xA0Kč", + isSoup: false, + } + ], + [ + { + amount: "-", + name: "Kuřecí vývar s rýží", + price: "45\xA0Kč", + isSoup: true, + }, + { + amount: "-", + name: "Rajská s plněnou paprikou, knedlík", + price: "170\xA0Kč", + isSoup: false, + } + ], + [ + { + amount: "-", + name: "Mexická fazolová polévka", + price: "45\xA0Kč", + isSoup: true, + }, + { + amount: "-", + name: "Ragú z trhané kachny, onsen vejce, soté ze špenátu a ředkvičky, bramborové pyré, lanýžová sůl, zelený olej", + price: "189\xA0Kč", + isSoup: false, + } + ], + ], } // Mockovací data pro Pizza day @@ -1293,6 +1377,10 @@ export const getMenuZastavkaUmichalaMock = () => { return MOCK_DATA['zastavkaUmichala']; } +export const getMenuSenkSerikovaMock = () => { + return MOCK_DATA['senkSerikova']; +} + export const getPizzaListMock = () => { return MOCK_PIZZA_LIST; } \ No newline at end of file diff --git a/server/src/restaurants.ts b/server/src/restaurants.ts index 9d12561..01334db 100644 --- a/server/src/restaurants.ts +++ b/server/src/restaurants.ts @@ -1,7 +1,7 @@ import axios from "axios"; import { load } from 'cheerio'; import { Food } from "../../types"; -import {getMenuSladovnickaMock, getMenuTechTowerMock, getMenuUMotlikuMock, getMenuZastavkaUmichalaMock} from "./mock"; +import {getMenuSladovnickaMock, getMenuTechTowerMock, getMenuUMotlikuMock, getMenuZastavkaUmichalaMock, getMenuSenkSerikovaMock} from "./mock"; import {formatDate} from "./utils"; // Fráze v názvech jídel, které naznačují že se jedná o polévku @@ -383,3 +383,52 @@ export const getMenuZastavkaUmichala = async (firstDayOfWeek: Date, mock: boolea } return result; } + +/** + * Získá obědovou nabídku SenkSerikova pro jeden týden. + * + * @param firstDayOfWeek první den v týdnu, pro který získat menu + * @param mock zda vrátit mock data + * @returns seznam jídel pro dané datum + */ +export const getMenuSenkSerikova = async (firstDayOfWeek: Date, mock: boolean = false): Promise => { + if (mock) { + return getMenuSenkSerikovaMock(); + } + + const decoder = new TextDecoder('windows-1250'); + const html = await axios.get(SENKSERIKOVA_URL, { + responseType: 'arraybuffer', + responseEncoding: 'binary' + }).then(res => decoder.decode(new Uint8Array(res.data))).then(content => content); + const $ = load(html); + + const nowDate = new Date().getDate(); + const currentDate = new Date(firstDayOfWeek); + const result: Food[][] = []; + let dayIndex = 0; + while(currentDate.getDate() < nowDate) { + result[dayIndex] = [{ + amount: undefined, + name: "Pro tento den není uveřejněna nabídka jídel", + price: "", + isSoup: false, + }]; + dayIndex = dayIndex + 1; + currentDate.setDate(firstDayOfWeek.getDate() + dayIndex); + } + + $('.menicka').each((i, element) => { + const currentDayFood: Food[] = []; + $(element).find('.popup-gallery li').each((j, element) => { + currentDayFood.push({ + amount: '-', + name: $(element).children('div.polozka').text(), + price: $(element).children('div.cena').text(), + isSoup: $(element).hasClass('polevka'), + }); + }); + result[dayIndex++] = currentDayFood; + }); + return result; +} diff --git a/server/src/service.ts b/server/src/service.ts index 0daa62f..244c9e5 100644 --- a/server/src/service.ts +++ b/server/src/service.ts @@ -1,7 +1,7 @@ import { InsufficientPermissions, formatDate, getDayOfWeekIndex, getFirstWorkDayOfWeek, getHumanDate, getIsWeekend, getWeekNumber } from "./utils"; import { ClientData, Restaurants, DayMenu, DepartureTime, DayData, WeekMenu, LocationKey } from "../../types"; import getStorage from "./storage"; -import { getMenuSladovnicka, getMenuTechTower, getMenuUMotliku, getMenuZastavkaUmichala } from "./restaurants"; +import { getMenuSladovnicka, getMenuTechTower, getMenuUMotliku, getMenuZastavkaUmichala, getMenuSenkSerikova } from "./restaurants"; import { getTodayMock } from "./mock"; const storage = getStorage(); @@ -62,6 +62,7 @@ export async function getData(date?: Date): Promise { // [Restaurants.UMOTLIKU]: await getRestaurantMenu(Restaurants.UMOTLIKU, date), [Restaurants.TECHTOWER]: await getRestaurantMenu(Restaurants.TECHTOWER, date), [Restaurants.ZASTAVKAUMICHALA]: await getRestaurantMenu(Restaurants.ZASTAVKAUMICHALA, date), + [Restaurants.SENKSERIKOVA]: await getRestaurantMenu(Restaurants.SENKSERIKOVA, date), } clientData = await addVolatileData(clientData); return clientData; @@ -182,6 +183,19 @@ export async function getRestaurantMenu(restaurant: Restaurants, date?: Date): P } catch (e: any) { console.error("Selhalo načtení jídel pro podnik Zastávka u Michala", e); } + case Restaurants.SENKSERIKOVA: + try { + const senkSerikovaFood = await getMenuSenkSerikova(firstDay, mock); + for (let i = 0; i < senkSerikovaFood.length; i++) { + menus[i][restaurant]!.food = senkSerikovaFood[i]; + if (senkSerikovaFood[i]?.length === 1 && senkSerikovaFood[i][0].name === 'Pro tento den nebylo zadáno menu.') { + menus[i][restaurant]!.closed = true; + } + } + break; + } catch (e: any) { + console.error("Selhalo načtení jídel pro podnik Pivovarský šenk Šeříková", e); + } } await storage.setData(getMenuKey(usedDate), menus); } diff --git a/types/Types.ts b/types/Types.ts index 7617518..82112f9 100644 --- a/types/Types.ts +++ b/types/Types.ts @@ -4,6 +4,7 @@ export enum Restaurants { // UMOTLIKU = 'uMotliku', TECHTOWER = 'techTower', ZASTAVKAUMICHALA = 'zastavkaUmichala', + SENKSERIKOVA = 'senkSerikova', } export type FoodChoices = { @@ -115,6 +116,7 @@ export enum Locations { // UMOTLIKU = 'U Motlíků', TECHTOWER = 'TechTower', ZASTAVKAUMICHALA = 'Zastávka u Michala', + SENKSERIKOVA = 'Pivovarský šenk Šeříková', SPSE = 'SPŠE', PIZZA = 'Pizza day', OBJEDNAVAM = 'Budu objednávat',