feat: enhance booking and scheduling features with shipping line support and improved search functionality

This commit is contained in:
Marshal
2026-08-16 08:18:40 +00:00
parent 9f53114778
commit 5ce5cbe29d
8 changed files with 225 additions and 75 deletions

View File

@@ -500,7 +500,7 @@ export default function BookingRequestsPage() {
<FilterBar
defs={bookingFilterDefs}
controls={controls}
searchPlaceholder="Search booking, contract or customer…"
searchPlaceholder="Search booking, contract, customer or shipping line…"
viewId="booking-requests"
/>
</Box>

View File

@@ -14,7 +14,7 @@ import { DatePickerInput } from "@mantine/dates";
import { getDateRangePresets } from "@/components/common/dateRangePresets";
import { useDebouncedValue } from "@mantine/hooks";
import { keepPreviousData, useQuery } from "@tanstack/react-query";
import { FileText, Inbox, RefreshCw, Search, User, X } from "lucide-react";
import { FileText, Inbox, RefreshCw, Search, Ship, User, X } from "lucide-react";
import { useCallback, useMemo, useState } from "react";
import { useNavigate } from "react-router-dom";
@@ -75,6 +75,12 @@ const OWNERSHIP_OPTIONS = [
{ value: "false", label: "Private" },
];
/** Who booked: shipping lines own bookings via `shippingLineCompanyId`, not a customer company. */
const CUSTOMER_KIND_OPTIONS = [
{ value: "SHIPPING_LINE", label: "Shipping line" },
{ value: "CUSTOMER", label: "Customer" },
];
function startOfDayIso(d: Date): string {
const x = new Date(d);
x.setHours(0, 0, 0, 0);
@@ -98,6 +104,7 @@ export default function ClearanceDocumentsPage() {
const [directionFilter, setDirectionFilter] = useState<string | null>(null);
const [freightTypeFilter, setFreightTypeFilter] = useState<string | null>(null);
const [ownershipFilter, setOwnershipFilter] = useState<string | null>(null);
const [customerKindFilter, setCustomerKindFilter] = useState<string | null>(null);
const [createdFrom, setCreatedFrom] = useState<Date | null>(null);
const [createdTo, setCreatedTo] = useState<Date | null>(null);
const { pagination, setPagination } = usePagination({ pageSize: PAGE_SIZE });
@@ -118,6 +125,7 @@ export default function ClearanceDocumentsPage() {
directionFilter,
freightTypeFilter,
ownershipFilter,
customerKindFilter,
createdFrom,
createdTo,
page,
@@ -138,6 +146,9 @@ export default function ClearanceDocumentsPage() {
...(ownershipFilter
? { isGovernment: ownershipFilter as "true" | "false" }
: {}),
...(customerKindFilter
? { customerKind: customerKindFilter as "SHIPPING_LINE" | "CUSTOMER" }
: {}),
...(createdFrom ? { createdFrom: startOfDayIso(createdFrom) } : {}),
...(createdTo ? { createdTo: endOfDayIso(createdTo) } : {}),
}),
@@ -153,17 +164,29 @@ export default function ClearanceDocumentsPage() {
header: () => <span className={bookingTable.headerCell}>Customer</span>,
cell: ({ row }) => {
const b = row.original;
const customer = b.isGovernment
? (b.governmentInstitution ?? "Government")
: (b.company?.name ?? "");
const isShippingLine = Boolean(b.shippingLineCompany ?? b.shippingLineCompanyId);
const customer = isShippingLine
? (b.shippingLineCompany?.name ?? "Shipping line")
: b.isGovernment
? (b.governmentInstitution ?? "Government")
: (b.company?.name ?? "—");
return (
<div className="flex items-center gap-3 py-1.5">
<div className={bookingTable.rowIcon}>
<User className="size-4" strokeWidth={1.75} />
{isShippingLine ? (
<Ship className="size-4" strokeWidth={1.75} />
) : (
<User className="size-4" strokeWidth={1.75} />
)}
</div>
<div className="min-w-0">
<p className="font-medium text-foreground">
<p className="flex items-center gap-1.5 font-medium text-foreground">
{customer}
{isShippingLine ? (
<Badge variant="secondary" className="h-4 shrink-0 px-1 text-[9px] font-medium">
Shipping line
</Badge>
) : null}
</p>
<p className="mt-0.5 flex items-center gap-1 text-xs text-muted-foreground">
<FileText className="size-3 shrink-0 opacity-70" />
@@ -267,7 +290,7 @@ export default function ClearanceDocumentsPage() {
<Box px="md" pt="md" pb="sm" w="100%">
<Group justify="space-between" gap="md" wrap="wrap">
<TextInput
placeholder="Search booking, contract or customer…"
placeholder="Search booking, contract, customer or shipping line…"
leftSection={<Search size={18} />}
value={query}
onChange={(e) => {
@@ -333,6 +356,19 @@ export default function ClearanceDocumentsPage() {
style={{ minWidth: 140 }}
aria-label="Filter by freight type"
/>
<Select
placeholder="Booked by"
data={CUSTOMER_KIND_OPTIONS}
value={customerKindFilter}
onChange={(v) => {
setCustomerKindFilter(v);
resetPage();
}}
clearable
radius="lg"
style={{ minWidth: 140 }}
aria-label="Filter by booked by"
/>
<Select
placeholder="Gov / Private"
data={OWNERSHIP_OPTIONS}