mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-08 00:45:41 +00:00
fix: type error and other fixes
This commit is contained in:
@@ -282,6 +282,7 @@ export class CompaniesService {
|
|||||||
async findCompanyById(id: string): Promise<Company> {
|
async findCompanyById(id: string): Promise<Company> {
|
||||||
const company = await this.companiesRepo.findById(id);
|
const company = await this.companiesRepo.findById(id);
|
||||||
if (!company) throw new NotFoundException(`Company ${id} not found`);
|
if (!company) throw new NotFoundException(`Company ${id} not found`);
|
||||||
|
company.companyProfiles = await this.companyProfilesRepo.findByCompanyId(id);
|
||||||
return company;
|
return company;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2152,6 +2152,7 @@ export class TrainSchedulingService {
|
|||||||
weightTons: roundTons(Number(sb.booking?.cargoTotalWeightVgm ?? 0)),
|
weightTons: roundTons(Number(sb.booking?.cargoTotalWeightVgm ?? 0)),
|
||||||
status: sb.booking?.status ?? null,
|
status: sb.booking?.status ?? null,
|
||||||
schedulingStatus: sb.booking?.schedulingStatus ?? null,
|
schedulingStatus: sb.booking?.schedulingStatus ?? null,
|
||||||
|
freightType: sb.booking?.freightType ?? null,
|
||||||
})) ?? [],
|
})) ?? [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -138,6 +138,8 @@ export interface BookingDetailView {
|
|||||||
priorityScore: number;
|
priorityScore: number;
|
||||||
cargoTotalWeightVgm: number;
|
cargoTotalWeightVgm: number;
|
||||||
pnrCode?: string | null;
|
pnrCode?: string | null;
|
||||||
|
consolidationPartnerId?: string | null;
|
||||||
|
consolidationPartner?: (BookingNamedRefView & { reference?: string }) | null;
|
||||||
/** End of the pay window once the booking is SELECTED_FOR_BATCH. */
|
/** End of the pay window once the booking is SELECTED_FOR_BATCH. */
|
||||||
paymentDeadline?: string | null;
|
paymentDeadline?: string | null;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
import type { TrainScheduleDetail } from "@/types/trainScheduling";
|
import type { TrainScheduleDetail } from "@/types/trainScheduling";
|
||||||
import { freightBrand } from "@/theme/freight-brand";
|
import { freightBrand } from "@/theme/freight-brand";
|
||||||
|
|
||||||
type Wagon = TrainScheduleDetail["trainSet"]["wagons"][number];
|
type Wagon = NonNullable<TrainScheduleDetail["trainSet"]>["wagons"][number];
|
||||||
|
|
||||||
export interface BookingDetailData {
|
export interface BookingDetailData {
|
||||||
bookingId: string;
|
bookingId: string;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
import type { TrainScheduleDetail } from "@/types/trainScheduling";
|
import type { TrainScheduleDetail } from "@/types/trainScheduling";
|
||||||
import { freightBrand } from "@/theme/freight-brand";
|
import { freightBrand } from "@/theme/freight-brand";
|
||||||
|
|
||||||
type Wagon = TrainScheduleDetail["trainSet"]["wagons"][number];
|
type Wagon = NonNullable<TrainScheduleDetail["trainSet"]>["wagons"][number];
|
||||||
type Locomotive = NonNullable<TrainScheduleDetail["trainSet"]>["locomotive"];
|
type Locomotive = NonNullable<TrainScheduleDetail["trainSet"]>["locomotive"];
|
||||||
|
|
||||||
interface InteractiveTrainConsistProps {
|
interface InteractiveTrainConsistProps {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Button, Group, Modal, Stack, Text, Badge } from "@mantine/core";
|
import { Button, Group, Modal, Stack, Text, Badge } from "@mantine/core";
|
||||||
import type { TrainScheduleDetail } from "@/types/trainScheduling";
|
import type { TrainScheduleDetail } from "@/types/trainScheduling";
|
||||||
|
|
||||||
type WagonWithAllocation = TrainScheduleDetail["trainSet"]["wagons"][number];
|
type WagonWithAllocation = NonNullable<TrainScheduleDetail["trainSet"]>["wagons"][number];
|
||||||
|
|
||||||
interface RemoveBookingModalProps {
|
interface RemoveBookingModalProps {
|
||||||
opened: boolean;
|
opened: boolean;
|
||||||
@@ -21,7 +21,6 @@ export const RemoveBookingModal = ({
|
|||||||
if (!wagon || !wagon.allocations?.[0]) return null;
|
if (!wagon || !wagon.allocations?.[0]) return null;
|
||||||
|
|
||||||
const allocation = wagon.allocations[0];
|
const allocation = wagon.allocations[0];
|
||||||
const booking = allocation.booking;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal opened={opened} onClose={onClose} title="Confirm Booking Removal" centered>
|
<Modal opened={opened} onClose={onClose} title="Confirm Booking Removal" centered>
|
||||||
@@ -32,12 +31,12 @@ export const RemoveBookingModal = ({
|
|||||||
</Text>
|
</Text>
|
||||||
<Stack gap={4}>
|
<Stack gap={4}>
|
||||||
<Text size="sm">
|
<Text size="sm">
|
||||||
<strong>Reference:</strong> {booking?.reference || "N/A"}
|
<strong>Reference:</strong> {allocation.bookingReference || "N/A"}
|
||||||
</Text>
|
</Text>
|
||||||
<Text size="sm">
|
<Text size="sm">
|
||||||
<strong>Freight Type:</strong>{" "}
|
<strong>Freight Type:</strong>{" "}
|
||||||
<Badge size="sm" variant="light">
|
<Badge size="sm" variant="light">
|
||||||
{booking?.freightType || "N/A"}
|
{allocation.loadType || "N/A"}
|
||||||
</Badge>
|
</Badge>
|
||||||
</Text>
|
</Text>
|
||||||
<Text size="sm">
|
<Text size="sm">
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { useMutation } from "@tanstack/react-query";
|
|||||||
import { api } from "@/services/api";
|
import { api } from "@/services/api";
|
||||||
import { freightBrand } from "@/theme/freight-brand";
|
import { freightBrand } from "@/theme/freight-brand";
|
||||||
|
|
||||||
type Wagon = TrainScheduleDetail["trainSet"]["wagons"][number];
|
type Wagon = NonNullable<TrainScheduleDetail["trainSet"]>["wagons"][number];
|
||||||
|
|
||||||
interface TrainConsistViewProps {
|
interface TrainConsistViewProps {
|
||||||
scheduleDetail: TrainScheduleDetail;
|
scheduleDetail: TrainScheduleDetail;
|
||||||
@@ -103,9 +103,9 @@ export const TrainConsistView = ({
|
|||||||
<Stack gap="md" style={{ width: "100%" }}>
|
<Stack gap="md" style={{ width: "100%" }}>
|
||||||
<TrainStatsBar
|
<TrainStatsBar
|
||||||
weightUsed={weightUsed}
|
weightUsed={weightUsed}
|
||||||
weightMax={scheduleDetail.locomotive?.maxWeightTons ?? trainSet?.locomotive?.maxPullWeightTons ?? null}
|
weightMax={trainSet?.locomotive?.maxPullWeightTons ?? null}
|
||||||
lengthUsed={lengthUsed}
|
lengthUsed={lengthUsed}
|
||||||
lengthMax={scheduleDetail.locomotive?.maxLengthMeters ?? trainSet?.locomotive?.maxTrainLengthMeters ?? null}
|
lengthMax={trainSet?.locomotive?.maxTrainLengthMeters ?? null}
|
||||||
wagonCount={wagons.length}
|
wagonCount={wagons.length}
|
||||||
wagonMax={maxWagons}
|
wagonMax={maxWagons}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import type { TrainScheduleDetail } from "@/types/trainScheduling";
|
|||||||
import { ContainerNumberInput } from "./ContainerNumberInput";
|
import { ContainerNumberInput } from "./ContainerNumberInput";
|
||||||
import { freightBrand } from "@/theme/freight-brand";
|
import { freightBrand } from "@/theme/freight-brand";
|
||||||
|
|
||||||
type Wagon = TrainScheduleDetail["trainSet"]["wagons"][number];
|
type Wagon = NonNullable<TrainScheduleDetail["trainSet"]>["wagons"][number];
|
||||||
|
|
||||||
interface WagonCardProps {
|
interface WagonCardProps {
|
||||||
wagon: Wagon;
|
wagon: Wagon;
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import { useMemo } from "react";
|
import { DataTable, type ColumnDef } from "@edr/ui-common";
|
||||||
import { ActionIcon, Badge, Button, Group, Text, Tooltip } from "@mantine/core";
|
import { ActionIcon, Badge, Button, Group, Text, Tooltip } from "@mantine/core";
|
||||||
import { ArrowRightLeft, ClipboardList, Coins, History } from "lucide-react";
|
import { ArrowRightLeft, ClipboardList, Coins, History } from "lucide-react";
|
||||||
import { DataTable, type ColumnDef } from "@edr/ui-common";
|
import { useMemo } from "react";
|
||||||
|
|
||||||
import type {
|
import {
|
||||||
InventoryAction,
|
INVENTORY_NEXT_ACTION,
|
||||||
WarehouseInventoryItem,
|
type InventoryAction,
|
||||||
|
type WarehouseInventoryItem,
|
||||||
} from "@/types/warehouse";
|
} from "@/types/warehouse";
|
||||||
import { InventoryStatusBadge } from "./badges";
|
import { InventoryStatusBadge } from "./badges";
|
||||||
import { formatDate, formatNumber, humanizeEnum } from "./options";
|
import { formatDate, formatNumber, humanizeEnum } from "./options";
|
||||||
@@ -54,12 +55,6 @@ export function WarehouseInventoryTable({
|
|||||||
onHistory,
|
onHistory,
|
||||||
onInspect,
|
onInspect,
|
||||||
onFeePreview,
|
onFeePreview,
|
||||||
onLastMile,
|
|
||||||
selectedIds,
|
|
||||||
onToggleSelect,
|
|
||||||
onToggleSelectAll,
|
|
||||||
allSelected,
|
|
||||||
someSelected,
|
|
||||||
}: WarehouseInventoryTableProps) {
|
}: WarehouseInventoryTableProps) {
|
||||||
const columns = useMemo<ColumnDef<WarehouseInventoryItem>[]>(
|
const columns = useMemo<ColumnDef<WarehouseInventoryItem>[]>(
|
||||||
() => [
|
() => [
|
||||||
|
|||||||
@@ -662,7 +662,7 @@ export default function NewBookingPage() {
|
|||||||
placeholder="Select bulk cargo type"
|
placeholder="Select bulk cargo type"
|
||||||
data={cargoData}
|
data={cargoData}
|
||||||
value={cargoTypeId}
|
value={cargoTypeId}
|
||||||
onChange={setCargoTypeId}
|
onChange={(value) => setCargoTypeId(value as string | null)}
|
||||||
searchable
|
searchable
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ const OverviewPage = () => {
|
|||||||
|
|
||||||
const getTabBadge = (tab: (typeof TAB_ITEMS)[number]) => {
|
const getTabBadge = (tab: (typeof TAB_ITEMS)[number]) => {
|
||||||
if (!summary?.kpis) return 0;
|
if (!summary?.kpis) return 0;
|
||||||
const group = summary.kpis[tab.kpiKey] as Record<string, number>;
|
const group = summary.kpis[tab.kpiKey] as unknown as Record<string, number>;
|
||||||
return group[tab.metricKey] ?? 0;
|
return group[tab.metricKey] ?? 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,49 +1,49 @@
|
|||||||
import { FormEvent, ReactNode, useMemo, useState } from 'react';
|
|
||||||
import { useMutation, useQuery } from '@tanstack/react-query';
|
import { useMutation, useQuery } from '@tanstack/react-query';
|
||||||
import { Edit, Eye, Plus, Search, Trash2 } from 'lucide-react';
|
import { Edit, Eye, Plus, Search, Trash2 } from 'lucide-react';
|
||||||
|
import { FormEvent, ReactNode, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import { api } from '@/services/api';
|
import { api } from '@/services/api';
|
||||||
import {
|
import {
|
||||||
ActionIcon,
|
ActionIcon,
|
||||||
Badge as MantineBadge,
|
Box,
|
||||||
Box,
|
Group,
|
||||||
Button as MantineButton,
|
Badge as MantineBadge,
|
||||||
Group,
|
Button as MantineButton,
|
||||||
Modal,
|
Select as MantineSelect,
|
||||||
NumberInput,
|
Table as MantineTable,
|
||||||
Pagination,
|
Modal,
|
||||||
Paper,
|
NumberInput,
|
||||||
ScrollArea,
|
Pagination,
|
||||||
Select as MantineSelect,
|
Paper,
|
||||||
SimpleGrid,
|
ScrollArea,
|
||||||
Stack,
|
SimpleGrid,
|
||||||
Table as MantineTable,
|
Stack,
|
||||||
Text,
|
Text,
|
||||||
TextInput,
|
TextInput,
|
||||||
Title,
|
Title,
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
|
|
||||||
|
import { DeliverCargoDialog } from '@/components/cargoes/DeliverCargoDialog';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogFooter,
|
DialogFooter,
|
||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from '@/components/ui/dialog';
|
} from '@/components/ui/dialog';
|
||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import { Label } from '@/components/ui/label';
|
import { Label } from '@/components/ui/label';
|
||||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@edr/ui-common';
|
|
||||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
|
||||||
import { useToast } from '@/hooks/use-toast';
|
import { useToast } from '@/hooks/use-toast';
|
||||||
import type { Cargo } from '@/services/cargoService';
|
import type { Cargo } from '@/services/cargoService';
|
||||||
import { DeliverCargoDialog } from '@/components/cargoes/DeliverCargoDialog';
|
|
||||||
import type { Container } from '@/services/containerService';
|
import type { Container } from '@/services/containerService';
|
||||||
import type { Locomotive } from '@/services/locomotives.service';
|
import type { Locomotive } from '@/services/locomotives.service';
|
||||||
import type { Train } from '@/services/trains.service';
|
import type { Train } from '@/services/trains.service';
|
||||||
import type { Wagon } from '@/services/wagon.service';
|
|
||||||
import type { WagonType } from '@/services/wagon-types.service';
|
import type { WagonType } from '@/services/wagon-types.service';
|
||||||
|
import type { Wagon } from '@/services/wagon.service';
|
||||||
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@edr/ui-common';
|
||||||
|
|
||||||
type FormValue = string | number | boolean | string[];
|
type FormValue = string | number | boolean | string[];
|
||||||
|
|
||||||
@@ -331,7 +331,7 @@ function FleetCrudPage<T extends { id: string }>({
|
|||||||
<TableRow key={item.id}>
|
<TableRow key={item.id}>
|
||||||
{columns.map((column) => (
|
{columns.map((column) => (
|
||||||
<TableCell key={String(column.key)}>
|
<TableCell key={String(column.key)}>
|
||||||
{column.render ? column.render(item) : String((item as Record<string, unknown>)[column.key] ?? '-')}
|
{column.render ? column.render(item) : String((item as Record<string, unknown>)[String(column.key)] ?? '-')}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
))}
|
))}
|
||||||
<TableCell>
|
<TableCell>
|
||||||
@@ -410,7 +410,7 @@ function FleetCrudPage<T extends { id: string }>({
|
|||||||
...current,
|
...current,
|
||||||
[field.key]: selectedValue,
|
[field.key]: selectedValue,
|
||||||
...(field.onValueChange?.(selectedValue, current) ?? {}),
|
...(field.onValueChange?.(selectedValue, current) ?? {}),
|
||||||
}))
|
}) as Record<string, FormValue>)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<SelectTrigger id={field.key}>
|
<SelectTrigger id={field.key}>
|
||||||
@@ -480,12 +480,6 @@ function FleetCrudPage<T extends { id: string }>({
|
|||||||
|
|
||||||
const statusBadge = (status?: string) => <Badge variant="outline">{status ?? '-'}</Badge>;
|
const statusBadge = (status?: string) => <Badge variant="outline">{status ?? '-'}</Badge>;
|
||||||
|
|
||||||
const activeBadge = (isActive?: boolean) => (
|
|
||||||
<Badge variant={isActive === false ? 'secondary' : 'outline'}>
|
|
||||||
{isActive === false ? 'Inactive' : 'Active'}
|
|
||||||
</Badge>
|
|
||||||
);
|
|
||||||
|
|
||||||
const optionLabel = (options: { value: string; label: string }[], value?: string | null) =>
|
const optionLabel = (options: { value: string; label: string }[], value?: string | null) =>
|
||||||
options.find((option) => option.value === value)?.label ?? value ?? '-';
|
options.find((option) => option.value === value)?.label ?? value ?? '-';
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,10 @@
|
|||||||
import type { ColumnDef } from "@edr/ui-common";
|
import type { ColumnDef } from "@edr/ui-common";
|
||||||
import { Box, Button, Card, Group, Modal, Select, Stack, Text } from "@mantine/core";
|
import { Box, Button, Card, Container, Group, Modal, Select, Stack, Text, Title } from "@mantine/core";
|
||||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||||
|
|
||||||
import { api } from "@/services/api";
|
import { api } from "@/services/api";
|
||||||
import {
|
import Breadcrumbs from "@/components/ui/Breadcrumbs";
|
||||||
Archive,
|
import { Plus } from "lucide-react";
|
||||||
Circle,
|
|
||||||
CircleCheck,
|
|
||||||
CircleSlash,
|
|
||||||
Layers,
|
|
||||||
Link2,
|
|
||||||
Plus,
|
|
||||||
Wrench,
|
|
||||||
type LucideIcon,
|
|
||||||
} from "lucide-react";
|
|
||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import { Navigate, useLocation } from "react-router-dom";
|
import { Navigate, useLocation } from "react-router-dom";
|
||||||
|
|
||||||
@@ -23,37 +14,20 @@ import FleetRecordActions from "@/components/fleet/FleetRecordActions";
|
|||||||
import FleetToolbar from "@/components/fleet/FleetToolbar";
|
import FleetToolbar from "@/components/fleet/FleetToolbar";
|
||||||
import { formatFleetCell, registerFleetOptionLabels } from "@/components/fleet/fleetFormat";
|
import { formatFleetCell, registerFleetOptionLabels } from "@/components/fleet/fleetFormat";
|
||||||
import { useFleetViewMode } from "@/components/fleet/useFleetViewMode";
|
import { useFleetViewMode } from "@/components/fleet/useFleetViewMode";
|
||||||
import { KpiStrip, PageContainer, PageHeader } from "@/components/page";
|
|
||||||
import { ruleEngineTable } from "@/components/ruleEngine/ruleEngineStyles";
|
import { ruleEngineTable } from "@/components/ruleEngine/ruleEngineStyles";
|
||||||
import { useToast } from "@/hooks/use-toast";
|
import { useToast } from "@/hooks/use-toast";
|
||||||
import {
|
import {
|
||||||
FLEET_SELECT_NONE,
|
FLEET_SELECT_NONE,
|
||||||
getFleetResource,
|
getFleetResource,
|
||||||
getFleetSlugFromPath,
|
getFleetSlugFromPath,
|
||||||
type FleetFormFieldDef,
|
type FleetFormFieldDef,
|
||||||
type FleetResourceSlug,
|
type FleetResourceSlug,
|
||||||
} from "@/pages/fleet/config/resources";
|
} from "@/pages/fleet/config/resources";
|
||||||
import type { FleetListFilters, FleetRecord } from "@/services/fleet/fleet.service";
|
import type { FleetListFilters, FleetRecord } from "@/services/fleet/fleet.service";
|
||||||
import { DataTable, DataTableFooter, usePagination } from "@edr/ui-common";
|
import { DataTable, DataTableFooter, usePagination } from "@edr/ui-common";
|
||||||
|
|
||||||
const DEFAULT_SLUG: FleetResourceSlug = "locomotives";
|
const DEFAULT_SLUG: FleetResourceSlug = "locomotives";
|
||||||
|
|
||||||
const FLEET_STATUS_META: Record<
|
|
||||||
string,
|
|
||||||
{ label: string; icon: LucideIcon; color: string }
|
|
||||||
> = {
|
|
||||||
AVAILABLE: { label: "Available", icon: CircleCheck, color: "edr-green" },
|
|
||||||
ASSIGNED: { label: "Assigned", icon: Link2, color: "blue" },
|
|
||||||
MAINTENANCE: { label: "Maintenance", icon: Wrench, color: "yellow" },
|
|
||||||
OUT_OF_SERVICE: { label: "Out of service", icon: CircleSlash, color: "red" },
|
|
||||||
RETIRED: { label: "Retired", icon: Archive, color: "gray" },
|
|
||||||
};
|
|
||||||
|
|
||||||
const humanizeStatus = (status: string) => {
|
|
||||||
const text = status.replace(/_/g, " ").toLowerCase();
|
|
||||||
return text.charAt(0).toUpperCase() + text.slice(1);
|
|
||||||
};
|
|
||||||
|
|
||||||
const FleetResourcePage = () => {
|
const FleetResourcePage = () => {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const slug = getFleetSlugFromPath(location.pathname) ?? DEFAULT_SLUG;
|
const slug = getFleetSlugFromPath(location.pathname) ?? DEFAULT_SLUG;
|
||||||
@@ -113,6 +87,9 @@ const FleetResourcePage = () => {
|
|||||||
const { data: yards = [], isLoading: yardsLoading } = useQuery(
|
const { data: yards = [], isLoading: yardsLoading } = useQuery(
|
||||||
api.routes.yards.queryOptions(),
|
api.routes.yards.queryOptions(),
|
||||||
);
|
);
|
||||||
|
const { data: drivers = [] } = useQuery(
|
||||||
|
api.fleet.list.queryOptions({ input: { slug: "drivers" } }),
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setPagination((prev) => ({ pageIndex: 0, pageSize: prev.pageSize }));
|
setPagination((prev) => ({ pageIndex: 0, pageSize: prev.pageSize }));
|
||||||
@@ -301,39 +278,6 @@ const FleetResourcePage = () => {
|
|||||||
|
|
||||||
const tableStatus = isLoading ? "loading" : isError ? "error" : "success";
|
const tableStatus = isLoading ? "loading" : isError ? "error" : "success";
|
||||||
|
|
||||||
const kpiItems = useMemo(() => {
|
|
||||||
const items = [
|
|
||||||
{
|
|
||||||
label: `Total ${config?.label.toLowerCase() ?? ""}`,
|
|
||||||
value: allRows.length,
|
|
||||||
icon: Layers,
|
|
||||||
color: "edr-green",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
if (hasStatusColumn) {
|
|
||||||
const counts = new Map<string, number>();
|
|
||||||
for (const row of allRows) {
|
|
||||||
const status = String(
|
|
||||||
(row as unknown as Record<string, unknown>).status ?? "",
|
|
||||||
);
|
|
||||||
if (status) counts.set(status, (counts.get(status) ?? 0) + 1);
|
|
||||||
}
|
|
||||||
const top = [...counts.entries()]
|
|
||||||
.sort((a, b) => b[1] - a[1])
|
|
||||||
.slice(0, 4);
|
|
||||||
for (const [status, count] of top) {
|
|
||||||
const meta = FLEET_STATUS_META[status];
|
|
||||||
items.push({
|
|
||||||
label: meta?.label ?? humanizeStatus(status),
|
|
||||||
value: count,
|
|
||||||
icon: meta?.icon ?? Circle,
|
|
||||||
color: meta?.color ?? "gray",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return items.slice(0, 5);
|
|
||||||
}, [allRows, hasStatusColumn, config?.label]);
|
|
||||||
|
|
||||||
if (!config) {
|
if (!config) {
|
||||||
return <Navigate to="/dashboard/locomotives" replace />;
|
return <Navigate to="/dashboard/locomotives" replace />;
|
||||||
}
|
}
|
||||||
@@ -376,7 +320,7 @@ const FleetResourcePage = () => {
|
|||||||
const handleAssignDriver = async () => {
|
const handleAssignDriver = async () => {
|
||||||
if (!assigningDriver || !("id" in assigningDriver) || !selectedDriver) return;
|
if (!assigningDriver || !("id" in assigningDriver) || !selectedDriver) return;
|
||||||
try {
|
try {
|
||||||
const selectedDriverRecord = (drivers as Array<Record<string, unknown>>).find(
|
const selectedDriverRecord = (drivers as unknown as Array<Record<string, unknown>>).find(
|
||||||
(d) => String(d.id) === selectedDriver
|
(d) => String(d.id) === selectedDriver
|
||||||
);
|
);
|
||||||
if (!selectedDriverRecord) return;
|
if (!selectedDriverRecord) return;
|
||||||
@@ -384,6 +328,7 @@ const FleetResourcePage = () => {
|
|||||||
const driverName = `${selectedDriverRecord.firstName} ${selectedDriverRecord.lastName}`;
|
const driverName = `${selectedDriverRecord.firstName} ${selectedDriverRecord.lastName}`;
|
||||||
|
|
||||||
await update.mutateAsync({
|
await update.mutateAsync({
|
||||||
|
slug,
|
||||||
id: String(assigningDriver.id),
|
id: String(assigningDriver.id),
|
||||||
data: {
|
data: {
|
||||||
assignedDriverId: selectedDriver,
|
assignedDriverId: selectedDriver,
|
||||||
@@ -608,7 +553,7 @@ const FleetResourcePage = () => {
|
|||||||
clearable
|
clearable
|
||||||
value={selectedDriver}
|
value={selectedDriver}
|
||||||
onChange={(value) => setSelectedDriver(value || "")}
|
onChange={(value) => setSelectedDriver(value || "")}
|
||||||
data={(drivers as Array<Record<string, unknown>>).map((driver) => ({
|
data={(drivers as unknown as Array<Record<string, unknown>>).map((driver) => ({
|
||||||
value: String(driver.id || ""),
|
value: String(driver.id || ""),
|
||||||
label: `${driver.firstName} ${driver.lastName} (${driver.licenseNumber})`,
|
label: `${driver.firstName} ${driver.lastName} (${driver.licenseNumber})`,
|
||||||
}))}
|
}))}
|
||||||
|
|||||||
@@ -1,58 +1,56 @@
|
|||||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
||||||
import { Navigate, useLocation, useParams } from "react-router-dom";
|
|
||||||
import { useAuth } from "@/auth/useAuth";
|
import { useAuth } from "@/auth/useAuth";
|
||||||
import { canAccessRuleEngineResource } from "@/lib/permissions";
|
import { canAccessRuleEngineResource } from "@/lib/permissions";
|
||||||
import type { ColumnDef } from "@edr/ui-common";
|
import type { ColumnDef } from "@edr/ui-common";
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Card,
|
Button,
|
||||||
Button,
|
Card,
|
||||||
Modal,
|
Group,
|
||||||
Stack,
|
List,
|
||||||
Group,
|
Loader,
|
||||||
Text,
|
Modal,
|
||||||
List,
|
Stack,
|
||||||
Loader,
|
Text,
|
||||||
} from "@mantine/core";
|
} from "@mantine/core";
|
||||||
import { Plus } from "lucide-react";
|
import { Plus } from "lucide-react";
|
||||||
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
|
import { Navigate, useLocation, useParams } from "react-router-dom";
|
||||||
|
|
||||||
import { PageContainer, PageHeader } from "@/components/page";
|
import { PageContainer, PageHeader } from "@/components/page";
|
||||||
|
import ManageRuleEngineOrderDialog from "@/components/ruleEngine/ManageRuleEngineOrderDialog";
|
||||||
import RuleEngineCardGrid from "@/components/ruleEngine/RuleEngineCardGrid";
|
import RuleEngineCardGrid from "@/components/ruleEngine/RuleEngineCardGrid";
|
||||||
import RuleEngineFormDialog from "@/components/ruleEngine/RuleEngineFormDialog";
|
import RuleEngineFormDialog from "@/components/ruleEngine/RuleEngineFormDialog";
|
||||||
import ManageRuleEngineOrderDialog from "@/components/ruleEngine/ManageRuleEngineOrderDialog";
|
|
||||||
import RuleEngineOrderControls from "@/components/ruleEngine/RuleEngineOrderControls";
|
import RuleEngineOrderControls from "@/components/ruleEngine/RuleEngineOrderControls";
|
||||||
import RuleEngineRecordActions from "@/components/ruleEngine/RuleEngineRecordActions";
|
import RuleEngineRecordActions from "@/components/ruleEngine/RuleEngineRecordActions";
|
||||||
import { getOrderItemLabel } from "@/components/ruleEngine/ruleEngineOrder.utils";
|
|
||||||
import RuleEngineToolbar from "@/components/ruleEngine/RuleEngineToolbar";
|
import RuleEngineToolbar from "@/components/ruleEngine/RuleEngineToolbar";
|
||||||
import { formatCell } from "@/components/ruleEngine/ruleEngineFormat";
|
import { formatCell } from "@/components/ruleEngine/ruleEngineFormat";
|
||||||
|
import { getOrderItemLabel } from "@/components/ruleEngine/ruleEngineOrder.utils";
|
||||||
import { ruleEngineTable } from "@/components/ruleEngine/ruleEngineStyles";
|
import { ruleEngineTable } from "@/components/ruleEngine/ruleEngineStyles";
|
||||||
import { useRuleEngineViewMode } from "@/components/ruleEngine/useRuleEngineViewMode";
|
import { useRuleEngineViewMode } from "@/components/ruleEngine/useRuleEngineViewMode";
|
||||||
import {
|
import {
|
||||||
DEFAULT_CONFIGURATION_SLUG,
|
useApprovalChain,
|
||||||
DEFAULT_RULES_SLUG,
|
useCargoTypeParentOptions,
|
||||||
RULE_ENGINE_CATEGORY_BASE_PATH,
|
useContainerTypeOptions,
|
||||||
RULE_ENGINE_SELECT_NONE,
|
useLiveRateOptions,
|
||||||
getRuleEngineResource,
|
useRateWorkflow,
|
||||||
type RuleEngineNavCategory,
|
useRuleEngineList,
|
||||||
} from "@/pages/ruleEngine/config/resources";
|
useRuleEngineMutations,
|
||||||
import {
|
useRuleEngineOrderList,
|
||||||
useApprovalChain,
|
useRuleEngineOrderMutations,
|
||||||
useCargoTypeParentOptions,
|
|
||||||
useContainerTypeOptions,
|
|
||||||
useLiveRateOptions,
|
|
||||||
useRateWorkflow,
|
|
||||||
useRuleEngineList,
|
|
||||||
useRuleEngineMutations,
|
|
||||||
useRuleEngineOrderList,
|
|
||||||
useRuleEngineOrderMutations,
|
|
||||||
} from "@/hooks/rule-engine/useRuleEngine";
|
} from "@/hooks/rule-engine/useRuleEngine";
|
||||||
|
import {
|
||||||
|
DEFAULT_CONFIGURATION_SLUG,
|
||||||
|
DEFAULT_RULES_SLUG,
|
||||||
|
RULE_ENGINE_CATEGORY_BASE_PATH,
|
||||||
|
RULE_ENGINE_SELECT_NONE,
|
||||||
|
getRuleEngineResource,
|
||||||
|
type RuleEngineNavCategory,
|
||||||
|
} from "@/pages/ruleEngine/config/resources";
|
||||||
import type { RuleEngineRecord } from "@/types/rule-engine";
|
import type { RuleEngineRecord } from "@/types/rule-engine";
|
||||||
import {
|
import {
|
||||||
DataTable,
|
DataTable,
|
||||||
DataTableFooter,
|
DataTableFooter,
|
||||||
getCoreRowModel,
|
usePagination,
|
||||||
usePagination,
|
|
||||||
useReactTable,
|
|
||||||
} from "@edr/ui-common";
|
} from "@edr/ui-common";
|
||||||
|
|
||||||
const pathCategory = (pathname: string): RuleEngineNavCategory | undefined => {
|
const pathCategory = (pathname: string): RuleEngineNavCategory | undefined => {
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ function mapCompany(dto: Record<string, unknown>): Company {
|
|||||||
const attrs = (dto.attributes as Record<string, unknown> | null) ?? {};
|
const attrs = (dto.attributes as Record<string, unknown> | null) ?? {};
|
||||||
return {
|
return {
|
||||||
...(dto as unknown as Company),
|
...(dto as unknown as Company),
|
||||||
|
companyProfiles: (dto.companyProfiles as Company["companyProfiles"]) ?? [],
|
||||||
contactPersonName: (attrs.contactPersonName as string | null) ?? null,
|
contactPersonName: (attrs.contactPersonName as string | null) ?? null,
|
||||||
contactPersonPhone: (attrs.contactPersonPhone as string | null) ?? null,
|
contactPersonPhone: (attrs.contactPersonPhone as string | null) ?? null,
|
||||||
generalManagerName: (attrs.generalManagerName as string | null) ?? null,
|
generalManagerName: (attrs.generalManagerName as string | null) ?? null,
|
||||||
|
|||||||
@@ -375,6 +375,7 @@ export interface TrainScheduleDetail {
|
|||||||
weightTons: number;
|
weightTons: number;
|
||||||
status: string | null;
|
status: string | null;
|
||||||
schedulingStatus?: SchedulingStatus | null;
|
schedulingStatus?: SchedulingStatus | null;
|
||||||
|
freightType?: FreightType | string | null;
|
||||||
}>;
|
}>;
|
||||||
warnings?: string[];
|
warnings?: string[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
|
|
||||||
export interface OperationsQueueGroups {
|
export interface OperationsQueueGroups {
|
||||||
government: BookingListRow[];
|
government: BookingListRow[];
|
||||||
commercial: ThreeHourBookingBucket[];
|
commercial: ThreeHourBookingBucket<BookingListRow>[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function groupBookingsForOperationsQueue(
|
export function groupBookingsForOperationsQueue(
|
||||||
|
|||||||
@@ -1,40 +1,40 @@
|
|||||||
import { URL_CONSTANTS } from "@/constants/URLS";
|
import { URL_CONSTANTS } from "@/constants/URLS";
|
||||||
|
import type {
|
||||||
|
AuthUser,
|
||||||
|
GenerateVerificationCodePayload,
|
||||||
|
LoginPayload,
|
||||||
|
LoginResponse,
|
||||||
|
OtpPayload,
|
||||||
|
OtpResponse,
|
||||||
|
SetPasswordPayload,
|
||||||
|
SignupPayload,
|
||||||
|
SignupResponse,
|
||||||
|
} from "@/types/auth";
|
||||||
import { client } from "@/utils/api";
|
import { client } from "@/utils/api";
|
||||||
import { ApiResponse } from "@edr/types";
|
import { ApiResponse } from "@edr/types";
|
||||||
import type {
|
|
||||||
AuthUser,
|
|
||||||
GenerateVerificationCodePayload,
|
|
||||||
LoginPayload,
|
|
||||||
LoginResponse,
|
|
||||||
OtpPayload,
|
|
||||||
OtpResponse,
|
|
||||||
SetPasswordPayload,
|
|
||||||
SignupPayload,
|
|
||||||
SignupResponse,
|
|
||||||
} from "@/types/auth";
|
|
||||||
|
|
||||||
export const authService = {
|
export const authService = {
|
||||||
login: async (body: LoginPayload) => {
|
login: async (body: LoginPayload) => {
|
||||||
const res = await client.post<ApiResponse<LoginResponse>>(
|
const res = await client.post<LoginResponse>(
|
||||||
URL_CONSTANTS.AUTH.LOGIN,
|
URL_CONSTANTS.AUTH.LOGIN,
|
||||||
body,
|
body,
|
||||||
);
|
);
|
||||||
return res.data.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
|
|
||||||
createUser: async (body: SignupPayload) => {
|
createUser: async (body: SignupPayload) => {
|
||||||
const res = await client.post<ApiResponse<SignupResponse>>(
|
const res = await client.post<SignupResponse & ApiResponse<void>> (
|
||||||
URL_CONSTANTS.USERS.SIGN_UP,
|
URL_CONSTANTS.USERS.SIGN_UP,
|
||||||
body,
|
body,
|
||||||
);
|
);
|
||||||
return res.data.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
|
|
||||||
getMyInfo: async () => {
|
getMyInfo: async () => {
|
||||||
const res = await client.get<ApiResponse<AuthUser>>(
|
const res = await client.get<AuthUser>(
|
||||||
URL_CONSTANTS.USERS.ME,
|
URL_CONSTANTS.USERS.ME,
|
||||||
);
|
);
|
||||||
return res.data.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
|
|
||||||
generateVerificationCode: async (body: GenerateVerificationCodePayload) => {
|
generateVerificationCode: async (body: GenerateVerificationCodePayload) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user