feat: uživatelsky přívětivější možnost zadání sledovací URL pro Bolt Food
CI / Generate TypeScript types (push) Successful in 13s
CI / Server unit tests (push) Successful in 22s
CI / Build server (push) Successful in 29s
CI / Build client (push) Successful in 37s
CI / Playwright E2E tests (push) Successful in 1m24s
CI / Build and push Docker image (push) Successful in 40s
CI / Notify (push) Successful in 2s
CI / Generate TypeScript types (push) Successful in 13s
CI / Server unit tests (push) Successful in 22s
CI / Build server (push) Successful in 29s
CI / Build client (push) Successful in 37s
CI / Playwright E2E tests (push) Successful in 1m24s
CI / Build and push Docker image (push) Successful in 40s
CI / Notify (push) Successful in 2s
This commit is contained in:
@@ -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 { Alert, Badge, Button, Card, Form, Modal, OverlayTrigger, Table, Tooltip } from 'react-bootstrap';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { faTrashCan } from '@fortawesome/free-regular-svg-icons';
|
import { faTrashCan } from '@fortawesome/free-regular-svg-icons';
|
||||||
import { faBasketShopping, faChevronLeft, faChevronRight, faCircleCheck, faClockRotateLeft, faGear, faLock, faLockOpen, faSearch, faUserPlus } from '@fortawesome/free-solid-svg-icons';
|
import { faBasketShopping, faChevronLeft, faChevronRight, faCircleCheck, faClockRotateLeft, faGear, faLock, faLockOpen, faPen, faSearch, faUserPlus } from '@fortawesome/free-solid-svg-icons';
|
||||||
import DatePicker, { registerLocale } from 'react-datepicker';
|
import DatePicker, { registerLocale } from 'react-datepicker';
|
||||||
import { cs } from 'date-fns/locale';
|
import { cs } from 'date-fns/locale';
|
||||||
import 'react-datepicker/dist/react-datepicker.css';
|
import 'react-datepicker/dist/react-datepicker.css';
|
||||||
@@ -43,6 +43,14 @@ function extractBoltToken(input: string): string | null {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Zkrátí dlouhý odkaz pro zobrazení v řádku (zachová začátek i konec). */
|
||||||
|
function shortenUrl(url: string, max = 48): string {
|
||||||
|
if (url.length <= max) return url;
|
||||||
|
const head = Math.ceil((max - 1) / 2);
|
||||||
|
const tail = Math.floor((max - 1) / 2);
|
||||||
|
return `${url.slice(0, head)}…${url.slice(url.length - tail)}`;
|
||||||
|
}
|
||||||
|
|
||||||
// Český lokál pro date picker (názvy měsíců/dnů, pondělí jako první den)
|
// Český lokál pro date picker (názvy měsíců/dnů, pondělí jako první den)
|
||||||
registerLocale('cs', cs);
|
registerLocale('cs', cs);
|
||||||
|
|
||||||
@@ -706,7 +714,7 @@ export default function OrderGroupsPage() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="d-flex align-items-center gap-1">
|
<div className="d-flex align-items-center gap-1">
|
||||||
<small className="text-muted text-nowrap">Bolt odkaz:</small>
|
<small className="text-muted text-nowrap">Bolt odkaz pro sledování:</small>
|
||||||
<Form.Control
|
<Form.Control
|
||||||
type="text"
|
type="text"
|
||||||
size="sm"
|
size="sm"
|
||||||
@@ -721,23 +729,60 @@ export default function OrderGroupsPage() {
|
|||||||
<Button size="sm" variant="outline-secondary" onClick={() => setEditTimes(prev => { const n = { ...prev }; delete n[group.id]; return n; })}>Zrušit</Button>
|
<Button size="sm" variant="outline-secondary" onClick={() => setEditTimes(prev => { const n = { ...prev }; delete n[group.id]; return n; })}>Zrušit</Button>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div className="d-flex align-items-center gap-3 flex-wrap">
|
||||||
className="d-flex align-items-center gap-3 flex-wrap"
|
{(() => {
|
||||||
style={{ cursor: !isReadOnly && isCreator ? 'pointer' : undefined }}
|
const canEdit = !isReadOnly && isCreator;
|
||||||
onClick={() => !isReadOnly && isCreator && setEditTimes(prev => ({ ...prev, [group.id]: { orderedAt: group.orderedAt ?? '', deliveryAt: group.deliveryAt ?? '', boltUrl: group.boltTrackingToken ? `${BOLT_SHARE_URL_PREFIX}${group.boltTrackingToken}` : '' } }))}
|
// Aktivace editačního režimu – stejné chování jako tlačítko s tužkou
|
||||||
title={!isReadOnly && isCreator ? 'Klikněte pro úpravu časů' : undefined}
|
const startEdit = () => canEdit && setEditTimes(prev => ({ ...prev, [group.id]: { orderedAt: group.orderedAt ?? '', deliveryAt: group.deliveryAt ?? '', boltUrl: group.boltTrackingToken ? `${BOLT_SHARE_URL_PREFIX}${group.boltTrackingToken}` : '' } }));
|
||||||
>
|
const trackingUrl = group.boltTrackingToken ? `${BOLT_SHARE_URL_PREFIX}${group.boltTrackingToken}` : null;
|
||||||
<small className="text-muted">
|
return (
|
||||||
Objednáno v: <strong>{group.orderedAt ?? '—'}</strong>
|
<>
|
||||||
</small>
|
{canEdit && (
|
||||||
<small className="text-muted">
|
<FontAwesomeIcon
|
||||||
Doručení v: <strong>{group.deliveryAt ?? '—'}</strong>
|
icon={faPen}
|
||||||
{group.boltTrackingToken && (
|
className="action-icon"
|
||||||
<OverlayTrigger overlay={<Tooltip>Čas doručení se aktualizuje automaticky z Bolt Food</Tooltip>}>
|
title="Upravit časy a odkaz pro sledování"
|
||||||
<Badge bg="success" className="ms-1">Bolt</Badge>
|
onClick={startEdit}
|
||||||
</OverlayTrigger>
|
/>
|
||||||
)}
|
)}
|
||||||
</small>
|
<small
|
||||||
|
className="text-muted"
|
||||||
|
style={{ cursor: canEdit ? 'pointer' : undefined }}
|
||||||
|
onClick={startEdit}
|
||||||
|
>
|
||||||
|
Objednáno v: <strong>{group.orderedAt ?? '—'}</strong>
|
||||||
|
</small>
|
||||||
|
<small
|
||||||
|
className="text-muted"
|
||||||
|
style={{ cursor: canEdit ? 'pointer' : undefined }}
|
||||||
|
onClick={startEdit}
|
||||||
|
>
|
||||||
|
Doručení v: <strong>{group.deliveryAt ?? '—'}</strong>
|
||||||
|
{group.boltTrackingToken && (
|
||||||
|
<OverlayTrigger overlay={<Tooltip>Čas doručení se aktualizuje automaticky z Bolt Food</Tooltip>}>
|
||||||
|
<Badge bg="success" className="ms-1">Bolt</Badge>
|
||||||
|
</OverlayTrigger>
|
||||||
|
)}
|
||||||
|
</small>
|
||||||
|
<small className="text-muted text-nowrap">
|
||||||
|
URL pro sledování:{' '}
|
||||||
|
{trackingUrl ? (
|
||||||
|
<a
|
||||||
|
href={trackingUrl}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
title={trackingUrl}
|
||||||
|
onClick={e => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
{shortenUrl(trackingUrl)}
|
||||||
|
</a>
|
||||||
|
) : (
|
||||||
|
<strong>—</strong>
|
||||||
|
)}
|
||||||
|
</small>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
})()}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
[
|
[
|
||||||
"Proklik na nabídku podniku ze stránky objednávek"
|
"Proklik na nabídku podniku ze stránky objednávek",
|
||||||
|
"Možnost přidat URL pro sledování stavu doručení pro Bolt Food",
|
||||||
|
"Automatická aktualizace času doručení na základě sledovací URL pro Bolt Food"
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user