diff --git a/README.md b/README.md index 3060e7c..b4e3f7f 100644 --- a/README.md +++ b/README.md @@ -7,11 +7,20 @@ Server je v adresáři /server, client v adresáři /client obojí lze spustit p ### `yarn start` ## TODO -- Předvyplnění poslední vybrané hodnoty občas nefunguje, viz komentář -- [x] Umožnit smazání aktuální volby "popelnicí", místo nutnosti vybrat prázdnou položku v selectu -- Popsat Food API, nginx -- Popsat spuštění pro vývoj +- [x] Umožnit smazání aktuální volby "popelnicí", místo nutnosti vybrat prázdnou položku v selectu +- [x] Přívětivější možnost odhlašování +- [x] Vyřešit responzivní design pro použití na mobilu - [x] Vyndat URL na Food API do .env -- Neselhat při nedostupnosti nebo chybě z Food API +- [x] Neselhat při nedostupnosti nebo chybě z Food API - [x] Dokončit docker-compose pro kompletní funkčnost -- Implementovat pizza day \ No newline at end of file +- [x] Implementovat základ pro pizza day + - [ ] Umožnit uzamčení objednávek zakladatelem + - [ ] Možnost uložení čísla účtu + - [ ] Automatické generování a zobrazení QR kódů + - [ ] Zobrazovat celkovou cenu +- [ ] Zobrazit upozornění před smazáním pizza day +- [ ] Předvyplnění poslední vybrané hodnoty občas nefunguje, viz komentář +- [ ] Nasazení nové verze v Docker smaže veškerá data (protože data.json není venku) +- [ ] Popsat Food API, nginx +- [ ] Popsat závislosti a postup spuštění pro vývoj +- [ ] Popsat dostupné env \ No newline at end of file diff --git a/client/src/Api.ts b/client/src/Api.ts index efb21c2..8dfe2c1 100644 --- a/client/src/Api.ts +++ b/client/src/Api.ts @@ -1,12 +1,4 @@ -// type Pizza = { -// name: string; -// // TODO ingredience -// sizes: [ -// size: number, -// price: number, -// ]; -// } - +import { PizzaOrder } from "./Types"; import { getBaseUrl } from "./Utils"; async function request( @@ -52,4 +44,8 @@ export const updateChoice = async (name: string, choice: number | null) => { export const addPizza = async (login: string, pizzaIndex: number, pizzaSizeIndex: number) => { return await api.post('/api/addPizza', JSON.stringify({ login, pizzaIndex, pizzaSizeIndex })); +} + +export const removePizza = async (login: string, pizzaOrder: PizzaOrder) => { + return await api.post('/api/removePizza', JSON.stringify({ login, pizzaOrder })); } \ No newline at end of file diff --git a/client/src/App.tsx b/client/src/App.tsx index 3aa10a7..7527aaa 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,10 +1,10 @@ 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, getData, getFood, getPizzy, updateChoice } from './Api'; +import { addPizza, createPizzaDay, deletePizzaDay, getData, getFood, getPizzy, removePizza, updateChoice } from './Api'; import { useAuth } from './context/auth'; import Login from './Login'; -import { Locations, ClientData, Pizza } from './Types'; +import { Locations, ClientData, Pizza, PizzaOrder } from './Types'; import { Alert, Button, Col, Form, Row, Table } from 'react-bootstrap'; import Header from './components/Header'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' @@ -99,29 +99,33 @@ function App() { } const suggestions: SelectSearchOption[] = []; pizzy.forEach((pizza, index) => { + const group: SelectSearchOption = { name: pizza.name, type: "group", items: [] } pizza.sizes.forEach((size, sizeIndex) => { - const name = `${pizza.name}, ${size.size} (${size.price} Kč)`; + const name = `${size.size} (${size.price} Kč)`; const value = `${index}|${sizeIndex}`; - suggestions.push({ name, value }); + group.items?.push({ name, value }); }) + suggestions.push(group); }) return suggestions; }, [pizzy]); const handlePizzaChange = async (value) => { - console.log("Pizza vybrána", value); if (auth?.login && pizzy) { const s = value.split('|'); const pizzaIndex = Number.parseInt(s[0]); const pizzaSizeIndex = Number.parseInt(s[1]); const pizza = pizzy[pizzaIndex]; - const size = pizza.sizes[pizzaSizeIndex]; - // TODO smazat - console.log("Vybraná pizza a velikost", pizza, size); await addPizza(auth.login, pizzaIndex, pizzaSizeIndex); } } + const handlePizzaDelete = (pizzaOrder: PizzaOrder) => { + if (auth?.login) { + removePizza(auth?.login, pizzaOrder); + } + } + const renderFoodTable = (name, food) => { return

