Možnost skrytí polévek

This commit is contained in:
Martin Berka 2024-01-24 18:54:05 +01:00
parent 2633d445cc
commit 72c7bfe80c
5 changed files with 67 additions and 37 deletions

View File

@ -13,7 +13,7 @@ import 'react-select-search/style.css';
import './App.css'; import './App.css';
import { SelectSearchOption } from 'react-select-search'; import { SelectSearchOption } from 'react-select-search';
import { faCircleCheck, faTrashCan } from '@fortawesome/free-regular-svg-icons'; import { faCircleCheck, faTrashCan } from '@fortawesome/free-regular-svg-icons';
import { useBank } from './context/bank'; import { useSettings } from './context/settings';
import { ClientData, Restaurants, Food, Order, Locations, PizzaOrder, PizzaDayState, FoodChoices, DayMenu, DepartureTime } from './types'; import { ClientData, Restaurants, Food, Order, Locations, PizzaOrder, PizzaDayState, FoodChoices, DayMenu, DepartureTime } from './types';
import Footer from './components/Footer'; import Footer from './components/Footer';
import { faChainBroken, faChevronLeft, faChevronRight, faGear, faSatelliteDish, faSearch } from '@fortawesome/free-solid-svg-icons'; import { faChainBroken, faChevronLeft, faChevronRight, faGear, faSatelliteDish, faSearch } from '@fortawesome/free-solid-svg-icons';
@ -26,7 +26,7 @@ const EVENT_CONNECT = "connect"
function App() { function App() {
const auth = useAuth(); const auth = useAuth();
const bank = useBank(); const settings = useSettings();
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<{ [key in Restaurants]?: DayMenu }>(); const [food, setFood] = useState<{ [key in Restaurants]?: DayMenu }>();
@ -302,7 +302,7 @@ function App() {
} else if (menu?.food?.length > 0) { } else if (menu?.food?.length > 0) {
content = <Table striped bordered hover> content = <Table striped bordered hover>
<tbody> <tbody>
{menu.food.map((f: any, index: number) => {menu.food.filter(f => (settings?.hideSoups ? !f.isSoup : true)).map((f: any, index: number) =>
<tr key={index}> <tr key={index}>
<td>{f.amount}</td> <td>{f.amount}</td>
<td>{f.name}</td> <td>{f.name}</td>
@ -360,7 +360,7 @@ function App() {
<Alert variant={'primary'}> <Alert variant={'primary'}>
Poslední změny: Poslední změny:
<ul> <ul>
<li>Základní pizza kalkulačka (v menu)</li> <li>Možnost skrytí polévek</li>
</ul> </ul>
</Alert> </Alert>
{dayIndex != null && {dayIndex != null &&
@ -540,7 +540,7 @@ function App() {
await lockPizzaDay(); await lockPizzaDay();
}}>Vrátit do "uzamčeno"</Button> }}>Vrátit do "uzamčeno"</Button>
<Button className='danger mb-3' style={{ marginLeft: '20px' }} title="Nastaví stav na 'Doručeno' - koncový stav." onClick={async () => { <Button className='danger mb-3' style={{ marginLeft: '20px' }} title="Nastaví stav na 'Doručeno' - koncový stav." onClick={async () => {
await finishDelivery(bank?.bankAccount, bank?.holderName); await finishDelivery(settings?.bankAccount, settings?.holderName);
}}>Doručeno</Button> }}>Doručeno</Button>
</div> </div>
} }

View File

@ -1,8 +1,8 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { Navbar, Nav, NavDropdown } from "react-bootstrap"; import { Navbar, Nav, NavDropdown } from "react-bootstrap";
import { useAuth } from "../context/auth"; import { useAuth } from "../context/auth";
import BankAccountModal from "./modals/BankAccountModal"; import SettingsModal from "./modals/SettingsModal";
import { useBank } from "../context/bank"; import { useSettings } from "../context/settings";
import FeaturesVotingModal from "./modals/FeaturesVotingModal"; import FeaturesVotingModal from "./modals/FeaturesVotingModal";
import { FeatureRequest } from "../types"; import { FeatureRequest } from "../types";
import { errorHandler } from "../api/Api"; import { errorHandler } from "../api/Api";
@ -12,8 +12,8 @@ import PizzaCalculatorModal from "./modals/PizzaCalculatorModal";
export default function Header() { export default function Header() {
const auth = useAuth(); const auth = useAuth();
const bank = useBank(); const settings = useSettings();
const [bankModalOpen, setBankModalOpen] = useState<boolean>(false); const [settingsModalOpen, setSettingsModalOpen] = useState<boolean>(false);
const [votingModalOpen, setVotingModalOpen] = useState<boolean>(false); const [votingModalOpen, setVotingModalOpen] = useState<boolean>(false);
const [pizzaModalOpen, setPizzaModalOpen] = useState<boolean>(false); const [pizzaModalOpen, setPizzaModalOpen] = useState<boolean>(false);
const [featureVotes, setFeatureVotes] = useState<FeatureRequest[]>([]); const [featureVotes, setFeatureVotes] = useState<FeatureRequest[]>([]);
@ -26,8 +26,8 @@ export default function Header() {
} }
}, [auth?.login]); }, [auth?.login]);
const closeBankModal = () => { const closeSettingsModal = () => {
setBankModalOpen(false); setSettingsModalOpen(false);
} }
const closeVotingModal = () => { const closeVotingModal = () => {
@ -48,7 +48,7 @@ export default function Header() {
return n !== Infinity && String(n) === str && n >= 0; return n !== Infinity && String(n) === str && n >= 0;
} }
const saveBankAccount = (bankAccountNumber?: string, bankAccountHolderName?: string) => { const saveSettings = (bankAccountNumber?: string, bankAccountHolderName?: string, hideSoupsOption?: boolean) => {
if (bankAccountNumber) { if (bankAccountNumber) {
try { try {
// Validace kódu banky // Validace kódu banky
@ -90,9 +90,10 @@ export default function Header() {
return return
} }
} }
bank?.setBankAccountNumber(bankAccountNumber); settings?.setBankAccountNumber(bankAccountNumber);
bank?.setBankAccountHolderName(bankAccountHolderName); settings?.setBankAccountHolderName(bankAccountHolderName);
closeBankModal(); settings?.setHideSoupsOption(hideSoupsOption);
closeSettingsModal();
} }
const saveFeatureVote = async (option: FeatureRequest, active: boolean) => { const saveFeatureVote = async (option: FeatureRequest, active: boolean) => {
@ -112,7 +113,7 @@ export default function Header() {
<Navbar.Collapse id="basic-navbar-nav"> <Navbar.Collapse id="basic-navbar-nav">
<Nav className="nav"> <Nav className="nav">
<NavDropdown align="end" title={auth?.login} id="basic-nav-dropdown"> <NavDropdown align="end" title={auth?.login} id="basic-nav-dropdown">
<NavDropdown.Item onClick={() => setBankModalOpen(true)}>Nastavit číslo účtu</NavDropdown.Item> <NavDropdown.Item onClick={() => setSettingsModalOpen(true)}>Nastavení</NavDropdown.Item>
<NavDropdown.Item onClick={() => setVotingModalOpen(true)}>Hlasovat o nových funkcích</NavDropdown.Item> <NavDropdown.Item onClick={() => setVotingModalOpen(true)}>Hlasovat o nových funkcích</NavDropdown.Item>
<NavDropdown.Item onClick={() => setPizzaModalOpen(true)}>Pizza kalkulačka</NavDropdown.Item> <NavDropdown.Item onClick={() => setPizzaModalOpen(true)}>Pizza kalkulačka</NavDropdown.Item>
<NavDropdown.Divider /> <NavDropdown.Divider />
@ -120,7 +121,7 @@ export default function Header() {
</NavDropdown> </NavDropdown>
</Nav> </Nav>
</Navbar.Collapse> </Navbar.Collapse>
<BankAccountModal isOpen={bankModalOpen} onClose={closeBankModal} onSave={saveBankAccount} /> <SettingsModal isOpen={settingsModalOpen} onClose={closeSettingsModal} onSave={saveSettings} />
<FeaturesVotingModal isOpen={votingModalOpen} onClose={closeVotingModal} onChange={saveFeatureVote} initialValues={featureVotes} /> <FeaturesVotingModal isOpen={votingModalOpen} onClose={closeVotingModal} onChange={saveFeatureVote} initialValues={featureVotes} />
<PizzaCalculatorModal isOpen={pizzaModalOpen} onClose={closePizzaModal} /> <PizzaCalculatorModal isOpen={pizzaModalOpen} onClose={closePizzaModal} />
</Navbar> </Navbar>

View File

@ -1,33 +1,40 @@
import { useRef } from "react"; import { useRef } from "react";
import { Modal, Button } from "react-bootstrap" import { Modal, Button } from "react-bootstrap"
import { useBank } from "../../context/bank"; import { useSettings } from "../../context/settings";
type Props = { type Props = {
isOpen: boolean, isOpen: boolean,
onClose: () => void, onClose: () => void,
onSave: (bankAccountNumber?: string, bankAccountHolderName?: string) => void, onSave: (bankAccountNumber?: string, bankAccountHolderName?: string, hideSoupsOption?: boolean) => void,
} }
/** Modální dialog pro nastavení čísla účtu a jména majitele. */ /** Modální dialog pro uživatelská nastavení. */
export default function BankAccountModal({ isOpen, onClose, onSave }: Props) { export default function SettingsModal({ isOpen, onClose, onSave }: Props) {
const bank = useBank(); const settings = useSettings();
const bankAccountRef = useRef<HTMLInputElement>(null); const bankAccountRef = useRef<HTMLInputElement>(null);
const nameRef = useRef<HTMLInputElement>(null); const nameRef = useRef<HTMLInputElement>(null);
const hideSoupsRef = useRef<HTMLInputElement>(null);
return <Modal show={isOpen} onHide={onClose} size="lg"> return <Modal show={isOpen} onHide={onClose} size="lg">
<Modal.Header closeButton> <Modal.Header closeButton>
<Modal.Title>Bankovní účet</Modal.Title> <Modal.Title><h2>Nastavení</h2></Modal.Title>
</Modal.Header> </Modal.Header>
<Modal.Body> <Modal.Body>
<h4>Obecné</h4>
<span title="V nabídkách nebudou zobrazovány polévky. Tato funkce je experimentální, a zejména u TechTower bývá často problém polévky spolehlivě rozeznat. V případě využití této funkce průběžně nahlašujte stále se zobrazující polévky." style={{ "cursor": "help" }}>
<input ref={hideSoupsRef} type="checkbox" defaultChecked={settings?.hideSoups} /> Skrýt polévky
</span>
<hr />
<h4>Bankovní účet</h4>
<p>Nastavením čísla účtu umožníte automatické generování QR kódů pro úhradu za vámi provedené objednávky v rámci Pizza day.<br />Pokud vaše číslo účtu neobsahuje předčíslí, je možné ho zcela vynechat.<br /><br />Číslo účtu není ukládáno na serveru, posílá se na něj pouze za účelem vygenerování QR kódů.</p> <p>Nastavením čísla účtu umožníte automatické generování QR kódů pro úhradu za vámi provedené objednávky v rámci Pizza day.<br />Pokud vaše číslo účtu neobsahuje předčíslí, je možné ho zcela vynechat.<br /><br />Číslo účtu není ukládáno na serveru, posílá se na něj pouze za účelem vygenerování QR kódů.</p>
Číslo účtu: <input className="mb-3" ref={bankAccountRef} type="text" placeholder="123456-1234567890/1234" defaultValue={bank?.bankAccount} /> <br /> Číslo účtu: <input className="mb-3" ref={bankAccountRef} type="text" placeholder="123456-1234567890/1234" defaultValue={settings?.bankAccount} /> <br />
Název příjemce (jméno majitele účtu): <input ref={nameRef} type="text" placeholder="Jan Novák" defaultValue={bank?.holderName} /> Název příjemce (jméno majitele účtu): <input ref={nameRef} type="text" placeholder="Jan Novák" defaultValue={settings?.holderName} />
</Modal.Body> </Modal.Body>
<Modal.Footer> <Modal.Footer>
<Button variant="secondary" onClick={onClose}> <Button variant="secondary" onClick={onClose}>
Storno Storno
</Button> </Button>
<Button variant="primary" onClick={() => onSave(bankAccountRef.current?.value, nameRef.current?.value)}> <Button variant="primary" onClick={() => onSave(bankAccountRef.current?.value, nameRef.current?.value, hideSoupsRef.current?.checked)}>
Uložit Uložit
</Button> </Button>
</Modal.Footer> </Modal.Footer>

View File

@ -3,32 +3,36 @@ 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';
const HIDE_SOUPS_KEY = 'hide_soups';
export type BankContextProps = { export type SettingsContextProps = {
bankAccount?: string, bankAccount?: string,
holderName?: string, holderName?: string,
hideSoups?: boolean,
setBankAccountNumber: (accountNumber?: string) => void, setBankAccountNumber: (accountNumber?: string) => void,
setBankAccountHolderName: (holderName?: string) => void, setBankAccountHolderName: (holderName?: string) => void,
setHideSoupsOption: (hideSoups?: boolean) => void,
} }
type ContextProps = { type ContextProps = {
children: ReactNode children: ReactNode
} }
const bankContext = React.createContext<BankContextProps | null>(null); const settingsContext = React.createContext<SettingsContextProps | null>(null);
export function ProvideBank(props: ContextProps) { export function ProvideSettings(props: ContextProps) {
const bank = useProvideBank(); const settings = useProvideSettings();
return <bankContext.Provider value={bank}>{props.children}</bankContext.Provider> return <settingsContext.Provider value={settings}>{props.children}</settingsContext.Provider>
} }
export const useBank = () => { export const useSettings = () => {
return useContext(bankContext); return useContext(settingsContext);
} }
function useProvideBank(): BankContextProps { function useProvideSettings(): SettingsContextProps {
const [bankAccount, setBankAccount] = useState<string | undefined>(); const [bankAccount, setBankAccount] = useState<string | undefined>();
const [holderName, setHolderName] = useState<string | undefined>(); const [holderName, setHolderName] = useState<string | undefined>();
const [hideSoups, setHideSoups] = useState<boolean | undefined>();
useEffect(() => { useEffect(() => {
const accountNumber = localStorage.getItem(BANK_ACCOUNT_NUMBER_KEY); const accountNumber = localStorage.getItem(BANK_ACCOUNT_NUMBER_KEY);
@ -39,6 +43,10 @@ function useProvideBank(): BankContextProps {
if (holderName) { if (holderName) {
setHolderName(holderName); setHolderName(holderName);
} }
const hideSoups = localStorage.getItem(HIDE_SOUPS_KEY);
if (hideSoups !== null) {
setHideSoups(hideSoups === 'true' ? true : false);
}
}, []) }, [])
useEffect(() => { useEffect(() => {
@ -57,6 +65,14 @@ function useProvideBank(): BankContextProps {
} }
}, [holderName]); }, [holderName]);
useEffect(() => {
if (hideSoups) {
localStorage.setItem(HIDE_SOUPS_KEY, hideSoups ? 'true' : 'false');
} else {
localStorage.removeItem(HIDE_SOUPS_KEY);
}
}, [hideSoups]);
function setBankAccountNumber(bankAccount?: string) { function setBankAccountNumber(bankAccount?: string) {
setBankAccount(bankAccount); setBankAccount(bankAccount);
} }
@ -65,10 +81,16 @@ function useProvideBank(): BankContextProps {
setHolderName(holderName); setHolderName(holderName);
} }
function setHideSoupsOption(hideSoups?: boolean) {
setHideSoups(hideSoups);
}
return { return {
bankAccount, bankAccount,
holderName, holderName,
hideSoups,
setBankAccountNumber, setBankAccountNumber,
setBankAccountHolderName, setBankAccountHolderName,
setHideSoupsOption,
} }
} }

View File

@ -4,7 +4,7 @@ import App from './App';
import { SocketContext, socket } from './context/socket'; import { SocketContext, socket } from './context/socket';
import { ProvideAuth } from './context/auth'; import { ProvideAuth } from './context/auth';
import { ToastContainer } from 'react-toastify'; import { ToastContainer } from 'react-toastify';
import { ProvideBank } from './context/bank'; import { ProvideSettings } from './context/settings';
import 'react-toastify/dist/ReactToastify.css'; import 'react-toastify/dist/ReactToastify.css';
import './index.css'; import './index.css';
@ -14,12 +14,12 @@ const root = ReactDOM.createRoot(
root.render( root.render(
<React.StrictMode> <React.StrictMode>
<ProvideAuth> <ProvideAuth>
<ProvideBank> <ProvideSettings>
<SocketContext.Provider value={socket}> <SocketContext.Provider value={socket}>
<App /> <App />
<ToastContainer /> <ToastContainer />
</SocketContext.Provider> </SocketContext.Provider>
</ProvideBank> </ProvideSettings>
</ProvideAuth> </ProvideAuth>
</React.StrictMode> </React.StrictMode>
); );