import { useEffect, useState } from "react"; import { Navbar, Nav, NavDropdown, Modal, Button } from "react-bootstrap"; import { useAuth } from "../context/auth"; import SettingsModal from "./modals/SettingsModal"; import { useSettings, ThemePreference } from "../context/settings"; import FeaturesVotingModal from "./modals/FeaturesVotingModal"; import PizzaCalculatorModal from "./modals/PizzaCalculatorModal"; import RefreshMenuModal from "./modals/RefreshMenuModal"; import GenerateQrModal from "./modals/GenerateQrModal"; import GenerateMockDataModal from "./modals/GenerateMockDataModal"; import ClearMockDataModal from "./modals/ClearMockDataModal"; import { useNavigate } from "react-router"; import { STATS_URL } from "../AppRoutes"; import { FeatureRequest, getVotes, updateVote, LunchChoices } from "../../../types"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faSun, faMoon } from "@fortawesome/free-solid-svg-icons"; const CHANGELOG = [ "Nový moderní design aplikace", "Oprava parsování Sladovnické a TechTower", "Možnost označit se jako objednávající u volby \"budu objednávat\"", "Možnost generovat QR kódy pro platby (i mimo Pizza day)", ]; const IS_DEV = process.env.NODE_ENV === 'development'; type Props = { choices?: LunchChoices; dayIndex?: number; }; export default function Header({ choices, dayIndex }: Props) { const auth = useAuth(); const settings = useSettings(); const navigate = useNavigate(); const [settingsModalOpen, setSettingsModalOpen] = useState(false); const [votingModalOpen, setVotingModalOpen] = useState(false); const [pizzaModalOpen, setPizzaModalOpen] = useState(false); const [refreshMenuModalOpen, setRefreshMenuModalOpen] = useState(false); const [changelogModalOpen, setChangelogModalOpen] = useState(false); const [qrModalOpen, setQrModalOpen] = useState(false); const [generateMockModalOpen, setGenerateMockModalOpen] = useState(false); const [clearMockModalOpen, setClearMockModalOpen] = useState(false); const [featureVotes, setFeatureVotes] = useState([]); // Zjistíme aktuální efektivní téma (pro zobrazení správné ikony) const [effectiveTheme, setEffectiveTheme] = useState<'light' | 'dark'>('light'); useEffect(() => { const updateEffectiveTheme = () => { if (settings?.themePreference === 'system') { const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches; setEffectiveTheme(isDark ? 'dark' : 'light'); } else { setEffectiveTheme(settings?.themePreference || 'light'); } }; updateEffectiveTheme(); const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); mediaQuery.addEventListener('change', updateEffectiveTheme); return () => mediaQuery.removeEventListener('change', updateEffectiveTheme); }, [settings?.themePreference]); useEffect(() => { if (auth?.login) { getVotes().then(response => { setFeatureVotes(response.data); }) } }, [auth?.login]); const closeSettingsModal = () => { setSettingsModalOpen(false); } const closeVotingModal = () => { setVotingModalOpen(false); } const closePizzaModal = () => { setPizzaModalOpen(false); } const closeRefreshMenuModal = () => { setRefreshMenuModalOpen(false); } const closeQrModal = () => { setQrModalOpen(false); } const handleQrMenuClick = () => { if (!settings?.bankAccount || !settings?.holderName) { alert('Pro generování QR kódů je nutné mít v nastavení vyplněné číslo účtu a jméno držitele účtu.'); return; } setQrModalOpen(true); } const toggleTheme = () => { // Přepínáme mezi light a dark (ignorujeme system pro jednoduchost) const newTheme: ThemePreference = effectiveTheme === 'dark' ? 'light' : 'dark'; settings?.setThemePreference(newTheme); } const isValidInteger = (str: string) => { str = str.trim(); if (!str) { return false; } str = str.replace(/^0+/, "") || "0"; const n = Math.floor(Number(str)); return n !== Infinity && String(n) === str && n >= 0; } const saveSettings = (bankAccountNumber?: string, bankAccountHolderName?: string, hideSoupsOption?: boolean, themePreference?: ThemePreference) => { if (bankAccountNumber) { try { // Validace kódu banky if (!bankAccountNumber.includes('/')) { throw new Error("Číslo účtu neobsahuje lomítko/kód banky") } const split = bankAccountNumber.split("/"); if (split[1].length !== 4) { throw new Error("Kód banky musí být 4 číslice") } if (!isValidInteger(split[1])) { throw new Error("Kód banky není číslo") } // Validace čísla a předčíslí let cislo = split[0]; if (cislo.indexOf('-') > 0) { cislo = cislo.replace('-', ''); } if (!isValidInteger(cislo)) { throw new Error("Předčíslí nebo číslo účtu neobsahuje pouze číslice") } if (cislo.length < 16) { cislo = cislo.padStart(16, '0'); } let sum = 0; for (let i = 0; i < cislo.length; i++) { const char = cislo.charAt(i); const order = (cislo.length - 1) - i; const weight = (2 ** order) % 11; sum += Number.parseInt(char) * weight } if (sum % 11 !== 0) { throw new Error("Číslo účtu je neplatné") } } catch (e: any) { alert(e.message) return } } settings?.setBankAccountNumber(bankAccountNumber); settings?.setBankAccountHolderName(bankAccountHolderName); settings?.setHideSoupsOption(hideSoupsOption); if (themePreference) { settings?.setThemePreference(themePreference); } closeSettingsModal(); } const saveFeatureVote = async (option: FeatureRequest, active: boolean) => { await updateVote({ body: { option, active } }); const votes = [...featureVotes || []]; if (active) { votes.push(option); } else { votes.splice(votes.indexOf(option), 1); } setFeatureVotes(votes); } return Luncher {choices && settings?.bankAccount && settings?.holderName && ( )} {IS_DEV && ( <> setGenerateMockModalOpen(false)} currentDayIndex={dayIndex} /> setClearMockModalOpen(false)} currentDayIndex={dayIndex} /> )} setChangelogModalOpen(false)}>

Novinky

    {CHANGELOG.map((item, index) => (
  • {item}
  • ))}
}