Connected frontend new contact and new address to backend
This commit is contained in:
296
frontend/src/components/ShipmentForm.tsx
Normal file
296
frontend/src/components/ShipmentForm.tsx
Normal file
@ -0,0 +1,296 @@
|
||||
import * as React from 'react';
|
||||
import { Box, Button, TextField, Typography, Select, MenuItem, Stack, FormControl, InputLabel } from '@mui/material';
|
||||
import { SelectChangeEvent } from '@mui/material';
|
||||
import { SxProps } from '@mui/material';
|
||||
import { useEffect } from "react";
|
||||
import { ContactPerson, Address, Proposal, DefaultService, OpenAPI } from "../../openapi";
|
||||
|
||||
// Define the Shipment interface (example; adjust according to your types)
|
||||
interface Shipment {
|
||||
shipment_name: string;
|
||||
contact_person: ContactPerson[];
|
||||
proposal_number: string;
|
||||
return_address: Address[];
|
||||
comments: string;
|
||||
}
|
||||
|
||||
// Define the ShipmentFormProps interface
|
||||
interface ShipmentFormProps {
|
||||
newShipment: Shipment;
|
||||
setNewShipment: React.Dispatch<React.SetStateAction<Shipment>>;
|
||||
handleSaveShipment: () => void;
|
||||
proposals: Proposal[]; // Define proposals type
|
||||
returnAddresses: Address[];
|
||||
sx?: SxProps;
|
||||
}
|
||||
|
||||
const ShipmentForm: React.FC<ShipmentFormProps> = ({
|
||||
newShipment,
|
||||
setNewShipment,
|
||||
handleSaveShipment,
|
||||
sx = {},
|
||||
}) => {
|
||||
const [contactPersons, setContactPersons] = React.useState<ContactPerson[]>([]); // State to hold contact persons
|
||||
const [returnAddresses, setReturnAddresses] = React.useState<Address[]>([]); // Renamed for consistency
|
||||
const [proposals, setProposals] = React.useState<Proposal[]>([]);
|
||||
const [isCreatingContactPerson, setIsCreatingContactPerson] = React.useState(false);
|
||||
const [isCreatingReturnAddress, setIsCreatingReturnAddress] = React.useState(false);
|
||||
const [newContactPerson, setNewContactPerson] = React.useState({
|
||||
firstName: '',
|
||||
lastName: '',
|
||||
phone: '',
|
||||
email: '',
|
||||
});
|
||||
const [newReturnAddress, setNewReturnAddress] = React.useState<Address>({
|
||||
street: '',
|
||||
city: '',
|
||||
zipcode: '',
|
||||
country: '',
|
||||
});
|
||||
const [errorMessage, setErrorMessage] = React.useState<string | null>(null); // For error handling
|
||||
|
||||
useEffect(() => {
|
||||
OpenAPI.BASE = 'http://127.0.0.1:8000'; // Set the base URL for OpenAPI
|
||||
|
||||
const getContacts = async () => {
|
||||
console.log('Trying to fetch some contacts');
|
||||
try {
|
||||
const c: ContactPerson[] = await DefaultService.getContactsContactsGet(); // Fetch contacts
|
||||
setContactPersons(c);
|
||||
} catch (err) {
|
||||
console.error('Failed to fetch contact persons:', err);
|
||||
setErrorMessage('Failed to load contact persons. Please try again later.');
|
||||
}
|
||||
};
|
||||
|
||||
const getAddresses = async () => {
|
||||
console.log('Trying to fetch some return addresses');
|
||||
try {
|
||||
const a: Address[] = await DefaultService.getReturnAddressesReturnAddressesGet(); // Fetch addresses
|
||||
setReturnAddresses(a);
|
||||
} catch (err) {
|
||||
console.error('Failed to fetch return addresses:', err);
|
||||
setErrorMessage('Failed to load return addresses. Please try again later.');
|
||||
}
|
||||
};
|
||||
|
||||
const getProposals = async () => {
|
||||
try {
|
||||
const p: Proposal[] = await DefaultService.getProposalsProposalsGet();
|
||||
console.log('Fetched Proposals:', p); // Debug log to check if proposals are being fetched
|
||||
setProposals(p);
|
||||
} catch (err) {
|
||||
console.error('Error fetching proposals:', err); // Log the error
|
||||
setErrorMessage('Failed to load proposals. Please try again later.');
|
||||
}
|
||||
};
|
||||
|
||||
getContacts();
|
||||
getAddresses();
|
||||
getProposals();
|
||||
}, []);
|
||||
|
||||
const handleContactPersonChange = (event: SelectChangeEvent) => {
|
||||
const value = event.target.value;
|
||||
if (value === 'new') {
|
||||
setIsCreatingContactPerson(true);
|
||||
setNewShipment({ ...newShipment, contact_person: [] }); // Reset for new person
|
||||
} else {
|
||||
setIsCreatingContactPerson(false);
|
||||
const selectedPerson = contactPersons.find((person) => person.lastname === value) || null;
|
||||
if (selectedPerson) {
|
||||
setNewShipment({ ...newShipment, contact_person: [selectedPerson] }); // Set selected person
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleReturnAddressChange = (event: SelectChangeEvent) => {
|
||||
const value = event.target.value;
|
||||
if (value === 'new') {
|
||||
setIsCreatingReturnAddress(true);
|
||||
setNewShipment({ ...newShipment, return_address: [] }); // Reset for new address
|
||||
} else {
|
||||
setIsCreatingReturnAddress(false);
|
||||
const selectedAddress = returnAddresses.find((address) => address.city === value); // Match by a unique ID
|
||||
if (selectedAddress) {
|
||||
setNewShipment({ ...newShipment, return_address: [selectedAddress] }); // Set selected address
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleProposalChange = (event: SelectChangeEvent) => {
|
||||
const selectedProposal = event.target.value;
|
||||
console.log('Selected Proposal:', selectedProposal); // Corrected log statement
|
||||
setNewShipment({ ...newShipment, proposal_number: selectedProposal });
|
||||
};
|
||||
|
||||
const handleNewReturnAddressChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const { name, value } = e.target;
|
||||
setNewReturnAddress((prev) => ({
|
||||
...prev,
|
||||
[name]: value,
|
||||
}));
|
||||
};
|
||||
|
||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const { name, value } = e.target;
|
||||
setNewShipment((prev) => ({ ...prev, [name]: value }));
|
||||
};
|
||||
|
||||
const handleSaveNewReturnAddress = async () => {
|
||||
OpenAPI.BASE = 'http://127.0.0.1:8000';
|
||||
|
||||
if (!newReturnAddress.street || !newReturnAddress.city || !newReturnAddress.zipcode || !newReturnAddress.country) {
|
||||
setErrorMessage('All fields are required.');
|
||||
return;
|
||||
}
|
||||
|
||||
const payload = {
|
||||
street: newReturnAddress.street.trim(),
|
||||
city: newReturnAddress.city.trim(),
|
||||
zipcode: newReturnAddress.zipcode.trim(),
|
||||
country: newReturnAddress.country.trim(),
|
||||
};
|
||||
|
||||
try {
|
||||
const a: Address = await DefaultService.createReturnAddressReturnAddressesPost(payload);
|
||||
setReturnAddresses([...returnAddresses, a]);
|
||||
setErrorMessage(null);
|
||||
} catch (err) {
|
||||
console.error('Failed to create a new return address:', err);
|
||||
setErrorMessage('Failed to create a new return address. Please try again later.');
|
||||
}
|
||||
|
||||
setNewReturnAddress({ street: '', city: '', zipcode: '', country: '' });
|
||||
setIsCreatingReturnAddress(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
padding: 4,
|
||||
border: '1px solid #ccc',
|
||||
borderRadius: '4px',
|
||||
marginBottom: 2,
|
||||
maxWidth: '600px',
|
||||
...sx,
|
||||
}}
|
||||
>
|
||||
<Typography variant="h6" sx={{ marginBottom: 2 }}>
|
||||
Create Shipment
|
||||
</Typography>
|
||||
{errorMessage && <Typography color="error">{errorMessage}</Typography>}
|
||||
<Stack spacing={2}>
|
||||
<TextField
|
||||
label="Shipment Name"
|
||||
name="shipment_name"
|
||||
value={newShipment.shipment_name || ''}
|
||||
onChange={handleChange}
|
||||
fullWidth
|
||||
/>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel>Contact Person</InputLabel>
|
||||
<Select
|
||||
value={newShipment.contact_person?.[0]?.lastname || ''}
|
||||
onChange={handleContactPersonChange}
|
||||
displayEmpty
|
||||
>
|
||||
{contactPersons.map((person) => (
|
||||
<MenuItem key={person.lastname + person.firstname} value={person.lastname}>
|
||||
{`${person.lastname}, ${person.firstname}`}
|
||||
</MenuItem>
|
||||
))}
|
||||
<MenuItem value="new">
|
||||
<em>Create New Contact Person</em>
|
||||
</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel>Proposal Number</InputLabel>
|
||||
<Select
|
||||
value={newShipment.proposal_number || ''}
|
||||
onChange={handleProposalChange}
|
||||
displayEmpty
|
||||
>
|
||||
{proposals.map((proposal) => (
|
||||
<MenuItem key={proposal.id} value={proposal.number}>
|
||||
{proposal.number}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel>Return Address</InputLabel>
|
||||
<Select
|
||||
value={newShipment.return_address?.[0]?.city || ''}
|
||||
onChange={handleReturnAddressChange}
|
||||
displayEmpty
|
||||
>
|
||||
{returnAddresses.map((address) => (
|
||||
<MenuItem key={address.city} value={address.city}>
|
||||
{`${address.street}, ${address.city}, ${address.zipcode}, ${address.country}`}
|
||||
</MenuItem>
|
||||
))}
|
||||
<MenuItem value="new">
|
||||
<em>Create New Return Address</em>
|
||||
</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
{isCreatingReturnAddress && (
|
||||
<>
|
||||
<TextField
|
||||
label="Street"
|
||||
name="street"
|
||||
value={newReturnAddress.street}
|
||||
onChange={handleNewReturnAddressChange}
|
||||
fullWidth
|
||||
/>
|
||||
<TextField
|
||||
label="City"
|
||||
name="city"
|
||||
value={newReturnAddress.city}
|
||||
onChange={handleNewReturnAddressChange}
|
||||
fullWidth
|
||||
/>
|
||||
<TextField
|
||||
label="Zip Code"
|
||||
name="zipcode"
|
||||
value={newReturnAddress.zipcode}
|
||||
onChange={handleNewReturnAddressChange}
|
||||
fullWidth
|
||||
/>
|
||||
<TextField
|
||||
label="Country"
|
||||
name="country"
|
||||
value={newReturnAddress.country}
|
||||
onChange={handleNewReturnAddressChange}
|
||||
fullWidth
|
||||
/>
|
||||
<Button variant="contained" color="primary" onClick={handleSaveNewReturnAddress}>
|
||||
Save New Return Address
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
<TextField
|
||||
label="Comments"
|
||||
name="comments"
|
||||
fullWidth
|
||||
multiline
|
||||
rows={4}
|
||||
value={newShipment.comments || ''}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={handleSaveShipment}
|
||||
sx={{ alignSelf: 'flex-end' }}
|
||||
>
|
||||
Save Shipment
|
||||
</Button>
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default ShipmentForm;
|
@ -5,7 +5,7 @@ import AddIcon from '@mui/icons-material/Add';
|
||||
import DeleteIcon from '@mui/icons-material/Delete'; // Import delete icon
|
||||
import UploadFileIcon from '@mui/icons-material/UploadFile'; // Import the upload icon
|
||||
import UploadDialog from './UploadDialog.tsx'; // Import the UploadDialog component
|
||||
import {Shipment} from '../types.ts'; // Ensure Shipment type is correctly imported
|
||||
//import {Shipment} from '../types.ts'; // Ensure Shipment type is correctly imported
|
||||
import { SxProps } from '@mui/material';
|
||||
import bottleGrey from '../assets/icons/bottle-svgrepo-com-grey.svg';
|
||||
import bottleYellow from '../assets/icons/bottle-svgrepo-com-yellow.svg';
|
||||
@ -13,17 +13,17 @@ import bottleGreen from '../assets/icons/bottle-svgrepo-com-green.svg';
|
||||
import bottleRed from '../assets/icons/bottle-svgrepo-com-red.svg';
|
||||
import {Shipment_Input, DefaultService, OpenAPI} from "../../openapi";
|
||||
|
||||
interface ShipmentPanelProps {
|
||||
selectedPage: string;
|
||||
setIsCreatingShipment: Dispatch<SetStateAction<boolean>>;
|
||||
newShipment: Shipment; // Ensure this aligns with the Shipment type
|
||||
setNewShipment: Dispatch<SetStateAction<Shipment>>;
|
||||
selectShipment: (shipment: Shipment | null) => void; // Allow null for deselection
|
||||
sx?: SxProps; // Optional sx prop for styling
|
||||
}
|
||||
//interface ShipmentPanelProps {
|
||||
// selectedPage: string;
|
||||
// setIsCreatingShipment: Dispatch<SetStateAction<boolean>>;
|
||||
// newShipment: Shipment; // Ensure this aligns with the Shipment type
|
||||
// setNewShipment: Dispatch<SetStateAction<Shipment>>;
|
||||
// selectShipment: (shipment: Shipment | null) => void; // Allow null for deselection
|
||||
// sx?: SxProps; // Optional sx prop for styling
|
||||
//}
|
||||
|
||||
const ShipmentPanel: React.FC<ShipmentPanelProps> = ({
|
||||
//setIsCreatingShipment,
|
||||
setIsCreatingShipment,
|
||||
//newShipment,
|
||||
//setNewShipment,
|
||||
//selectedPage,
|
||||
@ -53,18 +53,16 @@ const ShipmentPanel: React.FC<ShipmentPanelProps> = ({
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
OpenAPI.BASE='http://127.0.0.1:8000'
|
||||
OpenAPI.BASE = 'http://127.0.0.1:8000';
|
||||
const fetchShipments = async () => {
|
||||
console.log('trying to fetch some shipments');
|
||||
try {
|
||||
DefaultService.getShipmentsShipmentsGet().then((s : Shipment_Input[]) => {
|
||||
setShipments(s);
|
||||
});
|
||||
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
|
||||
|
||||
const data = await response.json();
|
||||
setShipments(data.shipments);
|
||||
// Await the response from the service call
|
||||
const s: Shipment_Input[] = await DefaultService.getShipmentsShipmentsGet();
|
||||
// Set the shipments state with the fetched data
|
||||
setShipments(s);
|
||||
} catch (error) {
|
||||
// If an error occurs, set the error message
|
||||
console.error('Failed to fetch shipments:', error);
|
||||
setError("Failed to fetch shipments. Please try again later.");
|
||||
}
|
||||
@ -100,7 +98,7 @@ const ShipmentPanel: React.FC<ShipmentPanelProps> = ({
|
||||
variant="contained"
|
||||
color="primary"
|
||||
startIcon={<AddIcon />}
|
||||
//onClick={() => {
|
||||
onClick={() => {
|
||||
// setNewShipment({
|
||||
// shipment_id: '', // Ensure this matches the Shipment type
|
||||
// shipment_name: '',
|
||||
@ -113,8 +111,8 @@ const ShipmentPanel: React.FC<ShipmentPanelProps> = ({
|
||||
// proposal_number: undefined, // Optional property
|
||||
// comments: '', // Optional property
|
||||
// });
|
||||
// setIsCreatingShipment(true);
|
||||
//}}
|
||||
setIsCreatingShipment(true);
|
||||
}}
|
||||
sx={{ marginBottom: 2, padding: '10px 16px' }}
|
||||
>
|
||||
Create Shipment
|
||||
|
Reference in New Issue
Block a user