From b1138bc104ff423658f80de6159d775294cbcd14 Mon Sep 17 00:00:00 2001 From: Martin Berka Date: Sun, 23 Jul 2023 22:12:47 +0200 Subject: [PATCH] =?UTF-8?q?NOMERGE:=20P=C5=99enos=20zm=C4=9Bn?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/Api.ts | 13 ++++++-- client/src/App.tsx | 57 +++++++++++++++++++--------------- server/src/index.ts | 71 ++++++++++++++++++++++++++++--------------- server/src/service.ts | 69 ++++++++++++++++++++++++++++++++--------- types/Types.ts | 5 ++- 5 files changed, 149 insertions(+), 66 deletions(-) diff --git a/client/src/Api.ts b/client/src/Api.ts index 2f330a5..317727d 100644 --- a/client/src/Api.ts +++ b/client/src/Api.ts @@ -60,8 +60,17 @@ export const finishDelivery = async (bankAccount?: string, bankAccountHolder?: s return await api.post('/api/finishDelivery', JSON.stringify({ bankAccount, bankAccountHolder })); } -export const updateChoice = async (choice: number | null) => { - return await api.post('/api/updateChoice', JSON.stringify({ choice })); +// TODO smazat +// export const updateChoice = async (choice: number | null) => { +// return await api.post('/api/updateChoice', JSON.stringify({ choice })); +// } + +export const addChoice = async (locationIndex: number) => { + return await api.post('/api/addChoice', JSON.stringify({ locationIndex })); +} + +export const removeChoices = async (location: Location) => { + return await api.post('/api/removeChoices', JSON.stringify({ location })); } export const addPizza = async (pizzaIndex: number, pizzaSizeIndex: number) => { diff --git a/client/src/App.tsx b/client/src/App.tsx index 31bc5dc..ccf622f 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,7 +1,7 @@ import React, { useContext, useEffect, useMemo, useRef, useState } from 'react'; import 'bootstrap/dist/css/bootstrap.min.css'; import { EVENT_DISCONNECT, EVENT_MESSAGE, SocketContext } from './context/socket'; -import { addPizza, createPizzaDay, deletePizzaDay, finishDelivery, finishOrder, getData, getFood, getPizzy, getQrUrl, lockPizzaDay, removePizza, unlockPizzaDay, updateChoice, updateNote } from './Api'; +import { addChoice, addPizza, createPizzaDay, deletePizzaDay, finishDelivery, finishOrder, getData, getFood, getPizzy, getQrUrl, lockPizzaDay, removeChoices, removePizza, unlockPizzaDay, updateNote } from './Api'; import { useAuth } from './context/auth'; import Login from './Login'; import { Alert, Button, Col, Form, Row, Table } from 'react-bootstrap'; @@ -74,14 +74,15 @@ function App() { return } // TODO tohle občas náhodně nezafunguje, nutno přepsat, viz https://medium.com/@teh_builder/ref-objects-inside-useeffect-hooks-eb7c15198780 - if (data?.choices && choiceRef.current) { - for (let entry of Object.entries(data.choices)) { - if (entry[1].includes(auth.login)) { - const value = entry[0] as any as number; // TODO tohle je absurdní - choiceRef.current.value = Object.values(Locations)[value]; - } - } - } + // TODO nutno opravit + // if (data?.choices && choiceRef.current) { + // for (let entry of Object.entries(data.choices)) { + // if (entry[1].includes(auth.login)) { + // const value = entry[0] as any as number; // TODO tohle je absurdní + // choiceRef.current.value = Object.values(Locations)[value]; + // } + // } + // } }, [auth, auth?.login, data?.choices]) // Reference na mojí objednávku @@ -92,16 +93,21 @@ function App() { } }, [auth?.login, data?.pizzaDay?.orders]) + // TODO přejmenovat na addChoice const changeChoice = async (event: React.ChangeEvent) => { const index = Object.values(Locations).indexOf(event.target.value as unknown as Locations); + console.log("Target value", event.target.value) + console.log("Change choices called with index", index); + // TODO implementovat if (auth?.login) { - await updateChoice(index > -1 ? index : null); + await addChoice(index); } } const removeChoice = async (key: string) => { if (auth?.login) { - await updateChoice(null); + console.log("Remove choice called with key", key) + // await removeChoices(key); // TODO tohle je určitě blbě if (choiceRef?.current?.value) { choiceRef.current.value = ""; } @@ -237,19 +243,22 @@ function App() { {Object.keys(data.choices).length > 0 ? - {Object.keys(data.choices).map((key: string, index: number) => - - - - + {Object.keys(data.choices).map((key: string, index: number) => { + console.log("Rendering for key", key) + return ( + + + + ) + } )}
{Object.values(Locations)[Number(key)]} -
    - {data.choices[Number(key)].map((p: string, index: number) => -
  • {p} {p === auth.login && { - removeChoice(key); - }} title='Odstranit' className='trash-icon' icon={faTrashCan} />}
  • - )} -
