fix: From device to vehicle table
This commit is contained in:
parent
e2ca6b4132
commit
5ef61bcef4
@ -15,7 +15,7 @@ import {
|
|||||||
} from "@shared";
|
} from "@shared";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { Button, Checkbox } from "@mui/material";
|
import { Button, Checkbox, Typography } from "@mui/material"; // Import Typography for the modal message
|
||||||
|
|
||||||
const formatDate = (dateString: string | undefined) => {
|
const formatDate = (dateString: string | undefined) => {
|
||||||
if (!dateString) return "Нет данных";
|
if (!dateString) return "Нет данных";
|
||||||
@ -48,21 +48,16 @@ function createData(
|
|||||||
return { uuid, online, lastUpdate, gps, media, connection };
|
return { uuid, online, lastUpdate, gps, media, connection };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keep the rows function as you provided it, without additional filters
|
||||||
const rows = (devices: any[], vehicles: any[]) => {
|
const rows = (devices: any[], vehicles: any[]) => {
|
||||||
return devices.map((device) => {
|
return vehicles.map((vehicle) => {
|
||||||
const { device_status } = vehicles.find(
|
|
||||||
(v) => v?.device_status?.device_uuid === device
|
|
||||||
);
|
|
||||||
const findVehicle = vehicles.find((v) => v?.vehicle?.uuid === device);
|
|
||||||
|
|
||||||
console.log(findVehicle);
|
|
||||||
return createData(
|
return createData(
|
||||||
findVehicle?.vehicle?.tail_number ?? "1243000",
|
vehicle?.vehicle?.tail_number ?? "1243000", // Using tail_number as UUID, as in your original code
|
||||||
device_status?.online,
|
vehicle?.device_status?.online ?? false,
|
||||||
device_status?.last_update,
|
vehicle?.device_status?.last_update,
|
||||||
device_status?.gps_ok,
|
vehicle?.device_status?.gps_ok,
|
||||||
device_status?.media_service_ok,
|
vehicle?.device_status?.media_service_ok,
|
||||||
device_status?.is_connected
|
vehicle?.device_status?.is_connected
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -71,14 +66,18 @@ export const DevicesTable = observer(() => {
|
|||||||
const {
|
const {
|
||||||
devices,
|
devices,
|
||||||
getDevices,
|
getDevices,
|
||||||
uuid,
|
// uuid, // This 'uuid' from devicesStore refers to a *single* selected device, not for batch actions.
|
||||||
setSelectedDevice,
|
setSelectedDevice, // Useful for individual device actions like 'Reload Status'
|
||||||
sendSnapshotModalOpen,
|
sendSnapshotModalOpen,
|
||||||
toggleSendSnapshotModal,
|
toggleSendSnapshotModal,
|
||||||
} = devicesStore;
|
} = devicesStore;
|
||||||
const { snapshots, getSnapshots } = snapshotStore;
|
const { snapshots, getSnapshots } = snapshotStore;
|
||||||
const { vehicles, getVehicles } = vehicleStore;
|
const { vehicles, getVehicles } = vehicleStore;
|
||||||
const [selectedDevices, setSelectedDevices] = useState<string[]>([]);
|
const [selectedDevices, setSelectedDevices] = useState<string[]>([]);
|
||||||
|
|
||||||
|
// Get the current list of rows displayed in the table
|
||||||
|
const currentRows = rows(devices, vehicles);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
await getVehicles();
|
await getVehicles();
|
||||||
@ -88,55 +87,98 @@ export const DevicesTable = observer(() => {
|
|||||||
fetchData();
|
fetchData();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleSendSnapshot = (uuid: string) => {
|
// Determine if all visible devices are selected
|
||||||
setSelectedDevice(uuid);
|
const isAllSelected =
|
||||||
toggleSendSnapshotModal();
|
currentRows.length > 0 && selectedDevices.length === currentRows.length;
|
||||||
};
|
|
||||||
|
|
||||||
const handleReloadStatus = async (uuid: string) => {
|
const handleSelectAllDevices = () => {
|
||||||
setSelectedDevice(uuid);
|
if (isAllSelected) {
|
||||||
await authInstance.post(`/devices/${uuid}/request-status`);
|
// If all are currently selected, deselect all
|
||||||
await getDevices();
|
setSelectedDevices([]);
|
||||||
|
} else {
|
||||||
|
// Otherwise, select all device UUIDs from the current rows
|
||||||
|
setSelectedDevices(currentRows.map((row) => row.uuid));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSelectDevice = (event: React.ChangeEvent<HTMLInputElement>) => {
|
const handleSelectDevice = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const deviceUuid = event.target.value;
|
||||||
if (event.target.checked) {
|
if (event.target.checked) {
|
||||||
setSelectedDevices([...selectedDevices, event.target.value]);
|
setSelectedDevices((prevSelected) => [...prevSelected, deviceUuid]);
|
||||||
} else {
|
} else {
|
||||||
setSelectedDevices(
|
setSelectedDevices((prevSelected) =>
|
||||||
selectedDevices.filter((device) => device !== event.target.value)
|
prevSelected.filter((uuid) => uuid !== deviceUuid)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSendSnapshotAction = async (uuid: string, snapshotId: string) => {
|
// This function now opens the modal for selected devices
|
||||||
await authInstance.post(`/devices/${uuid}/force-snapshot`, {
|
const handleOpenSendSnapshotModal = () => {
|
||||||
|
if (selectedDevices.length > 0) {
|
||||||
|
toggleSendSnapshotModal();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleReloadStatus = async (uuid: string) => {
|
||||||
|
setSelectedDevice(uuid); // Set the active device in store for context if needed
|
||||||
|
await authInstance.post(`/devices/${uuid}/request-status`);
|
||||||
|
await getDevices(); // Refresh devices after status request
|
||||||
|
};
|
||||||
|
|
||||||
|
// This function now handles sending snapshots to ALL selected devices
|
||||||
|
const handleSendSnapshotAction = async (snapshotId: string) => {
|
||||||
|
try {
|
||||||
|
for (const deviceUuid of selectedDevices) {
|
||||||
|
console.log(`Sending snapshot ${snapshotId} to device ${deviceUuid}`);
|
||||||
|
// Ensure you are using the correct API endpoint for force-snapshot
|
||||||
|
await authInstance.post(`/devices/${deviceUuid}/force-snapshot`, {
|
||||||
snapshot_id: snapshotId,
|
snapshot_id: snapshotId,
|
||||||
});
|
});
|
||||||
await getDevices();
|
}
|
||||||
|
// After all requests are sent
|
||||||
|
await getDevices(); // Refresh the device list to show updated status
|
||||||
|
setSelectedDevices([]); // Clear the selection
|
||||||
|
toggleSendSnapshotModal(); // Close the modal
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error sending snapshots:", error);
|
||||||
|
// You might want to show an error notification to the user here
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TableContainer component={Paper}>
|
<TableContainer component={Paper}>
|
||||||
<div className="flex justify-end p-3 gap-5">
|
<div className="flex justify-end p-3 gap-3">
|
||||||
<Button variant="contained" color="primary">
|
{" "}
|
||||||
Выбрать все
|
{/* Changed gap to 3 for slightly less space */}
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
onClick={handleSelectAllDevices}
|
||||||
|
>
|
||||||
|
{isAllSelected ? "Снять выбор со всех" : "Выбрать все"}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
disabled={selectedDevices.length === 0}
|
disabled={selectedDevices.length === 0}
|
||||||
className="ml-auto"
|
onClick={handleOpenSendSnapshotModal} // Call the new handler
|
||||||
onClick={() => handleSendSnapshot(uuid ?? "")}
|
|
||||||
>
|
>
|
||||||
Отправить снапшот
|
Отправить снапшот ({selectedDevices.length})
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<Table sx={{ minWidth: 650 }} aria-label="simple table">
|
<Table sx={{ minWidth: 650 }} aria-label="simple table">
|
||||||
<TableHead>
|
<TableHead>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell align="center"></TableCell>
|
<TableCell align="center" padding="checkbox">
|
||||||
|
{" "}
|
||||||
|
{/* Added padding="checkbox" */}
|
||||||
|
<Checkbox
|
||||||
|
checked={isAllSelected}
|
||||||
|
onChange={handleSelectAllDevices}
|
||||||
|
inputProps={{ "aria-label": "select all devices" }}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
<TableCell align="center">Бортовой номер</TableCell>
|
<TableCell align="center">Бортовой номер</TableCell>
|
||||||
<TableCell align="center">Онлайн</TableCell>
|
<TableCell align="center">Онлайн</TableCell>
|
||||||
<TableCell align="center">Последнее обновление</TableCell>
|
<TableCell align="center">Последнее обновление</TableCell>
|
||||||
@ -147,56 +189,58 @@ export const DevicesTable = observer(() => {
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{rows(devices, vehicles).map((row) => (
|
{currentRows.map((row) => (
|
||||||
<TableRow
|
<TableRow
|
||||||
key={row?.uuid}
|
key={row.uuid} // Use row.uuid as key for consistent rendering
|
||||||
sx={{ "&:last-child td, &:last-child th": { border: 0 } }}
|
sx={{ "&:last-child td, &:last-child th": { border: 0 } }}
|
||||||
className="flex items-center"
|
|
||||||
>
|
>
|
||||||
<TableCell align="center">
|
<TableCell align="center" padding="checkbox">
|
||||||
|
{" "}
|
||||||
|
{/* Added padding="checkbox" */}
|
||||||
<Checkbox
|
<Checkbox
|
||||||
className="h-full"
|
className="h-full"
|
||||||
onChange={handleSelectDevice}
|
onChange={handleSelectDevice}
|
||||||
value={row?.uuid}
|
value={row.uuid}
|
||||||
|
checked={selectedDevices.includes(row.uuid)} // THIS IS THE KEY CHANGE
|
||||||
/>
|
/>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|
||||||
<TableCell align="center" component="th" scope="row">
|
<TableCell align="center" component="th" scope="row">
|
||||||
{row?.uuid}
|
{row.uuid}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell align="center">
|
<TableCell align="center">
|
||||||
{row?.online ? (
|
{row.online ? (
|
||||||
<Check className="m-auto text-green-500" />
|
<Check className="m-auto text-green-500" />
|
||||||
) : (
|
) : (
|
||||||
<X className="m-auto text-red-500" />
|
<X className="m-auto text-red-500" />
|
||||||
)}
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell align="center">
|
<TableCell align="center">
|
||||||
{formatDate(row?.lastUpdate)}
|
{formatDate(row.lastUpdate)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell align="center">
|
<TableCell align="center">
|
||||||
{row?.gps ? (
|
{row.gps ? (
|
||||||
<Check className="m-auto text-green-500" />
|
<Check className="m-auto text-green-500" />
|
||||||
) : (
|
) : (
|
||||||
<X className="m-auto text-red-500" />
|
<X className="m-auto text-red-500" />
|
||||||
)}
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell align="center">
|
<TableCell align="center">
|
||||||
{row?.media ? (
|
{row.media ? (
|
||||||
<Check className="m-auto text-green-500" />
|
<Check className="m-auto text-green-500" />
|
||||||
) : (
|
) : (
|
||||||
<X className="m-auto text-red-500" />
|
<X className="m-auto text-red-500" />
|
||||||
)}
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell align="center">
|
<TableCell align="center">
|
||||||
{row?.connection ? (
|
{row.connection ? (
|
||||||
<Check className="m-auto text-green-500" />
|
<Check className="m-auto text-green-500" />
|
||||||
) : (
|
) : (
|
||||||
<X className="m-auto text-red-500" />
|
<X className="m-auto text-red-500" />
|
||||||
)}
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell align="center" className="flex justify-center">
|
<TableCell align="center">
|
||||||
<button onClick={() => handleReloadStatus(row?.uuid ?? "")}>
|
<button onClick={() => handleReloadStatus(row.uuid)}>
|
||||||
<RotateCcw className="m-auto" />
|
<RotateCcw className="m-auto" />
|
||||||
</button>
|
</button>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
@ -206,18 +250,35 @@ export const DevicesTable = observer(() => {
|
|||||||
</Table>
|
</Table>
|
||||||
</TableContainer>
|
</TableContainer>
|
||||||
<Modal open={sendSnapshotModalOpen} onClose={toggleSendSnapshotModal}>
|
<Modal open={sendSnapshotModalOpen} onClose={toggleSendSnapshotModal}>
|
||||||
<p>Выбрать снапшот</p>
|
<Typography variant="h6" component="p" sx={{ mb: 2 }}>
|
||||||
|
Выбрать снапшот для{" "}
|
||||||
|
<strong className="text-blue-600">{selectedDevices.length}</strong>{" "}
|
||||||
|
устройств
|
||||||
|
</Typography>
|
||||||
<div className="mt-5 flex flex-col gap-2 max-h-[300px] overflow-y-auto">
|
<div className="mt-5 flex flex-col gap-2 max-h-[300px] overflow-y-auto">
|
||||||
{snapshots &&
|
{snapshots && snapshots.length > 0 ? (
|
||||||
snapshots.map((snapshot) => (
|
snapshots.map((snapshot) => (
|
||||||
<button
|
<Button
|
||||||
onClick={() => handleSendSnapshotAction(uuid!, snapshot.ID)}
|
variant="outlined"
|
||||||
className="p-2 rounded-xl bg-slate-100"
|
onClick={() => handleSendSnapshotAction(snapshot.ID)}
|
||||||
|
sx={{
|
||||||
|
p: 1.5, // Adjust padding
|
||||||
|
borderRadius: 2, // Adjust border radius
|
||||||
|
backgroundColor: "white", // Ensure background is white
|
||||||
|
"&:hover": {
|
||||||
|
backgroundColor: "grey.100", // Light hover effect
|
||||||
|
},
|
||||||
|
}}
|
||||||
key={snapshot.ID}
|
key={snapshot.ID}
|
||||||
>
|
>
|
||||||
{snapshot.Name}
|
{snapshot.Name}
|
||||||
</button>
|
</Button>
|
||||||
))}
|
))
|
||||||
|
) : (
|
||||||
|
<Typography variant="body2" color="textSecondary">
|
||||||
|
Нет доступных снапшотов.
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
</>
|
</>
|
||||||
|
Loading…
Reference in New Issue
Block a user