feat: podpora více odkazů na podnik při objednávání

This commit is contained in:
mates committed 2026-08-25 11:28:57 +02:00
1 parent 93242b7c7e
commit ce051447e6
13 files changed
+338 -81

No files matched your search

+38 -6
View File
@@ -11,6 +11,7 @@ import {
getData, createGroup, deleteGroup, addGroupMember, removeGroupMember, updateGroupMember, setGroupState, updateGroupTimes, setTracking, getOrderDates,
} from '../../../types';
import { computeFeeShare, computeMemberTotal, countActiveMembers } from '../utils/groupFees';
import { getStoreUrls, isHttpUrl, storeUrlLabel } from '../utils/storeUrls';
import { EVENT_MESSAGE, EVENT_PENDING_QR, SocketContext } from '../context/socket';
import { useAuth } from '../context/auth';
import { useSettings } from '../context/settings';
@@ -125,6 +126,8 @@ export default function OrderGroupsPage() {
// ISO data dnů, ve kterých existuje aspoň jedna objednávka (pro zvýraznění v date pickeru)
const [orderDates, setOrderDates] = useState<string[]>([]);
const [newGroupName, setNewGroupName] = useState('');
// Vybraná URL na nabídku — podnik může být dostupný přes více dovozových služeb
const [newGroupUrl, setNewGroupUrl] = useState('');
const [creating, setCreating] = useState(false);
const [adminModalOpen, setAdminModalOpen] = useState(false);
const [editAmounts, setEditAmounts] = useState<Record<string, string>>({});
@@ -248,11 +251,18 @@ export default function OrderGroupsPage() {
const handleCreate = async () => {
if (!newGroupName || !auth?.login) return;
setCreating(true);
const ok = await refresh(() => createGroup({ body: { name: newGroupName } }));
if (ok) setNewGroupName('');
// Pojistka, kdyby se seznam obchodů mezitím změnil (socket) — vezmeme první URL podniku
const urls = getStoreUrls((data?.stores ?? []).find(s => s.name === newGroupName));
const url = urls.includes(newGroupUrl) ? newGroupUrl : urls[0];
const ok = await refresh(() => createGroup({ body: { name: newGroupName, url } }));
if (ok) {
setNewGroupName('');
setNewGroupUrl('');
}
setCreating(false);
};
const handleJoin = (groupId: string) =>
refresh(() => addGroupMember({ body: { id: groupId } }));
@@ -359,6 +369,8 @@ export default function OrderGroupsPage() {
const stores = data.stores ?? [];
const groups = data.groups ?? [];
// URL na nabídku vybíraného podniku — výběr nabízíme, jen když jich je víc
const newStoreUrls = getStoreUrls(stores.find(s => s.name === newGroupName));
// Zobrazené datum a režim historie (vše read-only, pokud nejde o aktuální den)
const displayedIso = data.isoDate;
@@ -456,12 +468,29 @@ export default function OrderGroupsPage() {
<div className="d-flex gap-2 align-items-center flex-wrap">
<Form.Select
value={newGroupName}
onChange={e => setNewGroupName(e.target.value)}
onChange={e => {
const name = e.target.value;
setNewGroupName(name);
// Výběr nabídky se resetuje na první URL nově vybraného podniku
setNewGroupUrl(getStoreUrls(stores.find(s => s.name === name))[0] ?? '');
}}
style={{ maxWidth: 260 }}
>
<option value="">— vyberte obchod —</option>
{stores.map(s => <option key={s.name} value={s.name}>{s.name}</option>)}
</Form.Select>
{newStoreUrls.length > 1 && (
<Form.Select
value={newStoreUrls.includes(newGroupUrl) ? newGroupUrl : newStoreUrls[0]}
onChange={e => setNewGroupUrl(e.target.value)}
style={{ maxWidth: 220 }}
title="Odkud se bude objednávat"
>
{newStoreUrls.map(url => (
<option key={url} value={url}>{storeUrlLabel(url)}</option>
))}
</Form.Select>
)}
<Button variant="primary" onClick={handleCreate} disabled={creating || !newGroupName}>
Vytvořit skupinu
</Button>
@@ -485,10 +514,13 @@ export default function OrderGroupsPage() {
const isLocked = group.state === GroupState.LOCKED;
const memberEntries = Object.entries(group.members) as [string, OrderGroupMember][];
const editingTimes = group.id in editTimes;
// URL na nabídku podniku (pokud ji má dohledatelný obchod vyplněnou).
// URL na nabídku podniku — přednostně ta, kterou zakladatel vybral při vytvoření
// skupiny. Skupiny z doby před výběrem URL ji nemají, pak zkusíme jedinou URL obchodu.
// Povolíme jen http(s), aby odkaz nemohl být zneužit (např. javascript:).
const rawStoreUrl = stores.find(s => s.name === group.name)?.url;
const storeUrl = rawStoreUrl && /^https?:\/\//i.test(rawStoreUrl) ? rawStoreUrl : undefined;
const groupStoreUrls = getStoreUrls(stores.find(s => s.name === group.name));
const storeUrl = isHttpUrl(group.url)
? group.url
: (groupStoreUrls.length === 1 ? groupStoreUrls[0] : undefined);
const totalFees = (group.fees ?? 0) + (group.shipping ?? 0) + (group.tip ?? 0);
// Poplatky se dělí jen mezi aktivní strávníky (kdo si reálně něco objednal).