-
{Object.values(Locations)[Number(key)]} +
    + {/* {data.choices[Number(key)].map((p: string, index: number) => +
  • {p} {p === auth.login && { + removeChoice(key); + }} title='Odstranit' className='trash-icon' icon={faTrashCan} />}
  • + )} */} +
+
diff --git a/server/src/index.ts b/server/src/index.ts index 94373d1..f874a71 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -3,13 +3,13 @@ import { Server } from "socket.io"; import bodyParser from "body-parser"; import { fetchPizzy } from "./chefie"; import cors from 'cors'; -import { addPizzaOrder, createPizzaDay, deletePizzaDay, finishPizzaDelivery, finishPizzaOrder, getData, lockPizzaDay, removePizzaOrder, unlockPizzaDay, updateChoice, updateNote } from "./service"; +import { addChoice, addPizzaOrder, createPizzaDay, deletePizzaDay, finishPizzaDelivery, finishPizzaOrder, getData, lockPizzaDay, removeChoice, removeChoices, removePizzaOrder, unlockPizzaDay, updateNote } from "./service"; import dotenv from 'dotenv'; import path from 'path'; import { getMenuSladovnicka, getMenuTechTower, getMenuUMotliku } from "./restaurants"; import { getQr } from "./qr"; import { generateToken, getLogin, verify } from "./auth"; -import { Restaurants } from "../../types"; +import { Locations, Restaurants } from "../../types"; const ENVIRONMENT = process.env.NODE_ENV || 'production'; dotenv.config({ path: path.resolve(__dirname, `./.env.${ENVIRONMENT}`) }); @@ -35,6 +35,15 @@ app.use(cors({ origin: '*' })); +// app.use((req, res, next) => { +// console.log("--- Request ---") +// console.log(req.url); +// console.log(req.baseUrl); +// console.log(req.originalUrl); +// console.log(req.path); +// next(); +// }); + app.use(express.static('public')) const parseToken = (req: any) => { @@ -195,35 +204,47 @@ app.post("/api/finishDelivery", (req, res) => { io.emit("message", data); res.status(200).json({}); }); - -app.post("/api/updateChoice", (req, res) => { - const login = getLogin(parseToken(req)); - const data = updateChoice(login, req.body.choice); - io.emit("message", data); +[ res.status(200).json(data); }); -app.post("/api/updateNote", (req, res) => { - const login = getLogin(parseToken(req)); - if (req.body.note && req.body.note.length > 100) { - throw Error("Poznámka může mít maximálně 100 znaků"); - } - const data = updateNote(login, req.body.note); - io.emit("message", data); - res.status(200).json(data); -}); - -io.on("connection", (socket) => { - console.log(`New client connected: ${socket.id}`); - - socket.on("message", (message) => { - io.emit("message", message); + app.post("/api/removeChoices", (req, res) => { + const login = getLogin(parseToken(req)); + console.log("Remove choices", req.body.location); // TODO smazat + const data = removeChoices(login, req.body.location); + io.emit("message", data); + res.status(200).json(data); }); - socket.on("disconnect", () => { - console.log(`Client disconnected: ${socket.id}`); + app.post("/api/removeChoice", (req, res) => { + const login = getLogin(parseToken(req)); + console.log("Remove choice", req.body.location, req.body.foodIndex); // TODO smazat + const data = removeChoice(login, req.body.location, req.body.foodIndex); + io.emit("message", data); + res.status(200).json(data); + }); + + app.post("/api/updateNote", (req, res) => { + const login = getLogin(parseToken(req)); + if (req.body.note && req.body.note.length > 100) { + throw Error("Poznámka může mít maximálně 100 znaků"); + } + const data = updateNote(login, req.body.note); + io.emit("message", data); + res.status(200).json(data); + }); + + io.on("connection", (socket) => { + console.log(`New client connected: ${socket.id}`); + + socket.on("message", (message) => { + io.emit("message", message); + }); + + socket.on("disconnect", () => { + console.log(`Client disconnected: ${socket.id}`); + }); }); -}); const PORT = process.env.PORT || 3001; const HOST = process.env.HOST || '0.0.0.0'; diff --git a/server/src/service.ts b/server/src/service.ts index 5d45482..7464389 100644 --- a/server/src/service.ts +++ b/server/src/service.ts @@ -239,34 +239,75 @@ export function initIfNeeded() { } } -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]; +/** + * Odstraní kompletně volbu uživatele (včetně případných podřízených jídel). + * + * @param login login uživatele + * @param location vybrané "umístění" + * @returns + */ +export function removeChoices(login: string, location: Locations) { + const today = formatDate(getToday()); + let data: ClientData = db.get(today); + if (location in data.choices) { + if (login in data.choices[location]) { + delete data.choices[location][login] + if (Object.keys(data.choices[location]).length === 0) { + delete data.choices[location] } } } return data; } -export function updateChoice(login: string, choice: Locations | null) { +/** + * Odstraní konkrétní volbu jídla uživatele. + * Neodstraňuje volbu samotnou, k tomu slouží {@link removeChoices}. + * + * @param login login uživatele + * @param location vybrané "umístění" + * @param foodIndex index jídla v jídelním lístku daného umístění, pokud existuje + * @returns + */ +export function removeChoice(login: string, location: Locations, foodIndex: number) { + const today = formatDate(getToday()); + let data: ClientData = db.get(today); + if (location in data.choices) { + if (login in data.choices[location]) { + if (data.choices[location][login].includes(foodIndex)) { + data.choices[location][login].splice(foodIndex, 1) + } + } + } + return data; +} + +/** + * Přidá volbu uživatele. + * + * @param login login uživatele + * @param location vybrané "umístění" + * @param foodIndex volitelný index jídla v daném umístění + * @returns aktuální data + */ +export function addChoice(login: string, location: Locations, foodIndex?: number) { initIfNeeded(); const today = formatDate(getToday()); 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); + if (!(location in data.choices)) { + data.choices[location] = {}; + } + if (!(login in data.choices[location])) { + data.choices[location][login] = []; + } + if (foodIndex != null && !data.choices[location][login].includes(foodIndex)) { + data.choices[location][login].push(foodIndex); } db.set(today, data); return data; } +// TODO přejmenovat, ať je jasné že to patří k pizza day export function updateNote(login: string, note?: string) { const today = formatDate(getToday()); let clientData: ClientData = db.get(today); diff --git a/types/Types.ts b/types/Types.ts index 4628dd1..f259b36 100644 --- a/types/Types.ts +++ b/types/Types.ts @@ -6,7 +6,9 @@ export enum Restaurants { } export interface Choices { - [location: string]: string[], + [location: string]: { + [login: string]: number[] + }, } /** Velikost konkrétní pizzy */ @@ -74,6 +76,7 @@ export interface Food { isSoup: boolean, // příznak, zda se jedná o polévku } +// TODO tohle je dost špatné pojmenování, vzhledem k tomu co to obsahuje export enum Locations { SLADOVNICKA = 'Sladovnická', UMOTLIKU = 'U Motlíků',