import { useContext, useEffect, useRef, useState } from 'react'; import { Badge, Button, Card, Form, Table } from 'react-bootstrap'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faNoteSticky, faTrashCan } from '@fortawesome/free-regular-svg-icons'; import { faBasketShopping, faGear, faLock, faLockOpen, faSearch, faUserPlus } from '@fortawesome/free-solid-svg-icons'; import { ClientData, GroupState, MealSlot, OrderGroup, OrderGroupMember, getData, createGroup, deleteGroup, addGroupMember, removeGroupMember, updateGroupMember, setGroupState, } from '../../../types'; import { EVENT_MESSAGE, SocketContext } from '../context/socket'; import { useAuth } from '../context/auth'; import { useSettings } from '../context/settings'; import Login from '../Login'; import Header from '../components/Header'; import Footer from '../components/Footer'; import Loader from '../components/Loader'; import NoteModal from '../components/modals/NoteModal'; import StoreAdminModal from '../components/modals/StoreAdminModal'; import PayForGroupModal from '../components/modals/PayForGroupModal'; const SLOT = MealSlot.EXTRA; function stateBadge(state: GroupState) { const map: Record = { [GroupState.OPEN]: { bg: 'success', label: 'Otevřeno' }, [GroupState.LOCKED]: { bg: 'warning', label: 'Uzamčeno' }, [GroupState.ORDERED]: { bg: 'secondary', label: 'Objednáno' }, }; const { bg, label } = map[state] ?? { bg: 'light', label: state }; return {label}; } export default function OrderGroupsPage() { const auth = useAuth(); const settings = useSettings(); const socket = useContext(SocketContext); const [data, setData] = useState(); const [failure, setFailure] = useState(false); const [newGroupName, setNewGroupName] = useState(''); const [creating, setCreating] = useState(false); const [adminModalOpen, setAdminModalOpen] = useState(false); const [noteModal, setNoteModal] = useState<{ groupId: string; login: string } | null>(null); const [editAmounts, setEditAmounts] = useState>({}); const [payModal, setPayModal] = useState(null); const inputRef = useRef(null); const fetchData = async () => { try { const r = await getData({ query: { slot: SLOT } }); if (r.data) setData(r.data); } catch { setFailure(true); } }; useEffect(() => { if (!auth?.login) return; fetchData(); }, [auth?.login]); useEffect(() => { socket.on(EVENT_MESSAGE, (newData: ClientData) => { if (newData.slot === SLOT) setData(newData); }); return () => { socket.off(EVENT_MESSAGE); }; }, [socket]); const refresh = async (fn: () => Promise) => { const result = await fn(); if (result?.data) { setData(result.data); const ws = result.data as ClientData; socket.emit?.('message', ws); } await fetchData(); }; const handleCreate = async () => { if (!newGroupName || !auth?.login) return; setCreating(true); try { await refresh(() => createGroup({ body: { name: newGroupName } })); setNewGroupName(''); } catch { /* swallow */ } setCreating(false); }; const handleJoin = (groupId: string) => refresh(() => addGroupMember({ body: { id: groupId } })); const handleLeave = (groupId: string) => refresh(() => removeGroupMember({ body: { id: groupId, login: auth?.login ?? '' } })); const handleToggleLock = (group: OrderGroup) => { const next = group.state === GroupState.OPEN ? GroupState.LOCKED : GroupState.OPEN; return refresh(() => setGroupState({ body: { id: group.id, state: next } })); }; const handleMarkOrdered = (group: OrderGroup) => refresh(() => setGroupState({ body: { id: group.id, state: GroupState.ORDERED } })); const handleDelete = (groupId: string) => refresh(() => deleteGroup({ body: { id: groupId } })); const handleSaveNote = async (note?: string) => { if (!noteModal || !auth?.login) return; await refresh(() => updateGroupMember({ body: { id: noteModal.groupId, login: noteModal.login, note } })); setNoteModal(null); }; const handleSaveAmount = async (groupId: string, login: string) => { const key = `${groupId}:${login}`; const raw = editAmounts[key]; const n = parseFloat(raw ?? ''); const amount = isNaN(n) || n < 0 ? undefined : n; await refresh(() => updateGroupMember({ body: { id: groupId, login, amount } })); setEditAmounts(prev => { const next = { ...prev }; delete next[key]; return next; }); }; const canEditMember = (group: OrderGroup, targetLogin: string) => { if (group.state === GroupState.ORDERED) return false; if (auth?.login === group.creatorLogin) return true; if (auth?.login === targetLogin && group.state === GroupState.OPEN) return true; return false; }; const canManageMembers = (group: OrderGroup) => { if (group.state === GroupState.ORDERED) return false; if (auth?.login === group.creatorLogin) return true; return group.state === GroupState.OPEN; }; if (!auth?.login) return ; if (failure) return ( ); if (!data) return ( ); const stores = data.stores ?? []; const groups = data.groups ?? []; return (

Objednání

Skupinové objednávky z obchodů a restaurací

{/* Vytvoření nové skupiny */}
Vytvořit skupinu
{stores.length === 0 ? (

Nejsou přidány žádné obchody.{' '}

) : (
setNewGroupName(e.target.value)} style={{ maxWidth: 260 }} > {stores.map(s => )}
)}
{/* Seznam skupin */} {groups.length === 0 && (

Zatím žádné skupiny pro dnešní den.

)} {groups.map(group => { const login = auth!.login ?? ''; const isCreator = login === group.creatorLogin; const isMember = login in group.members; const isOrdered = group.state === GroupState.ORDERED; const isLocked = group.state === GroupState.LOCKED; const memberEntries = Object.entries(group.members) as [string, OrderGroupMember][]; return (
{group.name} {stateBadge(group.state)} zakladatel: {group.creatorLogin}
{isCreator && !isOrdered && ( <> {isLocked && ( )} )} {isCreator && isOrdered && settings?.bankAccount && settings?.holderName && ( )} {!isMember && !isOrdered && ( )}
{memberEntries.map(([memberLogin, member]) => { const amountKey = `${group.id}:${memberLogin}`; const editingAmount = amountKey in editAmounts; const canEdit = canEditMember(group, memberLogin); return ( ); })}
Člen Částka (Kč) Poznámka
{memberLogin} {memberLogin === group.creatorLogin && ( )} {canEdit && editingAmount ? (
setEditAmounts(prev => ({ ...prev, [amountKey]: e.target.value }))} onKeyDown={e => { e.stopPropagation(); if (e.key === 'Enter') handleSaveAmount(group.id, memberLogin); }} style={{ width: 80 }} autoFocus={memberLogin === login} />
) : ( canEdit && setEditAmounts(prev => ({ ...prev, [amountKey]: String(member.amount ?? '') }))} title={canEdit ? 'Klikněte pro úpravu' : undefined} > {member.amount != null ? `${member.amount} Kč` : } )}
{member.note || '—'}
{memberLogin === login && ( setNoteModal({ groupId: group.id, login: memberLogin })} /> )} {canManageMembers(group) && (memberLogin !== group.creatorLogin) && ( refresh(() => removeGroupMember({ body: { id: group.id, login: memberLogin } }))} /> )}
); })}
); }