Prvotní nástřel fungující aplikace

This commit is contained in:
Martin Berka
2023-06-01 23:05:51 +02:00
parent bf379e13ed
commit 12583e6efb
59 changed files with 2194 additions and 1011 deletions

View File

@@ -6,7 +6,7 @@ import fs from 'fs';
type PizzaSize = {
size: string,
pizzaPrice: string,
pizzaPrice: number,
boxPrice: number,
price: number
}
@@ -21,12 +21,15 @@ type Pizza = {
const baseUrl = 'https://www.pizzachefie.cz';
const pizzyUrl = `${baseUrl}/pizzy.html?pobocka=plzen`;
// URL na Food API - získání jídelních lístků restaurací
const foodUrl = process.env.FOOD_API_URL || 'http://localhost:3002';
const buildPizzaUrl = (pizzaUrl: string) => {
return `${baseUrl}/${pizzaUrl}`;
}
// Ceny krabic dle velikosti
const boxPrices = {
const boxPrices: { [key: string]: number } = {
"30cm": 13,
"35cm": 15,
"40cm": 18,
@@ -55,19 +58,20 @@ const downloadPizzy = async () => {
// Název
const name = $('.produkt > h2', pizzaHtml).first().text()
// Přísady
const ingredients = []
const ingredients: string[] = []
const ingredientsHtml = $('.prisady > li', pizzaHtml);
ingredientsHtml.each((i, elm) => {
ingredients.push($(elm).text());
})
// Velikosti
const sizes = [];
const sizes: PizzaSize[] = [];
const a = $('.varianty > li > a', pizzaHtml);
a.each((i, elm) => {
const size = $('span', elm).text();
const priceKc = $(elm).text().split(size).pop().trim();
const price = Number.parseInt(priceKc.split(" Kč")[0]);
sizes.push({ size: size, pizzaPrice: price, boxPrice: boxPrices[size], price: price + boxPrices[size] });
// TODO nedoděláno
// const size = $('span', elm).text();
// const priceKc = $(elm).text().split(size).pop().trim();
// const price = Number.parseInt(priceKc.split(" Kč")[0]);
// sizes.push({ size: size, pizzaPrice: price, boxPrice: boxPrices[size], price: price + boxPrices[size] });
})
result.push({
name: name,
@@ -101,6 +105,15 @@ export const fetchPizzy = async () => {
console.log(`Zapsán ${dataPath}`);
return pizzy;
}
}
// TODO tohle sem absolutně nepatří! dát do vlastní servisky!
export const fetchFood = async () => {
try {
const json = await rp(foodUrl);
return JSON.parse(json);
} catch (error) {
console.error("Chyba při volání Food API", error);
return {};
}
}

3
server/src/database.ts Normal file
View File

@@ -0,0 +1,3 @@
import JSONdb from 'simple-json-db';
export const db = new JSONdb('./data.json');

View File

@@ -1,7 +1,9 @@
import express from "express";
import { Server } from "socket.io";
import bodyParser from "body-parser";
import { fetchPizzy } from "./chefie";
import { fetchFood, fetchPizzy } from "./chefie";
import cors from 'cors';
import { getData, updateChoice } from "./service";
const app = express();
const server = require("http").createServer(app);
@@ -13,12 +15,25 @@ const io = new Server(server, {
// Body-parser middleware for parsing JSON
app.use(bodyParser.json());
// app.use(express.json());
const cors = require('cors');
app.use(cors({
origin: '*'
}));
/** Vrátí data pro aktuální den. */
app.get("/api/data", (req, res) => {
res.status(200).json(getData());
});
/** Vrátí obědové menu pro dostupné podniky. */
app.get("/api/food", (req, res) => {
fetchFood().then(food => {
res.status(200).json(food);
})
});
/** Vrátí seznam dostupných pizz. */
app.get("/api/pizza", (req, res) => {
fetchPizzy().then(pizzaList => {
console.log("Výsledek", pizzaList);
@@ -26,6 +41,30 @@ app.get("/api/pizza", (req, res) => {
});
});
// /** Založí pizza day pro aktuální den, za předpokladu že dosud neexistuje. */
// app.post("/api/createPizzaDay", (req, res) => {
// const data = createPizzaDay();
// res.status(200).json(data);
// io.emit("message", data);
// });
// /** Smaže pizza day pro aktuální den, za předpokladu že existuje. */
// app.post("/api/deletePizzaDay", (req, res) => {
// deletePizzaDay();
// io.emit("message", getData());
// });
app.post("/api/updateChoice", (req, res) => {
console.log("Změna výběru", req.body);
if (!req.body.hasOwnProperty('name')) {
res.status(400).json({});
}
const data = updateChoice(req.body.name, req.body.choice);
io.emit("message", data);
res.status(200).json(data);
});
// TODO smazat
app.post("/api/zprava", (req, res) => {
const { username, message } = req.body;
@@ -49,6 +88,7 @@ io.on("connection", (socket) => {
io.emit("message", message);
});
// TODO smazat
socket.on("jduKafe", ({ username, timeString }) => {
console.log(`Received message: ${username}`);
socket.broadcast.emit("jduKafe", `${timeString}: ${username} -> jdu Kafe`);
@@ -60,7 +100,8 @@ io.on("connection", (socket) => {
});
const PORT = process.env.PORT || 3001;
const HOST = process.env.HOST || '0.0.0.0';
server.listen(PORT, () => {
console.log(`Server listening on port ${PORT}`);
console.log(`Server listening on ${HOST}, port ${PORT}`);
});

105
server/src/service.ts Normal file
View File

@@ -0,0 +1,105 @@
import { ClientData, Locations } from "./types";
import { db } from "./database";
import { getTodayString } from "./utils";
import { getDate } from "./utils";
// /** Jedna konkrétní pizza */
// interface Pizza {
// name: string, // název pizzy
// size: number, // velikost pizzy v cm
// price: number, // cena pizzy v Kč, včetně krabice
// }
// /** Objednávka jednoho člověka */
// interface Order {
// customer: string, // název člověka
// pizzaList: Pizza[], // seznam objednaných pizz
// totalPrice: number, // celková cena všech objednaných pizz a krabic
// }
// /** Stav pizza dne. */
// enum State {
// NOT_CREATED, // Pizza day nebyl založen
// CREATED, // Pizza day je založen
// LOCKED // Objednávky uzamčeny
// }
// /** Veškerá data pro zobrazení na klientovi */
// interface ClientData {
// date: string, // dnešní datum pro zobrazení
// state: State, // stav pizza dne
// orders?: Order[], // seznam objednávek, pokud není vyplněno, není založen pizza day
// }
/** Vrátí "prázdná" (implicitní) data, pokud ještě nikdo nehlasoval. */
function getEmptyData(): ClientData {
return { date: getTodayString(), choices: {} };
}
/**
* Vrátí veškerá klientská data pro aktuální den.
*/
export function getData(): ClientData {
const data = db.get(getDate()) || getEmptyData();
console.log("Vracím data pro dnešní den", data); // TODO smazat
return data;
}
// /**
// * Vytvoří pizza day pro aktuální den a vrátí data pro klienta.
// */
// export function createPizzaDay(): ClientData {
// const today = getDate();
// if (db.has(today)) {
// throw Error("Pizza day pro dnešní den již existuje");
// }
// const data = { date: getTodayString(), state: State.CREATED, orders: [] };
// db.set(today, data);
// return data;
// }
// /**
// * Smaže pizza day pro aktuální den.
// */
// export function deletePizzaDay() {
// const today = getDate();
// if (!db.has(today)) {
// throw Error("Pizza day pro dnešní den neexistuje");
// }
// db.delete(today);
// }
export function initIfNeeded() {
const today = getDate();
if (!db.has(today)) {
db.set(today, getEmptyData());
}
}
export function removeChoice(login: string, data: ClientData) {
for (let key of Object.keys(data.choices)) {
if (data.choices[key] && data.choices[key].includes(login)) {
const index = data.choices[key].indexOf(login);
data.choices[key].splice(index, 1);
if (data.choices[key].length == 0) {
delete data.choices[key];
}
}
}
return data;
}
export function updateChoice(login: string, choice: Locations | null) {
initIfNeeded();
const today = getDate();
let data: ClientData = db.get(today);
data = removeChoice(login, data);
if (choice !== null) {
if (!data.choices?.[choice]) {
data.choices[choice] = [];
}
data.choices[choice].push(login);
}
db.set(today, data);
return data;
}

18
server/src/types.ts Normal file
View File

@@ -0,0 +1,18 @@
export interface Choices {
[location: string]: string[],
}
export interface ClientData {
date: string, // dnešní datum pro zobrazení
choices: Choices, // seznam voleb
}
export enum Locations {
SLADOVNICKA = 'Sladovnická',
UMOTLIKU = 'U Motlíků',
TECHTOWER = 'TechTower',
SPSE = 'SPŠE',
VLASTNI = 'Mám vlastní',
OBJEDNAVAM = 'Objednávám',
NEOBEDVAM = 'Neobědvám',
}

17
server/src/utils.ts Normal file
View File

@@ -0,0 +1,17 @@
export function getDate() {
const date = new Date();
let currentDay = String(date.getDate()).padStart(2, '0');
let currentMonth = String(date.getMonth() + 1).padStart(2, "0");
let currentYear = date.getFullYear();
return `${currentYear}-${currentMonth}-${currentDay}`;
}
/** Vrátí human-readable reprezentaci dnešního data pro zobrazení. */
export function getTodayString() {
const date = new Date();
let currentDay = String(date.getDate()).padStart(2, '0');
let currentMonth = String(date.getMonth() + 1).padStart(2, "0");
let currentYear = date.getFullYear();
let currentDayOfWeek = date.toLocaleDateString("CZ-cs", { weekday: 'long' });
return `${currentDay}.${currentMonth}.${currentYear} (${currentDayOfWeek})`;
}