Connected frontend new contact and new address to backend

This commit is contained in:
GotthardG
2024-10-27 18:14:50 +01:00
parent 2a4f2d1d85
commit e5073eacb8
4 changed files with 286 additions and 130 deletions

View 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;

View File

@ -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