Parsování jídel na celý týden
This commit is contained in:
parent
74893c38eb
commit
ca9a7c5c23
@ -14,7 +14,7 @@ import './App.css';
|
|||||||
import { SelectSearchOption } from 'react-select-search';
|
import { SelectSearchOption } from 'react-select-search';
|
||||||
import { faCircleCheck, faTrashCan } from '@fortawesome/free-regular-svg-icons';
|
import { faCircleCheck, faTrashCan } from '@fortawesome/free-regular-svg-icons';
|
||||||
import { useBank } from './context/bank';
|
import { useBank } from './context/bank';
|
||||||
import { ClientData, Restaurants, Food, Order, Locations, PizzaOrder, PizzaDayState, FoodChoices, Menu } from './types';
|
import { ClientData, Restaurants, Food, Order, Locations, PizzaOrder, PizzaDayState, FoodChoices, DayMenu } from './types';
|
||||||
import Footer from './components/Footer';
|
import Footer from './components/Footer';
|
||||||
import { faChainBroken, faChevronLeft, faChevronRight, faGear, faSatelliteDish, faSearch } from '@fortawesome/free-solid-svg-icons';
|
import { faChainBroken, faChevronLeft, faChevronRight, faGear, faSatelliteDish, faSearch } from '@fortawesome/free-solid-svg-icons';
|
||||||
import Loader from './components/Loader';
|
import Loader from './components/Loader';
|
||||||
@ -28,7 +28,7 @@ function App() {
|
|||||||
const bank = useBank();
|
const bank = useBank();
|
||||||
const [isConnected, setIsConnected] = useState<boolean>(false);
|
const [isConnected, setIsConnected] = useState<boolean>(false);
|
||||||
const [data, setData] = useState<ClientData>();
|
const [data, setData] = useState<ClientData>();
|
||||||
const [food, setFood] = useState<{ [key in Restaurants]?: Menu }>();
|
const [food, setFood] = useState<{ [key in Restaurants]?: DayMenu }>();
|
||||||
const [myOrder, setMyOrder] = useState<Order>();
|
const [myOrder, setMyOrder] = useState<Order>();
|
||||||
const [foodChoiceList, setFoodChoiceList] = useState<Food[]>();
|
const [foodChoiceList, setFoodChoiceList] = useState<Food[]>();
|
||||||
const [closed, setClosed] = useState<boolean>(false);
|
const [closed, setClosed] = useState<boolean>(false);
|
||||||
@ -288,7 +288,7 @@ function App() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderFoodTable = (name: string, menu: Menu) => {
|
const renderFoodTable = (name: string, menu: DayMenu) => {
|
||||||
let content;
|
let content;
|
||||||
if (menu?.closed) {
|
if (menu?.closed) {
|
||||||
content = <h3>Zavřeno</h3>
|
content = <h3>Zavřeno</h3>
|
||||||
@ -352,13 +352,7 @@ function App() {
|
|||||||
<Alert variant={'primary'}>
|
<Alert variant={'primary'}>
|
||||||
Poslední změny:
|
Poslední změny:
|
||||||
<ul>
|
<ul>
|
||||||
<li>Oprava generování QR kódů pro Pizza day</li>
|
<li>Parsování jídelních lístků na celý týden</li>
|
||||||
<li>Serverová validace času odchodu</li>
|
|
||||||
<li>Loader při zakládání Pizza day</li>
|
|
||||||
<li>Možnost ručního zadání příplatku k Pizza day objednávkám</li>
|
|
||||||
<li>Vylepšená detekce uzavření pro podniky Sladovnická a TechTower</li>
|
|
||||||
<li>Úprava zvýraznění aktuálního dne</li>
|
|
||||||
<li>Možnost hlasování o nových funkcích</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</Alert>
|
</Alert>
|
||||||
{dayIndex != null &&
|
{dayIndex != null &&
|
||||||
|
@ -1124,16 +1124,16 @@ export const getTodayMock = () => {
|
|||||||
return '2023-05-31'; // středa
|
return '2023-05-31'; // středa
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getMenuSladovnickaMock = (date: Date) => {
|
export const getMenuSladovnickaMock = () => {
|
||||||
return MOCK_DATA['sladovnicka'][getDayOfWeekIndex(date)];
|
return MOCK_DATA['sladovnicka'];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getMenuUMotlikuMock = (date: Date) => {
|
export const getMenuUMotlikuMock = () => {
|
||||||
return MOCK_DATA['uMotliku'][getDayOfWeekIndex(date)];
|
return MOCK_DATA['uMotliku'];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getMenuTechTowerMock = (date: Date) => {
|
export const getMenuTechTowerMock = () => {
|
||||||
return MOCK_DATA['techTower'][getDayOfWeekIndex(date)];
|
return MOCK_DATA['techTower'];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getPizzaListMock = () => {
|
export const getPizzaListMock = () => {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { formatDate } from "./utils";
|
import { formatDate } from "./utils";
|
||||||
import { callNotifikace } from "./notifikace";
|
import { callNotifikace } from "./notifikace";
|
||||||
import { generateQr } from "./qr";
|
import { generateQr } from "./qr";
|
||||||
import { ClientData, PizzaDayState, UdalostEnum, Pizza, PizzaSize, Order, PizzaOrder } from "../../types";
|
import { ClientData, PizzaDayState, UdalostEnum, Pizza, PizzaSize, Order, PizzaOrder, DayData } from "../../types";
|
||||||
import getStorage from "./storage";
|
import getStorage from "./storage";
|
||||||
import { downloadPizzy } from "./chefie";
|
import { downloadPizzy } from "./chefie";
|
||||||
import { getToday, initIfNeeded } from "./service";
|
import { getToday, initIfNeeded } from "./service";
|
||||||
@ -15,7 +15,7 @@ const storage = getStorage();
|
|||||||
export async function getPizzaList(): Promise<Pizza[] | undefined> {
|
export async function getPizzaList(): Promise<Pizza[] | undefined> {
|
||||||
await initIfNeeded();
|
await initIfNeeded();
|
||||||
const today = formatDate(getToday());
|
const today = formatDate(getToday());
|
||||||
let clientData: ClientData = await storage.getData(today);
|
let clientData: DayData = await storage.getData(today);
|
||||||
if (!clientData.pizzaList) {
|
if (!clientData.pizzaList) {
|
||||||
const mock = process.env.MOCK_DATA === 'true';
|
const mock = process.env.MOCK_DATA === 'true';
|
||||||
clientData = await savePizzaList(await downloadPizzy(mock));
|
clientData = await savePizzaList(await downloadPizzy(mock));
|
||||||
@ -31,7 +31,7 @@ export async function getPizzaList(): Promise<Pizza[] | undefined> {
|
|||||||
export async function savePizzaList(pizzaList: Pizza[]): Promise<ClientData> {
|
export async function savePizzaList(pizzaList: Pizza[]): Promise<ClientData> {
|
||||||
await initIfNeeded();
|
await initIfNeeded();
|
||||||
const today = formatDate(getToday());
|
const today = formatDate(getToday());
|
||||||
const clientData: ClientData = await storage.getData(today);
|
const clientData: DayData = await storage.getData(today);
|
||||||
clientData.pizzaList = pizzaList;
|
clientData.pizzaList = pizzaList;
|
||||||
clientData.pizzaListLastUpdate = new Date();
|
clientData.pizzaListLastUpdate = new Date();
|
||||||
await storage.setData(today, clientData);
|
await storage.setData(today, clientData);
|
||||||
@ -44,7 +44,7 @@ export async function savePizzaList(pizzaList: Pizza[]): Promise<ClientData> {
|
|||||||
export async function createPizzaDay(creator: string): Promise<ClientData> {
|
export async function createPizzaDay(creator: string): Promise<ClientData> {
|
||||||
await initIfNeeded();
|
await initIfNeeded();
|
||||||
const today = formatDate(getToday());
|
const today = formatDate(getToday());
|
||||||
const clientData: ClientData = await storage.getData(today);
|
const clientData: DayData = await storage.getData(today);
|
||||||
if (clientData.pizzaDay) {
|
if (clientData.pizzaDay) {
|
||||||
throw Error("Pizza day pro dnešní den již existuje");
|
throw Error("Pizza day pro dnešní den již existuje");
|
||||||
}
|
}
|
||||||
@ -61,7 +61,7 @@ export async function createPizzaDay(creator: string): Promise<ClientData> {
|
|||||||
*/
|
*/
|
||||||
export async function deletePizzaDay(login: string): Promise<ClientData> {
|
export async function deletePizzaDay(login: string): Promise<ClientData> {
|
||||||
const today = formatDate(getToday());
|
const today = formatDate(getToday());
|
||||||
const clientData: ClientData = await storage.getData(today);
|
const clientData: DayData = await storage.getData(today);
|
||||||
if (!clientData.pizzaDay) {
|
if (!clientData.pizzaDay) {
|
||||||
throw Error("Pizza day pro dnešní den neexistuje");
|
throw Error("Pizza day pro dnešní den neexistuje");
|
||||||
}
|
}
|
||||||
@ -82,7 +82,7 @@ export async function deletePizzaDay(login: string): Promise<ClientData> {
|
|||||||
*/
|
*/
|
||||||
export async function addPizzaOrder(login: string, pizza: Pizza, size: PizzaSize) {
|
export async function addPizzaOrder(login: string, pizza: Pizza, size: PizzaSize) {
|
||||||
const today = formatDate(getToday());
|
const today = formatDate(getToday());
|
||||||
const clientData: ClientData = await storage.getData(today);
|
const clientData: DayData = await storage.getData(today);
|
||||||
if (!clientData.pizzaDay) {
|
if (!clientData.pizzaDay) {
|
||||||
throw Error("Pizza day pro dnešní den neexistuje");
|
throw Error("Pizza day pro dnešní den neexistuje");
|
||||||
}
|
}
|
||||||
@ -118,7 +118,7 @@ export async function addPizzaOrder(login: string, pizza: Pizza, size: PizzaSize
|
|||||||
*/
|
*/
|
||||||
export async function removePizzaOrder(login: string, pizzaOrder: PizzaOrder) {
|
export async function removePizzaOrder(login: string, pizzaOrder: PizzaOrder) {
|
||||||
const today = formatDate(getToday());
|
const today = formatDate(getToday());
|
||||||
const clientData: ClientData = await storage.getData(today);
|
const clientData: DayData = await storage.getData(today);
|
||||||
if (!clientData.pizzaDay) {
|
if (!clientData.pizzaDay) {
|
||||||
throw Error("Pizza day pro dnešní den neexistuje");
|
throw Error("Pizza day pro dnešní den neexistuje");
|
||||||
}
|
}
|
||||||
@ -149,7 +149,7 @@ export async function removePizzaOrder(login: string, pizzaOrder: PizzaOrder) {
|
|||||||
*/
|
*/
|
||||||
export async function lockPizzaDay(login: string) {
|
export async function lockPizzaDay(login: string) {
|
||||||
const today = formatDate(getToday());
|
const today = formatDate(getToday());
|
||||||
const clientData: ClientData = await storage.getData(today);
|
const clientData: DayData = await storage.getData(today);
|
||||||
if (!clientData.pizzaDay) {
|
if (!clientData.pizzaDay) {
|
||||||
throw Error("Pizza day pro dnešní den neexistuje");
|
throw Error("Pizza day pro dnešní den neexistuje");
|
||||||
}
|
}
|
||||||
@ -172,7 +172,7 @@ export async function lockPizzaDay(login: string) {
|
|||||||
*/
|
*/
|
||||||
export async function unlockPizzaDay(login: string) {
|
export async function unlockPizzaDay(login: string) {
|
||||||
const today = formatDate(getToday());
|
const today = formatDate(getToday());
|
||||||
const clientData: ClientData = await storage.getData(today);
|
const clientData: DayData = await storage.getData(today);
|
||||||
if (!clientData.pizzaDay) {
|
if (!clientData.pizzaDay) {
|
||||||
throw Error("Pizza day pro dnešní den neexistuje");
|
throw Error("Pizza day pro dnešní den neexistuje");
|
||||||
}
|
}
|
||||||
@ -195,7 +195,7 @@ export async function unlockPizzaDay(login: string) {
|
|||||||
*/
|
*/
|
||||||
export async function finishPizzaOrder(login: string) {
|
export async function finishPizzaOrder(login: string) {
|
||||||
const today = formatDate(getToday());
|
const today = formatDate(getToday());
|
||||||
const clientData: ClientData = await storage.getData(today);
|
const clientData: DayData = await storage.getData(today);
|
||||||
if (!clientData.pizzaDay) {
|
if (!clientData.pizzaDay) {
|
||||||
throw Error("Pizza day pro dnešní den neexistuje");
|
throw Error("Pizza day pro dnešní den neexistuje");
|
||||||
}
|
}
|
||||||
@ -220,7 +220,7 @@ export async function finishPizzaOrder(login: string) {
|
|||||||
*/
|
*/
|
||||||
export async function finishPizzaDelivery(login: string, bankAccount?: string, bankAccountHolder?: string) {
|
export async function finishPizzaDelivery(login: string, bankAccount?: string, bankAccountHolder?: string) {
|
||||||
const today = formatDate(getToday());
|
const today = formatDate(getToday());
|
||||||
const clientData: ClientData = await storage.getData(today);
|
const clientData: DayData = await storage.getData(today);
|
||||||
if (!clientData.pizzaDay) {
|
if (!clientData.pizzaDay) {
|
||||||
throw Error("Pizza day pro dnešní den neexistuje");
|
throw Error("Pizza day pro dnešní den neexistuje");
|
||||||
}
|
}
|
||||||
@ -255,7 +255,7 @@ export async function finishPizzaDelivery(login: string, bankAccount?: string, b
|
|||||||
*/
|
*/
|
||||||
export async function updatePizzaDayNote(login: string, note?: string) {
|
export async function updatePizzaDayNote(login: string, note?: string) {
|
||||||
const today = formatDate(getToday());
|
const today = formatDate(getToday());
|
||||||
let clientData: ClientData = await storage.getData(today);
|
let clientData: DayData = await storage.getData(today);
|
||||||
if (!clientData.pizzaDay) {
|
if (!clientData.pizzaDay) {
|
||||||
throw Error("Pizza day pro dnešní den neexistuje");
|
throw Error("Pizza day pro dnešní den neexistuje");
|
||||||
}
|
}
|
||||||
@ -282,7 +282,7 @@ export async function updatePizzaDayNote(login: string, note?: string) {
|
|||||||
*/
|
*/
|
||||||
export async function updatePizzaFee(login: string, targetLogin: string, text?: string, price?: number) {
|
export async function updatePizzaFee(login: string, targetLogin: string, text?: string, price?: number) {
|
||||||
const today = formatDate(getToday());
|
const today = formatDate(getToday());
|
||||||
let clientData: ClientData = await storage.getData(today);
|
let clientData: DayData = await storage.getData(today);
|
||||||
if (!clientData.pizzaDay) {
|
if (!clientData.pizzaDay) {
|
||||||
throw Error("Pizza day pro dnešní den neexistuje");
|
throw Error("Pizza day pro dnešní den neexistuje");
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ import axios from "axios";
|
|||||||
import { load } from 'cheerio';
|
import { load } from 'cheerio';
|
||||||
import { Food } from "../../types";
|
import { Food } from "../../types";
|
||||||
import { getMenuSladovnickaMock, getMenuTechTowerMock, getMenuUMotlikuMock } from "./mock";
|
import { getMenuSladovnickaMock, getMenuTechTowerMock, getMenuUMotlikuMock } from "./mock";
|
||||||
import { getDayOfWeekIndex } from "./utils";
|
|
||||||
|
|
||||||
// Fráze v názvech jídel, které naznačují že se jedná o polévku
|
// Fráze v názvech jídel, které naznačují že se jedná o polévku
|
||||||
const SOUP_NAMES = ['polévka', 'česnečka', 'česnekový krém', 'cibulačka', 'vývar']
|
const SOUP_NAMES = ['polévka', 'česnečka', 'česnekový krém', 'cibulačka', 'vývar']
|
||||||
@ -48,27 +47,29 @@ const getHtml = async (url: string): Promise<any> => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Získá obědovou nabídku Sladovnické pro předané datum.
|
* Získá obědovou nabídku Sladovnické pro jeden týden.
|
||||||
*
|
*
|
||||||
* @param date datum, pro které získat menu
|
* @param firstDayOfWeek první den v týdnu, pro který získat menu
|
||||||
* @param mock zda vrátit mock data
|
* @param mock zda vrátit mock data
|
||||||
* @returns seznam jídel pro dané datum
|
* @returns seznam jídel pro daný týden
|
||||||
*/
|
*/
|
||||||
export const getMenuSladovnicka = async (date: Date = new Date(), mock: boolean = false): Promise<Food[]> => {
|
export const getMenuSladovnicka = async (firstDayOfWeek: Date, mock: boolean = false): Promise<Food[][]> => {
|
||||||
if (mock) {
|
if (mock) {
|
||||||
return getMenuSladovnickaMock(date);
|
return getMenuSladovnickaMock();
|
||||||
}
|
|
||||||
const todayDayIndex = getDayOfWeekIndex(date);
|
|
||||||
if (todayDayIndex == 5 || todayDayIndex == 6) { // Víkend
|
|
||||||
return [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const html = await getHtml(SLADOVNICKA_URL);
|
const html = await getHtml(SLADOVNICKA_URL);
|
||||||
const $ = load(html);
|
const $ = load(html);
|
||||||
|
|
||||||
|
const list = $('ul.tab-links').children();
|
||||||
|
const result: Food[][] = [];
|
||||||
|
for (let dayIndex = 0; dayIndex < 5; dayIndex++) {
|
||||||
|
const currentDate = new Date(firstDayOfWeek);
|
||||||
|
currentDate.setDate(firstDayOfWeek.getDate() + dayIndex);
|
||||||
|
const searchedDayText = `${currentDate.getDate()}.${currentDate.getMonth() + 1}.${capitalize(DAYS_IN_WEEK[dayIndex])}`;
|
||||||
// Najdeme index pro vstupní datum (např. při svátcích bude posunutý)
|
// Najdeme index pro vstupní datum (např. při svátcích bude posunutý)
|
||||||
// TODO validovat, že vstupní datum je v aktuálním týdnu
|
// TODO validovat, že vstupní datum je v aktuálním týdnu
|
||||||
// TODO tenhle způsob je zbytečně komplikovaný - stačilo by hledat rovnou v div.tab-content, protože každý den tam má datum taky (akorát je print-only)
|
// TODO tenhle způsob je zbytečně komplikovaný - stačilo by hledat rovnou v div.tab-content, protože každý den tam má datum taky (akorát je print-only)
|
||||||
const list = $('ul.tab-links').children();
|
|
||||||
const searchedDayText = `${date.getDate()}.${date.getMonth() + 1}.${capitalize(DAYS_IN_WEEK[todayDayIndex])}`;
|
|
||||||
let index = undefined;
|
let index = undefined;
|
||||||
list.each((i, dayRow) => {
|
list.each((i, dayRow) => {
|
||||||
const rowText = $(dayRow).first().text().trim();
|
const rowText = $(dayRow).first().text().trim();
|
||||||
@ -79,12 +80,13 @@ export const getMenuSladovnicka = async (date: Date = new Date(), mock: boolean
|
|||||||
})
|
})
|
||||||
if (index === undefined) {
|
if (index === undefined) {
|
||||||
// Pravděpodobně svátek, nebo je zavřeno
|
// Pravděpodobně svátek, nebo je zavřeno
|
||||||
return [{
|
result[dayIndex] = [{
|
||||||
amount: undefined,
|
amount: undefined,
|
||||||
name: "Pro daný den nebyla nalezena denní nabídka",
|
name: "Pro daný den nebyla nalezena denní nabídka",
|
||||||
price: "",
|
price: "",
|
||||||
isSoup: false,
|
isSoup: false,
|
||||||
}];
|
}];
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dle dohledaného indexu najdeme správný tabpanel
|
// Dle dohledaného indexu najdeme správný tabpanel
|
||||||
@ -109,13 +111,13 @@ export const getMenuSladovnicka = async (date: Date = new Date(), mock: boolean
|
|||||||
if (tables.length !== 2) {
|
if (tables.length !== 2) {
|
||||||
throw Error("Neočekávaný počet tabulek na řádce nalezeného dne: " + tables.length + ", ale očekávány byly 2");
|
throw Error("Neočekávaný počet tabulek na řádce nalezeného dne: " + tables.length + ", ale očekávány byly 2");
|
||||||
}
|
}
|
||||||
const results: Food[] = [];
|
const currentDayFood: Food[] = [];
|
||||||
// Polévka - div -> table -> tbody -> tr -> 3x td
|
// Polévka - div -> table -> tbody -> tr -> 3x td
|
||||||
const soupCells = $(tables.get(0)).children().first().children().first().children();
|
const soupCells = $(tables.get(0)).children().first().children().first().children();
|
||||||
if (soupCells.length !== 3) {
|
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");
|
throw Error("Neočekávaný počet buněk v tabulce polévky: " + soupCells.length + ", ale očekávány byly 3");
|
||||||
}
|
}
|
||||||
results.push({
|
currentDayFood.push({
|
||||||
amount: sanitizeText($(soupCells.get(0)).text()),
|
amount: sanitizeText($(soupCells.get(0)).text()),
|
||||||
name: sanitizeText($(soupCells.get(1)).text()),
|
name: sanitizeText($(soupCells.get(1)).text()),
|
||||||
price: sanitizeText($(soupCells.get(2)).text().replace(' ', '\xA0')),
|
price: sanitizeText($(soupCells.get(2)).text().replace(' ', '\xA0')),
|
||||||
@ -123,60 +125,61 @@ export const getMenuSladovnicka = async (date: Date = new Date(), mock: boolean
|
|||||||
});
|
});
|
||||||
// Hlavní jídla - div -> table -> tbody -> 3x tr
|
// Hlavní jídla - div -> table -> tbody -> 3x tr
|
||||||
const mainCourseRows = $(tables.get(1)).children().first().children();
|
const mainCourseRows = $(tables.get(1)).children().first().children();
|
||||||
// Záměrně zakomentováno - občas je ve Sladovnické jídel méně
|
|
||||||
// if (mainCourseRows.length !== 3) {
|
|
||||||
// throw Error("Neočekávaný počet řádek jídel: " + mainCourseRows.length + ", ale očekávány byly 3");
|
|
||||||
// }
|
|
||||||
mainCourseRows.each((i, foodRow) => {
|
mainCourseRows.each((i, foodRow) => {
|
||||||
const foodCells = $(foodRow).children();
|
const foodCells = $(foodRow).children();
|
||||||
if (foodCells.length !== 3) {
|
if (foodCells.length !== 3) {
|
||||||
throw Error("Neočekávaný počet buněk v řádku jídla: " + foodCells.length + ", ale očekávány byly 3");
|
throw Error("Neočekávaný počet buněk v řádku jídla: " + foodCells.length + ", ale očekávány byly 3");
|
||||||
}
|
}
|
||||||
results.push({
|
currentDayFood.push({
|
||||||
amount: sanitizeText($(foodCells.get(0)).text()),
|
amount: sanitizeText($(foodCells.get(0)).text()),
|
||||||
name: sanitizeText($(foodCells.get(1)).text()),
|
name: sanitizeText($(foodCells.get(1)).text()),
|
||||||
price: sanitizeText($(foodCells.get(2)).text().replace(' ', '\xA0')),
|
price: sanitizeText($(foodCells.get(2)).text().replace(' ', '\xA0')),
|
||||||
isSoup: false,
|
isSoup: false,
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
return results;
|
result[index] = currentDayFood;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Získá obědovou nabídku restaurace U Motlíků pro předané datum.
|
* Získá obědovou nabídku restaurace U Motlíků pro jeden týden.
|
||||||
*
|
*
|
||||||
* @param date datum, pro které získat menu
|
* @param firstDayOfWeek první den v týdnu, pro který získat menu
|
||||||
* @param mock zda vrátit mock data
|
* @param mock zda vrátit mock data
|
||||||
* @returns seznam jídel pro dané datum
|
* @returns seznam jídel pro dané datum
|
||||||
*/
|
*/
|
||||||
export const getMenuUMotliku = async (date: Date = new Date(), mock: boolean = false): Promise<Food[]> => {
|
export const getMenuUMotliku = async (firstDayOfWeek: Date, mock: boolean = false): Promise<Food[][]> => {
|
||||||
if (mock) {
|
if (mock) {
|
||||||
return getMenuUMotlikuMock(date);
|
return getMenuUMotlikuMock();
|
||||||
}
|
|
||||||
const todayDayIndex = getDayOfWeekIndex(date);
|
|
||||||
if (todayDayIndex == 5 || todayDayIndex == 6) { // Víkend
|
|
||||||
return [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const html = await getHtml(U_MOTLIKU_URL);
|
const html = await getHtml(U_MOTLIKU_URL);
|
||||||
const $ = load(html);
|
const $ = load(html);
|
||||||
|
|
||||||
const table = $('table.table.table-hover.Xtable-striped').first();
|
const table = $('table.table.table-hover.Xtable-striped').first();
|
||||||
const body = table.children().first();
|
const body = table.children().first();
|
||||||
const rows = body.children();
|
const rows = body.children();
|
||||||
const results: Food[] = [];
|
|
||||||
|
const result: Food[][] = [];
|
||||||
|
for (let dayIndex = 0; dayIndex < 5; dayIndex++) {
|
||||||
|
if (!(dayIndex in result)) {
|
||||||
|
result[dayIndex] = [];
|
||||||
|
}
|
||||||
let parsing = false;
|
let parsing = false;
|
||||||
let isSoup = false;
|
let isSoup = false;
|
||||||
rows.each((i, row) => {
|
rows.each((i, row) => {
|
||||||
const firstChild = $(row).children().get(0);
|
const firstChild = $(row).children().get(0);
|
||||||
if (firstChild?.name == 'th') {
|
if (firstChild?.name == 'th') {
|
||||||
const childText = $(firstChild).text();
|
const childText = $(firstChild).text();
|
||||||
if (capitalize(DAYS_IN_WEEK[todayDayIndex]) === childText) { // Našli jsme dnešek
|
if (capitalize(DAYS_IN_WEEK[dayIndex]) === childText) {
|
||||||
parsing = true;
|
parsing = true;
|
||||||
} else if (parsing) {
|
} else if (parsing) {
|
||||||
// Narazili jsme na další den - konec parsování
|
// Narazili jsme na další den - konec parsování
|
||||||
parsing = false;
|
parsing = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (parsing) { // Jsme aktuálně na dnešním dni
|
} else if (parsing) {
|
||||||
const children = $(row).children();
|
const children = $(row).children();
|
||||||
if (children.length === 1) { // Nadpis "Polévka" nebo "Hlavní jídlo"
|
if (children.length === 1) { // Nadpis "Polévka" nebo "Hlavní jídlo"
|
||||||
const foodType = children.first().text();
|
const foodType = children.first().text();
|
||||||
@ -194,7 +197,7 @@ export const getMenuUMotliku = async (date: Date = new Date(), mock: boolean = f
|
|||||||
const amount = sanitizeText($(children.get(0)).text());
|
const amount = sanitizeText($(children.get(0)).text());
|
||||||
const name = sanitizeText($(children.get(1)).text());
|
const name = sanitizeText($(children.get(1)).text());
|
||||||
const price = sanitizeText($(children.get(2)).text()).replace(',-', '').replace(' ', '\xA0');
|
const price = sanitizeText($(children.get(2)).text()).replace(',-', '').replace(' ', '\xA0');
|
||||||
results.push({
|
result[dayIndex].push({
|
||||||
amount,
|
amount,
|
||||||
name,
|
name,
|
||||||
price,
|
price,
|
||||||
@ -203,26 +206,25 @@ export const getMenuUMotliku = async (date: Date = new Date(), mock: boolean = f
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return results;
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Získá obědovou nabídku TechTower pro předané datum.
|
* Získá obědovou nabídku TechTower pro jeden týden.
|
||||||
*
|
*
|
||||||
* @param date datum, pro které získat menu
|
* @param firstDayOfWeek první den v týdnu, pro který získat menu
|
||||||
* @param mock zda vrátit mock data
|
* @param mock zda vrátit mock data
|
||||||
* @returns seznam jídel pro dané datum
|
* @returns seznam jídel pro dané datum
|
||||||
*/
|
*/
|
||||||
export const getMenuTechTower = async (date: Date = new Date(), mock: boolean = false) => {
|
export const getMenuTechTower = async (firstDayOfWeek: Date, mock: boolean = false): Promise<Food[][]> => {
|
||||||
if (mock) {
|
if (mock) {
|
||||||
return getMenuTechTowerMock(date);
|
return getMenuTechTowerMock();
|
||||||
}
|
|
||||||
const todayDayIndex = getDayOfWeekIndex(date);
|
|
||||||
if (todayDayIndex == 5 || todayDayIndex == 6) { // Víkend
|
|
||||||
return [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const html = await getHtml(TECHTOWER_URL);
|
const html = await getHtml(TECHTOWER_URL);
|
||||||
const $ = load(html);
|
const $ = load(html);
|
||||||
|
|
||||||
const fonts = $('font.wsw-41');
|
const fonts = $('font.wsw-41');
|
||||||
let font = undefined;
|
let font = undefined;
|
||||||
fonts.each((i, f) => {
|
fonts.each((i, f) => {
|
||||||
@ -236,11 +238,16 @@ export const getMenuTechTower = async (date: Date = new Date(), mock: boolean =
|
|||||||
// TODO validovat, že v textu nalezeného <font> je rozsah, do kterého spadá vstupní datum
|
// TODO validovat, že v textu nalezeného <font> je rozsah, do kterého spadá vstupní datum
|
||||||
const siblings = $(font).parent().parent().siblings();
|
const siblings = $(font).parent().parent().siblings();
|
||||||
let parsing = false;
|
let parsing = false;
|
||||||
const results: Food[] = [];
|
const result: Food[][] = [];
|
||||||
|
// TODO toto je kvůli poslednímu "línému" refaktoru neoptimální, stačilo by to projít jedním cyklem
|
||||||
|
for (let dayIndex = 0; dayIndex < 5; dayIndex++) {
|
||||||
|
if (!(dayIndex in result)) {
|
||||||
|
result[dayIndex] = [];
|
||||||
|
}
|
||||||
for (let i = 0; i < siblings.length; i++) {
|
for (let i = 0; i < siblings.length; i++) {
|
||||||
const text = $(siblings.get(i)).text().trim().replace('\t', '').replace('\n', ' ');
|
const text = $(siblings.get(i)).text().trim().replace('\t', '').replace('\n', ' ');
|
||||||
if (DAYS_IN_WEEK.includes(text)) {
|
if (DAYS_IN_WEEK.includes(text)) {
|
||||||
if (text === DAYS_IN_WEEK[todayDayIndex]) {
|
if (text === DAYS_IN_WEEK[dayIndex]) {
|
||||||
// Našli jsme dnešní den, odtud začínáme parsovat jídla
|
// Našli jsme dnešní den, odtud začínáme parsovat jídla
|
||||||
parsing = true;
|
parsing = true;
|
||||||
continue
|
continue
|
||||||
@ -261,7 +268,7 @@ export const getMenuTechTower = async (date: Date = new Date(), mock: boolean =
|
|||||||
price = `${split.slice(1)[0]}\xA0Kč`
|
price = `${split.slice(1)[0]}\xA0Kč`
|
||||||
name = split[0]
|
name = split[0]
|
||||||
}
|
}
|
||||||
results.push({
|
result[dayIndex].push({
|
||||||
amount: '-',
|
amount: '-',
|
||||||
name,
|
name,
|
||||||
price,
|
price,
|
||||||
@ -269,5 +276,6 @@ export const getMenuTechTower = async (date: Date = new Date(), mock: boolean =
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return results;
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
@ -1,10 +1,11 @@
|
|||||||
import { InsufficientPermissions, formatDate, getDayOfWeekIndex, getHumanDate, getHumanTime, getIsWeekend } from "./utils";
|
import { InsufficientPermissions, formatDate, getDayOfWeekIndex, getFirstWorkDayOfWeek, getHumanDate, getHumanTime, getIsWeekend, getLastWorkDayOfWeek, getWeekNumber } from "./utils";
|
||||||
import { ClientData, Locations, Restaurants, Menu, DepartureTime } from "../../types";
|
import { ClientData, Locations, Restaurants, DayMenu, DepartureTime, DayData, WeekMenu } from "../../types";
|
||||||
import getStorage from "./storage";
|
import getStorage from "./storage";
|
||||||
import { getMenuSladovnicka, getMenuTechTower, getMenuUMotliku } from "./restaurants";
|
import { getMenuSladovnicka, getMenuTechTower, getMenuUMotliku } from "./restaurants";
|
||||||
import { getTodayMock } from "./mock";
|
import { getTodayMock } from "./mock";
|
||||||
|
|
||||||
const storage = getStorage();
|
const storage = getStorage();
|
||||||
|
const MENU_PREFIX = 'menu';
|
||||||
|
|
||||||
/** Vrátí dnešní datum, případně fiktivní datum pro účely vývoje a testování. */
|
/** Vrátí dnešní datum, případně fiktivní datum pro účely vývoje a testování. */
|
||||||
export function getToday(): Date {
|
export function getToday(): Date {
|
||||||
@ -34,7 +35,7 @@ function getEmptyData(date?: Date): ClientData {
|
|||||||
isWeekend: getIsWeekend(usedDate),
|
isWeekend: getIsWeekend(usedDate),
|
||||||
weekIndex: getDayOfWeekIndex(usedDate),
|
weekIndex: getDayOfWeekIndex(usedDate),
|
||||||
choices: {},
|
choices: {},
|
||||||
departureTimes: Object.values(DepartureTime),
|
departureTimes: Object.values(DepartureTime), // TODO tohle zmizí, bude se přidávat do dat dynamicky
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,73 +43,112 @@ function getEmptyData(date?: Date): ClientData {
|
|||||||
* Vrátí veškerá klientská data pro předaný den, nebo aktuální den, pokud není předán.
|
* Vrátí veškerá klientská data pro předaný den, nebo aktuální den, pokud není předán.
|
||||||
*/
|
*/
|
||||||
export async function getData(date?: Date): Promise<ClientData> {
|
export async function getData(date?: Date): Promise<ClientData> {
|
||||||
const dateString = formatDate(date ?? getToday());
|
const targetDate = date ?? getToday();
|
||||||
const data: ClientData = await storage.getData(dateString) || getEmptyData(date);
|
const dateString = formatDate(targetDate);
|
||||||
data.todayWeekIndex = getDayOfWeekIndex(getToday());
|
const data: DayData = await storage.getData(dateString) || getEmptyData(date);
|
||||||
// Dotažení jídel, pokud je ještě nemáme
|
const clientData: ClientData = { ...data };
|
||||||
if (!data.menus) {
|
clientData.todayWeekIndex = getDayOfWeekIndex(getToday());
|
||||||
data.menus = {
|
clientData.menus = {
|
||||||
[Restaurants.SLADOVNICKA]: await getRestaurantMenu(Restaurants.SLADOVNICKA, date ?? getToday()),
|
[Restaurants.SLADOVNICKA]: await getRestaurantMenu(Restaurants.SLADOVNICKA, targetDate),
|
||||||
[Restaurants.UMOTLIKU]: await getRestaurantMenu(Restaurants.UMOTLIKU, date ?? getToday()),
|
[Restaurants.UMOTLIKU]: await getRestaurantMenu(Restaurants.UMOTLIKU, targetDate),
|
||||||
[Restaurants.TECHTOWER]: await getRestaurantMenu(Restaurants.TECHTOWER, date ?? getToday()),
|
[Restaurants.TECHTOWER]: await getRestaurantMenu(Restaurants.TECHTOWER, targetDate),
|
||||||
}
|
}
|
||||||
await storage.setData(dateString, data);
|
return clientData;
|
||||||
}
|
}
|
||||||
return data;
|
|
||||||
|
/**
|
||||||
|
* Vrátí klíč, pod kterým je uloženo menu pro předané datum.
|
||||||
|
*
|
||||||
|
* @param date datum
|
||||||
|
* @returns databázový klíč
|
||||||
|
*/
|
||||||
|
function getMenuKey(date: Date) {
|
||||||
|
const weekNumber = getWeekNumber(date);
|
||||||
|
return `${MENU_PREFIX}_${date.getFullYear()}_${weekNumber}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vrátí menu restaurací pro předané datum, pokud již existují.
|
||||||
|
*
|
||||||
|
* @param date datum
|
||||||
|
* @returns menu restaurací pro předané datum
|
||||||
|
*/
|
||||||
|
async function getMenu(date: Date): Promise<WeekMenu | undefined> {
|
||||||
|
return await storage.getData(getMenuKey(date));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO přesun do restaurants.ts
|
// TODO přesun do restaurants.ts
|
||||||
/**
|
/**
|
||||||
* Vrátí menu dané restaurace pro předaný den. Pokud neexistuje, provede jeho stažení a uložení do DB.
|
* Vrátí menu dané restaurace pro předaný den.
|
||||||
|
* Pokud neexistuje, provede stažení menu pro příslušný týden a uložení do DB.
|
||||||
*
|
*
|
||||||
* @param restaurant restaurace
|
* @param restaurant restaurace
|
||||||
* @param date datum
|
* @param date datum, ke kterému získat menu
|
||||||
* @param mock příznak, zda chceme pouze mock data
|
* @param mock příznak, zda chceme pouze mock data
|
||||||
*/
|
*/
|
||||||
export async function getRestaurantMenu(restaurant: Restaurants, date?: Date): Promise<Menu> {
|
export async function getRestaurantMenu(restaurant: Restaurants, date?: Date): Promise<DayMenu> {
|
||||||
await initIfNeeded(date);
|
const usedDate = date ?? getToday();
|
||||||
const selectedDay = formatDate(date ?? getToday());
|
const dayOfWeekIndex = getDayOfWeekIndex(usedDate);
|
||||||
const clientData: ClientData = await storage.getData(selectedDay);
|
|
||||||
if (!clientData.menus) {
|
let menus = await getMenu(usedDate);
|
||||||
clientData.menus = {};
|
if (menus == null) {
|
||||||
storage.setData(selectedDay, clientData);
|
menus = [];
|
||||||
}
|
}
|
||||||
if (!clientData.menus[restaurant]) {
|
for (let i = 0; i < 5; i++) {
|
||||||
clientData.menus[restaurant] = {
|
if (menus[i] == null) {
|
||||||
|
menus[i] = {};
|
||||||
|
}
|
||||||
|
if (menus[i][restaurant] == null) {
|
||||||
|
menus[i][restaurant] = {
|
||||||
lastUpdate: getHumanTime(new Date()),
|
lastUpdate: getHumanTime(new Date()),
|
||||||
closed: false,
|
closed: false,
|
||||||
food: [],
|
food: [],
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!menus[dayOfWeekIndex][restaurant]?.food?.length) {
|
||||||
|
const firstDay = getFirstWorkDayOfWeek(usedDate);
|
||||||
const mock = process.env.MOCK_DATA === 'true';
|
const mock = process.env.MOCK_DATA === 'true';
|
||||||
switch (restaurant) {
|
switch (restaurant) {
|
||||||
case Restaurants.SLADOVNICKA:
|
case Restaurants.SLADOVNICKA:
|
||||||
const sladovnickaFood = await getMenuSladovnicka(date, mock);
|
const sladovnickaFood = await getMenuSladovnicka(firstDay, mock);
|
||||||
clientData.menus[restaurant]!.food = sladovnickaFood;
|
for (let i = 0; i < sladovnickaFood.length; i++) {
|
||||||
|
menus[i][restaurant]!.food = sladovnickaFood[i];
|
||||||
// Velice chatrný a nespolehlivý způsob detekce uzavření...
|
// Velice chatrný a nespolehlivý způsob detekce uzavření...
|
||||||
if (sladovnickaFood.length === 1 && sladovnickaFood[0].name.toLowerCase() === 'pro daný den nebyla nalezena denní nabídka') {
|
if (sladovnickaFood[i].length === 1 && sladovnickaFood[i][0].name.toLowerCase() === 'pro daný den nebyla nalezena denní nabídka') {
|
||||||
clientData.menus[restaurant]!.closed = true;
|
menus[i][restaurant]!.closed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Restaurants.UMOTLIKU:
|
case Restaurants.UMOTLIKU:
|
||||||
const uMotlikuFood = await getMenuUMotliku(date, mock);
|
const uMotlikuFood = await getMenuUMotliku(firstDay, mock);
|
||||||
clientData.menus[restaurant]!.food = uMotlikuFood;
|
for (let i = 0; i < uMotlikuFood.length; i++) {
|
||||||
if (uMotlikuFood.length === 1 && uMotlikuFood[0].name.toLowerCase() === 'zavřeno') {
|
menus[i][restaurant]!.food = uMotlikuFood[i];
|
||||||
clientData.menus[restaurant]!.closed = true;
|
if (uMotlikuFood[i].length === 1 && uMotlikuFood[i][0].name.toLowerCase() === 'zavřeno') {
|
||||||
|
menus[i][restaurant]!.closed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Restaurants.TECHTOWER:
|
case Restaurants.TECHTOWER:
|
||||||
const techTowerFood = await getMenuTechTower(date, mock);
|
const techTowerFood = await getMenuTechTower(firstDay, mock);
|
||||||
clientData.menus[restaurant]!.food = techTowerFood;
|
for (let i = 0; i < techTowerFood.length; i++) {
|
||||||
if (techTowerFood.length === 1 && techTowerFood[0].name.toLowerCase() === 'svátek') {
|
menus[i][restaurant]!.food = techTowerFood[i];
|
||||||
clientData.menus[restaurant]!.closed = true;
|
if (techTowerFood[i].length === 1 && techTowerFood[i][0].name.toLowerCase() === 'svátek') {
|
||||||
|
menus[i][restaurant]!.closed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
storage.setData(selectedDay, clientData);
|
await storage.setData(getMenuKey(usedDate), menus);
|
||||||
}
|
}
|
||||||
return clientData.menus[restaurant]!;
|
return menus[dayOfWeekIndex][restaurant]!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inicializuje výchozí data pro předané datum, nebo dnešek, pokud není datum předáno.
|
||||||
|
*
|
||||||
|
* @param date datum
|
||||||
|
*/
|
||||||
export async function initIfNeeded(date?: Date) {
|
export async function initIfNeeded(date?: Date) {
|
||||||
const usedDate = formatDate(date ?? getToday());
|
const usedDate = formatDate(date ?? getToday());
|
||||||
const hasData = await storage.hasData(usedDate);
|
const hasData = await storage.hasData(usedDate);
|
||||||
@ -128,7 +168,7 @@ export async function initIfNeeded(date?: Date) {
|
|||||||
*/
|
*/
|
||||||
export async function removeChoices(login: string, trusted: boolean, location: Locations, date?: Date) {
|
export async function removeChoices(login: string, trusted: boolean, location: Locations, date?: Date) {
|
||||||
const selectedDay = formatDate(date ?? getToday());
|
const selectedDay = formatDate(date ?? getToday());
|
||||||
let data: ClientData = await storage.getData(selectedDay);
|
let data: DayData = await storage.getData(selectedDay);
|
||||||
validateTrusted(data, login, trusted);
|
validateTrusted(data, login, trusted);
|
||||||
if (location in data.choices) {
|
if (location in data.choices) {
|
||||||
if (login in data.choices[location]) {
|
if (login in data.choices[location]) {
|
||||||
@ -155,7 +195,7 @@ export async function removeChoices(login: string, trusted: boolean, location: L
|
|||||||
*/
|
*/
|
||||||
export async function removeChoice(login: string, trusted: boolean, location: Locations, foodIndex: number, date?: Date) {
|
export async function removeChoice(login: string, trusted: boolean, location: Locations, foodIndex: number, date?: Date) {
|
||||||
const selectedDay = formatDate(date ?? getToday());
|
const selectedDay = formatDate(date ?? getToday());
|
||||||
let data: ClientData = await storage.getData(selectedDay);
|
let data: DayData = await storage.getData(selectedDay);
|
||||||
validateTrusted(data, login, trusted);
|
validateTrusted(data, login, trusted);
|
||||||
if (location in data.choices) {
|
if (location in data.choices) {
|
||||||
if (login in data.choices[location]) {
|
if (login in data.choices[location]) {
|
||||||
@ -175,7 +215,7 @@ export async function removeChoice(login: string, trusted: boolean, location: Lo
|
|||||||
* @param login login uživatele
|
* @param login login uživatele
|
||||||
*/
|
*/
|
||||||
async function removeChoiceIfPresent(login: string, date: string) {
|
async function removeChoiceIfPresent(login: string, date: string) {
|
||||||
let data: ClientData = await storage.getData(date);
|
let data: DayData = await storage.getData(date);
|
||||||
for (const key of Object.keys(data.choices)) {
|
for (const key of Object.keys(data.choices)) {
|
||||||
if (login in data.choices[key]) {
|
if (login in data.choices[key]) {
|
||||||
delete data.choices[key][login];
|
delete data.choices[key][login];
|
||||||
@ -222,9 +262,10 @@ function validateTrusted(data: ClientData, login: string, trusted: boolean) {
|
|||||||
* @returns aktuální data
|
* @returns aktuální data
|
||||||
*/
|
*/
|
||||||
export async function addChoice(login: string, trusted: boolean, location: Locations, foodIndex?: number, date?: Date) {
|
export async function addChoice(login: string, trusted: boolean, location: Locations, foodIndex?: number, date?: Date) {
|
||||||
await initIfNeeded();
|
const usedDate = date ?? getToday();
|
||||||
const selectedDate = formatDate(date ?? getToday());
|
await initIfNeeded(usedDate);
|
||||||
let data: ClientData = await storage.getData(selectedDate);
|
const selectedDate = formatDate(usedDate);
|
||||||
|
let data: DayData = await storage.getData(selectedDate);
|
||||||
validateTrusted(data, login, trusted);
|
validateTrusted(data, login, trusted);
|
||||||
// Pokud měníme pouze lokaci, mažeme případné předchozí
|
// Pokud měníme pouze lokaci, mažeme případné předchozí
|
||||||
if (foodIndex == null) {
|
if (foodIndex == null) {
|
||||||
@ -255,7 +296,7 @@ export async function addChoice(login: string, trusted: boolean, location: Locat
|
|||||||
*/
|
*/
|
||||||
export async function updateDepartureTime(login: string, time?: string, date?: Date) {
|
export async function updateDepartureTime(login: string, time?: string, date?: Date) {
|
||||||
const selectedDate = formatDate(date ?? getToday());
|
const selectedDate = formatDate(date ?? getToday());
|
||||||
let clientData: ClientData = await storage.getData(selectedDate);
|
let clientData: DayData = await storage.getData(selectedDate);
|
||||||
const found = Object.values(clientData.choices).find(location => login in location);
|
const found = Object.values(clientData.choices).find(location => login in location);
|
||||||
// TODO validace, že se jedná o restauraci
|
// TODO validace, že se jedná o restauraci
|
||||||
if (found) {
|
if (found) {
|
||||||
|
@ -39,6 +39,29 @@ export function getIsWeekend(date: Date) {
|
|||||||
return index == 5 || index == 6;
|
return index == 5 || index == 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Vrátí první pracovní den v týdnu předaného data. */
|
||||||
|
export function getFirstWorkDayOfWeek(date: Date) {
|
||||||
|
const firstDay = new Date(date.getTime());
|
||||||
|
firstDay.setDate(date.getDate() - getDayOfWeekIndex(date));
|
||||||
|
return firstDay;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Vrátí poslední pracovní den v týdnu předaného data. */
|
||||||
|
export function getLastWorkDayOfWeek(date: Date) {
|
||||||
|
const lastDay = new Date(date.getTime());
|
||||||
|
lastDay.setDate(date.getDate() + (4 - getDayOfWeekIndex(date)));
|
||||||
|
return lastDay;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Vrátí pořadové číslo týdne předaného data v roce dle ISO 8601. */
|
||||||
|
export function getWeekNumber(inputDate: Date) {
|
||||||
|
var date = new Date(inputDate.getTime());
|
||||||
|
date.setHours(0, 0, 0, 0);
|
||||||
|
date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7);
|
||||||
|
var week1 = new Date(date.getFullYear(), 0, 4);
|
||||||
|
return 1 + Math.round(((date.getTime() - week1.getTime()) / 86400000 - 3 + (week1.getDay() + 6) % 7) / 7);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Vrátí JWT token z hlaviček, pokud ho obsahují.
|
* Vrátí JWT token z hlaviček, pokud ho obsahují.
|
||||||
*
|
*
|
||||||
|
@ -67,24 +67,36 @@ interface PizzaDay {
|
|||||||
orders: Order[], // seznam objednávek jednotlivých lidí
|
orders: Order[], // seznam objednávek jednotlivých lidí
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Veškerá data pro zobrazení na klientovi */
|
/** Týdenní menu jednotlivých restaurací. */
|
||||||
export interface ClientData {
|
export interface WeekMenu {
|
||||||
date: string, // datum vybraného dne pro zobrazení
|
[dayIndex: number]: {
|
||||||
isWeekend: boolean, // příznak, zda je zvolené datum víkend
|
[restaurant in Restaurants]?: DayMenu
|
||||||
weekIndex: number, // index zvoleného dne v týdnu (0-6)
|
}
|
||||||
todayWeekIndex?: number, // index dnešního dne v týdnu (0-6)
|
}
|
||||||
choices: Choices, // seznam voleb
|
|
||||||
|
/** Data vztahující se k jednomu konkrétnímu dni. */
|
||||||
|
export interface DayData {
|
||||||
|
date: string, // datum dne
|
||||||
|
isWeekend: boolean, // příznak, zda je datum víkend
|
||||||
|
weekIndex: number, // index dne v týdnu (0-6)
|
||||||
|
choices: Choices, // seznam voleb uživatelů
|
||||||
|
// TODO smazat
|
||||||
departureTimes: DepartureTime[], // seznam možných časů odchodu
|
departureTimes: DepartureTime[], // seznam možných časů odchodu
|
||||||
menus?: { [restaurant in Restaurants]?: Menu }, // menu jednotlivých restaurací
|
menus?: { [restaurant in Restaurants]?: DayMenu }, // menu jednotlivých restaurací
|
||||||
pizzaDay?: PizzaDay, // pizza day pro dnešní den, pokud existuje
|
pizzaDay?: PizzaDay, // pizza day pro dnešní den, pokud existuje
|
||||||
pizzaList?: Pizza[], // seznam dostupných pizz pro dnešní den
|
pizzaList?: Pizza[], // seznam dostupných pizz pro dnešní den
|
||||||
pizzaListLastUpdate?: Date, // datum a čas poslední aktualizace pizz
|
pizzaListLastUpdate?: Date, // datum a čas poslední aktualizace pizz
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Nabídka jídel jednoho podniku. */
|
/** Veškerá data pro zobrazení na klientovi. */
|
||||||
export interface Menu {
|
export interface ClientData extends DayData {
|
||||||
|
todayWeekIndex?: number, // index dnešního dne v týdnu (0-6)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Nabídka jídel jednoho podniku pro jeden konkrétní den. */
|
||||||
|
export interface DayMenu {
|
||||||
lastUpdate: string, // human-readable čas poslední aktualizace menu
|
lastUpdate: string, // human-readable čas poslední aktualizace menu
|
||||||
closed: boolean, // příznak, zda je daný podnik aktuálně zavřený
|
closed: boolean, // příznak, zda je daný podnik v tento den zavřený
|
||||||
food: Food[], // seznam jídel v menu
|
food: Food[], // seznam jídel v menu
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user