{name}

@@ -200,29 +204,35 @@ function App() { :
Zatím nikdo nehlasoval...
} - {!data.pizzaDay && -
-

Pro dnešní den není aktuálně založen Pizza day.

- -
- } - {data.pizzaDay &&
-

Pizza Day je založen uživatelem {data.pizzaDay.creator}

- { - data.pizzaDay.creator === auth.login && +
+ {!data.pizzaDay && +
+

Pro dnešní den není aktuálně založen Pizza day.

+ +
} - - -
} + {data.pizzaDay && +
+
+

Pizza Day je založen uživatelem {data.pizzaDay.creator}

+ { + data.pizzaDay.creator === auth.login && + } +
+ + +
+ } +
} diff --git a/client/src/Types.tsx b/client/src/Types.tsx index f971e06..ae5caf4 100644 --- a/client/src/Types.tsx +++ b/client/src/Types.tsx @@ -14,10 +14,17 @@ export interface Pizza { sizes: PizzaSize[], // dostupné velikosti pizzy } -/** Jedna objednávka v rámci Pizza day */ +/** Objednávka jedné konkrétní pizzy */ +export interface PizzaOrder { + name: string, // název pizzy + size: string, // velikost pizzy jako string (30cm) + price: number, // cena pizzy v Kč, včetně krabice +} + +/** Celková objednávka jednoho člověka */ export interface Order { - customer: string, // název člověka - pizzaList: Pizza[], // seznam objednaných pizz + customer: string, // jméno objednatele + pizzaList: PizzaOrder[], // seznam objednaných pizz totalPrice: number, // celková cena všech objednaných pizz a krabic } diff --git a/client/src/components/PizzaOrderList.tsx b/client/src/components/PizzaOrderList.tsx index 3afadd4..a268671 100644 --- a/client/src/components/PizzaOrderList.tsx +++ b/client/src/components/PizzaOrderList.tsx @@ -1,21 +1,36 @@ import React from "react"; import { Table } from "react-bootstrap"; -import { Order } from "../Types"; +import { Order, PizzaOrder } from "../Types"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faTrashCan } from "@fortawesome/free-regular-svg-icons"; +import { useAuth } from "../context/auth"; + +export default function PizzaOrderList({ orders, onDelete }: { orders: Order[], onDelete: (pizzaOrder: PizzaOrder) => void }) { + const auth = useAuth(); -export default function PizzaOrderList({ orders }: { orders: Order[] }) { return - - + + - {orders.map(order => - + {orders.map(order => - + + )}
Pizza JménoCena (Kč)ObjednávkaCelkem
{order.pizzaList[0].name}
{order.customer}{order.totalPrice}{order.pizzaList.map((pizzaOrder, index) => + + {`${pizzaOrder.name}, ${pizzaOrder.size} (${pizzaOrder.price} Kč)`} + {auth?.login === order.customer && + { + onDelete(pizzaOrder); + }} title='Odstranit' className='trash-icon' icon={faTrashCan} /> + } + ) + .reduce((prev, curr) => [prev,
, curr])} +
{order.totalPrice} Kč
diff --git a/client/yarn.lock b/client/yarn.lock index d5446c3..e833e2b 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -2342,14 +2342,14 @@ "@types/yargs-parser" "*" "@typescript-eslint/eslint-plugin@^5.5.0": - version "5.59.8" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.8.tgz#1e7a3e5318ece22251dfbc5c9c6feeb4793cc509" - integrity sha512-JDMOmhXteJ4WVKOiHXGCoB96ADWg9q7efPWHRViT/f09bA8XOMLAVHHju3l0MkZnG1izaWXYmgvQcUjTRcpShQ== + version "5.59.9" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.9.tgz#2604cfaf2b306e120044f901e20c8ed926debf15" + integrity sha512-4uQIBq1ffXd2YvF7MAvehWKW3zVv/w+mSfRAu+8cKbfj3nwzyqJLNcZJpQ/WZ1HLbJDiowwmQ6NO+63nCA+fqA== dependencies: "@eslint-community/regexpp" "^4.4.0" - "@typescript-eslint/scope-manager" "5.59.8" - "@typescript-eslint/type-utils" "5.59.8" - "@typescript-eslint/utils" "5.59.8" + "@typescript-eslint/scope-manager" "5.59.9" + "@typescript-eslint/type-utils" "5.59.9" + "@typescript-eslint/utils" "5.59.9" debug "^4.3.4" grapheme-splitter "^1.0.4" ignore "^5.2.0" @@ -2358,78 +2358,78 @@ tsutils "^3.21.0" "@typescript-eslint/experimental-utils@^5.0.0": - version "5.59.8" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.59.8.tgz#21d20f3b657f8dbd237887d9bbb40bf1b5b38cd0" - integrity sha512-jAf+hihtd0G2RLB9x796+3i8D0L5T5xjftuPpJ82RLsPNHdzGXmbZNNftQ558h90ogc45DD8/W3OrxmdSO5Nng== + version "5.59.9" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.59.9.tgz#e77482a8b70f1a6aa3a1c6a128be4a5e0e6db940" + integrity sha512-eZTK/Ci0QAqNc/q2MqMwI2+QI5ZI9HM12FcfGwbEvKif5ev/CIIYLmrlckvgPrC8XSbl39HtErR5NJiQkRkvWg== dependencies: - "@typescript-eslint/utils" "5.59.8" + "@typescript-eslint/utils" "5.59.9" "@typescript-eslint/parser@^5.5.0": - version "5.59.8" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.59.8.tgz#60cbb00671d86cf746044ab797900b1448188567" - integrity sha512-AnR19RjJcpjoeGojmwZtCwBX/RidqDZtzcbG3xHrmz0aHHoOcbWnpDllenRDmDvsV0RQ6+tbb09/kyc+UT9Orw== + version "5.59.9" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.59.9.tgz#a85c47ccdd7e285697463da15200f9a8561dd5fa" + integrity sha512-FsPkRvBtcLQ/eVK1ivDiNYBjn3TGJdXy2fhXX+rc7czWl4ARwnpArwbihSOHI2Peg9WbtGHrbThfBUkZZGTtvQ== dependencies: - "@typescript-eslint/scope-manager" "5.59.8" - "@typescript-eslint/types" "5.59.8" - "@typescript-eslint/typescript-estree" "5.59.8" + "@typescript-eslint/scope-manager" "5.59.9" + "@typescript-eslint/types" "5.59.9" + "@typescript-eslint/typescript-estree" "5.59.9" debug "^4.3.4" -"@typescript-eslint/scope-manager@5.59.8": - version "5.59.8" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.59.8.tgz#ff4ad4fec6433647b817c4a7d4b4165d18ea2fa8" - integrity sha512-/w08ndCYI8gxGf+9zKf1vtx/16y8MHrZs5/tnjHhMLNSixuNcJavSX4wAiPf4aS5x41Es9YPCn44MIe4cxIlig== +"@typescript-eslint/scope-manager@5.59.9": + version "5.59.9" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.59.9.tgz#eadce1f2733389cdb58c49770192c0f95470d2f4" + integrity sha512-8RA+E+w78z1+2dzvK/tGZ2cpGigBZ58VMEHDZtpE1v+LLjzrYGc8mMaTONSxKyEkz3IuXFM0IqYiGHlCsmlZxQ== dependencies: - "@typescript-eslint/types" "5.59.8" - "@typescript-eslint/visitor-keys" "5.59.8" + "@typescript-eslint/types" "5.59.9" + "@typescript-eslint/visitor-keys" "5.59.9" -"@typescript-eslint/type-utils@5.59.8": - version "5.59.8" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.59.8.tgz#aa6c029a9d7706d26bbd25eb4666398781df6ea2" - integrity sha512-+5M518uEIHFBy3FnyqZUF3BMP+AXnYn4oyH8RF012+e7/msMY98FhGL5SrN29NQ9xDgvqCgYnsOiKp1VjZ/fpA== +"@typescript-eslint/type-utils@5.59.9": + version "5.59.9" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.59.9.tgz#53bfaae2e901e6ac637ab0536d1754dfef4dafc2" + integrity sha512-ksEsT0/mEHg9e3qZu98AlSrONAQtrSTljL3ow9CGej8eRo7pe+yaC/mvTjptp23Xo/xIf2mLZKC6KPv4Sji26Q== dependencies: - "@typescript-eslint/typescript-estree" "5.59.8" - "@typescript-eslint/utils" "5.59.8" + "@typescript-eslint/typescript-estree" "5.59.9" + "@typescript-eslint/utils" "5.59.9" debug "^4.3.4" tsutils "^3.21.0" -"@typescript-eslint/types@5.59.8": - version "5.59.8" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.8.tgz#212e54414733618f5d0fd50b2da2717f630aebf8" - integrity sha512-+uWuOhBTj/L6awoWIg0BlWy0u9TyFpCHrAuQ5bNfxDaZ1Ppb3mx6tUigc74LHcbHpOHuOTOJrBoAnhdHdaea1w== +"@typescript-eslint/types@5.59.9": + version "5.59.9" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.9.tgz#3b4e7ae63718ce1b966e0ae620adc4099a6dcc52" + integrity sha512-uW8H5NRgTVneSVTfiCVffBb8AbwWSKg7qcA4Ot3JI3MPCJGsB4Db4BhvAODIIYE5mNj7Q+VJkK7JxmRhk2Lyjw== -"@typescript-eslint/typescript-estree@5.59.8": - version "5.59.8" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.8.tgz#801a7b1766481629481b3b0878148bd7a1f345d7" - integrity sha512-Jy/lPSDJGNow14vYu6IrW790p7HIf/SOV1Bb6lZ7NUkLc2iB2Z9elESmsaUtLw8kVqogSbtLH9tut5GCX1RLDg== +"@typescript-eslint/typescript-estree@5.59.9": + version "5.59.9" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.9.tgz#6bfea844e468427b5e72034d33c9fffc9557392b" + integrity sha512-pmM0/VQ7kUhd1QyIxgS+aRvMgw+ZljB3eDb+jYyp6d2bC0mQWLzUDF+DLwCTkQ3tlNyVsvZRXjFyV0LkU/aXjA== dependencies: - "@typescript-eslint/types" "5.59.8" - "@typescript-eslint/visitor-keys" "5.59.8" + "@typescript-eslint/types" "5.59.9" + "@typescript-eslint/visitor-keys" "5.59.9" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/utils@5.59.8", "@typescript-eslint/utils@^5.58.0": - version "5.59.8" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.59.8.tgz#34d129f35a2134c67fdaf024941e8f96050dca2b" - integrity sha512-Tr65630KysnNn9f9G7ROF3w1b5/7f6QVCJ+WK9nhIocWmx9F+TmCAcglF26Vm7z8KCTwoKcNEBZrhlklla3CKg== +"@typescript-eslint/utils@5.59.9", "@typescript-eslint/utils@^5.58.0": + version "5.59.9" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.59.9.tgz#adee890107b5ffe02cd46fdaa6c2125fb3c6c7c4" + integrity sha512-1PuMYsju/38I5Ggblaeb98TOoUvjhRvLpLa1DoTOFaLWqaXl/1iQ1eGurTXgBY58NUdtfTXKP5xBq7q9NDaLKg== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@types/json-schema" "^7.0.9" "@types/semver" "^7.3.12" - "@typescript-eslint/scope-manager" "5.59.8" - "@typescript-eslint/types" "5.59.8" - "@typescript-eslint/typescript-estree" "5.59.8" + "@typescript-eslint/scope-manager" "5.59.9" + "@typescript-eslint/types" "5.59.9" + "@typescript-eslint/typescript-estree" "5.59.9" eslint-scope "^5.1.1" semver "^7.3.7" -"@typescript-eslint/visitor-keys@5.59.8": - version "5.59.8" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.8.tgz#aa6a7ef862add919401470c09e1609392ef3cc40" - integrity sha512-pJhi2ms0x0xgloT7xYabil3SGGlojNNKjK/q6dB3Ey0uJLMjK2UDGJvHieiyJVW/7C3KI+Z4Q3pEHkm4ejA+xQ== +"@typescript-eslint/visitor-keys@5.59.9": + version "5.59.9" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.9.tgz#9f86ef8e95aca30fb5a705bb7430f95fc58b146d" + integrity sha512-bT7s0td97KMaLwpEBckbzj/YohnvXtqbe2XgqNvTl6RJVakY5mvENOTPvw5u66nljfZxthESpDozs86U+oLY8Q== dependencies: - "@typescript-eslint/types" "5.59.8" + "@typescript-eslint/types" "5.59.9" eslint-visitor-keys "^3.3.0" "@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5": @@ -4015,9 +4015,9 @@ ejs@^3.1.6: jake "^10.8.5" electron-to-chromium@^1.4.411: - version "1.4.419" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.419.tgz#6fbea1f3abb65bf46e8ad874b5c1f0816ce2f8ce" - integrity sha512-jdie3RiEgygvDTyS2sgjq71B36q2cDSBfPlwzUyuOrfYTNoYWyBxxjGJV/HAu3A2hB0Y+HesvCVkVAFoCKwCSw== + version "1.4.420" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.420.tgz#21d4b55e9deef16cdbf009557fb2fe8f96798248" + integrity sha512-BpPy2KXZc+UPbI8NGo2QdHU1Mkq11pO/zaNDHY57L09K/0ytrPw+IiLOUvZ1NjI5BlAVF5DkNr1UBUS76Tc4ow== emittery@^0.10.2: version "0.10.2" @@ -5063,9 +5063,9 @@ html-encoding-sniffer@^2.0.1: whatwg-encoding "^1.0.5" html-entities@^2.1.0, html-entities@^2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.3.3.tgz#117d7626bece327fc8baace8868fa6f5ef856e46" - integrity sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA== + version "2.3.4" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.3.4.tgz#c65db1302652a0a2986f216ef911df65015dc1ac" + integrity sha512-TtiHkpRBqP40OzizVWjwBPBsiqchEZxAg/nys6D6lIpdoVLo7sWZ/5Sf/s4UaBHQ6pzUzEr3NiItvEoO46sPtQ== html-escaper@^2.0.0: version "2.0.2" @@ -8875,9 +8875,9 @@ toidentifier@1.0.1: integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== tough-cookie@^4.0.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.2.tgz#e53e84b85f24e0b65dd526f46628db6c85f6b874" - integrity sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ== + version "4.1.3" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf" + integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw== dependencies: psl "^1.1.33" punycode "^2.1.1" @@ -9285,9 +9285,9 @@ webpack-sources@^3.2.3: integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== webpack@^5.64.4: - version "5.85.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.85.0.tgz#c14a6a3a91f84d67c450225661fda8da36bc7f49" - integrity sha512-7gazTiYqwo5OSqwH1tigLDL2r3qDeP2dOKYgd+LlXpsUMqDTklg6tOghexqky0/+6QY38kb/R/uRPUleuL43zg== + version "5.85.1" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.85.1.tgz#d77406352f8f14ec847c54e4dcfb80b28c776b3f" + integrity sha512-xTb7MRf4LY8Z5rzn7aIx4TDrwYJrjcHnIfU1TqtyZOoObyuGSpAUwIvVuqq5wPnv7WEgQr8UvO1q/dgoGG4HjA== dependencies: "@types/eslint-scope" "^3.7.3" "@types/estree" "^1.0.0" diff --git a/server/src/index.ts b/server/src/index.ts index 45f0ec4..10010c3 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -3,7 +3,7 @@ import { Server } from "socket.io"; import bodyParser from "body-parser"; import { fetchPizzy } from "./chefie"; import cors from 'cors'; -import { createPizzaDay, deletePizzaDay, getData, updateChoice } from "./service"; +import { addPizzaOrder, createPizzaDay, deletePizzaDay, getData, removePizzaOrder, updateChoice } from "./service"; import dotenv from 'dotenv'; import path from 'path'; import { fetchMenus } from "./restaurants"; @@ -49,7 +49,6 @@ 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) => { - console.log("Založení pizza day", req) // TODO smazat if (!req.body?.creator) { throw Error("Nebyl předán název zakládajícího"); } @@ -86,17 +85,25 @@ app.post("/api/addPizza", (req, res) => { if (!pizzy[pizzaIndex].sizes[pizzaSizeIndex]) { throw Error("Neplatný index velikosti pizzy: " + pizzaSizeIndex); } - console.log("Vybraná pizza", pizzy[pizzaIndex], pizzy[pizzaIndex].sizes[pizzaSizeIndex]); - // TODO implementovat přidání objednávky - nutno zjistit co vlastně chceme ukládat - // pravděpodobně název, velikost, cenu + const data = addPizzaOrder(req.body.login, pizzy[pizzaIndex], pizzy[pizzaIndex].sizes[pizzaSizeIndex]); + io.emit("message", data); res.status(200).json({}); - // TODO odeslat aktuální data socketem - // io.emit("message", data); }) }); +app.post("/api/removePizza", (req, res) => { + if (!req.body?.login) { + throw Error("Nebyl předán login"); + } + if (!req.body?.pizzaOrder) { + throw Error("Nebyla předána objednávka"); + } + const data = removePizzaOrder(req.body.login, req.body?.pizzaOrder); + io.emit("message", data); + res.status(200).json({}); +}); + app.post("/api/updateChoice", (req, res) => { - console.log("Změna výběru", req.body); if (!req.body.hasOwnProperty('name')) { res.status(400).json({}); } @@ -105,23 +112,6 @@ app.post("/api/updateChoice", (req, res) => { res.status(200).json(data); }); -// TODO smazat -app.post("/api/zprava", (req, res) => { - const { username, message } = req.body; - - if ( - typeof username !== "string" || - typeof message !== "string" || - username.length > 500 || - message.length > 500 - ) { - return res.status(400).json({ error: "Invalid input" }); - } - console.log(`posílám ${username} ${message} `); - io.emit("externalMessage", `${username} -> ${message}`); - res.status(200).json({ success: "Message sent" }); -}); - io.on("connection", (socket) => { console.log(`New client connected: ${socket.id}`); @@ -129,12 +119,6 @@ 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`); - }); - socket.on("disconnect", () => { console.log(`Client disconnected: ${socket.id}`); }); diff --git a/server/src/service.ts b/server/src/service.ts index f9fe66f..966bd25 100644 --- a/server/src/service.ts +++ b/server/src/service.ts @@ -1,4 +1,4 @@ -import { ClientData, Locations, State } from "./types"; +import { ClientData, Locations, Order, Pizza, PizzaDayState, PizzaOrder, PizzaSize } from "./types"; import { db } from "./database"; import { getHumanDate, getIsWeekend } from "./utils"; import { formatDate } from "./utils"; @@ -34,7 +34,7 @@ export function createPizzaDay(creator: string): ClientData { if (clientData.pizzaDay) { throw Error("Pizza day pro dnešní den již existuje"); } - const data: ClientData = { pizzaDay: { state: State.CREATED, creator, orders: [] }, ...clientData }; + const data: ClientData = { pizzaDay: { state: PizzaDayState.CREATED, creator, orders: [] }, ...clientData }; db.set(today, data); return data; } @@ -54,6 +54,70 @@ export function deletePizzaDay(login: string) { db.delete(today); } +/** + * Přidá objednávku pizzy uživateli. + * + * @param login login uživatele + * @param pizza zvolená pizza + * @param size zvolená velikost pizzy + */ +export function addPizzaOrder(login: string, pizza: Pizza, size: PizzaSize) { + const today = formatDate(getToday()); + const clientData: ClientData = db.get(today); + if (!clientData.pizzaDay) { + throw Error("Pizza day pro dnešní den neexistuje"); + } + let order: Order | undefined = clientData.pizzaDay.orders.find(o => o.customer === login); + if (!order) { + order = { + customer: login, + pizzaList: [], + totalPrice: 0, + } + clientData.pizzaDay.orders.push(order); + } + const pizzaOrder: PizzaOrder = { + name: pizza.name, + size: size.size, + price: size.price, + } + order.pizzaList.push(pizzaOrder); + order.totalPrice += pizzaOrder.price; + db.set(today, clientData); + return clientData; +} + +/** + * Odstraní danou objednávku pizzy. + * + * @param login login uživatele + * @param pizzaOrder objednávka pizzy + */ +export function removePizzaOrder(login: string, pizzaOrder: PizzaOrder) { + const today = formatDate(getToday()); + const clientData: ClientData = db.get(today); + if (!clientData.pizzaDay) { + throw Error("Pizza day pro dnešní den neexistuje"); + } + const orderIndex = clientData.pizzaDay.orders.findIndex(o => o.customer === login); + if (orderIndex < 0) { + throw Error("Nebyly nalezeny žádné objednávky pro uživatele " + login); + } + const order = clientData.pizzaDay.orders[orderIndex]; + const index = order.pizzaList.findIndex(o => o.name === pizzaOrder.name && o.size === pizzaOrder.size); + if (index < 0) { + throw Error("Objednávka s danými parametry nebyla nalezena"); + } + const price = order.pizzaList[index].price; + order.pizzaList.splice(index, 1); + order.totalPrice -= price; + if (order.pizzaList.length == 0) { + clientData.pizzaDay.orders.splice(orderIndex, 1); + } + db.set(today, clientData); + return clientData; +} + export function initIfNeeded() { const today = formatDate(getToday()); if (!db.has(today)) { diff --git a/server/src/types.ts b/server/src/types.ts index bb59fec..07785bf 100644 --- a/server/src/types.ts +++ b/server/src/types.ts @@ -2,34 +2,50 @@ export interface Choices { [location: string]: string[], } -// /** Jedna konkrétní pizza */ -interface Pizza { +/** Velikost konkrétní pizzy */ +export interface PizzaSize { + size: string, // velikost pizzy, např. "30cm" + pizzaPrice: number, // cena samotné pizzy + boxPrice: number, // cena krabice + price: number, // celková cena (pizza + krabice) +} + +/** Jedna konkrétní pizza */ +export interface Pizza { name: string, // název pizzy - size: number, // velikost pizzy v cm + ingredients: string[], // seznam ingrediencí + sizes: PizzaSize[], // dostupné velikosti pizzy +} + +/** Objednávka jedné konkrétní pizzy */ +export interface PizzaOrder { + name: string, // název pizzy + size: string, // velikost pizzy jako string (30cm) 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 +/** Celková objednávka jednoho člověka */ +export interface Order { + customer: string, // jméno objednatele + pizzaList: PizzaOrder[], // seznam objednaných pizz totalPrice: number, // celková cena všech objednaných pizz a krabic } -// /** Stav pizza dne. */ -export enum State { +/** Stav pizza dne */ +export enum PizzaDayState { 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 */ +/** Informace o pizza day pro dnešní den */ interface PizzaDay { - state: State, // stav pizza dne + state: PizzaDayState, // stav pizza dne creator: string, // jméno zakladatele - orders: Order[], // seznam objednávek, pokud není vyplněno, není založen pizza day + orders: Order[], // seznam objednávek jednotlivých lidí } +/** Veškerá data pro zobrazení na klientovi */ export interface ClientData { date: string, // dnešní datum pro zobrazení isWeekend: boolean, // příznak, zda je dnes víkend