fix: From device to vehicle table

This commit is contained in:
Илья Куприец 2025-05-29 16:43:25 +03:00
parent e2ca6b4132
commit 5ef61bcef4

View File

@ -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 = () => {
snapshot_id: snapshotId, if (selectedDevices.length > 0) {
}); toggleSendSnapshotModal();
await getDevices(); }
};
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,
});
}
// 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>
</> </>