Základní funkčnost Pizza Day

This commit is contained in:
Martin Berka 2023-06-05 22:49:37 +02:00
parent 2e80faa6b8
commit cdcd620ee5
9 changed files with 263 additions and 162 deletions

View File

@ -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] 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
- [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

View File

@ -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<TResponse>(
@ -53,3 +45,7 @@ export const updateChoice = async (name: string, choice: number | null) => {
export const addPizza = async (login: string, pizzaIndex: number, pizzaSizeIndex: number) => {
return await api.post<any, any>('/api/addPizza', JSON.stringify({ login, pizzaIndex, pizzaSizeIndex }));
}
export const removePizza = async (login: string, pizzaOrder: PizzaOrder) => {
return await api.post<any, any>('/api/removePizza', JSON.stringify({ login, pizzaOrder }));
}

View File

@ -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 <Col md={12} lg={4}>
<h3>{name}</h3>
@ -200,29 +204,35 @@ function App() {
: <div className='mt-5'><i>Zatím nikdo nehlasoval...</i></div>
}
</div>
{!data.pizzaDay &&
<div>
<p>Pro dnešní den není aktuálně založen Pizza day.</p>
<Button onClick={async () => {
await createPizzaDay(auth.login);
}}>Založit Pizza day</Button>
</div>
}
{data.pizzaDay && <div>
<p>Pizza Day je založen uživatelem {data.pizzaDay.creator}</p>
{
data.pizzaDay.creator === auth.login && <Button className='danger mb-3' onClick={async () => {
await deletePizzaDay(auth.login);
}}>Smazat Pizza day</Button>
<div className='mt-5'>
{!data.pizzaDay &&
<div style={{ textAlign: 'center' }}>
<p>Pro dnešní den není aktuálně založen Pizza day.</p>
<Button onClick={async () => {
await createPizzaDay(auth.login);
}}>Založit Pizza day</Button>
</div>
}
<SelectSearch
search={true}
options={pizzaSuggestions}
placeholder='Vyhledat pizzu...'
onChange={handlePizzaChange}
/>
<PizzaOrderList orders={data.pizzaDay.orders} />
</div>}
{data.pizzaDay &&
<div>
<div style={{ textAlign: 'center' }}>
<p>Pizza Day je založen uživatelem {data.pizzaDay.creator}</p>
{
data.pizzaDay.creator === auth.login && <Button className='danger mb-3' onClick={async () => {
await deletePizzaDay(auth.login);
}}>Smazat Pizza day</Button>
}
</div>
<SelectSearch
search={true}
options={pizzaSuggestions}
placeholder='Vyhledat pizzu...'
onChange={handlePizzaChange}
/>
<PizzaOrderList orders={data.pizzaDay.orders} onDelete={handlePizzaDelete} />
</div>
}
</div>
</div>
</>}
</div>

View File

@ -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
}

View File

@ -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 <Table className="mt-3" striped bordered hover>
<thead>
<tr>
<th>Pizza</th>
<th>Jméno</th>
<th>Cena ()</th>
<th>Objednávka</th>
<th>Celkem</th>
</tr>
</thead>
<tbody>
{orders.map(order => <tr>
<td>{order.pizzaList[0].name}</td>
{orders.map(order => <tr key={order.customer}>
<td>{order.customer}</td>
<td>{order.totalPrice}</td>
<td>{order.pizzaList.map<React.ReactNode>((pizzaOrder, index) =>
<span key={index}>
{`${pizzaOrder.name}, ${pizzaOrder.size} (${pizzaOrder.price} Kč)`}
{auth?.login === order.customer &&
<FontAwesomeIcon onClick={() => {
onDelete(pizzaOrder);
}} title='Odstranit' className='trash-icon' icon={faTrashCan} />
}
</span>)
.reduce((prev, curr) => [prev, <br />, curr])}
</td>
<td>{order.totalPrice} </td>
</tr>)}
</tbody>
</Table>

View File

@ -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"

View File

@ -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}`);
});

View File

@ -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)) {

View File

@ -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