mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-27 00:52:50 +00:00
add checkbox
This commit is contained in:
@@ -385,6 +385,7 @@ const FirstMilePage = () => {
|
||||
const [rowSelection, setRowSelection] = useState<Record<string, boolean>>({});
|
||||
|
||||
const [assignOpen, setAssignOpen] = useState(false);
|
||||
const [bulkMode, setBulkMode] = useState(false);
|
||||
const [detailOpen, setDetailOpen] = useState(false);
|
||||
const [tripSlipOpen, setTripSlipOpen] = useState(false);
|
||||
const [tripSlipJob, setTripSlipJob] = useState<FirstMileJob | null>(null);
|
||||
@@ -396,6 +397,11 @@ const FirstMilePage = () => {
|
||||
[jobs, activeJobId],
|
||||
);
|
||||
|
||||
const selectedIds = useMemo(
|
||||
() => Object.keys(rowSelection).filter((id) => rowSelection[id]),
|
||||
[rowSelection],
|
||||
);
|
||||
|
||||
const matchesStatusFilter = (job: FirstMileJob) => {
|
||||
switch (statusFilter) {
|
||||
case "ALL":
|
||||
@@ -445,11 +451,19 @@ const FirstMilePage = () => {
|
||||
|
||||
const openAssign = (jobId: string | null) => {
|
||||
const resolved = jobId ?? filteredJobs.find((job) => job.status === "UNASSIGNED")?.id ?? null;
|
||||
setBulkMode(false);
|
||||
setActiveJobId(resolved);
|
||||
setVehicleValue(null);
|
||||
setAssignOpen(true);
|
||||
};
|
||||
|
||||
const openBulkAssign = () => {
|
||||
setBulkMode(true);
|
||||
setActiveJobId(null);
|
||||
setVehicleValue(null);
|
||||
setAssignOpen(true);
|
||||
};
|
||||
|
||||
const openDetail = (jobId: string) => {
|
||||
setActiveJobId(jobId);
|
||||
setDetailOpen(true);
|
||||
@@ -457,6 +471,7 @@ const FirstMilePage = () => {
|
||||
|
||||
const closeAssign = () => {
|
||||
setAssignOpen(false);
|
||||
setBulkMode(false);
|
||||
setActiveJobId(null);
|
||||
setVehicleValue(null);
|
||||
};
|
||||
@@ -467,8 +482,7 @@ const FirstMilePage = () => {
|
||||
};
|
||||
|
||||
const handleAssign = () => {
|
||||
const jobId = activeJobId ?? filteredJobs.find((job) => job.status === "UNASSIGNED")?.id;
|
||||
if (!jobId || !vehicleValue) {
|
||||
if (!vehicleValue) {
|
||||
toast({
|
||||
title: "Select a vehicle",
|
||||
description: "Choose a vehicle to assign to this pickup.",
|
||||
@@ -480,15 +494,30 @@ const FirstMilePage = () => {
|
||||
const vehicleLabel =
|
||||
VEHICLE_OPTIONS.find((option) => option.value === vehicleValue)?.label ?? vehicleValue;
|
||||
|
||||
const targetIds = bulkMode
|
||||
? selectedIds
|
||||
: [activeJobId ?? filteredJobs.find((job) => job.status === "UNASSIGNED")?.id].filter(
|
||||
(id): id is string => Boolean(id),
|
||||
);
|
||||
|
||||
if (!targetIds.length) return;
|
||||
|
||||
const targetSet = new Set(targetIds);
|
||||
setJobs((current) =>
|
||||
current.map((job) =>
|
||||
job.id === jobId
|
||||
targetSet.has(job.id)
|
||||
? { ...job, status: "ASSIGNED", assignedVehicle: vehicleLabel }
|
||||
: job,
|
||||
),
|
||||
);
|
||||
|
||||
toast({ title: "Vehicle assigned", description: vehicleLabel });
|
||||
toast({
|
||||
title: "Vehicle assigned",
|
||||
description: bulkMode
|
||||
? `${targetIds.length} pickups → ${vehicleLabel}`
|
||||
: vehicleLabel,
|
||||
});
|
||||
if (bulkMode) setRowSelection({});
|
||||
closeAssign();
|
||||
};
|
||||
|
||||
@@ -708,12 +737,23 @@ const FirstMilePage = () => {
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
w={260}
|
||||
/>
|
||||
<Button
|
||||
leftSection={<Truck size={16} />}
|
||||
onClick={() => openAssign(null)}
|
||||
>
|
||||
Assign Mile
|
||||
</Button>
|
||||
<Group gap="sm">
|
||||
{selectedIds.length > 0 && (
|
||||
<Button
|
||||
variant="light"
|
||||
leftSection={<Truck size={16} />}
|
||||
onClick={openBulkAssign}
|
||||
>
|
||||
Assign vehicle ({selectedIds.length})
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
leftSection={<Truck size={16} />}
|
||||
onClick={() => openAssign(null)}
|
||||
>
|
||||
Assign Mile
|
||||
</Button>
|
||||
</Group>
|
||||
</Group>
|
||||
<Group gap="xs" wrap="wrap">
|
||||
{FILTER_OPTIONS.map((option) => {
|
||||
@@ -777,7 +817,15 @@ const FirstMilePage = () => {
|
||||
centered
|
||||
>
|
||||
<Stack gap="md">
|
||||
{activeJob ? (
|
||||
{bulkMode ? (
|
||||
<Text size="sm">
|
||||
Assigning a vehicle to{" "}
|
||||
<Text span fw={600}>
|
||||
{selectedIds.length}
|
||||
</Text>{" "}
|
||||
selected {selectedIds.length === 1 ? "pickup" : "pickups"}.
|
||||
</Text>
|
||||
) : activeJob ? (
|
||||
<BookingInfo job={activeJob} />
|
||||
) : (
|
||||
<Text size="sm" c="dimmed">
|
||||
@@ -797,8 +845,11 @@ const FirstMilePage = () => {
|
||||
<Button variant="default" onClick={closeAssign}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button onClick={handleAssign} disabled={!activeJob}>
|
||||
{activeJob?.status === "ASSIGNED" ? "Reassign" : "Assign"}
|
||||
<Button
|
||||
onClick={handleAssign}
|
||||
disabled={bulkMode ? selectedIds.length === 0 : !activeJob}
|
||||
>
|
||||
{!bulkMode && activeJob?.status === "ASSIGNED" ? "Reassign" : "Assign"}
|
||||
</Button>
|
||||
</Group>
|
||||
</Stack>
|
||||
|
||||
@@ -385,6 +385,7 @@ const LastMilePage = () => {
|
||||
const [rowSelection, setRowSelection] = useState<Record<string, boolean>>({});
|
||||
|
||||
const [assignOpen, setAssignOpen] = useState(false);
|
||||
const [bulkMode, setBulkMode] = useState(false);
|
||||
const [detailOpen, setDetailOpen] = useState(false);
|
||||
const [tripSlipOpen, setTripSlipOpen] = useState(false);
|
||||
const [tripSlipJob, setTripSlipJob] = useState<LastMileJob | null>(null);
|
||||
@@ -396,6 +397,11 @@ const LastMilePage = () => {
|
||||
[jobs, activeJobId],
|
||||
);
|
||||
|
||||
const selectedIds = useMemo(
|
||||
() => Object.keys(rowSelection).filter((id) => rowSelection[id]),
|
||||
[rowSelection],
|
||||
);
|
||||
|
||||
const matchesStatusFilter = (job: LastMileJob) => {
|
||||
switch (statusFilter) {
|
||||
case "ALL":
|
||||
@@ -445,11 +451,19 @@ const LastMilePage = () => {
|
||||
|
||||
const openAssign = (jobId: string | null) => {
|
||||
const resolved = jobId ?? filteredJobs.find((job) => job.status === "UNASSIGNED")?.id ?? null;
|
||||
setBulkMode(false);
|
||||
setActiveJobId(resolved);
|
||||
setVehicleValue(null);
|
||||
setAssignOpen(true);
|
||||
};
|
||||
|
||||
const openBulkAssign = () => {
|
||||
setBulkMode(true);
|
||||
setActiveJobId(null);
|
||||
setVehicleValue(null);
|
||||
setAssignOpen(true);
|
||||
};
|
||||
|
||||
const openDetail = (jobId: string) => {
|
||||
setActiveJobId(jobId);
|
||||
setDetailOpen(true);
|
||||
@@ -457,6 +471,7 @@ const LastMilePage = () => {
|
||||
|
||||
const closeAssign = () => {
|
||||
setAssignOpen(false);
|
||||
setBulkMode(false);
|
||||
setActiveJobId(null);
|
||||
setVehicleValue(null);
|
||||
};
|
||||
@@ -467,8 +482,7 @@ const LastMilePage = () => {
|
||||
};
|
||||
|
||||
const handleAssign = () => {
|
||||
const jobId = activeJobId ?? filteredJobs.find((job) => job.status === "UNASSIGNED")?.id;
|
||||
if (!jobId || !vehicleValue) {
|
||||
if (!vehicleValue) {
|
||||
toast({
|
||||
title: "Select a vehicle",
|
||||
description: "Choose a vehicle to assign to this delivery.",
|
||||
@@ -480,15 +494,30 @@ const LastMilePage = () => {
|
||||
const vehicleLabel =
|
||||
VEHICLE_OPTIONS.find((option) => option.value === vehicleValue)?.label ?? vehicleValue;
|
||||
|
||||
const targetIds = bulkMode
|
||||
? selectedIds
|
||||
: [activeJobId ?? filteredJobs.find((job) => job.status === "UNASSIGNED")?.id].filter(
|
||||
(id): id is string => Boolean(id),
|
||||
);
|
||||
|
||||
if (!targetIds.length) return;
|
||||
|
||||
const targetSet = new Set(targetIds);
|
||||
setJobs((current) =>
|
||||
current.map((job) =>
|
||||
job.id === jobId
|
||||
targetSet.has(job.id)
|
||||
? { ...job, status: "ASSIGNED", assignedVehicle: vehicleLabel }
|
||||
: job,
|
||||
),
|
||||
);
|
||||
|
||||
toast({ title: "Vehicle assigned", description: vehicleLabel });
|
||||
toast({
|
||||
title: "Vehicle assigned",
|
||||
description: bulkMode
|
||||
? `${targetIds.length} deliveries → ${vehicleLabel}`
|
||||
: vehicleLabel,
|
||||
});
|
||||
if (bulkMode) setRowSelection({});
|
||||
closeAssign();
|
||||
};
|
||||
|
||||
@@ -708,12 +737,23 @@ const LastMilePage = () => {
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
w={260}
|
||||
/>
|
||||
<Button
|
||||
leftSection={<Truck size={16} />}
|
||||
onClick={() => openAssign(null)}
|
||||
>
|
||||
Assign Mile
|
||||
</Button>
|
||||
<Group gap="sm">
|
||||
{selectedIds.length > 0 && (
|
||||
<Button
|
||||
variant="light"
|
||||
leftSection={<Truck size={16} />}
|
||||
onClick={openBulkAssign}
|
||||
>
|
||||
Assign vehicle ({selectedIds.length})
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
leftSection={<Truck size={16} />}
|
||||
onClick={() => openAssign(null)}
|
||||
>
|
||||
Assign Mile
|
||||
</Button>
|
||||
</Group>
|
||||
</Group>
|
||||
<Group gap="xs" wrap="wrap">
|
||||
{FILTER_OPTIONS.map((option) => {
|
||||
@@ -777,7 +817,15 @@ const LastMilePage = () => {
|
||||
centered
|
||||
>
|
||||
<Stack gap="md">
|
||||
{activeJob ? (
|
||||
{bulkMode ? (
|
||||
<Text size="sm">
|
||||
Assigning a vehicle to{" "}
|
||||
<Text span fw={600}>
|
||||
{selectedIds.length}
|
||||
</Text>{" "}
|
||||
selected {selectedIds.length === 1 ? "delivery" : "deliveries"}.
|
||||
</Text>
|
||||
) : activeJob ? (
|
||||
<BookingInfo job={activeJob} />
|
||||
) : (
|
||||
<Text size="sm" c="dimmed">
|
||||
@@ -797,8 +845,11 @@ const LastMilePage = () => {
|
||||
<Button variant="default" onClick={closeAssign}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button onClick={handleAssign} disabled={!activeJob}>
|
||||
{activeJob?.status === "ASSIGNED" ? "Reassign" : "Assign"}
|
||||
<Button
|
||||
onClick={handleAssign}
|
||||
disabled={bulkMode ? selectedIds.length === 0 : !activeJob}
|
||||
>
|
||||
{!bulkMode && activeJob?.status === "ASSIGNED" ? "Reassign" : "Assign"}
|
||||
</Button>
|
||||
</Group>
|
||||
</Stack>
|
||||
|
||||
Reference in New Issue
Block a user