This commit is contained in:
parent
55fd368663
commit
e55ee7c11e
@ -24,7 +24,7 @@ import { useEasterEgg } from './context/eggs';
|
|||||||
import { getImage } from './api/EasterEggApi';
|
import { getImage } from './api/EasterEggApi';
|
||||||
import { Link } from 'react-router';
|
import { Link } from 'react-router';
|
||||||
import { STATS_URL } from './AppRoutes';
|
import { STATS_URL } from './AppRoutes';
|
||||||
import { ClientData, Food, PizzaOrder, DepartureTime, PizzaDayState, Restaurant, RestaurantDayMenu, RestaurantDayMenuMap, LunchChoice, LunchChoices, UserLunchChoice, PizzaVariant } from '../../types';
|
import { ClientData, Food, PizzaOrder, DepartureTime, PizzaDayState, Restaurant, RestaurantDayMenu, RestaurantDayMenuMap, LunchChoice, UserLunchChoice, PizzaVariant } from '../../types';
|
||||||
|
|
||||||
const EVENT_CONNECT = "connect"
|
const EVENT_CONNECT = "connect"
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ const EASTER_EGG_DEFAULT_DURATION = 0.75;
|
|||||||
function App() {
|
function App() {
|
||||||
const auth = useAuth();
|
const auth = useAuth();
|
||||||
const settings = useSettings();
|
const settings = useSettings();
|
||||||
const [easterEgg, easterEggLoading] = useEasterEgg(auth);
|
const [easterEgg, _] = useEasterEgg(auth);
|
||||||
const [isConnected, setIsConnected] = useState<boolean>(false);
|
const [isConnected, setIsConnected] = useState<boolean>(false);
|
||||||
const [data, setData] = useState<ClientData>();
|
const [data, setData] = useState<ClientData>();
|
||||||
const [food, setFood] = useState<RestaurantDayMenuMap>();
|
const [food, setFood] = useState<RestaurantDayMenuMap>();
|
||||||
@ -65,7 +65,7 @@ function App() {
|
|||||||
|
|
||||||
// Načtení dat po přihlášení
|
// Načtení dat po přihlášení
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!auth || !auth.login) {
|
if (!auth?.login) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
getData().then(({ data }) => {
|
getData().then(({ data }) => {
|
||||||
@ -82,7 +82,7 @@ function App() {
|
|||||||
|
|
||||||
// Přenačtení pro zvolený den
|
// Přenačtení pro zvolený den
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!auth || !auth.login) {
|
if (!auth?.login) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
getData(dayIndex).then((data: ClientData) => {
|
getData(dayIndex).then((data: ClientData) => {
|
||||||
@ -96,11 +96,9 @@ function App() {
|
|||||||
// Registrace socket eventů
|
// Registrace socket eventů
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
socket.on(EVENT_CONNECT, () => {
|
socket.on(EVENT_CONNECT, () => {
|
||||||
// console.log("Connected!");
|
|
||||||
setIsConnected(true);
|
setIsConnected(true);
|
||||||
});
|
});
|
||||||
socket.on(EVENT_DISCONNECT, () => {
|
socket.on(EVENT_DISCONNECT, () => {
|
||||||
// console.log("Disconnected!");
|
|
||||||
setIsConnected(false);
|
setIsConnected(false);
|
||||||
});
|
});
|
||||||
socket.on(EVENT_MESSAGE, (newData: ClientData) => {
|
socket.on(EVENT_MESSAGE, (newData: ClientData) => {
|
||||||
@ -119,7 +117,7 @@ function App() {
|
|||||||
}, [socket]);
|
}, [socket]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!auth || !auth.login) {
|
if (!auth?.login) {
|
||||||
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
|
||||||
@ -277,7 +275,7 @@ function App() {
|
|||||||
|
|
||||||
const handlePizzaChange = async (value: SelectedOptionValue | SelectedOptionValue[]) => {
|
const handlePizzaChange = async (value: SelectedOptionValue | SelectedOptionValue[]) => {
|
||||||
if (auth?.login && data?.pizzaList) {
|
if (auth?.login && data?.pizzaList) {
|
||||||
if (!(typeof value === 'string')) {
|
if (typeof value !== 'string') {
|
||||||
throw Error('Nepodporovaný typ hodnoty');
|
throw Error('Nepodporovaný typ hodnoty');
|
||||||
}
|
}
|
||||||
const s = value.split('|');
|
const s = value.split('|');
|
||||||
@ -365,13 +363,13 @@ function App() {
|
|||||||
content = <h3>Chyba načtení dat</h3>
|
content = <h3>Chyba načtení dat</h3>
|
||||||
}
|
}
|
||||||
return <Col md={12} lg={3} className='mt-3'>
|
return <Col md={12} lg={3} className='mt-3'>
|
||||||
<h3 style={{ cursor: 'pointer' }} onClick={() => doAddClickFoodChoice(location, undefined)}>{location}</h3>
|
<h3 style={{ cursor: 'pointer' }} onClick={() => doAddClickFoodChoice(location)}>{location}</h3>
|
||||||
{menu?.lastUpdate && <small>Poslední aktualizace: {getHumanDateTime(new Date(menu.lastUpdate))}</small>}
|
{menu?.lastUpdate && <small>Poslední aktualizace: {getHumanDateTime(new Date(menu.lastUpdate))}</small>}
|
||||||
{content}
|
{content}
|
||||||
</Col>
|
</Col>
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!auth || !auth.login) {
|
if (!auth?.login) {
|
||||||
return <Login />;
|
return <Login />;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -411,8 +409,8 @@ function App() {
|
|||||||
<div className='wrapper'>
|
<div className='wrapper'>
|
||||||
{data.isWeekend ? <h4>Užívejte víkend :)</h4> : <>
|
{data.isWeekend ? <h4>Užívejte víkend :)</h4> : <>
|
||||||
<Alert variant={'primary'}>
|
<Alert variant={'primary'}>
|
||||||
<img src='hat.png' style={{ position: "absolute", width: "70px", rotate: "-45deg", left: -40, top: -58 }} />
|
<img alt="" src='hat.png' style={{ position: "absolute", width: "70px", rotate: "-45deg", left: -40, top: -58 }} />
|
||||||
<img src='snowman.png' style={{ position: "absolute", height: "110px", right: 10, top: 5 }} />
|
<img alt="" src='snowman.png' style={{ position: "absolute", height: "110px", right: 10, top: 5 }} />
|
||||||
Poslední změny:
|
Poslední změny:
|
||||||
<ul>
|
<ul>
|
||||||
<li>Možnost výběru restaurace a jídel kliknutím v tabulce</li>
|
<li>Možnost výběru restaurace a jídel kliknutím v tabulce</li>
|
||||||
@ -429,7 +427,6 @@ function App() {
|
|||||||
<Row className='food-tables'>
|
<Row className='food-tables'>
|
||||||
{/* TODO zjednodušit, stačí iterovat klíče typu Restaurant */}
|
{/* TODO zjednodušit, stačí iterovat klíče typu Restaurant */}
|
||||||
{food['SLADOVNICKA'] && renderFoodTable('SLADOVNICKA', food['SLADOVNICKA'])}
|
{food['SLADOVNICKA'] && renderFoodTable('SLADOVNICKA', food['SLADOVNICKA'])}
|
||||||
{/* {food['UMOTLIKU'] && renderFoodTable('UMOTLIKU', food['UMOTLIKU'])} */}
|
|
||||||
{food['TECHTOWER'] && renderFoodTable('TECHTOWER', food['TECHTOWER'])}
|
{food['TECHTOWER'] && renderFoodTable('TECHTOWER', food['TECHTOWER'])}
|
||||||
{food['ZASTAVKAUMICHALA'] && renderFoodTable('ZASTAVKAUMICHALA', food['ZASTAVKAUMICHALA'])}
|
{food['ZASTAVKAUMICHALA'] && renderFoodTable('ZASTAVKAUMICHALA', food['ZASTAVKAUMICHALA'])}
|
||||||
{food['SENKSERIKOVA'] && renderFoodTable('SENKSERIKOVA', food['SENKSERIKOVA'])}
|
{food['SENKSERIKOVA'] && renderFoodTable('SENKSERIKOVA', food['SENKSERIKOVA'])}
|
||||||
@ -452,7 +449,7 @@ function App() {
|
|||||||
<p style={{ marginTop: "10px" }}>Na co dobrého? <small>(nepovinné)</small></p>
|
<p style={{ marginTop: "10px" }}>Na co dobrého? <small>(nepovinné)</small></p>
|
||||||
<Form.Select ref={foodChoiceRef} onChange={doAddFoodChoice}>
|
<Form.Select ref={foodChoiceRef} onChange={doAddFoodChoice}>
|
||||||
<option></option>
|
<option></option>
|
||||||
{foodChoiceList.map((food, index) => <option key={index} value={index}>{food.name}</option>)}
|
{foodChoiceList.map((food, index) => <option key={food.name} value={index}>{food.name}</option>)}
|
||||||
</Form.Select>
|
</Form.Select>
|
||||||
</>}
|
</>}
|
||||||
{foodChoiceList && !closed && <>
|
{foodChoiceList && !closed && <>
|
||||||
@ -491,7 +488,7 @@ function App() {
|
|||||||
const userPayload = entry[1];
|
const userPayload = entry[1];
|
||||||
const userChoices = userPayload?.selectedFoods;
|
const userChoices = userPayload?.selectedFoods;
|
||||||
const trusted = userPayload?.trusted || false;
|
const trusted = userPayload?.trusted || false;
|
||||||
return <tr key={index}>
|
return <tr key={entry[0]}>
|
||||||
<td>
|
<td>
|
||||||
{trusted && <span className='trusted-icon'>
|
{trusted && <span className='trusted-icon'>
|
||||||
<FontAwesomeIcon title='Uživatel ověřený doménovým přihlášením' icon={faCircleCheck} style={{ cursor: "help" }} />
|
<FontAwesomeIcon title='Uživatel ověřený doménovým přihlášením' icon={faCircleCheck} style={{ cursor: "help" }} />
|
||||||
@ -587,9 +584,6 @@ function App() {
|
|||||||
<Button className='danger mb-3' title="Umožní znovu editovat objednávky." onClick={async () => {
|
<Button className='danger mb-3' title="Umožní znovu editovat objednávky." onClick={async () => {
|
||||||
await unlockPizzaDay();
|
await unlockPizzaDay();
|
||||||
}}>Odemknout</Button>
|
}}>Odemknout</Button>
|
||||||
{/* <Button className='danger mb-3' style={{ marginLeft: '20px' }} onClick={async () => {
|
|
||||||
await addToCart();
|
|
||||||
}}>Přidat vše do košíku</Button> */}
|
|
||||||
<Button className='danger mb-3' style={{ marginLeft: '20px' }} title={noOrders ? "Nelze objednat - neexistuje žádná objednávka" : "Použij po objednání. Objednávky zůstanou zamčeny."} disabled={noOrders} onClick={async () => {
|
<Button className='danger mb-3' style={{ marginLeft: '20px' }} title={noOrders ? "Nelze objednat - neexistuje žádná objednávka" : "Použij po objednání. Objednávky zůstanou zamčeny."} disabled={noOrders} onClick={async () => {
|
||||||
await finishOrder();
|
await finishOrder();
|
||||||
}}>Objednáno</Button>
|
}}>Objednáno</Button>
|
||||||
|
@ -25,9 +25,8 @@ export default function Login() {
|
|||||||
}, [auth]);
|
}, [auth]);
|
||||||
|
|
||||||
const doLogin = useCallback(async () => {
|
const doLogin = useCallback(async () => {
|
||||||
const length = loginRef?.current?.value && loginRef?.current?.value.length && loginRef.current.value.replace(/\s/g, '').length
|
const length = loginRef?.current?.value.length && loginRef.current.value.replace(/\s/g, '').length
|
||||||
if (length) {
|
if (length) {
|
||||||
// TODO odchytávat cokoliv mimo 200
|
|
||||||
const token = await login(loginRef.current?.value);
|
const token = await login(loginRef.current?.value);
|
||||||
if (token) {
|
if (token) {
|
||||||
auth?.setToken(token);
|
auth?.setToken(token);
|
||||||
@ -35,7 +34,7 @@ export default function Login() {
|
|||||||
}
|
}
|
||||||
}, [auth]);
|
}, [auth]);
|
||||||
|
|
||||||
if (!auth || !auth.login) {
|
if (!auth?.login) {
|
||||||
return <div className='login'>
|
return <div className='login'>
|
||||||
<h1>Luncher</h1>
|
<h1>Luncher</h1>
|
||||||
<h4 style={{ marginBottom: "50px" }}>Aplikace pro profesionální management obědů</h4>
|
<h4 style={{ marginBottom: "50px" }}>Aplikace pro profesionální management obědů</h4>
|
||||||
|
@ -93,7 +93,7 @@ export function formatDate(date: Date, format?: string) {
|
|||||||
let month = String(date.getMonth() + 1).padStart(2, "0");
|
let month = String(date.getMonth() + 1).padStart(2, "0");
|
||||||
let year = String(date.getFullYear());
|
let year = String(date.getFullYear());
|
||||||
|
|
||||||
const f = (format === undefined) ? 'YYYY-MM-DD' : format;
|
const f = format ?? 'YYYY-MM-DD';
|
||||||
return f.replace('DD', day).replace('MM', month).replace('YYYY', year);
|
return f.replace('DD', day).replace('MM', month).replace('YYYY', year);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { AddChoiceRequest, ChangeDepartureTimeRequest, RemoveChoiceRequest, RemoveChoicesRequest, UpdateNoteRequest } from "../../../types";
|
import { AddChoiceRequest, ChangeDepartureTimeRequest, LunchChoice, RemoveChoiceRequest, RemoveChoicesRequest, UpdateNoteRequest } from "../../../types";
|
||||||
import { LunchChoice } from "../../../types";
|
|
||||||
import { api } from "./Api";
|
import { api } from "./Api";
|
||||||
|
|
||||||
const FOOD_API_PREFIX = '/api/food';
|
const FOOD_API_PREFIX = '/api/food';
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { AddPizzaRequest, FinishDeliveryRequest, RemovePizzaRequest, UpdatePizzaDayNoteRequest, UpdatePizzaFeeRequest } from "../../../types";
|
import { AddPizzaRequest, FinishDeliveryRequest, PizzaVariant, RemovePizzaRequest, UpdatePizzaDayNoteRequest, UpdatePizzaFeeRequest } from "../../../types";
|
||||||
import { PizzaVariant } from "../../../types";
|
|
||||||
import { api } from "./Api";
|
import { api } from "./Api";
|
||||||
|
|
||||||
const PIZZADAY_API_PREFIX = '/api/pizzaDay';
|
const PIZZADAY_API_PREFIX = '/api/pizzaDay';
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { UpdateFeatureVoteRequest } from "../../../types";
|
import { FeatureRequest, UpdateFeatureVoteRequest } from "../../../types";
|
||||||
import { FeatureRequest } from "../../../types";
|
|
||||||
import { api } from "./Api";
|
import { api } from "./Api";
|
||||||
|
|
||||||
const VOTING_API_PREFIX = '/api/voting';
|
const VOTING_API_PREFIX = '/api/voting';
|
||||||
|
@ -78,7 +78,7 @@ export default function Header() {
|
|||||||
cislo = cislo.padStart(16, '0');
|
cislo = cislo.padStart(16, '0');
|
||||||
}
|
}
|
||||||
let sum = 0;
|
let sum = 0;
|
||||||
for (var i = 0; i < cislo.length; i++) {
|
for (let i = 0; i < cislo.length; i++) {
|
||||||
const char = cislo.charAt(i);
|
const char = cislo.charAt(i);
|
||||||
const order = (cislo.length - 1) - i;
|
const order = (cislo.length - 1) - i;
|
||||||
const weight = (2 ** order) % 11;
|
const weight = (2 ** order) % 11;
|
||||||
|
@ -2,15 +2,15 @@ import { IconDefinition } from '@fortawesome/free-solid-svg-icons';
|
|||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
title?: String,
|
title?: string,
|
||||||
icon: IconDefinition,
|
icon: IconDefinition,
|
||||||
description: String,
|
description: string,
|
||||||
animation?: String,
|
animation?: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
function Loader(props: Props) {
|
function Loader(props: Readonly<Props>) {
|
||||||
return <div className='loader'>
|
return <div className='loader'>
|
||||||
<h1>{props.title || 'Prosím čekejte...'}</h1>
|
<h1>{props.title ?? 'Prosím čekejte...'}</h1>
|
||||||
<FontAwesomeIcon icon={props.icon} className={`loader-icon mb-3 ` + (props.animation ?? '')} />
|
<FontAwesomeIcon icon={props.icon} className={`loader-icon mb-3 ` + (props.animation ?? '')} />
|
||||||
<p>{props.description}</p>
|
<p>{props.description}</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -10,7 +10,7 @@ type Props = {
|
|||||||
creator: string,
|
creator: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function PizzaOrderList({ state, orders, onDelete, creator }: Props) {
|
export default function PizzaOrderList({ state, orders, onDelete, creator }: Readonly<Props>) {
|
||||||
const saveFees = async (customer: string, text?: string, price?: number) => {
|
const saveFees = async (customer: string, text?: string, price?: number) => {
|
||||||
await updatePizzaFee(customer, text, price);
|
await updatePizzaFee(customer, text, price);
|
||||||
}
|
}
|
||||||
@ -21,26 +21,24 @@ export default function PizzaOrderList({ state, orders, onDelete, creator }: Pro
|
|||||||
|
|
||||||
const total = orders.reduce((total, order) => total + order.totalPrice, 0);
|
const total = orders.reduce((total, order) => total + order.totalPrice, 0);
|
||||||
|
|
||||||
return <>
|
return <Table className="mt-3" striped bordered hover>
|
||||||
<Table className="mt-3" striped bordered hover>
|
<thead>
|
||||||
<thead>
|
<tr>
|
||||||
<tr>
|
<th>Jméno</th>
|
||||||
<th>Jméno</th>
|
<th>Objednávka</th>
|
||||||
<th>Objednávka</th>
|
<th>Poznámka</th>
|
||||||
<th>Poznámka</th>
|
<th>Příplatek</th>
|
||||||
<th>Příplatek</th>
|
<th>Cena</th>
|
||||||
<th>Cena</th>
|
</tr>
|
||||||
</tr>
|
</thead>
|
||||||
</thead>
|
<tbody>
|
||||||
<tbody>
|
{orders.map(order => <tr key={order.customer}>
|
||||||
{orders.map(order => <tr key={order.customer}>
|
<PizzaOrderRow creator={creator} state={state} order={order} onDelete={onDelete} onFeeModalSave={saveFees} />
|
||||||
<PizzaOrderRow creator={creator} state={state} order={order} onDelete={onDelete} onFeeModalSave={saveFees} />
|
</tr>)}
|
||||||
</tr>)}
|
<tr style={{ fontWeight: 'bold' }}>
|
||||||
<tr style={{ fontWeight: 'bold' }}>
|
<td colSpan={4}>Celkem</td>
|
||||||
<td colSpan={4}>Celkem</td>
|
<td>{`${total} Kč`}</td>
|
||||||
<td>{`${total} Kč`}</td>
|
</tr>
|
||||||
</tr>
|
</tbody>
|
||||||
</tbody>
|
</Table>
|
||||||
</Table>
|
|
||||||
</>
|
|
||||||
}
|
}
|
@ -13,19 +13,19 @@ type Props = {
|
|||||||
onFeeModalSave: (customer: string, name?: string, price?: number) => void,
|
onFeeModalSave: (customer: string, name?: string, price?: number) => void,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function PizzaOrderRow({ creator, order, state, onDelete, onFeeModalSave }: Props) {
|
export default function PizzaOrderRow({ creator, order, state, onDelete, onFeeModalSave }: Readonly<Props>) {
|
||||||
const auth = useAuth();
|
const auth = useAuth();
|
||||||
const [isFeeModalOpen, setFeeModalOpen] = useState<boolean>(false);
|
const [isFeeModalOpen, setIsFeeModalOpen] = useState<boolean>(false);
|
||||||
|
|
||||||
const saveFees = (customer: string, text?: string, price?: number) => {
|
const saveFees = (customer: string, text?: string, price?: number) => {
|
||||||
onFeeModalSave(customer, text, price);
|
onFeeModalSave(customer, text, price);
|
||||||
setFeeModalOpen(false);
|
setIsFeeModalOpen(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
<td>{order.customer}</td>
|
<td>{order.customer}</td>
|
||||||
<td>{order.pizzaList!.map<React.ReactNode>((pizzaOrder, index) =>
|
<td>{order.pizzaList!.map<React.ReactNode>(pizzaOrder =>
|
||||||
<span key={index}>
|
<span key={pizzaOrder.name}>
|
||||||
{`${pizzaOrder.name}, ${pizzaOrder.size} (${pizzaOrder.price} Kč)`}
|
{`${pizzaOrder.name}, ${pizzaOrder.size} (${pizzaOrder.price} Kč)`}
|
||||||
{auth?.login === order.customer && state === PizzaDayState.CREATED &&
|
{auth?.login === order.customer && state === PizzaDayState.CREATED &&
|
||||||
<FontAwesomeIcon onClick={() => {
|
<FontAwesomeIcon onClick={() => {
|
||||||
@ -35,11 +35,11 @@ export default function PizzaOrderRow({ creator, order, state, onDelete, onFeeMo
|
|||||||
</span>)
|
</span>)
|
||||||
.reduce((prev, curr, index) => [prev, <br key={`br-${index}`} />, curr])}
|
.reduce((prev, curr, index) => [prev, <br key={`br-${index}`} />, curr])}
|
||||||
</td>
|
</td>
|
||||||
<td style={{ maxWidth: "200px" }}>{order.note || '-'}</td>
|
<td style={{ maxWidth: "200px" }}>{order.note ?? '-'}</td>
|
||||||
<td style={{ maxWidth: "200px" }}>{order.fee?.price ? `${order.fee.price} Kč${order.fee.text ? ` (${order.fee.text})` : ''}` : '-'}</td>
|
<td style={{ maxWidth: "200px" }}>{order.fee?.price ? `${order.fee.price} Kč${order.fee.text ? ` (${order.fee.text})` : ''}` : '-'}</td>
|
||||||
<td>
|
<td>
|
||||||
{order.totalPrice} Kč{auth?.login === creator && state === PizzaDayState.CREATED && <FontAwesomeIcon onClick={() => { setFeeModalOpen(true) }} title='Nastavit příplatek' className='action-icon' icon={faMoneyBill1} />}
|
{order.totalPrice} Kč{auth?.login === creator && state === PizzaDayState.CREATED && <FontAwesomeIcon onClick={() => { setIsFeeModalOpen(true) }} title='Nastavit příplatek' className='action-icon' icon={faMoneyBill1} />}
|
||||||
</td>
|
</td>
|
||||||
<PizzaAdditionalFeeModal customerName={order.customer} isOpen={isFeeModalOpen} onClose={() => setFeeModalOpen(false)} onSave={saveFees} initialValues={{ text: order.fee?.text, price: order.fee?.price?.toString() }} />
|
<PizzaAdditionalFeeModal customerName={order.customer} isOpen={isFeeModalOpen} onClose={() => setIsFeeModalOpen(false)} onSave={saveFees} initialValues={{ text: order.fee?.text, price: order.fee?.price?.toString() }} />
|
||||||
</>
|
</>
|
||||||
}
|
}
|
@ -9,7 +9,7 @@ type Props = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Modální dialog pro hlasování o nových funkcích. */
|
/** Modální dialog pro hlasování o nových funkcích. */
|
||||||
export default function FeaturesVotingModal({ isOpen, onClose, onChange, initialValues }: Props) {
|
export default function FeaturesVotingModal({ isOpen, onClose, onChange, initialValues }: Readonly<Props>) {
|
||||||
|
|
||||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
onChange(e.currentTarget.value as FeatureRequest, e.currentTarget.checked);
|
onChange(e.currentTarget.value as FeatureRequest, e.currentTarget.checked);
|
||||||
@ -31,7 +31,7 @@ export default function FeaturesVotingModal({ isOpen, onClose, onChange, initial
|
|||||||
label={FeatureRequest[key]}
|
label={FeatureRequest[key]}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
value={key}
|
value={key}
|
||||||
defaultChecked={initialValues && initialValues.includes(key as FeatureRequest)}
|
defaultChecked={initialValues?.includes(key as FeatureRequest)}
|
||||||
/>
|
/>
|
||||||
})}
|
})}
|
||||||
<p className="mt-3" style={{ fontSize: '12px' }}>Něco jiného? Dejte vědět.</p>
|
<p className="mt-3" style={{ fontSize: '12px' }}>Něco jiného? Dejte vědět.</p>
|
||||||
|
@ -8,7 +8,7 @@ type Props = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Modální dialog pro úpravu obecné poznámky. */
|
/** Modální dialog pro úpravu obecné poznámky. */
|
||||||
export default function NoteModal({ isOpen, onClose, onSave }: Props) {
|
export default function NoteModal({ isOpen, onClose, onSave }: Readonly<Props>) {
|
||||||
const note = useRef<HTMLInputElement>(null);
|
const note = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
const save = () => {
|
const save = () => {
|
||||||
|
@ -10,17 +10,17 @@ type Props = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Modální dialog pro nastavení příplatků za pizzu. */
|
/** Modální dialog pro nastavení příplatků za pizzu. */
|
||||||
export default function PizzaAdditionalFeeModal({ customerName, isOpen, onClose, onSave, initialValues }: Props) {
|
export default function PizzaAdditionalFeeModal({ customerName, isOpen, onClose, onSave, initialValues }: Readonly<Props>) {
|
||||||
const textRef = useRef<HTMLInputElement>(null);
|
const textRef = useRef<HTMLInputElement>(null);
|
||||||
const priceRef = useRef<HTMLInputElement>(null);
|
const priceRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
const doSubmit = () => {
|
const doSubmit = () => {
|
||||||
onSave(customerName, textRef.current?.value, parseInt(priceRef.current?.value || "0"));
|
onSave(customerName, textRef.current?.value, parseInt(priceRef.current?.value ?? "0"));
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||||
if (e.key === 'Enter') {
|
if (e.key === 'Enter') {
|
||||||
onSave(customerName, textRef.current?.value, parseInt(priceRef.current?.value || "0"));
|
onSave(customerName, textRef.current?.value, parseInt(priceRef.current?.value ?? "0"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ type Result = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Modální dialog pro výpočet výhodnosti pizzy. */
|
/** Modální dialog pro výpočet výhodnosti pizzy. */
|
||||||
export default function PizzaCalculatorModal({ isOpen, onClose }: Props) {
|
export default function PizzaCalculatorModal({ isOpen, onClose }: Readonly<Props>) {
|
||||||
const diameter1Ref = useRef<HTMLInputElement>(null);
|
const diameter1Ref = useRef<HTMLInputElement>(null);
|
||||||
const price1Ref = useRef<HTMLInputElement>(null);
|
const price1Ref = useRef<HTMLInputElement>(null);
|
||||||
const diameter2Ref = useRef<HTMLInputElement>(null);
|
const diameter2Ref = useRef<HTMLInputElement>(null);
|
||||||
|
@ -9,7 +9,7 @@ type Props = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Modální dialog pro uživatelská nastavení. */
|
/** Modální dialog pro uživatelská nastavení. */
|
||||||
export default function SettingsModal({ isOpen, onClose, onSave }: Props) {
|
export default function SettingsModal({ isOpen, onClose, onSave }: Readonly<Props>) {
|
||||||
const settings = useSettings();
|
const settings = useSettings();
|
||||||
const bankAccountRef = useRef<HTMLInputElement>(null);
|
const bankAccountRef = useRef<HTMLInputElement>(null);
|
||||||
const nameRef = useRef<HTMLInputElement>(null);
|
const nameRef = useRef<HTMLInputElement>(null);
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import React, { ReactNode, useContext, useState } from "react"
|
import React, { ReactNode, useContext, useEffect, useState } from "react"
|
||||||
import { useEffect } from "react"
|
|
||||||
import { useJwt } from "react-jwt";
|
import { useJwt } from "react-jwt";
|
||||||
import { deleteToken, getToken, storeToken } from "../Utils";
|
import { deleteToken, getToken, storeToken } from "../Utils";
|
||||||
|
|
||||||
@ -16,7 +15,7 @@ type ContextProps = {
|
|||||||
|
|
||||||
const authContext = React.createContext<AuthContextProps | null>(null);
|
const authContext = React.createContext<AuthContextProps | null>(null);
|
||||||
|
|
||||||
export function ProvideAuth(props: ContextProps) {
|
export function ProvideAuth(props: Readonly<ContextProps>) {
|
||||||
const auth = useProvideAuth();
|
const auth = useProvideAuth();
|
||||||
return <authContext.Provider value={auth}>{props.children}</authContext.Provider>
|
return <authContext.Provider value={auth}>{props.children}</authContext.Provider>
|
||||||
}
|
}
|
||||||
@ -29,7 +28,7 @@ function useProvideAuth(): AuthContextProps {
|
|||||||
const [loginName, setLoginName] = useState<string | undefined>();
|
const [loginName, setLoginName] = useState<string | undefined>();
|
||||||
const [trusted, setTrusted] = useState<boolean | undefined>();
|
const [trusted, setTrusted] = useState<boolean | undefined>();
|
||||||
const [token, setToken] = useState<string | undefined>(getToken());
|
const [token, setToken] = useState<string | undefined>(getToken());
|
||||||
const { decodedToken } = useJwt(token || '');
|
const { decodedToken } = useJwt(token ?? '');
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (token && token.length > 0) {
|
if (token && token.length > 0) {
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import React, { ReactNode, useContext, useState } from "react"
|
import React, { ReactNode, useContext, useEffect, useState } from "react"
|
||||||
import { useEffect } from "react"
|
|
||||||
|
|
||||||
const BANK_ACCOUNT_NUMBER_KEY = 'bank_account_number';
|
const BANK_ACCOUNT_NUMBER_KEY = 'bank_account_number';
|
||||||
const BANK_ACCOUNT_HOLDER_KEY = 'bank_account_holder_name';
|
const BANK_ACCOUNT_HOLDER_KEY = 'bank_account_holder_name';
|
||||||
@ -20,7 +19,7 @@ type ContextProps = {
|
|||||||
|
|
||||||
const settingsContext = React.createContext<SettingsContextProps | null>(null);
|
const settingsContext = React.createContext<SettingsContextProps | null>(null);
|
||||||
|
|
||||||
export function ProvideSettings(props: ContextProps) {
|
export function ProvideSettings(props: Readonly<ContextProps>) {
|
||||||
const settings = useProvideSettings();
|
const settings = useProvideSettings();
|
||||||
return <settingsContext.Provider value={settings}>{props.children}</settingsContext.Provider>
|
return <settingsContext.Provider value={settings}>{props.children}</settingsContext.Provider>
|
||||||
}
|
}
|
||||||
@ -45,7 +44,7 @@ function useProvideSettings(): SettingsContextProps {
|
|||||||
}
|
}
|
||||||
const hideSoups = localStorage.getItem(HIDE_SOUPS_KEY);
|
const hideSoups = localStorage.getItem(HIDE_SOUPS_KEY);
|
||||||
if (hideSoups !== null) {
|
if (hideSoups !== null) {
|
||||||
setHideSoups(hideSoups === 'true' ? true : false);
|
setHideSoups(hideSoups === 'true');
|
||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
@ -18,8 +18,3 @@ export const SocketContext = React.createContext();
|
|||||||
export const EVENT_CONNECT = 'connect';
|
export const EVENT_CONNECT = 'connect';
|
||||||
export const EVENT_DISCONNECT = 'disconnect';
|
export const EVENT_DISCONNECT = 'disconnect';
|
||||||
export const EVENT_MESSAGE = 'message';
|
export const EVENT_MESSAGE = 'message';
|
||||||
// export const EVENT_CONFIG = 'config';
|
|
||||||
// export const EVENT_TOASTER = 'toaster';
|
|
||||||
// export const EVENT_VOTING = 'voting';
|
|
||||||
// export const EVENT_VOTE_CONFIG = 'voteSettings';
|
|
||||||
// export const EVENT_ADMIN = 'admin';
|
|
||||||
|
@ -49,16 +49,16 @@ export async function downloadPizzy(mock: boolean): Promise<Pizza[]> {
|
|||||||
const $ = load(html);
|
const $ = load(html);
|
||||||
const links = $('.vypisproduktu > div > h4 > a');
|
const links = $('.vypisproduktu > div > h4 > a');
|
||||||
const urls = [];
|
const urls = [];
|
||||||
for (let i = 0; i < links.length; i++) {
|
for (const element of links) {
|
||||||
if (links[i].name === 'a' && links[i].attribs?.href) {
|
if (element.name === 'a' && element.attribs?.href) {
|
||||||
const pizzaUrl = links[i].attribs?.href;
|
const pizzaUrl = element.attribs?.href;
|
||||||
urls.push(buildPizzaUrl(pizzaUrl));
|
urls.push(buildPizzaUrl(pizzaUrl));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Scrapneme jednotlivé pizzy
|
// Scrapneme jednotlivé pizzy
|
||||||
const result: Pizza[] = [];
|
const result: Pizza[] = [];
|
||||||
for (let i = 0; i < urls.length; i++) {
|
for (const element of urls) {
|
||||||
const pizzaUrl = urls[i];
|
const pizzaUrl = element;
|
||||||
const pizzaHtml = await axios.get(pizzaUrl).then(res => res.data);
|
const pizzaHtml = await axios.get(pizzaUrl).then(res => res.data);
|
||||||
// Název
|
// Název
|
||||||
const name = $('.produkt > h2', pizzaHtml).first().text()
|
const name = $('.produkt > h2', pizzaHtml).first().text()
|
||||||
|
@ -14,7 +14,7 @@ import votingRoutes from "./routes/votingRoutes";
|
|||||||
import easterEggRoutes from "./routes/easterEggRoutes";
|
import easterEggRoutes from "./routes/easterEggRoutes";
|
||||||
import statsRoutes from "./routes/statsRoutes";
|
import statsRoutes from "./routes/statsRoutes";
|
||||||
|
|
||||||
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}`) });
|
||||||
|
|
||||||
// Validace nastavení JWT tokenu - nemá bez něj smysl vůbec povolit server spustit
|
// Validace nastavení JWT tokenu - nemá bez něj smysl vůbec povolit server spustit
|
||||||
@ -35,7 +35,7 @@ app.use(cors({
|
|||||||
|
|
||||||
// Zapínatelný login přes hlavičky - pokud je zapnutý nepovolí "basicauth"
|
// Zapínatelný login přes hlavičky - pokud je zapnutý nepovolí "basicauth"
|
||||||
const HTTP_REMOTE_USER_ENABLED = process.env.HTTP_REMOTE_USER_ENABLED === 'true' || false;
|
const HTTP_REMOTE_USER_ENABLED = process.env.HTTP_REMOTE_USER_ENABLED === 'true' || false;
|
||||||
const HTTP_REMOTE_USER_HEADER_NAME = process.env.HTTP_REMOTE_USER_HEADER_NAME || 'remote-user';
|
const HTTP_REMOTE_USER_HEADER_NAME = process.env.HTTP_REMOTE_USER_HEADER_NAME ?? 'remote-user';
|
||||||
if (HTTP_REMOTE_USER_ENABLED) {
|
if (HTTP_REMOTE_USER_ENABLED) {
|
||||||
if (!process.env.HTTP_REMOTE_TRUSTED_IPS) {
|
if (!process.env.HTTP_REMOTE_TRUSTED_IPS) {
|
||||||
throw new Error('Je zapnutý login z hlaviček, ale není nastaven rozsah adres ze kterých hlavička může přijít.');
|
throw new Error('Je zapnutý login z hlaviček, ale není nastaven rozsah adres ze kterých hlavička může přijít.');
|
||||||
@ -79,7 +79,6 @@ app.post("/api/login", (req, res) => {
|
|||||||
|
|
||||||
// TODO dočasné řešení - QR se zobrazuje přes <img>, nemáme sem jak dostat token
|
// TODO dočasné řešení - QR se zobrazuje přes <img>, nemáme sem jak dostat token
|
||||||
app.get("/api/qr", (req, res) => {
|
app.get("/api/qr", (req, res) => {
|
||||||
// const login = getLogin(parseToken(req));
|
|
||||||
if (!req.query?.login) {
|
if (!req.query?.login) {
|
||||||
throw Error("Nebyl předán login");
|
throw Error("Nebyl předán login");
|
||||||
}
|
}
|
||||||
@ -148,8 +147,8 @@ app.use((err: any, req: any, res: any, next: any) => {
|
|||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
|
||||||
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';
|
||||||
|
|
||||||
server.listen(PORT, () => {
|
server.listen(PORT, () => {
|
||||||
console.log(`Server listening on ${HOST}, port ${PORT}`);
|
console.log(`Server listening on ${HOST}, port ${PORT}`);
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
/** Notifikace */
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import dotenv from 'dotenv';
|
import dotenv from 'dotenv';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { getClientData, getToday } from "./service";
|
import { getClientData, getToday } from "./service";
|
||||||
import { getUsersByLocation, getHumanTime } from "./utils";
|
import { getUsersByLocation, getHumanTime } from "./utils";
|
||||||
import getStorage from "./storage";
|
|
||||||
import { NotifikaceData, NotifikaceInput } from '../../types';
|
import { NotifikaceData, NotifikaceInput } from '../../types';
|
||||||
|
|
||||||
const storage = getStorage();
|
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}`) });
|
||||||
|
|
||||||
// const gotifyDataRaw = process.env.GOTIFY_SERVERS_AND_KEYS || "{}";
|
// const gotifyDataRaw = process.env.GOTIFY_SERVERS_AND_KEYS || "{}";
|
||||||
|
@ -128,11 +128,11 @@ export async function removePizzaOrder(login: string, pizzaOrder: PizzaVariant)
|
|||||||
if (!clientData.pizzaDay) {
|
if (!clientData.pizzaDay) {
|
||||||
throw Error("Pizza day pro dnešní den neexistuje");
|
throw Error("Pizza day pro dnešní den neexistuje");
|
||||||
}
|
}
|
||||||
const orderIndex = clientData.pizzaDay!.orders!.findIndex(o => o.customer === login);
|
const orderIndex = clientData.pizzaDay.orders!.findIndex(o => o.customer === login);
|
||||||
if (orderIndex < 0) {
|
if (orderIndex < 0) {
|
||||||
throw Error("Nebyly nalezeny žádné objednávky pro uživatele " + login);
|
throw Error("Nebyly nalezeny žádné objednávky pro uživatele " + login);
|
||||||
}
|
}
|
||||||
const order = clientData.pizzaDay!.orders![orderIndex];
|
const order = clientData.pizzaDay.orders![orderIndex];
|
||||||
const index = order.pizzaList!.findIndex(o => o.name === pizzaOrder.name && o.size === pizzaOrder.size);
|
const index = order.pizzaList!.findIndex(o => o.name === pizzaOrder.name && o.size === pizzaOrder.size);
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
throw Error("Objednávka s danými parametry nebyla nalezena");
|
throw Error("Objednávka s danými parametry nebyla nalezena");
|
||||||
@ -308,7 +308,7 @@ export async function updatePizzaFee(login: string, targetLogin: string, text?:
|
|||||||
targetOrder.fee = { text, price };
|
targetOrder.fee = { text, price };
|
||||||
}
|
}
|
||||||
// Přepočet ceny
|
// Přepočet ceny
|
||||||
targetOrder.totalPrice = targetOrder.pizzaList.reduce((price, pizzaOrder) => price + pizzaOrder.price, 0) + (targetOrder.fee?.price || 0);
|
targetOrder.totalPrice = targetOrder.pizzaList.reduce((price, pizzaOrder) => price + pizzaOrder.price, 0) + (targetOrder.fee?.price ?? 0);
|
||||||
await storage.setData(today, clientData);
|
await storage.setData(today, clientData);
|
||||||
return clientData;
|
return clientData;
|
||||||
}
|
}
|
@ -92,7 +92,6 @@ export const getMenuSladovnicka = async (firstDayOfWeek: Date, mock: boolean = f
|
|||||||
const rowText = $(dayRow).first().text().trim();
|
const rowText = $(dayRow).first().text().trim();
|
||||||
if (rowText === searchedDayText) {
|
if (rowText === searchedDayText) {
|
||||||
index = i;
|
index = i;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if (index === undefined) {
|
if (index === undefined) {
|
||||||
@ -360,7 +359,6 @@ export const getMenuZastavkaUmichala = async (firstDayOfWeek: Date, mock: boolea
|
|||||||
price: "",
|
price: "",
|
||||||
isSoup: false,
|
isSoup: false,
|
||||||
}];
|
}];
|
||||||
continue;
|
|
||||||
} else {
|
} else {
|
||||||
const url = (currentDate.getDate() === nowDate) ?
|
const url = (currentDate.getDate() === nowDate) ?
|
||||||
ZASTAVKAUMICHALA_URL : ZASTAVKAUMICHALA_URL + '/?do=dailyMenu-changeDate&dailyMenu-dateString=' + formatDate(currentDate, 'DD.MM.YYYY');
|
ZASTAVKAUMICHALA_URL : ZASTAVKAUMICHALA_URL + '/?do=dailyMenu-changeDate&dailyMenu-dateString=' + formatDate(currentDate, 'DD.MM.YYYY');
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import express, { NextFunction } from "express";
|
import express, { NextFunction } from "express";
|
||||||
import { getLogin, getTrusted } from "../auth";
|
import { getLogin } from "../auth";
|
||||||
import { parseToken } from "../utils";
|
import { parseToken } from "../utils";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
@ -34,16 +34,11 @@ function generateUrl() {
|
|||||||
*/
|
*/
|
||||||
function getEasterEggImage(req: any, res: any, next: NextFunction) {
|
function getEasterEggImage(req: any, res: any, next: NextFunction) {
|
||||||
const login = getLogin(parseToken(req));
|
const login = getLogin(parseToken(req));
|
||||||
const trusted = getTrusted(parseToken(req));
|
|
||||||
try {
|
try {
|
||||||
// TODO vrátit!
|
if (login in easterEggs) {
|
||||||
// if (trusted) {
|
const imagePath = easterEggs[login][Math.floor(Math.random() * easterEggs[login].length)].path;
|
||||||
if (true) {
|
res.sendFile(path.join(__dirname, IMAGES_PATH, imagePath));
|
||||||
if (login in easterEggs) {
|
return;
|
||||||
const imagePath = easterEggs[login][Math.floor(Math.random() * easterEggs[login].length)].path;
|
|
||||||
res.sendFile(path.join(__dirname, IMAGES_PATH, imagePath));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
res.sendStatus(404);
|
res.sendStatus(404);
|
||||||
} catch (e: any) { next(e) }
|
} catch (e: any) { next(e) }
|
||||||
@ -124,7 +119,7 @@ let easterEggs: EasterEggsJson;
|
|||||||
if (fs.existsSync(EASTER_EGGS_JSON_PATH)) {
|
if (fs.existsSync(EASTER_EGGS_JSON_PATH)) {
|
||||||
const content = fs.readFileSync(EASTER_EGGS_JSON_PATH, 'utf-8');
|
const content = fs.readFileSync(EASTER_EGGS_JSON_PATH, 'utf-8');
|
||||||
easterEggs = JSON.parse(content);
|
easterEggs = JSON.parse(content);
|
||||||
for (const [key, eggs] of Object.entries(easterEggs)) {
|
for (const [_, eggs] of Object.entries(easterEggs)) {
|
||||||
for (const easterEgg of eggs) {
|
for (const easterEgg of eggs) {
|
||||||
const url = generateUrl();
|
const url = generateUrl();
|
||||||
easterEgg.url = url;
|
easterEgg.url = url;
|
||||||
@ -138,16 +133,11 @@ if (fs.existsSync(EASTER_EGGS_JSON_PATH)) {
|
|||||||
// Získání náhodného easter eggu pro přihlášeného uživatele
|
// Získání náhodného easter eggu pro přihlášeného uživatele
|
||||||
router.get("/", async (req, res, next) => {
|
router.get("/", async (req, res, next) => {
|
||||||
const login = getLogin(parseToken(req));
|
const login = getLogin(parseToken(req));
|
||||||
const trusted = getTrusted(parseToken(req));
|
|
||||||
try {
|
try {
|
||||||
// TODO vrátit!
|
if (easterEggs && login in easterEggs) {
|
||||||
// if (trusted) {
|
const randomEasterEgg = easterEggs[login][Math.floor(Math.random() * easterEggs[login].length)];
|
||||||
if (true) {
|
const { path, startOffset, endOffset, ...strippedEasterEgg } = randomEasterEgg; // Path klient k ničemu nepotřebuje a nemá ho znát
|
||||||
if (easterEggs && login in easterEggs) {
|
return res.status(200).json({ ...strippedEasterEgg, ...getRandomPosition(startOffset, endOffset) });
|
||||||
const randomEasterEgg = easterEggs[login][Math.floor(Math.random() * easterEggs[login].length)];
|
|
||||||
const { path, startOffset, endOffset, ...strippedEasterEgg } = randomEasterEgg; // Path klient k ničemu nepotřebuje a nemá ho znát
|
|
||||||
return res.status(200).json({ ...strippedEasterEgg, ...getRandomPosition(startOffset, endOffset) });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return res.status(200).send();
|
return res.status(200).send();
|
||||||
} catch (e: any) { next(e) }
|
} catch (e: any) { next(e) }
|
||||||
|
@ -4,8 +4,7 @@ import { addChoice, getDateForWeekIndex, getToday, removeChoice, removeChoices,
|
|||||||
import { getDayOfWeekIndex, parseToken } from "../utils";
|
import { getDayOfWeekIndex, parseToken } from "../utils";
|
||||||
import { getWebsocket } from "../websocket";
|
import { getWebsocket } from "../websocket";
|
||||||
import { callNotifikace } from "../notifikace";
|
import { callNotifikace } from "../notifikace";
|
||||||
import { AddChoiceRequest, ChangeDepartureTimeRequest, IDayIndex, RemoveChoiceRequest, RemoveChoicesRequest, UpdateNoteRequest } from "../../../types";
|
import { AddChoiceRequest, ChangeDepartureTimeRequest, IDayIndex, RemoveChoiceRequest, RemoveChoicesRequest, UdalostEnum, UpdateNoteRequest } from "../../../types";
|
||||||
import { UdalostEnum } from "../../../types";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ověří a vrátí index dne v týdnu z požadavku, za předpokladu, že byl předán, a je zároveň
|
* Ověří a vrátí index dne v týdnu z požadavku, za předpokladu, že byl předán, a je zároveň
|
||||||
|
@ -2,8 +2,7 @@ import express, { Request, Response } from "express";
|
|||||||
import { getLogin } from "../auth";
|
import { getLogin } from "../auth";
|
||||||
import { parseToken } from "../utils";
|
import { parseToken } from "../utils";
|
||||||
import { getUserVotes, updateFeatureVote } from "../voting";
|
import { getUserVotes, updateFeatureVote } from "../voting";
|
||||||
import { UpdateFeatureVoteRequest } from "../../../types";
|
import { FeatureRequest, UpdateFeatureVoteRequest } from "../../../types";
|
||||||
import { FeatureRequest } from "../../../types";
|
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { InsufficientPermissions, formatDate, getDayOfWeekIndex, getFirstWorkDayOfWeek, getHumanDate, getIsWeekend, getWeekNumber } from "./utils";
|
import { InsufficientPermissions, formatDate, getDayOfWeekIndex, getFirstWorkDayOfWeek, getHumanDate, getIsWeekend, getWeekNumber } from "./utils";
|
||||||
import getStorage from "./storage";
|
import getStorage from "./storage";
|
||||||
import { getMenuSladovnicka, getMenuTechTower, getMenuUMotliku, getMenuZastavkaUmichala, getMenuSenkSerikova } from "./restaurants";
|
import { getMenuSladovnicka, getMenuTechTower, getMenuZastavkaUmichala, getMenuSenkSerikova } from "./restaurants";
|
||||||
import { getTodayMock } from "./mock";
|
import { getTodayMock } from "./mock";
|
||||||
import { ClientData, DepartureTime, LunchChoice, Restaurant, RestaurantDayMenu, WeekMenu } from "../../types";
|
import { ClientData, DepartureTime, LunchChoice, Restaurant, RestaurantDayMenu, WeekMenu } from "../../types";
|
||||||
|
|
||||||
@ -152,10 +152,10 @@ export async function getRestaurantMenu(restaurant: keyof typeof Restaurant, dat
|
|||||||
weekMenu[i][restaurant]!.closed = true;
|
weekMenu[i][restaurant]!.closed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
console.error("Selhalo načtení jídel pro podnik TechTower", e);
|
console.error("Selhalo načtení jídel pro podnik TechTower", e);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case 'ZASTAVKAUMICHALA':
|
case 'ZASTAVKAUMICHALA':
|
||||||
try {
|
try {
|
||||||
const zastavkaUmichalaFood = await getMenuZastavkaUmichala(firstDay, mock);
|
const zastavkaUmichalaFood = await getMenuZastavkaUmichala(firstDay, mock);
|
||||||
@ -165,10 +165,10 @@ export async function getRestaurantMenu(restaurant: keyof typeof Restaurant, dat
|
|||||||
weekMenu[i][restaurant]!.closed = true;
|
weekMenu[i][restaurant]!.closed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
console.error("Selhalo načtení jídel pro podnik Zastávka u Michala", e);
|
console.error("Selhalo načtení jídel pro podnik Zastávka u Michala", e);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case 'SENKSERIKOVA':
|
case 'SENKSERIKOVA':
|
||||||
try {
|
try {
|
||||||
const senkSerikovaFood = await getMenuSenkSerikova(firstDay, mock);
|
const senkSerikovaFood = await getMenuSenkSerikova(firstDay, mock);
|
||||||
@ -178,10 +178,10 @@ export async function getRestaurantMenu(restaurant: keyof typeof Restaurant, dat
|
|||||||
weekMenu[i][restaurant]!.closed = true;
|
weekMenu[i][restaurant]!.closed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
console.error("Selhalo načtení jídel pro podnik Pivovarský šenk Šeříková", e);
|
console.error("Selhalo načtení jídel pro podnik Pivovarský šenk Šeříková", e);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
await storage.setData(getMenuKey(usedDate), weekMenu);
|
await storage.setData(getMenuKey(usedDate), weekMenu);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ import { DailyStats, LunchChoice, WeeklyStats } from "../../types";
|
|||||||
import { getStatsMock } from "./mock";
|
import { getStatsMock } from "./mock";
|
||||||
import { getClientData } from "./service";
|
import { getClientData } from "./service";
|
||||||
import getStorage from "./storage";
|
import getStorage from "./storage";
|
||||||
import { formatDate } from "./utils";
|
|
||||||
|
|
||||||
const storage = getStorage();
|
const storage = getStorage();
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import { StorageInterface } from "./StorageInterface";
|
|||||||
import JsonStorage from "./json";
|
import JsonStorage from "./json";
|
||||||
import RedisStorage from "./redis";
|
import RedisStorage from "./redis";
|
||||||
|
|
||||||
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}`) });
|
||||||
|
|
||||||
const JSON_KEY = 'json';
|
const JSON_KEY = 'json';
|
||||||
|
@ -8,15 +8,15 @@ let client: RedisClientType;
|
|||||||
*/
|
*/
|
||||||
export default class RedisStorage implements StorageInterface {
|
export default class RedisStorage implements StorageInterface {
|
||||||
constructor() {
|
constructor() {
|
||||||
const HOST = process.env.REDIS_HOST || 'localhost';
|
const HOST = process.env.REDIS_HOST ?? 'localhost';
|
||||||
const PORT = process.env.REDIS_PORT || 6379;
|
const PORT = process.env.REDIS_PORT ?? 6379;
|
||||||
client = createClient({ url: `redis://${HOST}:${PORT}` });
|
client = createClient({ url: `redis://${HOST}:${PORT}` });
|
||||||
client.connect();
|
client.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
async hasData(key: string) {
|
async hasData(key: string) {
|
||||||
const data = await client.json.get(key);
|
const data = await client.json.get(key);
|
||||||
return (data ? true : false);
|
return (!!data);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getData<Type>(key: string) {
|
async getData<Type>(key: string) {
|
||||||
|
@ -8,7 +8,7 @@ export function formatDate(date: Date, format?: string) {
|
|||||||
let month = String(date.getMonth() + 1).padStart(2, "0");
|
let month = String(date.getMonth() + 1).padStart(2, "0");
|
||||||
let year = String(date.getFullYear());
|
let year = String(date.getFullYear());
|
||||||
|
|
||||||
const f = (format === undefined) ? 'YYYY-MM-DD' : format;
|
const f = format ?? 'YYYY-MM-DD';
|
||||||
return f.replace('DD', day).replace('MM', month).replace('YYYY', year);
|
return f.replace('DD', day).replace('MM', month).replace('YYYY', year);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,10 +61,10 @@ export function getLastWorkDayOfWeek(date: Date) {
|
|||||||
|
|
||||||
/** Vrátí pořadové číslo týdne předaného data v roce dle ISO 8601. */
|
/** Vrátí pořadové číslo týdne předaného data v roce dle ISO 8601. */
|
||||||
export function getWeekNumber(inputDate: Date) {
|
export function getWeekNumber(inputDate: Date) {
|
||||||
var date = new Date(inputDate.getTime());
|
const date = new Date(inputDate.getTime());
|
||||||
date.setHours(0, 0, 0, 0);
|
date.setHours(0, 0, 0, 0);
|
||||||
date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7);
|
date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7);
|
||||||
var week1 = new Date(date.getFullYear(), 0, 4);
|
const week1 = new Date(date.getFullYear(), 0, 4);
|
||||||
return 1 + Math.round(((date.getTime() - week1.getTime()) / 86400000 - 3 + (week1.getDay() + 6) % 7) / 7);
|
return 1 + Math.round(((date.getTime() - week1.getTime()) / 86400000 - 3 + (week1.getDay() + 6) % 7) / 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user