CI / Generate TypeScript types (push) Successful in 10s
CI / Server unit tests (push) Successful in 28s
CI / Build server (push) Successful in 37s
CI / Build client (push) Successful in 45s
CI / Playwright E2E tests (push) Successful in 2m15s
CI / Build and push Docker image (push) Successful in 45s
CI / Notify (push) Successful in 2s
75 lines
2.7 KiB
TypeScript
75 lines
2.7 KiB
TypeScript
import { useEffect, useState } from "react";
|
|
import { Modal, Button, Form } from "react-bootstrap";
|
|
|
|
type Props = {
|
|
isOpen: boolean,
|
|
onClose: () => void,
|
|
/** Uložená cena v haléřích */
|
|
price?: number,
|
|
/** Cena v haléřích spočtená z vybraných jídel v menu, nabídne se, pokud cena ještě není uložená */
|
|
suggestedPrice?: number,
|
|
/** Cena v haléřích, undefined cenu odstraní */
|
|
onSave: (price?: number) => void,
|
|
}
|
|
|
|
const toCrownsText = (amount?: number) => amount ? String(amount / 100).replace('.', ',') : '';
|
|
|
|
/** Modální dialog pro zadání ceny oběda, která se promítne do přehledu stravování. */
|
|
const PriceModal = ({ isOpen, onClose, price, suggestedPrice, onSave }: Readonly<Props>) => {
|
|
const [value, setValue] = useState('');
|
|
|
|
useEffect(() => {
|
|
if (isOpen) {
|
|
setValue(toCrownsText(price ?? suggestedPrice));
|
|
}
|
|
}, [isOpen, price, suggestedPrice]);
|
|
|
|
const parsed = value.trim().length ? Number.parseFloat(value.replace(',', '.')) : undefined;
|
|
const invalid = parsed != null && (Number.isNaN(parsed) || parsed < 0);
|
|
|
|
const save = () => {
|
|
if (invalid) return;
|
|
onSave(parsed == null ? undefined : Math.round(parsed * 100));
|
|
}
|
|
|
|
return <Modal show={isOpen} onHide={onClose}>
|
|
<Modal.Header closeButton>
|
|
<Modal.Title>Cena oběda</Modal.Title>
|
|
</Modal.Header>
|
|
<Modal.Body>
|
|
<p className="text-muted small">Cena se promítne do vašeho měsíčního přehledu stravování (export).</p>
|
|
<div className="d-flex align-items-center gap-2">
|
|
<Form.Control
|
|
autoFocus
|
|
type="text"
|
|
inputMode="decimal"
|
|
placeholder="např. 145"
|
|
value={value}
|
|
isInvalid={invalid}
|
|
onChange={e => setValue(e.target.value.replace(/[^0-9.,]/g, ''))}
|
|
onKeyDown={event => {
|
|
if (event.key === 'Enter') {
|
|
save();
|
|
}
|
|
event.stopPropagation();
|
|
}}
|
|
/>
|
|
<span>Kč</span>
|
|
</div>
|
|
</Modal.Body>
|
|
<Modal.Footer>
|
|
{price != null && <Button variant="outline-danger" className="me-auto" onClick={() => onSave(undefined)}>
|
|
Odstranit cenu
|
|
</Button>}
|
|
<Button variant="secondary" onClick={() => onClose()}>
|
|
Storno
|
|
</Button>
|
|
<Button variant="primary" onClick={() => save()} disabled={invalid}>
|
|
Uložit
|
|
</Button>
|
|
</Modal.Footer>
|
|
</Modal>
|
|
}
|
|
|
|
export default PriceModal;
|