feat: rozdělení nastavení do 2 sloupců
CI / Generate TypeScript types (push) Successful in 10s
CI / Server unit tests (push) Successful in 27s
CI / Build server (push) Successful in 29s
CI / Build client (push) Successful in 41s
CI / Playwright E2E tests (push) Successful in 2m24s
CI / Build and push Docker image (push) Successful in 47s
CI / Notify (push) Successful in 2s

This commit is contained in:
mates committed 2026-10-13 11:25:52 +02:00
1 parent dc17fa0f0f
commit 9fa00fa9c5
1 file changed
+171 -165
+171 -165
View File
@@ -1,5 +1,5 @@
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { Modal, Button, Form } from "react-bootstrap" import { Modal, Button, Form, Row, Col } from "react-bootstrap"
import { useSettings, ThemePreference, StyleTheme, STYLE_THEMES } from "../../context/settings"; import { useSettings, ThemePreference, StyleTheme, STYLE_THEMES } from "../../context/settings";
import { NotificationSettings, UdalostEnum, getNotificationSettings, updateNotificationSettings } from "../../../../types"; import { NotificationSettings, UdalostEnum, getNotificationSettings, updateNotificationSettings } from "../../../../types";
import { useAuth } from "../../context/auth"; import { useAuth } from "../../context/auth";
@@ -92,187 +92,193 @@ export default function SettingsModal({ isOpen, onClose, onSave }: Readonly<Prop
}; };
return ( return (
<Modal show={isOpen} onHide={onClose} size="lg"> <Modal show={isOpen} onHide={onClose} size="xl">
<Modal.Header closeButton> <Modal.Header closeButton>
<Modal.Title><h2>Nastavení</h2></Modal.Title> <Modal.Title><h2>Nastavení</h2></Modal.Title>
</Modal.Header> </Modal.Header>
<Modal.Body> <Modal.Body>
<h4>Vzhled</h4> {/* Na širších obrazovkách rozdělení do dvou sloupců, na užších pod sebou */}
<Form.Group className="mb-3"> <Row className="gx-5">
<Form.Label>Styl</Form.Label> <Col lg={6}>
<Form.Select ref={styleThemeRef} defaultValue={settings?.styleTheme}> <h4>Vzhled</h4>
{STYLE_THEMES.map(t => <option key={t.value} value={t.value}>{t.label}</option>)} <Form.Group className="mb-3">
</Form.Select> <Form.Label>Styl</Form.Label>
</Form.Group> <Form.Select ref={styleThemeRef} defaultValue={settings?.styleTheme}>
<Form.Group className="mb-3"> {STYLE_THEMES.map(t => <option key={t.value} value={t.value}>{t.label}</option>)}
<Form.Label>Barevný motiv</Form.Label> </Form.Select>
<Form.Select ref={themeRef} defaultValue={settings?.themePreference}> </Form.Group>
<option value="system">Podle systému</option> <Form.Group className="mb-3">
<option value="light">Světlý</option> <Form.Label>Barevný motiv</Form.Label>
<option value="dark">Tmavý</option> <Form.Select ref={themeRef} defaultValue={settings?.themePreference}>
</Form.Select> <option value="system">Podle systému</option>
</Form.Group> <option value="light">Světlý</option>
<Form.Group className="mb-3"> <option value="dark">Tmavý</option>
<Form.Check </Form.Select>
id="showButterfliesCheckbox" </Form.Group>
ref={showButterfliesRef} <Form.Group className="mb-3">
type="checkbox" <Form.Check
label="Zobrazit motýlky" id="showButterfliesCheckbox"
defaultChecked={settings?.showButterflies ?? true} ref={showButterfliesRef}
/> type="checkbox"
<Form.Text className="text-muted"> label="Zobrazit motýlky"
Po vypnutí se poletující motýlci ani minihra nebudou vůbec zobrazovat. defaultChecked={settings?.showButterflies ?? true}
</Form.Text> />
</Form.Group> <Form.Text className="text-muted">
Po vypnutí se poletující motýlci ani minihra nebudou vůbec zobrazovat.
</Form.Text>
</Form.Group>
<hr /> <hr />
<h4>Obecné</h4> <h4>Obecné</h4>
<Form.Group className="mb-3"> <Form.Group className="mb-3">
<Form.Check <Form.Check
id="hideSoupsCheckbox" id="hideSoupsCheckbox"
ref={hideSoupsRef} ref={hideSoupsRef}
type="checkbox" type="checkbox"
label="Skrýt polévky" label="Skrýt polévky"
defaultChecked={settings?.hideSoups} defaultChecked={settings?.hideSoups}
title="V nabídkách nebudou zobrazovány polévky. Tato funkce je experimentální." title="V nabídkách nebudou zobrazovány polévky. Tato funkce je experimentální."
/> />
<Form.Text className="text-muted"> <Form.Text className="text-muted">
Experimentální funkce - zejména u TechTower bývá problém polévky spolehlivě rozeznat. Experimentální funkce - zejména u TechTower bývá problém polévky spolehlivě rozeznat.
</Form.Text> </Form.Text>
</Form.Group> </Form.Group>
<hr /> <hr />
<h4>Notifikace</h4> <h4>Bankovní účet</h4>
<p> <p>
Nastavením notifikací budete dostávat upozornění o událostech (např. "Jdeme na oběd") přímo do vámi zvoleného komunikačního kanálu. 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.
</p> </p>
<Form.Group className="mb-3"> <Form.Group className="mb-3">
<Form.Label>Připomínka výběru oběda</Form.Label> <Form.Label>Číslo účtu</Form.Label>
<Form.Control <Form.Control
ref={reminderTimeRef} ref={bankAccountRef}
type="time" type="text"
defaultValue={notifSettings.reminderTime ?? ''} placeholder="123456-1234567890/1234"
key={notifSettings.reminderTime ?? 'reminder-empty'} defaultValue={settings?.bankAccount}
/> onKeyDown={e => e.stopPropagation()}
<Form.Text className="text-muted"> />
V zadaný čas vám přijde push notifikace, pokud nemáte zvolenou možnost stravování. Nechte prázdné pro vypnutí. <Form.Text className="text-muted">
</Form.Text> Pokud vaše číslo účtu neobsahuje předčíslí, je možné ho zcela vynechat.
</Form.Group> </Form.Text>
</Form.Group>
<Form.Group className="mb-3"> <Form.Group className="mb-3">
<Form.Check <Form.Label>Název příjemce</Form.Label>
id="boltDeliveredCheckbox" <Form.Control
ref={boltDeliveredRef} ref={nameRef}
type="checkbox" type="text"
label="Upozornění na doručení objednávky (Bolt Food / Wolt)" placeholder="Jan Novák"
defaultChecked={notifSettings.boltDeliveredPush ?? false} defaultValue={settings?.holderName}
key={`bolt-delivered-${notifSettings.boltDeliveredPush ?? false}`} onKeyDown={e => e.stopPropagation()}
/> />
<Form.Text className="text-muted"> <Form.Text className="text-muted">
Až bude sledovaná skupinová objednávka doručena, přijde vám push notifikace. Jméno majitele účtu pro QR platbu.
Zakladateli skupiny se neposílá — ten dostane upozornění přímo z aplikace rozvozové služby. </Form.Text>
</Form.Text> </Form.Group>
</Form.Group> </Col>
<Col lg={6}>
<hr className="d-lg-none" />
<Form.Group className="mb-3"> <h4>Notifikace</h4>
<Form.Label>ntfy téma (topic)</Form.Label> <p>
<Form.Control Nastavením notifikací budete dostávat upozornění o událostech (např. "Jdeme na oběd") přímo do vámi zvoleného komunikačního kanálu.
ref={ntfyTopicRef} </p>
type="text"
placeholder="moje-tema"
defaultValue={notifSettings.ntfyTopic}
key={notifSettings.ntfyTopic ?? 'ntfy-empty'}
onKeyDown={e => e.stopPropagation()}
/>
<Form.Text className="text-muted">
Téma pro ntfy push notifikace. Nechte prázdné pro vypnutí.
</Form.Text>
</Form.Group>
<Form.Group className="mb-3"> <Form.Group className="mb-3">
<Form.Label>Discord webhook URL</Form.Label> <Form.Label>Připomínka výběru oběda</Form.Label>
<Form.Control <Form.Control
ref={discordWebhookRef} ref={reminderTimeRef}
type="text" type="time"
placeholder="https://discord.com/api/webhooks/..." defaultValue={notifSettings.reminderTime ?? ''}
defaultValue={notifSettings.discordWebhookUrl} key={notifSettings.reminderTime ?? 'reminder-empty'}
key={notifSettings.discordWebhookUrl ?? 'discord-empty'} />
onKeyDown={e => e.stopPropagation()} <Form.Text className="text-muted">
/> V zadaný čas vám přijde push notifikace, pokud nemáte zvolenou možnost stravování. Nechte prázdné pro vypnutí.
<Form.Text className="text-muted"> </Form.Text>
URL webhooku Discord kanálu. Nechte prázdné pro vypnutí. </Form.Group>
</Form.Text>
</Form.Group>
<Form.Group className="mb-3"> <Form.Group className="mb-3">
<Form.Label>MS Teams webhook URL</Form.Label> <Form.Check
<Form.Control id="boltDeliveredCheckbox"
ref={teamsWebhookRef} ref={boltDeliveredRef}
type="text" type="checkbox"
placeholder="https://outlook.office.com/webhook/..." label="Upozornění na doručení objednávky (Bolt Food / Wolt)"
defaultValue={notifSettings.teamsWebhookUrl} defaultChecked={notifSettings.boltDeliveredPush ?? false}
key={notifSettings.teamsWebhookUrl ?? 'teams-empty'} key={`bolt-delivered-${notifSettings.boltDeliveredPush ?? false}`}
onKeyDown={e => e.stopPropagation()} />
/> <Form.Text className="text-muted">
<Form.Text className="text-muted"> Až bude sledovaná skupinová objednávka doručena, přijde vám push notifikace.
URL webhooku MS Teams kanálu. Nechte prázdné pro vypnutí. Zakladateli skupiny se neposílá — ten dostane upozornění přímo z aplikace rozvozové služby.
</Form.Text> </Form.Text>
</Form.Group> </Form.Group>
<Form.Group className="mb-3"> <Form.Group className="mb-3">
<Form.Label>Události k odběru</Form.Label> <Form.Label>ntfy téma (topic)</Form.Label>
{Object.values(UdalostEnum).map(event => ( <Form.Control
<Form.Check ref={ntfyTopicRef}
key={event} type="text"
id={`notif-event-${event}`} placeholder="moje-tema"
type="checkbox" defaultValue={notifSettings.ntfyTopic}
label={event} key={notifSettings.ntfyTopic ?? 'ntfy-empty'}
checked={enabledEvents.includes(event)} onKeyDown={e => e.stopPropagation()}
onChange={() => toggleEvent(event)} />
/> <Form.Text className="text-muted">
))} Téma pro ntfy push notifikace. Nechte prázdné pro vypnutí.
<Form.Text className="text-muted"> </Form.Text>
Zvolte události, o kterých chcete být notifikováni. Notifikace jsou odesílány pouze uživatelům se stejnou zvolenou lokalitou. </Form.Group>
</Form.Text>
</Form.Group>
<hr /> <Form.Group className="mb-3">
<Form.Label>Discord webhook URL</Form.Label>
<Form.Control
ref={discordWebhookRef}
type="text"
placeholder="https://discord.com/api/webhooks/..."
defaultValue={notifSettings.discordWebhookUrl}
key={notifSettings.discordWebhookUrl ?? 'discord-empty'}
onKeyDown={e => e.stopPropagation()}
/>
<Form.Text className="text-muted">
URL webhooku Discord kanálu. Nechte prázdné pro vypnutí.
</Form.Text>
</Form.Group>
<h4>Bankovní účet</h4> <Form.Group className="mb-3">
<p> <Form.Label>MS Teams webhook URL</Form.Label>
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. <Form.Control
</p> ref={teamsWebhookRef}
type="text"
placeholder="https://outlook.office.com/webhook/..."
defaultValue={notifSettings.teamsWebhookUrl}
key={notifSettings.teamsWebhookUrl ?? 'teams-empty'}
onKeyDown={e => e.stopPropagation()}
/>
<Form.Text className="text-muted">
URL webhooku MS Teams kanálu. Nechte prázdné pro vypnutí.
</Form.Text>
</Form.Group>
<Form.Group className="mb-3"> <Form.Group className="mb-3">
<Form.Label>Číslo účtu</Form.Label> <Form.Label>Události k odběru</Form.Label>
<Form.Control {Object.values(UdalostEnum).map(event => (
ref={bankAccountRef} <Form.Check
type="text" key={event}
placeholder="123456-1234567890/1234" id={`notif-event-${event}`}
defaultValue={settings?.bankAccount} type="checkbox"
onKeyDown={e => e.stopPropagation()} label={event}
/> checked={enabledEvents.includes(event)}
<Form.Text className="text-muted"> onChange={() => toggleEvent(event)}
Pokud vaše číslo účtu neobsahuje předčíslí, je možné ho zcela vynechat. />
</Form.Text> ))}
</Form.Group> <Form.Text className="text-muted">
Zvolte události, o kterých chcete být notifikováni. Notifikace jsou odesílány pouze uživatelům se stejnou zvolenou lokalitou.
<Form.Group className="mb-3"> </Form.Text>
<Form.Label>Název příjemce</Form.Label> </Form.Group>
<Form.Control </Col>
ref={nameRef} </Row>
type="text"
placeholder="Jan Novák"
defaultValue={settings?.holderName}
onKeyDown={e => e.stopPropagation()}
/>
<Form.Text className="text-muted">
Jméno majitele účtu pro QR platbu.
</Form.Text>
</Form.Group>
</Modal.Body> </Modal.Body>
<Modal.Footer> <Modal.Footer>
<Button variant="secondary" onClick={onClose}> <Button variant="secondary" onClick={onClose}>