NOMERGE: Přenos změn

This commit is contained in:
Martin Berka 2023-07-23 22:12:47 +02:00
parent bc6035862a
commit b1138bc104
5 changed files with 149 additions and 66 deletions

View File

@ -60,8 +60,17 @@ export const finishDelivery = async (bankAccount?: string, bankAccountHolder?: s
return await api.post<any, any>('/api/finishDelivery', JSON.stringify({ bankAccount, bankAccountHolder })); return await api.post<any, any>('/api/finishDelivery', JSON.stringify({ bankAccount, bankAccountHolder }));
} }
export const updateChoice = async (choice: number | null) => { // TODO smazat
return await api.post<any, any>('/api/updateChoice', JSON.stringify({ choice })); // export const updateChoice = async (choice: number | null) => {
// return await api.post<any, any>('/api/updateChoice', JSON.stringify({ choice }));
// }
export const addChoice = async (locationIndex: number) => {
return await api.post<any, any>('/api/addChoice', JSON.stringify({ locationIndex }));
}
export const removeChoices = async (location: Location) => {
return await api.post<any, any>('/api/removeChoices', JSON.stringify({ location }));
} }
export const addPizza = async (pizzaIndex: number, pizzaSizeIndex: number) => { export const addPizza = async (pizzaIndex: number, pizzaSizeIndex: number) => {

View File

@ -1,7 +1,7 @@
import React, { useContext, useEffect, useMemo, useRef, useState } from 'react'; import React, { useContext, useEffect, useMemo, useRef, useState } from 'react';
import 'bootstrap/dist/css/bootstrap.min.css'; import 'bootstrap/dist/css/bootstrap.min.css';
import { EVENT_DISCONNECT, EVENT_MESSAGE, SocketContext } from './context/socket'; 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 { useAuth } from './context/auth';
import Login from './Login'; import Login from './Login';
import { Alert, Button, Col, Form, Row, Table } from 'react-bootstrap'; import { Alert, Button, Col, Form, Row, Table } from 'react-bootstrap';
@ -74,14 +74,15 @@ function App() {
return return
} }
// TODO tohle občas náhodně nezafunguje, nutno přepsat, viz https://medium.com/@teh_builder/ref-objects-inside-useeffect-hooks-eb7c15198780 // 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) { // TODO nutno opravit
for (let entry of Object.entries(data.choices)) { // if (data?.choices && choiceRef.current) {
if (entry[1].includes(auth.login)) { // for (let entry of Object.entries(data.choices)) {
const value = entry[0] as any as number; // TODO tohle je absurdní // if (entry[1].includes(auth.login)) {
choiceRef.current.value = Object.values(Locations)[value]; // const value = entry[0] as any as number; // TODO tohle je absurdní
} // choiceRef.current.value = Object.values(Locations)[value];
} // }
} // }
// }
}, [auth, auth?.login, data?.choices]) }, [auth, auth?.login, data?.choices])
// Reference na mojí objednávku // Reference na mojí objednávku
@ -92,16 +93,21 @@ function App() {
} }
}, [auth?.login, data?.pizzaDay?.orders]) }, [auth?.login, data?.pizzaDay?.orders])
// TODO přejmenovat na addChoice
const changeChoice = async (event: React.ChangeEvent<HTMLSelectElement>) => { const changeChoice = async (event: React.ChangeEvent<HTMLSelectElement>) => {
const index = Object.values(Locations).indexOf(event.target.value as unknown as Locations); 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) { if (auth?.login) {
await updateChoice(index > -1 ? index : null); await addChoice(index);
} }
} }
const removeChoice = async (key: string) => { const removeChoice = async (key: string) => {
if (auth?.login) { 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) { if (choiceRef?.current?.value) {
choiceRef.current.value = ""; choiceRef.current.value = "";
} }
@ -237,19 +243,22 @@ function App() {
{Object.keys(data.choices).length > 0 ? {Object.keys(data.choices).length > 0 ?
<Table striped bordered hover className='results-table mt-5'> <Table striped bordered hover className='results-table mt-5'>
<tbody> <tbody>
{Object.keys(data.choices).map((key: string, index: number) => {Object.keys(data.choices).map((key: string, index: number) => {
<tr key={index}> console.log("Rendering for key", key)
<td>{Object.values(Locations)[Number(key)]}</td> return (
<td> <tr key={index}>
<ul> <td>{Object.values(Locations)[Number(key)]}</td>
{data.choices[Number(key)].map((p: string, index: number) => <td>
<li key={index}>{p} {p === auth.login && <FontAwesomeIcon onClick={() => { <ul>
removeChoice(key); {/* {data.choices[Number(key)].map((p: string, index: number) =>
}} title='Odstranit' className='trash-icon' icon={faTrashCan} />}</li> <li key={index}>{p} {p === auth.login && <FontAwesomeIcon onClick={() => {
)} removeChoice(key);
</ul> }} title='Odstranit' className='trash-icon' icon={faTrashCan} />}</li>
</td> )} */}
</tr> </ul>
</td>
</tr>)
}
)} )}
</tbody> </tbody>
</Table> </Table>

View File

@ -3,13 +3,13 @@ import { Server } from "socket.io";
import bodyParser from "body-parser"; import bodyParser from "body-parser";
import { fetchPizzy } from "./chefie"; import { fetchPizzy } from "./chefie";
import cors from 'cors'; 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 dotenv from 'dotenv';
import path from 'path'; import path from 'path';
import { getMenuSladovnicka, getMenuTechTower, getMenuUMotliku } from "./restaurants"; import { getMenuSladovnicka, getMenuTechTower, getMenuUMotliku } from "./restaurants";
import { getQr } from "./qr"; import { getQr } from "./qr";
import { generateToken, getLogin, verify } from "./auth"; import { generateToken, getLogin, verify } from "./auth";
import { Restaurants } from "../../types"; import { Locations, Restaurants } from "../../types";
const ENVIRONMENT = process.env.NODE_ENV || 'production'; const ENVIRONMENT = process.env.NODE_ENV || 'production';
dotenv.config({ path: path.resolve(__dirname, `./.env.${ENVIRONMENT}`) }); dotenv.config({ path: path.resolve(__dirname, `./.env.${ENVIRONMENT}`) });
@ -35,6 +35,15 @@ app.use(cors({
origin: '*' 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')) app.use(express.static('public'))
const parseToken = (req: any) => { const parseToken = (req: any) => {
@ -195,35 +204,47 @@ app.post("/api/finishDelivery", (req, res) => {
io.emit("message", data); io.emit("message", data);
res.status(200).json({}); 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); res.status(200).json(data);
}); });
app.post("/api/updateNote", (req, res) => { app.post("/api/removeChoices", (req, res) => {
const login = getLogin(parseToken(req)); const login = getLogin(parseToken(req));
if (req.body.note && req.body.note.length > 100) { console.log("Remove choices", req.body.location); // TODO smazat
throw Error("Poznámka může mít maximálně 100 znaků"); const data = removeChoices(login, req.body.location);
} io.emit("message", data);
const data = updateNote(login, req.body.note); res.status(200).json(data);
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", () => { app.post("/api/removeChoice", (req, res) => {
console.log(`Client disconnected: ${socket.id}`); 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 PORT = process.env.PORT || 3001;
const HOST = process.env.HOST || '0.0.0.0'; const HOST = process.env.HOST || '0.0.0.0';

View File

@ -239,34 +239,75 @@ export function initIfNeeded() {
} }
} }
export function removeChoice(login: string, data: ClientData) { /**
for (let key of Object.keys(data.choices)) { * Odstraní kompletně volbu uživatele (včetně případných podřízených jídel).
if (data.choices[key] && data.choices[key].includes(login)) { *
const index = data.choices[key].indexOf(login); * @param login login uživatele
data.choices[key].splice(index, 1); * @param location vybrané "umístění"
if (data.choices[key].length == 0) { * @returns
delete data.choices[key]; */
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; 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(); initIfNeeded();
const today = formatDate(getToday()); const today = formatDate(getToday());
let data: ClientData = db.get(today); let data: ClientData = db.get(today);
data = removeChoice(login, data); if (!(location in data.choices)) {
if (choice !== null) { data.choices[location] = {};
if (!data.choices?.[choice]) { }
data.choices[choice] = []; if (!(login in data.choices[location])) {
} data.choices[location][login] = [];
data.choices[choice].push(login); }
if (foodIndex != null && !data.choices[location][login].includes(foodIndex)) {
data.choices[location][login].push(foodIndex);
} }
db.set(today, data); db.set(today, data);
return data; return data;
} }
// TODO přejmenovat, ať je jasné že to patří k pizza day
export function updateNote(login: string, note?: string) { export function updateNote(login: string, note?: string) {
const today = formatDate(getToday()); const today = formatDate(getToday());
let clientData: ClientData = db.get(today); let clientData: ClientData = db.get(today);

View File

@ -6,7 +6,9 @@ export enum Restaurants {
} }
export interface Choices { export interface Choices {
[location: string]: string[], [location: string]: {
[login: string]: number[]
},
} }
/** Velikost konkrétní pizzy */ /** Velikost konkrétní pizzy */
@ -74,6 +76,7 @@ export interface Food {
isSoup: boolean, // příznak, zda se jedná o polévku 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 { export enum Locations {
SLADOVNICKA = 'Sladovnická', SLADOVNICKA = 'Sladovnická',
UMOTLIKU = 'U Motlíků', UMOTLIKU = 'U Motlíků',