mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
feat: add service type fitler
This commit is contained in:
@@ -130,6 +130,15 @@ export default function BookingRequestsPage() {
|
|||||||
[yardRefs],
|
[yardRefs],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Service-type options — same reference-data payload the booking form uses.
|
||||||
|
const { data: refData } = useQuery(
|
||||||
|
api.bookings.referenceData.queryOptions({ staleTime: 5 * 60_000 }),
|
||||||
|
);
|
||||||
|
const serviceTypeOptions = useMemo(
|
||||||
|
() => (refData?.service ?? []).map((s) => ({ value: s.id, label: s.name })),
|
||||||
|
[refData],
|
||||||
|
);
|
||||||
|
|
||||||
// Deep links land here pre-filtered (?statuses=A,B&tradeDirection=IMPORT) —
|
// Deep links land here pre-filtered (?statuses=A,B&tradeDirection=IMPORT) —
|
||||||
// the header's document-review alarm opens exactly the undecided requests
|
// the header's document-review alarm opens exactly the undecided requests
|
||||||
// it is counting down for. No sync effect needed any more: controls.values
|
// it is counting down for. No sync effect needed any more: controls.values
|
||||||
@@ -147,6 +156,7 @@ export default function BookingRequestsPage() {
|
|||||||
options: filterOptions(TRADE_DIRECTION_OPTIONS),
|
options: filterOptions(TRADE_DIRECTION_OPTIONS),
|
||||||
},
|
},
|
||||||
{ key: "freightType", label: "Freight", type: "enum", multiple: false, options: FREIGHT_TYPE_OPTIONS },
|
{ key: "freightType", label: "Freight", type: "enum", multiple: false, options: FREIGHT_TYPE_OPTIONS },
|
||||||
|
{ key: "serviceTypeId", label: "Service", type: "enum", multiple: false, options: serviceTypeOptions },
|
||||||
{ key: "paymentStatus", label: "Payment", type: "enum", multiple: false, options: PAYMENT_STATUS_OPTIONS, secondary: true },
|
{ key: "paymentStatus", label: "Payment", type: "enum", multiple: false, options: PAYMENT_STATUS_OPTIONS, secondary: true },
|
||||||
{
|
{
|
||||||
// Wins over the `paymentStatus` filter above — the queue is by
|
// Wins over the `paymentStatus` filter above — the queue is by
|
||||||
@@ -172,7 +182,7 @@ export default function BookingRequestsPage() {
|
|||||||
toParams: dateRangeParams("scheduledFrom", "scheduledTo"),
|
toParams: dateRangeParams("scheduledFrom", "scheduledTo"),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[filterOptions, yardOptions],
|
[filterOptions, yardOptions, serviceTypeOptions],
|
||||||
);
|
);
|
||||||
|
|
||||||
const controls = useFilters(bookingFilterDefs, { defaultSort: "createdAt:DESC", pageSize: 10 });
|
const controls = useFilters(bookingFilterDefs, { defaultSort: "createdAt:DESC", pageSize: 10 });
|
||||||
|
|||||||
@@ -115,6 +115,15 @@ export default function ContractRequestsPage() {
|
|||||||
[yardRefs],
|
[yardRefs],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Service-type options — same reference-data payload the booking form uses.
|
||||||
|
const { data: refData } = useQuery(
|
||||||
|
api.bookings.referenceData.queryOptions({ staleTime: 5 * 60_000 }),
|
||||||
|
);
|
||||||
|
const serviceTypeOptions = useMemo(
|
||||||
|
() => (refData?.service ?? []).map((s) => ({ value: s.id, label: s.name })),
|
||||||
|
[refData],
|
||||||
|
);
|
||||||
|
|
||||||
// Static shape only (no facet counts) — this is what useFilters needs to
|
// Static shape only (no facet counts) — this is what useFilters needs to
|
||||||
// parse the URL and build API params. Counts are attached separately below,
|
// parse the URL and build API params. Counts are attached separately below,
|
||||||
// for rendering only, once the summary query (which itself depends on
|
// for rendering only, once the summary query (which itself depends on
|
||||||
@@ -143,6 +152,13 @@ export default function ContractRequestsPage() {
|
|||||||
multiple: false,
|
multiple: false,
|
||||||
options: FREIGHT_TYPE_OPTIONS,
|
options: FREIGHT_TYPE_OPTIONS,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: "serviceTypeId",
|
||||||
|
label: "Service",
|
||||||
|
type: "enum",
|
||||||
|
multiple: false,
|
||||||
|
options: serviceTypeOptions,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: "paymentCurrency",
|
key: "paymentCurrency",
|
||||||
label: "Currency",
|
label: "Currency",
|
||||||
@@ -170,7 +186,7 @@ export default function ContractRequestsPage() {
|
|||||||
toParams: ({ v }) => ({ originYardId: v[0], destinationYardId: v[1] }),
|
toParams: ({ v }) => ({ originYardId: v[0], destinationYardId: v[1] }),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[filterOptions, yardOptions],
|
[filterOptions, yardOptions, serviceTypeOptions],
|
||||||
);
|
);
|
||||||
|
|
||||||
const controls = useFilters(filterDefs, {
|
const controls = useFilters(filterDefs, {
|
||||||
|
|||||||
@@ -2741,6 +2741,13 @@ export const api = {
|
|||||||
({ id }) => QUERY_KEYS.BOOKINGS.byId(id),
|
({ id }) => QUERY_KEYS.BOOKINGS.byId(id),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
referenceData: endpoint<void, Freight.BookingReferenceData>(
|
||||||
|
"bookings",
|
||||||
|
"referenceData",
|
||||||
|
() => bookingsService.getReferenceData() as Promise<Freight.BookingReferenceData>,
|
||||||
|
() => ["bookings", "reference-data"],
|
||||||
|
),
|
||||||
|
|
||||||
remove: endpoint<{ id: string }, void>("bookings", "remove", ({ id }) =>
|
remove: endpoint<{ id: string }, void>("bookings", "remove", ({ id }) =>
|
||||||
bookingsService.remove(id),
|
bookingsService.remove(id),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ export interface BookingListFilter {
|
|||||||
/** Bookings drawn down under this contract (contract detail's Shipments tab). */
|
/** Bookings drawn down under this contract (contract detail's Shipments tab). */
|
||||||
contractId?: string;
|
contractId?: string;
|
||||||
freightType?: string;
|
freightType?: string;
|
||||||
|
/** Service type (rule-engine service_types.id). */
|
||||||
|
serviceTypeId?: string;
|
||||||
/** ONE_TIME | GENERAL_CONTRACT — the booking-kind tab filter. */
|
/** ONE_TIME | GENERAL_CONTRACT — the booking-kind tab filter. */
|
||||||
bookingType?: string;
|
bookingType?: string;
|
||||||
/** 'true' → customs bookings, 'false' → self-clearance (non-customs). */
|
/** 'true' → customs bookings, 'false' → self-clearance (non-customs). */
|
||||||
@@ -142,6 +144,7 @@ export const bookingsService = {
|
|||||||
if (filter.pageSize != null) params.pageSize = filter.pageSize;
|
if (filter.pageSize != null) params.pageSize = filter.pageSize;
|
||||||
if (filter.companyId) params.companyId = filter.companyId;
|
if (filter.companyId) params.companyId = filter.companyId;
|
||||||
if (filter.freightType) params.freightType = filter.freightType;
|
if (filter.freightType) params.freightType = filter.freightType;
|
||||||
|
if (filter.serviceTypeId) params.serviceTypeId = filter.serviceTypeId;
|
||||||
if (filter.bookingType) params.bookingType = filter.bookingType;
|
if (filter.bookingType) params.bookingType = filter.bookingType;
|
||||||
if (filter.tradeDirection) params.tradeDirection = filter.tradeDirection;
|
if (filter.tradeDirection) params.tradeDirection = filter.tradeDirection;
|
||||||
if (filter.paymentCurrency) params.paymentCurrency = filter.paymentCurrency;
|
if (filter.paymentCurrency) params.paymentCurrency = filter.paymentCurrency;
|
||||||
@@ -176,6 +179,7 @@ export const bookingsService = {
|
|||||||
if (filter.companyId) params.companyId = filter.companyId;
|
if (filter.companyId) params.companyId = filter.companyId;
|
||||||
if (filter.contractId) params.contractId = filter.contractId;
|
if (filter.contractId) params.contractId = filter.contractId;
|
||||||
if (filter.freightType) params.freightType = filter.freightType;
|
if (filter.freightType) params.freightType = filter.freightType;
|
||||||
|
if (filter.serviceTypeId) params.serviceTypeId = filter.serviceTypeId;
|
||||||
if (filter.bookingType) params.bookingType = filter.bookingType;
|
if (filter.bookingType) params.bookingType = filter.bookingType;
|
||||||
if (filter.tradeDirection) params.tradeDirection = filter.tradeDirection;
|
if (filter.tradeDirection) params.tradeDirection = filter.tradeDirection;
|
||||||
if (filter.paymentCurrency) params.paymentCurrency = filter.paymentCurrency;
|
if (filter.paymentCurrency) params.paymentCurrency = filter.paymentCurrency;
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ export interface ContractListFilter {
|
|||||||
tab?: string;
|
tab?: string;
|
||||||
companyId?: string;
|
companyId?: string;
|
||||||
freightType?: string;
|
freightType?: string;
|
||||||
|
/** Service type (rule-engine service_types.id). */
|
||||||
|
serviceTypeId?: string;
|
||||||
tradeDirection?: string;
|
tradeDirection?: string;
|
||||||
contractKind?: string;
|
contractKind?: string;
|
||||||
paymentCurrency?: string;
|
paymentCurrency?: string;
|
||||||
@@ -171,6 +173,7 @@ function buildListParams(filter?: ContractListFilter) {
|
|||||||
if (filter.sortOrder) params.sortOrder = filter.sortOrder;
|
if (filter.sortOrder) params.sortOrder = filter.sortOrder;
|
||||||
if (filter.companyId) params.companyId = filter.companyId;
|
if (filter.companyId) params.companyId = filter.companyId;
|
||||||
if (filter.freightType) params.freightType = filter.freightType;
|
if (filter.freightType) params.freightType = filter.freightType;
|
||||||
|
if (filter.serviceTypeId) params.serviceTypeId = filter.serviceTypeId;
|
||||||
if (filter.tradeDirection) params.tradeDirection = filter.tradeDirection;
|
if (filter.tradeDirection) params.tradeDirection = filter.tradeDirection;
|
||||||
if (filter.contractKind) params.contractKind = filter.contractKind;
|
if (filter.contractKind) params.contractKind = filter.contractKind;
|
||||||
if (filter.paymentCurrency) params.paymentCurrency = filter.paymentCurrency;
|
if (filter.paymentCurrency) params.paymentCurrency = filter.paymentCurrency;
|
||||||
|
|||||||
@@ -374,6 +374,16 @@ export default function BookingsListPage() {
|
|||||||
const [debouncedQuery] = useDebouncedValue(query, 300);
|
const [debouncedQuery] = useDebouncedValue(query, 300);
|
||||||
const [typeFilter, setTypeFilter] = useState<string | null>(null);
|
const [typeFilter, setTypeFilter] = useState<string | null>(null);
|
||||||
const [freightFilter, setFreightFilter] = useState<string | null>(null);
|
const [freightFilter, setFreightFilter] = useState<string | null>(null);
|
||||||
|
const [serviceFilter, setServiceFilter] = useState<string | null>(null);
|
||||||
|
|
||||||
|
// Service-type options — same reference-data payload the booking form uses.
|
||||||
|
const { data: refData } = useQuery(
|
||||||
|
api.bookings.referenceData.queryOptions({ staleTime: 5 * 60_000 }),
|
||||||
|
);
|
||||||
|
const serviceTypeOptions = useMemo(
|
||||||
|
() => (refData?.service ?? []).map((s) => ({ value: s.id, label: s.name })),
|
||||||
|
[refData],
|
||||||
|
);
|
||||||
const [sort, setSort] = useState<string>("createdAt:DESC");
|
const [sort, setSort] = useState<string>("createdAt:DESC");
|
||||||
const [createdFrom, setCreatedFrom] = useState<string>("");
|
const [createdFrom, setCreatedFrom] = useState<string>("");
|
||||||
const [createdTo, setCreatedTo] = useState<string>("");
|
const [createdTo, setCreatedTo] = useState<string>("");
|
||||||
@@ -395,10 +405,11 @@ export default function BookingsListPage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const hasExtraFilters =
|
const hasExtraFilters =
|
||||||
!!typeFilter || !!freightFilter || !!createdFrom || !!createdTo;
|
!!typeFilter || !!freightFilter || !!serviceFilter || !!createdFrom || !!createdTo;
|
||||||
const clearExtraFilters = () => {
|
const clearExtraFilters = () => {
|
||||||
setTypeFilter(null);
|
setTypeFilter(null);
|
||||||
setFreightFilter(null);
|
setFreightFilter(null);
|
||||||
|
setServiceFilter(null);
|
||||||
setCreatedFrom("");
|
setCreatedFrom("");
|
||||||
setCreatedTo("");
|
setCreatedTo("");
|
||||||
resetPage();
|
resetPage();
|
||||||
@@ -410,6 +421,7 @@ export default function BookingsListPage() {
|
|||||||
assignedToSchedule,
|
assignedToSchedule,
|
||||||
bookingType: typeFilter ?? undefined,
|
bookingType: typeFilter ?? undefined,
|
||||||
freightType: freightFilter ?? undefined,
|
freightType: freightFilter ?? undefined,
|
||||||
|
serviceTypeId: serviceFilter ?? undefined,
|
||||||
createdFrom: createdFrom || undefined,
|
createdFrom: createdFrom || undefined,
|
||||||
// include the whole selected end day
|
// include the whole selected end day
|
||||||
createdTo: createdTo ? `${createdTo}T23:59:59.999Z` : undefined,
|
createdTo: createdTo ? `${createdTo}T23:59:59.999Z` : undefined,
|
||||||
@@ -425,6 +437,7 @@ export default function BookingsListPage() {
|
|||||||
assignedToSchedule,
|
assignedToSchedule,
|
||||||
typeFilter,
|
typeFilter,
|
||||||
freightFilter,
|
freightFilter,
|
||||||
|
serviceFilter,
|
||||||
createdFrom,
|
createdFrom,
|
||||||
createdTo,
|
createdTo,
|
||||||
debouncedQuery,
|
debouncedQuery,
|
||||||
@@ -852,6 +865,20 @@ export default function BookingsListPage() {
|
|||||||
style={{ width: 150 }}
|
style={{ width: 150 }}
|
||||||
aria-label="Filter by cargo type"
|
aria-label="Filter by cargo type"
|
||||||
/>
|
/>
|
||||||
|
<Select
|
||||||
|
placeholder="Any service"
|
||||||
|
data={serviceTypeOptions}
|
||||||
|
value={serviceFilter}
|
||||||
|
onChange={(v) => {
|
||||||
|
setServiceFilter(v);
|
||||||
|
resetPage();
|
||||||
|
}}
|
||||||
|
clearable
|
||||||
|
radius="md"
|
||||||
|
comboboxProps={{ withinPortal: true }}
|
||||||
|
style={{ width: 190 }}
|
||||||
|
aria-label="Filter by service type"
|
||||||
|
/>
|
||||||
<Select
|
<Select
|
||||||
data={SORT_OPTIONS.map((o) => ({
|
data={SORT_OPTIONS.map((o) => ({
|
||||||
value: o.value,
|
value: o.value,
|
||||||
|
|||||||
@@ -71,6 +71,16 @@ export default function ContractsList() {
|
|||||||
const [disclaimerOpen, setDisclaimerOpen] = useState(false);
|
const [disclaimerOpen, setDisclaimerOpen] = useState(false);
|
||||||
const [freightFilter, setFreightFilter] = useState<string | null>(null);
|
const [freightFilter, setFreightFilter] = useState<string | null>(null);
|
||||||
const [kindFilter, setKindFilter] = useState<string | null>(null);
|
const [kindFilter, setKindFilter] = useState<string | null>(null);
|
||||||
|
const [serviceFilter, setServiceFilter] = useState<string | null>(null);
|
||||||
|
|
||||||
|
// Service-type options — same reference-data payload the contract form uses.
|
||||||
|
const { data: refData } = useQuery(
|
||||||
|
api.bookings.referenceData.queryOptions({ staleTime: 5 * 60_000 }),
|
||||||
|
);
|
||||||
|
const serviceTypeOptions = useMemo(
|
||||||
|
() => (refData?.service ?? []).map((s) => ({ value: s.id, label: s.name })),
|
||||||
|
[refData],
|
||||||
|
);
|
||||||
const [createdFrom, setCreatedFrom] = useState<string>("");
|
const [createdFrom, setCreatedFrom] = useState<string>("");
|
||||||
const [createdTo, setCreatedTo] = useState<string>("");
|
const [createdTo, setCreatedTo] = useState<string>("");
|
||||||
const [expanded, setExpanded] = useState<Set<string>>(new Set());
|
const [expanded, setExpanded] = useState<Set<string>>(new Set());
|
||||||
@@ -96,10 +106,11 @@ export default function ContractsList() {
|
|||||||
const resetPage = () =>
|
const resetPage = () =>
|
||||||
setPagination({ pageIndex: 0, pageSize: pagination.pageSize });
|
setPagination({ pageIndex: 0, pageSize: pagination.pageSize });
|
||||||
const hasExtraFilters =
|
const hasExtraFilters =
|
||||||
!!freightFilter || !!kindFilter || !!createdFrom || !!createdTo;
|
!!freightFilter || !!kindFilter || !!serviceFilter || !!createdFrom || !!createdTo;
|
||||||
const clearExtraFilters = () => {
|
const clearExtraFilters = () => {
|
||||||
setFreightFilter(null);
|
setFreightFilter(null);
|
||||||
setKindFilter(null);
|
setKindFilter(null);
|
||||||
|
setServiceFilter(null);
|
||||||
setCreatedFrom("");
|
setCreatedFrom("");
|
||||||
setCreatedTo("");
|
setCreatedTo("");
|
||||||
resetPage();
|
resetPage();
|
||||||
@@ -109,6 +120,7 @@ export default function ContractsList() {
|
|||||||
() => ({
|
() => ({
|
||||||
contractKind: kindFilter ?? undefined,
|
contractKind: kindFilter ?? undefined,
|
||||||
freightType: freightFilter ?? undefined,
|
freightType: freightFilter ?? undefined,
|
||||||
|
serviceTypeId: serviceFilter ?? undefined,
|
||||||
createdFrom: createdFrom || undefined,
|
createdFrom: createdFrom || undefined,
|
||||||
createdTo: createdTo ? `${createdTo}T23:59:59.999Z` : undefined,
|
createdTo: createdTo ? `${createdTo}T23:59:59.999Z` : undefined,
|
||||||
// Server-side free-text search (contract reference, company name).
|
// Server-side free-text search (contract reference, company name).
|
||||||
@@ -121,6 +133,7 @@ export default function ContractsList() {
|
|||||||
[
|
[
|
||||||
kindFilter,
|
kindFilter,
|
||||||
freightFilter,
|
freightFilter,
|
||||||
|
serviceFilter,
|
||||||
createdFrom,
|
createdFrom,
|
||||||
createdTo,
|
createdTo,
|
||||||
debouncedQuery,
|
debouncedQuery,
|
||||||
@@ -322,6 +335,21 @@ export default function ContractsList() {
|
|||||||
styles={{ input: { height: 42 } }}
|
styles={{ input: { height: 42 } }}
|
||||||
aria-label="Filter by cargo type"
|
aria-label="Filter by cargo type"
|
||||||
/>
|
/>
|
||||||
|
<Select
|
||||||
|
placeholder="Any service"
|
||||||
|
data={serviceTypeOptions}
|
||||||
|
value={serviceFilter}
|
||||||
|
onChange={(v) => {
|
||||||
|
setServiceFilter(v);
|
||||||
|
resetPage();
|
||||||
|
}}
|
||||||
|
clearable
|
||||||
|
radius="md"
|
||||||
|
comboboxProps={{ withinPortal: true }}
|
||||||
|
style={{ width: 180 }}
|
||||||
|
styles={{ input: { height: 42 } }}
|
||||||
|
aria-label="Filter by service type"
|
||||||
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
type="date"
|
type="date"
|
||||||
value={createdFrom}
|
value={createdFrom}
|
||||||
|
|||||||
@@ -182,6 +182,8 @@ export interface BookingListFilter {
|
|||||||
bookingType?: string;
|
bookingType?: string;
|
||||||
/** CONTAINER or BULK. */
|
/** CONTAINER or BULK. */
|
||||||
freightType?: string;
|
freightType?: string;
|
||||||
|
/** Service type (rule-engine service_types.id). */
|
||||||
|
serviceTypeId?: string;
|
||||||
/** IMPORT / EXPORT / DOMESTIC. */
|
/** IMPORT / EXPORT / DOMESTIC. */
|
||||||
tradeDirection?: string;
|
tradeDirection?: string;
|
||||||
/** Narrow to a single operational profile (importer/exporter/freight_forwarder). */
|
/** Narrow to a single operational profile (importer/exporter/freight_forwarder). */
|
||||||
|
|||||||
@@ -88,6 +88,8 @@ export interface ContractListFilter {
|
|||||||
contractKind?: string;
|
contractKind?: string;
|
||||||
/** CONTAINER or BULK. */
|
/** CONTAINER or BULK. */
|
||||||
freightType?: string;
|
freightType?: string;
|
||||||
|
/** Service type (rule-engine service_types.id). */
|
||||||
|
serviceTypeId?: string;
|
||||||
/** IMPORT / EXPORT / DOMESTIC. */
|
/** IMPORT / EXPORT / DOMESTIC. */
|
||||||
tradeDirection?: string;
|
tradeDirection?: string;
|
||||||
companyProfileId?: string;
|
companyProfileId?: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user