Connected frontend new contact, new address and shipments to backend
This commit is contained in:
330
frontend/src/components/ShipmentDetails.tsx
Normal file
330
frontend/src/components/ShipmentDetails.tsx
Normal file
@ -0,0 +1,330 @@
|
||||
import React from 'react';
|
||||
import {Box, Typography, Button, Stack, TextField, Stepper, Step, StepLabel} from '@mui/material';
|
||||
import DewarDetails from '../components/DewarDetails.tsx';
|
||||
import { SxProps } from '@mui/system';
|
||||
import QRCode from 'react-qr-code';
|
||||
import bottleIcon from '../assets/icons/bottle-svgrepo-com-grey.svg';
|
||||
import AirplanemodeActiveIcon from "@mui/icons-material/AirplanemodeActive";
|
||||
import StoreIcon from "@mui/icons-material/Store";
|
||||
import DeleteIcon from "@mui/icons-material/Delete";
|
||||
import {ContactPerson, Dewar, Proposal, Address, Shipment_Input, DefaultService} from "../../openapi"; // Import delete icon
|
||||
|
||||
interface ShipmentDetailsProps {
|
||||
selectedShipment: Shipment_Input | null;
|
||||
setSelectedDewar: React.Dispatch<React.SetStateAction<Dewar | null>>;
|
||||
isCreatingShipment: boolean;
|
||||
newShipment: Shipment_Input;
|
||||
setNewShipment: React.Dispatch<React.SetStateAction<Shipment_Input>>;
|
||||
handleSaveShipment: () => void;
|
||||
contactPersons: ContactPerson[];
|
||||
proposals: Proposal[];
|
||||
returnAddresses: Address[];
|
||||
sx?: SxProps;
|
||||
}
|
||||
|
||||
const ShipmentDetails: React.FC<ShipmentDetailsProps> = ({
|
||||
selectedShipment,
|
||||
setSelectedDewar,
|
||||
setNewShipment,
|
||||
contactPersons,
|
||||
returnAddresses,
|
||||
sx = {},
|
||||
}) => {
|
||||
const [localSelectedDewar, setLocalSelectedDewar] = React.useState<Dewar | null>(null);
|
||||
const [trackingNumber, setTrackingNumber] = React.useState<string>('');
|
||||
const [isAddingDewar, setIsAddingDewar] = React.useState<boolean>(false);
|
||||
const [newDewar, setNewDewar] = React.useState<Partial<Dewar>>({
|
||||
dewar_name: '',
|
||||
tracking_number: '',
|
||||
});
|
||||
|
||||
// Step titles based on your status
|
||||
const steps = ['Ready for Shipping', 'Shipped', 'Arrived'];
|
||||
const totalPucks = selectedShipment.dewars.reduce((acc, dewar) => acc + (dewar.number_of_pucks || 0), 0);
|
||||
const totalSamples = selectedShipment.dewars.reduce((acc, dewar) => acc + (dewar.number_of_samples || 0), 0);
|
||||
|
||||
// Handle dewar selection
|
||||
const handleDewarSelection = (dewar: Dewar) => {
|
||||
setLocalSelectedDewar(prevDewar => (prevDewar?.tracking_number === dewar.tracking_number ? null : dewar));
|
||||
setSelectedDewar(prevDewar => (prevDewar?.tracking_number === dewar.tracking_number ? null : dewar));
|
||||
};
|
||||
|
||||
// Handle dewar deletion
|
||||
const handleDeleteDewar = () => {
|
||||
if (localSelectedDewar) {
|
||||
const confirmed = window.confirm('Are you sure you want to delete this dewar?');
|
||||
if (confirmed) {
|
||||
const updatedDewars = selectedShipment.dewars.filter(dewar => dewar.tracking_number !== localSelectedDewar.tracking_number);
|
||||
console.log('Updated Dewars:', updatedDewars); // Log or update state as needed
|
||||
setLocalSelectedDewar(null); // Reset selection after deletion
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Handle form input changes for the new dewar
|
||||
const handleNewDewarChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const { name, value } = e.target;
|
||||
setNewDewar((prev) => ({
|
||||
...prev,
|
||||
[name]: value,
|
||||
}));
|
||||
};
|
||||
|
||||
const createDewar = async (newDewar: Partial<Dewar>, shipmentId: string) => {
|
||||
console.log("Payload being sent to the API:", newDewar);
|
||||
try {
|
||||
const response = await DefaultService.createDewarDewarsPost(shipmentId, newDewar);
|
||||
console.log("Response from API:", response);
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.error("Error creating dewar:", error);
|
||||
if (error.response) {
|
||||
console.error("Validation error details:", error.response.data);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// Handle adding a new dewar
|
||||
const handleAddDewar = async () => {
|
||||
if (selectedShipment && newDewar.dewar_name) {
|
||||
try {
|
||||
const newDewarToPost: Dewar = {
|
||||
//id: `DEWAR${Date.now()}`,
|
||||
dewar_name: newDewar.dewar_name.trim() || 'Unnamed Dewar',
|
||||
number_of_pucks: newDewar.number_of_pucks ?? 0,
|
||||
number_of_samples: newDewar.number_of_samples ?? 0,
|
||||
return_address: selectedShipment.return_address,
|
||||
contact_person: selectedShipment.contact_person,
|
||||
status: 'In preparation',
|
||||
shippingStatus: 'not shipped',
|
||||
arrivalStatus: 'not arrived',
|
||||
qrcode: newDewar.qrcode || 'N/A',
|
||||
//tracking_number: newDewar.tracking_number?.trim() || `TN-${Date.now()}`,
|
||||
//ready_date: newDewar.ready_date || 'N/A',
|
||||
//shipping_date: newDewar.shipping_date || 'N/A',
|
||||
//arrival_date: newDewar.arrival_date || 'N/A',
|
||||
};
|
||||
|
||||
|
||||
// Post to backend
|
||||
const createdDewar = await createDewar(newDewarToPost, selectedShipment.id);
|
||||
|
||||
// Update state with the response from backend
|
||||
setNewShipment(prev => ({
|
||||
...prev,
|
||||
dewars: [...prev.dewars, createdDewar],
|
||||
}));
|
||||
|
||||
// Reset form fields
|
||||
setIsAddingDewar(false);
|
||||
//setNewDewar({ dewar_name: '', number_of_pucks: 0, number_of_samples: 0, tracking_number: '' });
|
||||
} catch (error) {
|
||||
alert("Failed to add dewar. Please try again.");
|
||||
console.error("Error adding dewar:", error);
|
||||
}
|
||||
} else {
|
||||
alert('Please fill in the Dewar Name');
|
||||
}
|
||||
};
|
||||
|
||||
// Function to generate QR Code (Placeholder)
|
||||
const generateQRCode = () => {
|
||||
console.log('Generate QR Code');
|
||||
};
|
||||
|
||||
// Handle adding new contact person and return address
|
||||
const addNewContactPerson = (name: string) => {
|
||||
// Implementation to add a new contact person
|
||||
console.log('Add new contact person:', name);
|
||||
};
|
||||
|
||||
const addNewReturnAddress = (address: string) => {
|
||||
// Implementation to add a new return address
|
||||
console.log('Add new return address:', address);
|
||||
};
|
||||
|
||||
// Function to determine the color of the step icon
|
||||
const getStepIconColor = (dewar: Dewar) => {
|
||||
const { status, shippingStatus, arrivalStatus } = dewar;
|
||||
if (status === 'Ready for Shipping') return 'green'; // Bottle Icon
|
||||
if (shippingStatus === 'shipped') return 'green'; // Plane Icon
|
||||
if (shippingStatus === 'not shipped') return 'yellow'; // Plane Icon
|
||||
if (arrivalStatus === 'arrived') return 'green'; // Store Icon
|
||||
if (arrivalStatus === 'not arrived') return 'yellow'; // Store Icon
|
||||
return 'grey'; // Default color
|
||||
};
|
||||
|
||||
return (
|
||||
<Box sx={{ ...sx, padding: 2, textAlign: 'left' }}>
|
||||
{/* Add Dewar Button - only visible if no dewar is selected */}
|
||||
{!localSelectedDewar && !isAddingDewar && (
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={() => setIsAddingDewar(true)}
|
||||
sx={{ marginBottom: 2 }}
|
||||
>
|
||||
Add Dewar
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{/* Add Dewar Form */}
|
||||
{isAddingDewar && (
|
||||
<Box sx={{ marginBottom: 2, width: '20%' }}>
|
||||
<Typography variant="h6">Add New Dewar</Typography>
|
||||
<TextField
|
||||
label="Dewar Name"
|
||||
name="dewar_name"
|
||||
value={newDewar.dewar_name}
|
||||
onChange={handleNewDewarChange}
|
||||
fullWidth
|
||||
sx={{ marginBottom: 2 }}
|
||||
/>
|
||||
<Button variant="contained" color="primary" onClick={handleAddDewar} sx={{ marginRight: 2 }}>
|
||||
Save Dewar
|
||||
</Button>
|
||||
<Button variant="outlined" color="secondary" onClick={() => setIsAddingDewar(false)}>
|
||||
Cancel
|
||||
</Button>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
<Typography variant="h5">{selectedShipment.shipment_name}</Typography>
|
||||
|
||||
{/* Iterate over contact persons if it's an array */}
|
||||
{selectedShipment.contact_person && selectedShipment.contact_person.length > 0 ? (
|
||||
selectedShipment.contact_person.map((person, index) => (
|
||||
<Typography key={index} variant="body1">
|
||||
Contact Person: {person.firstname} {person.lastname}
|
||||
</Typography>
|
||||
))
|
||||
) : (
|
||||
<Typography variant="body1">No contact person assigned.</Typography>
|
||||
)}
|
||||
|
||||
<Typography variant="body1">Number of Pucks: {totalPucks}</Typography>
|
||||
<Typography variant="body1">Number of Samples: {totalSamples}</Typography>
|
||||
<Typography variant="body1">Shipment Date: {selectedShipment.shipment_date}</Typography>
|
||||
|
||||
<Stack spacing={1}>
|
||||
{/* Render the DewarDetails component only if a dewar is selected */}
|
||||
{localSelectedDewar && (
|
||||
<DewarDetails
|
||||
dewar={localSelectedDewar}
|
||||
trackingNumber={trackingNumber}
|
||||
setTrackingNumber={setTrackingNumber}
|
||||
onGenerateQRCode={generateQRCode}
|
||||
contactPersons={contactPersons} // Pass contact persons
|
||||
returnAddresses={returnAddresses} // Pass return addresses
|
||||
addNewContactPerson={addNewContactPerson} // Pass function to add a new contact person
|
||||
addNewReturnAddress={addNewReturnAddress} // Pass function to add a new return address
|
||||
/>
|
||||
)}
|
||||
|
||||
{selectedShipment.dewars.map((dewar) => (
|
||||
<Button
|
||||
key={dewar.tracking_number}
|
||||
onClick={() => handleDewarSelection(dewar)}
|
||||
variant="outlined"
|
||||
sx={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
padding: 1,
|
||||
border: '1px solid #ccc',
|
||||
borderRadius: 1,
|
||||
backgroundColor: localSelectedDewar?.tracking_number === dewar.tracking_number ? '#f0f0f0' : '#fff', // Color when selected
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginRight: 2,
|
||||
}}
|
||||
>
|
||||
{dewar.qrcode ? (
|
||||
<QRCode value={dewar.qrcode} size={70} />
|
||||
) : (
|
||||
<Box
|
||||
sx={{
|
||||
width: 70,
|
||||
height: 70,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
border: '1px dashed #ccc', // Dashed border for placeholder
|
||||
borderRadius: 1,
|
||||
color: 'text.secondary'
|
||||
}}
|
||||
>
|
||||
<Typography variant="body2">No QR Code</Typography>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
<Box sx={{ flexGrow: 1, marginRight: 0 }}>
|
||||
<Typography variant="body1">{dewar.dewar_name}</Typography>
|
||||
<Typography variant="body2">Number of Pucks: {dewar.number_of_pucks || 0}</Typography>
|
||||
<Typography variant="body2">Number of Samples: {dewar.number_of_samples || 0}</Typography>
|
||||
<Typography variant="body2">Tracking Number: {dewar.tracking_number}</Typography>
|
||||
</Box>
|
||||
|
||||
<Box sx={{ flexGrow: 1, display: 'flex', alignItems: 'center', flexDirection: 'row', justifyContent: 'space-between' }}>
|
||||
{/* Horizontal Stepper for status */}
|
||||
<Stepper alternativeLabel activeStep={steps.indexOf(dewar.status) !== -1 ? steps.indexOf(dewar.status) : 0}>
|
||||
{steps.map((label, index) => (
|
||||
<Step key={label}>
|
||||
<StepLabel StepIconComponent={({ active, completed }) => {
|
||||
const color = getStepIconColor(dewar); // Use status for color
|
||||
return (
|
||||
<span style={{ color }}>
|
||||
{index === 0 ? (
|
||||
<img src={bottleIcon} alt="Bottle Icon" style={{ width: 24, height: 24 }} />
|
||||
) : index === 1 ? (
|
||||
<AirplanemodeActiveIcon style={{ color }} />
|
||||
) : index === 2 ? (
|
||||
<StoreIcon style={{ color , width: 24, height: 24}} />
|
||||
) : (
|
||||
<StoreIcon style={{ color }} // Use store icon for arrival status
|
||||
/>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
}}>{label}</StepLabel>
|
||||
{/* Display associated date */}
|
||||
<Typography variant="body2">
|
||||
{index === 0 ? dewar.ready_date :
|
||||
index === 1 ? dewar.shipping_date :
|
||||
index === 2 ? dewar.arrival_date : ''}
|
||||
</Typography>
|
||||
</Step>
|
||||
))}
|
||||
</Stepper>
|
||||
|
||||
{/* Delete button if the dewar is selected */}
|
||||
{localSelectedDewar?.tracking_number === dewar.tracking_number && (
|
||||
<Button
|
||||
onClick={handleDeleteDewar}
|
||||
color="error"
|
||||
sx={{
|
||||
minWidth: '40px',
|
||||
height: '40px',
|
||||
marginLeft: 2,
|
||||
padding: 0,
|
||||
alignSelf: 'center',
|
||||
}}
|
||||
>
|
||||
<DeleteIcon />
|
||||
</Button>
|
||||
)}
|
||||
</Box>
|
||||
</Button>
|
||||
))}
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default ShipmentDetails;
|
Reference in New Issue
Block a user