Enhance Dewar handling and display in logistics system
Added new fields and enriched data representations in DewarStatusTab, backend schemas, and APIs to improve dewar tracking and management. Introduced new API endpoint `/dewar/table` for simplified data rendering. Applied logging and validations for missing relationships.
This commit is contained in:
@ -2,12 +2,18 @@ import React, { useEffect, useState } from "react";
|
||||
import DataGrid from "react-data-grid";
|
||||
import { Box, Typography, Snackbar, Alert, CircularProgress } from "@mui/material";
|
||||
import { LogisticsService } from "../../../frontend/openapi";
|
||||
import "react-data-grid/lib/styles.css";
|
||||
import dayjs from 'dayjs'; // Import dayjs library
|
||||
|
||||
|
||||
|
||||
interface Dewar {
|
||||
id: string;
|
||||
dewar_name: string;
|
||||
shipment_name: string; // Added new field
|
||||
slot_id: string; // Added new field
|
||||
status: string;
|
||||
location: string;
|
||||
beamline_location: string;
|
||||
timestamp: string; // You can change this type based on your API response
|
||||
}
|
||||
|
||||
@ -15,54 +21,149 @@ const DewarStatusTab: React.FC = () => {
|
||||
const [dewars, setDewars] = useState<Dewar[]>([]);
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const columns = [
|
||||
{ key: "dewar_name", name: "Dewar Name", resizable: true },
|
||||
{
|
||||
key: "status",
|
||||
name: "Status",
|
||||
editable: true,
|
||||
resizable: true,
|
||||
editor: (props: { row: any; column: any; onRowChange: any }) => {
|
||||
return (
|
||||
<input
|
||||
type="text"
|
||||
value={props.row[props.column.key]}
|
||||
onChange={(e) => props.onRowChange({ ...props.row, [props.column.key]: e.target.value })}
|
||||
style={{
|
||||
border: "none",
|
||||
outline: "none",
|
||||
padding: "4px",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{ key: "location", name: "Location", resizable: true },
|
||||
{ key: "timestamp", name: "Last Updated", resizable: true },
|
||||
const slotQRCodes = [
|
||||
"A1-X06SA",
|
||||
"A2-X06SA",
|
||||
"A3-X06SA",
|
||||
"A4-X06SA",
|
||||
"A5-X06SA",
|
||||
"B1-X06SA",
|
||||
"B2-X06SA",
|
||||
"B3-X06SA",
|
||||
"B4-X06SA",
|
||||
"B5-X06SA",
|
||||
"C1-X06SA",
|
||||
"C2-X06SA",
|
||||
"C3-X06SA",
|
||||
"C4-X06SA",
|
||||
"C5-X06SA",
|
||||
"D1-X06SA",
|
||||
"D2-X06SA",
|
||||
"D3-X06SA",
|
||||
"D4-X06SA",
|
||||
"D5-X06SA",
|
||||
"A1-X10SA",
|
||||
"A2-X10SA",
|
||||
"A3-X10SA",
|
||||
"A4-X10SA",
|
||||
"A5-X10SA",
|
||||
"B1-X10SA",
|
||||
"B2-X10SA",
|
||||
"B3-X10SA",
|
||||
"B4-X10SA",
|
||||
"B5-X10SA",
|
||||
"C1-X10SA",
|
||||
"C2-X10SA",
|
||||
"C3-X10SA",
|
||||
"C4-X10SA",
|
||||
"C5-X10SA",
|
||||
"D1-X10SA",
|
||||
"D2-X10SA",
|
||||
"D3-X10SA",
|
||||
"D4-X10SA",
|
||||
"D5-X10SA",
|
||||
"NB1",
|
||||
"NB2",
|
||||
"NB3",
|
||||
"NB4",
|
||||
"NB5",
|
||||
"NB6",
|
||||
"X10SA-Beamline",
|
||||
"X06SA-Beamline",
|
||||
"X06DA-Beamline",
|
||||
"Outgoing X10SA",
|
||||
"Outgoing X06SA",
|
||||
];
|
||||
|
||||
// Fetch dewars when component mounts
|
||||
useEffect(() => {
|
||||
fetchDewarData();
|
||||
}, []);
|
||||
// Updated columns array
|
||||
const columns = [
|
||||
{ key: "shipment_name", name: "Shipment Name", resizable: true },
|
||||
{ key: "dewar_name", name: "Dewar Name", resizable: true },
|
||||
{ key: "slot_id", name: "Storage", resizable: true },
|
||||
{ key: "status", name: "Status", editable: true, resizable: true },
|
||||
{ key: "beamline_location", name: "Location", resizable: true },
|
||||
{ key: "last_updated", name: "Last Updated", resizable: true },
|
||||
{ key: "local_contact", name: "Local Contact", resizable: true }, // Now a string
|
||||
{ key: "contact", name: "Contact", resizable: true }, // Now a string
|
||||
{ key: "address", name: "Return Address", resizable: true }, // Now a string
|
||||
];
|
||||
|
||||
const fetchDewarData = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const dewarData = await LogisticsService.getAllDewarsLogisticsDewarsGet(); // Use your real API call
|
||||
setDewars(dewarData);
|
||||
// Fetch data from API
|
||||
const dewarData = await LogisticsService.getAllDewarsTableLogisticsDewarTableGet();
|
||||
|
||||
// Log the raw data for debugging
|
||||
console.log("Fetched dewarData:", dewarData);
|
||||
|
||||
// Flatten and enrich data
|
||||
const enrichedData = dewarData.map((dewar: any) => {
|
||||
// Format address into a single string
|
||||
const returnAddress = dewar.address && dewar.address.length > 0
|
||||
? `${dewar.address[0].house_number || ""} ${dewar.address[0].street || ""}, ${dewar.address[0].city || ""}, ${dewar.address[0].state || ""}, ${dewar.address[0].zipcode || ""}, ${dewar.address[0].country || ""}`.trim()
|
||||
: "N/A";
|
||||
|
||||
// Format contact into a single string
|
||||
const contact = dewar.contact && dewar.contact.length > 0
|
||||
? `${dewar.contact[0].firstname || "N/A"} ${dewar.contact[0].lastname || "N/A"} (${dewar.contact[0].email || "N/A"})`
|
||||
: "N/A";
|
||||
|
||||
// Format local_contact into a single string
|
||||
const localContact = dewar.local_contact
|
||||
? `${dewar.local_contact.firstname || "N/A"} ${dewar.local_contact.lastname || "N/A"} (${dewar.local_contact.phone_number || "N/A"})`
|
||||
: "N/A";
|
||||
const beamline_location = dewar.events.slot_id || "N/A";
|
||||
console.log("Beamline location:", beamline_location);
|
||||
// Log any fields that are missing or appear incorrect
|
||||
if (!dewar.local_contact) console.warn("Missing local_contact for dewar:", dewar);
|
||||
if (!dewar.contact) console.warn("Missing contact for dewar:", dewar);
|
||||
if (!dewar.address) console.warn("Missing address for dewar:", dewar);
|
||||
|
||||
return {
|
||||
...dewar,
|
||||
local_contact: localContact,
|
||||
contact: contact,
|
||||
address: returnAddress, // Replace `address` object with single formatted string
|
||||
beamline_location: dewar.events !== undefined && slotQRCodes[dewar.events]
|
||||
? slotQRCodes[dewar.events -1]
|
||||
: "",
|
||||
slot_id: dewar.slot_id !== undefined && slotQRCodes[dewar.slot_id]
|
||||
? slotQRCodes[dewar.slot_id -1]
|
||||
: "", // Convert slot_id to descriptive label
|
||||
last_updated: dewar.last_updated
|
||||
? new Date(dewar.last_updated).toLocaleString('en-US', {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
hour12: true,
|
||||
})
|
||||
: ""
|
||||
|
||||
};
|
||||
});
|
||||
|
||||
setDewars(enrichedData);
|
||||
console.log("Final enrichedData:", enrichedData);
|
||||
} catch (e) {
|
||||
console.error("Failed to fetch or process dewar data:", e);
|
||||
setError("Failed to fetch dewar data");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const onRowsChange = async (updatedRow: Dewar[]) => {
|
||||
setDewars(updatedRow);
|
||||
|
||||
useEffect(() => {
|
||||
fetchDewarData();
|
||||
}, []);
|
||||
|
||||
const onRowsChange = async (updatedRows: Dewar[]) => {
|
||||
setDewars(updatedRows);
|
||||
try {
|
||||
const updatedDewar = updatedRow[updatedRow.length - 1]; // Get the last edited row
|
||||
const updatedDewar = updatedRows[updatedRows.length - 1]; // Get the last edited row
|
||||
await LogisticsService.updateDewarStatus({ ...updatedDewar }); // Mock API update
|
||||
} catch (err) {
|
||||
setError("Error updating dewar");
|
||||
@ -87,7 +188,7 @@ const DewarStatusTab: React.FC = () => {
|
||||
columns={columns}
|
||||
rows={dewars}
|
||||
onRowsChange={onRowsChange}
|
||||
style={{ height: 600, width: "100%" }}
|
||||
style={{ height: 600, width: "100%" }} // Make sure height and width are set
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
|
Reference in New Issue
Block a user