diff --git a/client/src/components/modals/PayForGroupModal.tsx b/client/src/components/modals/PayForGroupModal.tsx index 92f6d06..b097d43 100644 --- a/client/src/components/modals/PayForGroupModal.tsx +++ b/client/src/components/modals/PayForGroupModal.tsx @@ -1,6 +1,6 @@ import { useState, useEffect } from "react"; import { Modal, Button, Form, Table, Alert } from "react-bootstrap"; -import { generateQr, OrderGroup, OrderGroupMember, QrRecipient } from "../../../../types"; +import { generateQr, GroupState, OrderGroup, OrderGroupMember, QrRecipient } from "../../../../types"; import { sanitizeQrMessage } from "../../Utils"; import { computeFeeShare, computeMemberTotal, countActiveMembers, isActiveMember } from "../../utils/groupFees"; @@ -102,6 +102,8 @@ export default function PayForGroupModal({ isOpen, onClose, onSuccess, group, pa }; const hasFees = totalFees > 0; + // Generování QR je poslední krok objednávky — server skupinu zároveň překlopí do stavu Doručeno + const willBeMarkedDelivered = group.state !== GroupState.DELIVERED; return ( @@ -115,6 +117,12 @@ export default function PayForGroupModal({ isOpen, onClose, onSuccess, group, pa ) : ( <> + {willBeMarkedDelivered && ( + + Objednávka není ve stavu Doručeno — vygenerováním QR kódů se do tohoto stavu automaticky přepne. + + )} +

Zaplatili jste za skupinu. Vyberte, komu vygenerovat QR kód k úhradě.

{error && ( diff --git a/client/src/pages/OrderGroupsPage.tsx b/client/src/pages/OrderGroupsPage.tsx index df9ee94..112847b 100644 --- a/client/src/pages/OrderGroupsPage.tsx +++ b/client/src/pages/OrderGroupsPage.tsx @@ -2,7 +2,7 @@ import { useCallback, useContext, useEffect, useRef, useState } from 'react'; import { Alert, Badge, Button, Card, Form, Modal, OverlayTrigger, Table, Tooltip } from 'react-bootstrap'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faTrashCan } from '@fortawesome/free-regular-svg-icons'; -import { faBasketShopping, faChevronLeft, faChevronRight, faCircleCheck, faClockRotateLeft, faGear, faLock, faLockOpen, faPen, faSearch, faUserPlus } from '@fortawesome/free-solid-svg-icons'; +import { faBasketShopping, faChevronLeft, faChevronRight, faCircleCheck, faClockRotateLeft, faGear, faLock, faLockOpen, faPen, faSearch, faTruck, faUserPlus } from '@fortawesome/free-solid-svg-icons'; import DatePicker, { registerLocale } from 'react-datepicker'; import { cs } from 'date-fns/locale'; import 'react-datepicker/dist/react-datepicker.css'; @@ -102,11 +102,17 @@ function isoToDate(iso?: string): Date | null { return iso ? new Date(`${iso}T00:00:00`) : null; } +/** Stavy, ve kterých je objednávka již odeslána do podniku (objednáno/doručeno) — skupina se nesmí upravovat. */ +function isSubmittedState(state: GroupState): boolean { + return state === GroupState.ORDERED || state === GroupState.DELIVERED; +} + 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' }, + [GroupState.DELIVERED]: { bg: 'info', label: 'Doručeno' }, }; const { bg, label } = map[state] ?? { bg: 'light', label: state }; return {label}; @@ -281,6 +287,12 @@ export default function OrderGroupsPage() { const handleRevertOrdered = (group: OrderGroup) => refresh(() => setGroupState({ body: { id: group.id, state: GroupState.LOCKED } })); + const handleSetDelivered = (group: OrderGroup) => + refresh(() => setGroupState({ body: { id: group.id, state: GroupState.DELIVERED } })); + + const handleRevertDelivered = (group: OrderGroup) => + refresh(() => setGroupState({ body: { id: group.id, state: GroupState.ORDERED } })); + const handleDelete = (groupId: string) => refresh(() => deleteGroup({ body: { id: groupId } })); @@ -346,7 +358,7 @@ export default function OrderGroupsPage() { // Historie (jiný než aktuální den) je vždy read-only. const canEditMember = (group: OrderGroup, targetLogin: string) => { if (selectedDate) return false; - if (group.state === GroupState.ORDERED) return false; + if (isSubmittedState(group.state)) return false; if (auth?.login === group.creatorLogin) return true; if (auth?.login === targetLogin && group.state === GroupState.OPEN) return true; return false; @@ -354,7 +366,7 @@ export default function OrderGroupsPage() { const canManageMembers = (group: OrderGroup) => { if (selectedDate) return false; - if (group.state === GroupState.ORDERED) return false; + if (isSubmittedState(group.state)) return false; if (auth?.login === group.creatorLogin) return true; return group.state === GroupState.OPEN; }; @@ -520,6 +532,9 @@ export default function OrderGroupsPage() { const isCreator = login === group.creatorLogin; const isMember = login in group.members; const isOrdered = group.state === GroupState.ORDERED; + const isDelivered = group.state === GroupState.DELIVERED; + // Objednáno i Doručeno = objednávka je odeslána do podniku, skupina se už needituje + const isSubmitted = isOrdered || isDelivered; const isLocked = group.state === GroupState.LOCKED; const memberEntries = Object.entries(group.members) as [string, OrderGroupMember][]; const editingTimes = group.id in editTimes; @@ -556,7 +571,7 @@ export default function OrderGroupsPage() { zakladatel: {group.creatorLogin}
- {!isReadOnly && isCreator && !isOrdered && ( + {!isReadOnly && isCreator && !isSubmitted && ( <> )} - {!isReadOnly && isCreator && isOrdered && ( + {!isReadOnly && isCreator && isSubmitted && ( <> + {isOrdered && ( + + )} {settings?.bankAccount && settings?.holderName && !group.qrGenerated && ( )} - + {isDelivered ? ( + + ) : ( + + )} )} - {!isReadOnly && !isMember && !isOrdered && !isLocked && ( + {!isReadOnly && !isMember && !isSubmitted && !isLocked && (