import { useState, useEffect, useCallback } from "react"; import { Modal, Button, Form, Table, Alert } from "react-bootstrap"; import { generateQr, LunchChoices, QrRecipient } from "../../../../types"; type UserEntry = { login: string; selected: boolean; purpose: string; amount: string; }; type Props = { isOpen: boolean; onClose: () => void; choices: LunchChoices; bankAccount: string; bankAccountHolder: string; }; /** Modální dialog pro generování QR kódů pro platbu. */ export default function GenerateQrModal({ isOpen, onClose, choices, bankAccount, bankAccountHolder }: Readonly) { const [users, setUsers] = useState([]); const [error, setError] = useState(null); const [loading, setLoading] = useState(false); const [success, setSuccess] = useState(false); // Při otevření modálu načteme seznam uživatelů z choices useEffect(() => { if (isOpen && choices) { const userLogins = new Set(); // Projdeme všechny lokace a získáme unikátní loginy Object.values(choices).forEach(locationChoices => { if (locationChoices) { Object.keys(locationChoices).forEach(login => { userLogins.add(login); }); } }); // Vytvoříme seznam uživatelů const userList: UserEntry[] = Array.from(userLogins) .sort((a, b) => a.localeCompare(b, 'cs')) .map(login => ({ login, selected: false, purpose: '', amount: '', })); setUsers(userList); setError(null); setSuccess(false); } }, [isOpen, choices]); const handleCheckboxChange = useCallback((login: string, checked: boolean) => { setUsers(prev => prev.map(u => u.login === login ? { ...u, selected: checked } : u )); }, []); const handlePurposeChange = useCallback((login: string, value: string) => { setUsers(prev => prev.map(u => u.login === login ? { ...u, purpose: value } : u )); }, []); const handleAmountChange = useCallback((login: string, value: string) => { // Povolíme pouze čísla, tečku a čárku const sanitized = value.replace(/[^0-9.,]/g, '').replace(',', '.'); setUsers(prev => prev.map(u => u.login === login ? { ...u, amount: sanitized } : u )); }, []); const validateAmount = (amountStr: string): number | null => { if (!amountStr || amountStr.trim().length === 0) { return null; } const amount = parseFloat(amountStr); if (isNaN(amount) || amount <= 0) { return null; } // Max 2 desetinná místa const parts = amountStr.split('.'); if (parts.length === 2 && parts[1].length > 2) { return null; } return Math.round(amount * 100) / 100; // Zaokrouhlíme na 2 desetinná místa }; const handleGenerate = async () => { setError(null); const selectedUsers = users.filter(u => u.selected); if (selectedUsers.length === 0) { setError("Nebyl vybrán žádný uživatel"); return; } // Validace const recipients: QrRecipient[] = []; for (const user of selectedUsers) { if (!user.purpose || user.purpose.trim().length === 0) { setError(`Uživatel ${user.login} nemá vyplněný účel platby`); return; } const amount = validateAmount(user.amount); if (amount === null) { setError(`Uživatel ${user.login} má neplatnou částku (musí být kladné číslo s max. 2 desetinnými místy)`); return; } recipients.push({ login: user.login, purpose: user.purpose.trim(), amount, }); } setLoading(true); try { const response = await generateQr({ body: { recipients, bankAccount, bankAccountHolder, } }); if (response.error) { setError((response.error as any).error || 'Nastala chyba při generování QR kódů'); } else { setSuccess(true); // Po 2 sekundách zavřeme modal setTimeout(() => { onClose(); }, 2000); } } catch (e: any) { setError(e.message || 'Nastala chyba při generování QR kódů'); } finally { setLoading(false); } }; const handleClose = () => { setError(null); setSuccess(false); onClose(); }; const selectedCount = users.filter(u => u.selected).length; return (

Generování QR kódů

{success ? ( QR kódy byly úspěšně vygenerovány! Uživatelé je uvidí v sekci "Nevyřízené platby". ) : ( <>

Vyberte uživatele, kterým chcete vygenerovat QR kód pro platbu. QR kódy se uživatelům zobrazí v sekci "Nevyřízené platby".

{error && ( setError(null)} dismissible> {error} )} {users.length === 0 ? ( V tento den nemá žádný uživatel zvolenou možnost stravování. ) : ( {users.map(user => ( ))}
Uživatel Účel platby Částka (Kč)
handleCheckboxChange(user.login, e.target.checked)} /> {user.login} handlePurposeChange(user.login, e.target.value)} disabled={!user.selected} size="sm" onKeyDown={e => e.stopPropagation()} /> handleAmountChange(user.login, e.target.value)} disabled={!user.selected} size="sm" onKeyDown={e => e.stopPropagation()} />
)} )}
{!success && ( <> Vybráno: {selectedCount} / {users.length} )} {success && ( )}
); }