Connected frontend new contact and new address to backend
This commit is contained in:
@ -3,6 +3,9 @@ from fastapi.middleware.cors import CORSMiddleware
|
|||||||
from fastapi import HTTPException, status
|
from fastapi import HTTPException, status
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
||||||
app = FastAPI()
|
app = FastAPI()
|
||||||
|
|
||||||
@ -28,6 +31,9 @@ class Address(BaseModel):
|
|||||||
zipcode: str
|
zipcode: str
|
||||||
country: str
|
country: str
|
||||||
|
|
||||||
|
class Proposal(BaseModel):
|
||||||
|
id: int
|
||||||
|
number: str
|
||||||
|
|
||||||
class Dewar(BaseModel):
|
class Dewar(BaseModel):
|
||||||
id: str
|
id: str
|
||||||
@ -52,7 +58,7 @@ class Shipment(BaseModel):
|
|||||||
shipment_date: str
|
shipment_date: str
|
||||||
shipment_status: str
|
shipment_status: str
|
||||||
contact_person: List[ContactPerson]
|
contact_person: List[ContactPerson]
|
||||||
proposal_number: Optional[str] = None
|
proposal_number: List[Proposal]
|
||||||
return_address: List[Address]
|
return_address: List[Address]
|
||||||
comments: Optional[str] = None
|
comments: Optional[str] = None
|
||||||
dewars: List[Dewar]
|
dewars: List[Dewar]
|
||||||
@ -60,9 +66,15 @@ class Shipment(BaseModel):
|
|||||||
def get_number_of_dewars(self) -> int:
|
def get_number_of_dewars(self) -> int:
|
||||||
return len(self.dewars)
|
return len(self.dewars)
|
||||||
|
|
||||||
def get_shipment_contact_persons(self) -> str:
|
def get_shipment_contact_persons(self) -> List[ContactPerson]:
|
||||||
return self.contact_person
|
return self.contact_person
|
||||||
|
|
||||||
|
def get_shipment_return_addresses(self) -> List[Address]:
|
||||||
|
return self.return_address
|
||||||
|
|
||||||
|
def get_proposals(self) -> List[Proposal]:
|
||||||
|
return self.proposal_number
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
orm_mode = True
|
orm_mode = True
|
||||||
|
|
||||||
@ -143,33 +155,62 @@ dewars = [
|
|||||||
qrcode='QR123DEWAR003'
|
qrcode='QR123DEWAR003'
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
# Example: Attach a specific Dewar by its id to a shipment
|
|
||||||
specific_dewar_id = 'DEWAR003' # The ID of the Dewar you want to attach
|
|
||||||
|
|
||||||
# Find the Dewar with the matching id
|
# Proposal data inspired by the Lord of the Rings
|
||||||
specific_dewar = next((dewar for dewar in dewars if dewar.id == specific_dewar_id), None)
|
proposals = [
|
||||||
|
Proposal(id=1, number="PROPOSAL-FRODO-001"), # "The Quest for the Ring"
|
||||||
|
Proposal(id=2, number="PROPOSAL-GANDALF-002"), # "The Fellowship's Journey"
|
||||||
|
Proposal(id=3, number="PROPOSAL-ARAGORN-003"), # "Return of the King"
|
||||||
|
Proposal(id=4, number="PROPOSAL-SAURON-004"), # "The Dark Lord's Plot"
|
||||||
|
Proposal(id=5, number="PROPOSAL-MORDOR-005"), # "The Road to Mount Doom"
|
||||||
|
]
|
||||||
|
|
||||||
# Since shipments need dewars, define them afterward
|
# Example: Attach specific Dewars by their ids to shipments
|
||||||
|
specific_dewar_ids1 = ['DEWAR003'] # The IDs of the Dewars you want to attach to the first shipment
|
||||||
|
specific_dewar_ids2 = ['DEWAR001', 'DEWAR002'] # The IDs of the Dewars you want to attach to the second shipment
|
||||||
|
|
||||||
|
# Find the Dewars with the matching ids
|
||||||
|
specific_dewars1 = [dewar for dewar in dewars if dewar.id in specific_dewar_ids1]
|
||||||
|
specific_dewars2 = [dewar for dewar in dewars if dewar.id in specific_dewar_ids2]
|
||||||
|
|
||||||
|
# Define shipments with the selected Dewars
|
||||||
shipments = [
|
shipments = [
|
||||||
Shipment(
|
Shipment(
|
||||||
shipment_id='SHIPMORDOR',
|
shipment_id='SHIPMORDOR',
|
||||||
shipment_date='2024-10-10',
|
shipment_date='2024-10-10',
|
||||||
shipment_name='Shipment example test',
|
shipment_name='Shipment from Mordor',
|
||||||
shipment_status='Delivered',
|
shipment_status='Delivered',
|
||||||
contact_person=[contacts[1]],
|
contact_person=[contacts[1]],
|
||||||
proposal_number='PROJ001',
|
proposal_number=[proposals[1]],
|
||||||
return_address=[return_addresses[0]],
|
return_address=[return_addresses[0]],
|
||||||
comments='Handle with care',
|
comments='Handle with care',
|
||||||
dewars=[specific_dewar] # Taking all dewars as an example
|
dewars=specific_dewars1 # Attach specific Dewars for this shipment
|
||||||
|
),
|
||||||
|
Shipment(
|
||||||
|
shipment_id='SHIPMORDOR2',
|
||||||
|
shipment_date='2024-10-24',
|
||||||
|
shipment_name='Shipment from Mordor',
|
||||||
|
shipment_status='In Transit',
|
||||||
|
contact_person=[contacts[3]],
|
||||||
|
proposal_number=[proposals[2]],
|
||||||
|
return_address=[return_addresses[1]], # Changed index to a valid one
|
||||||
|
comments='Contains the one ring',
|
||||||
|
dewars=specific_dewars2 # Attach specific Dewars for this shipment
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@app.get("/contacts", response_model=List[ContactPerson])
|
@app.get("/contacts", response_model=List[ContactPerson])
|
||||||
async def get_contacts():
|
async def get_contacts():
|
||||||
return contacts
|
return contacts
|
||||||
|
|
||||||
|
@app.get("/return_addresses", response_model=List[Address])
|
||||||
|
async def get_return_addresses():
|
||||||
|
return return_addresses
|
||||||
|
|
||||||
|
@app.get("/proposals", response_model=List[Proposal])
|
||||||
|
async def get_proposals():
|
||||||
|
return proposals
|
||||||
|
|
||||||
|
|
||||||
@app.get("/shipments", response_model=List[Shipment])
|
@app.get("/shipments", response_model=List[Shipment])
|
||||||
async def get_shipments():
|
async def get_shipments():
|
||||||
@ -204,3 +245,31 @@ async def create_shipment(shipment: Shipment):
|
|||||||
|
|
||||||
shipments.append(shipment)
|
shipments.append(shipment)
|
||||||
return shipment
|
return shipment
|
||||||
|
|
||||||
|
# Creation of a new contact
|
||||||
|
@app.post("/contacts", response_model=ContactPerson, status_code=status.HTTP_201_CREATED)
|
||||||
|
async def create_contact(contact: ContactPerson):
|
||||||
|
logging.info(f"Received contact creation request: {contact}")
|
||||||
|
# Check for duplicate contact by email (or other unique fields)
|
||||||
|
if any(c.email == contact.email for c in contacts):
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
detail="Contact with this email already exists."
|
||||||
|
)
|
||||||
|
|
||||||
|
contacts.append(contact)
|
||||||
|
return contact
|
||||||
|
|
||||||
|
# Creation of a return address
|
||||||
|
@app.post("/return_addresses", response_model=Address, status_code=status.HTTP_201_CREATED)
|
||||||
|
async def create_return_address(address: Address):
|
||||||
|
logging.info(f"Received contact creation request: {address}")
|
||||||
|
# Check for duplicate address by city
|
||||||
|
if any(a.city == address.city for a in return_addresses):
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
detail="Address in this city already exists."
|
||||||
|
)
|
||||||
|
|
||||||
|
return_addresses.append(address)
|
||||||
|
return address
|
||||||
|
@ -1,17 +1,25 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { Box, Button, TextField, Typography, Select, MenuItem, Stack, FormControl, InputLabel } from '@mui/material';
|
import { Box, Button, TextField, Typography, Select, MenuItem, Stack, FormControl, InputLabel } from '@mui/material';
|
||||||
import { SelectChangeEvent } from '@mui/material';
|
import { SelectChangeEvent } from '@mui/material';
|
||||||
import { Shipment, ContactPerson, Proposal, Address } from '../types.ts'; // Adjust import paths as necessary
|
|
||||||
import { SxProps } from '@mui/material';
|
import { SxProps } from '@mui/material';
|
||||||
import {useEffect} from "react";
|
import { useEffect } from "react";
|
||||||
import {DefaultService} from "../../openapi";
|
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 {
|
interface ShipmentFormProps {
|
||||||
newShipment: Shipment;
|
newShipment: Shipment;
|
||||||
setNewShipment: React.Dispatch<React.SetStateAction<Shipment>>;
|
setNewShipment: React.Dispatch<React.SetStateAction<Shipment>>;
|
||||||
handleSaveShipment: () => void;
|
handleSaveShipment: () => void;
|
||||||
contactPersons: ContactPerson[];
|
proposals: Proposal[]; // Define proposals type
|
||||||
proposals: Proposal[];
|
|
||||||
returnAddresses: Address[];
|
returnAddresses: Address[];
|
||||||
sx?: SxProps;
|
sx?: SxProps;
|
||||||
}
|
}
|
||||||
@ -20,11 +28,11 @@ const ShipmentForm: React.FC<ShipmentFormProps> = ({
|
|||||||
newShipment,
|
newShipment,
|
||||||
setNewShipment,
|
setNewShipment,
|
||||||
handleSaveShipment,
|
handleSaveShipment,
|
||||||
contactPersons,
|
|
||||||
proposals,
|
|
||||||
returnAddresses,
|
|
||||||
sx = {},
|
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 [isCreatingContactPerson, setIsCreatingContactPerson] = React.useState(false);
|
||||||
const [isCreatingReturnAddress, setIsCreatingReturnAddress] = React.useState(false);
|
const [isCreatingReturnAddress, setIsCreatingReturnAddress] = React.useState(false);
|
||||||
const [newContactPerson, setNewContactPerson] = React.useState({
|
const [newContactPerson, setNewContactPerson] = React.useState({
|
||||||
@ -33,18 +41,65 @@ const ShipmentForm: React.FC<ShipmentFormProps> = ({
|
|||||||
phone: '',
|
phone: '',
|
||||||
email: '',
|
email: '',
|
||||||
});
|
});
|
||||||
const [newReturnAddress, setNewReturnAddress] = React.useState('');
|
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 handleContactPersonChange = (event: SelectChangeEvent) => {
|
||||||
const value = event.target.value;
|
const value = event.target.value;
|
||||||
if (value === 'new') {
|
if (value === 'new') {
|
||||||
setIsCreatingContactPerson(true);
|
setIsCreatingContactPerson(true);
|
||||||
setNewShipment({ ...newShipment, contact_person: [] }); // Set to empty array for new person
|
setNewShipment({ ...newShipment, contact_person: [] }); // Reset for new person
|
||||||
} else {
|
} else {
|
||||||
setIsCreatingContactPerson(false);
|
setIsCreatingContactPerson(false);
|
||||||
const selectedPerson = contactPersons.find((person) => person.lastname === value) || null;
|
const selectedPerson = contactPersons.find((person) => person.lastname === value) || null;
|
||||||
if (selectedPerson) {
|
if (selectedPerson) {
|
||||||
setNewShipment({ ...newShipment, contact_person: [selectedPerson] }); // Wrap in array
|
setNewShipment({ ...newShipment, contact_person: [selectedPerson] }); // Set selected person
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -53,33 +108,61 @@ const ShipmentForm: React.FC<ShipmentFormProps> = ({
|
|||||||
const value = event.target.value;
|
const value = event.target.value;
|
||||||
if (value === 'new') {
|
if (value === 'new') {
|
||||||
setIsCreatingReturnAddress(true);
|
setIsCreatingReturnAddress(true);
|
||||||
setNewShipment({ ...newShipment, return_address: [] }); // Set to empty array for new address
|
setNewShipment({ ...newShipment, return_address: [] }); // Reset for new address
|
||||||
} else {
|
} else {
|
||||||
setIsCreatingReturnAddress(false);
|
setIsCreatingReturnAddress(false);
|
||||||
const selectedAddress = returnAddresses.find((address) => address.address === value);
|
const selectedAddress = returnAddresses.find((address) => address.city === value); // Match by a unique ID
|
||||||
if (selectedAddress) {
|
if (selectedAddress) {
|
||||||
setNewShipment({ ...newShipment, return_address: [selectedAddress] }); // Wrap in array of Address
|
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 handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const { name, value } = e.target;
|
const { name, value } = e.target;
|
||||||
setNewShipment((prev) => ({ ...prev, [name]: value }));
|
setNewShipment((prev) => ({ ...prev, [name]: value }));
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSaveNewContactPerson = () => {
|
const handleSaveNewReturnAddress = async () => {
|
||||||
// Add logic to save the new contact person
|
OpenAPI.BASE = 'http://127.0.0.1:8000';
|
||||||
console.log('Saving new contact person:', newContactPerson);
|
|
||||||
setIsCreatingContactPerson(false);
|
if (!newReturnAddress.street || !newReturnAddress.city || !newReturnAddress.zipcode || !newReturnAddress.country) {
|
||||||
setNewContactPerson({ firstName: '', lastName: '', phone: '', email: '' }); // Reset fields
|
setErrorMessage('All fields are required.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
street: newReturnAddress.street.trim(),
|
||||||
|
city: newReturnAddress.city.trim(),
|
||||||
|
zipcode: newReturnAddress.zipcode.trim(),
|
||||||
|
country: newReturnAddress.country.trim(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSaveNewReturnAddress = () => {
|
try {
|
||||||
// Add logic to save the new return address
|
const a: Address = await DefaultService.createReturnAddressReturnAddressesPost(payload);
|
||||||
console.log('Saving new return address:', newReturnAddress);
|
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);
|
setIsCreatingReturnAddress(false);
|
||||||
setNewReturnAddress(''); // Reset field
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -96,6 +179,7 @@ const ShipmentForm: React.FC<ShipmentFormProps> = ({
|
|||||||
<Typography variant="h6" sx={{ marginBottom: 2 }}>
|
<Typography variant="h6" sx={{ marginBottom: 2 }}>
|
||||||
Create Shipment
|
Create Shipment
|
||||||
</Typography>
|
</Typography>
|
||||||
|
{errorMessage && <Typography color="error">{errorMessage}</Typography>}
|
||||||
<Stack spacing={2}>
|
<Stack spacing={2}>
|
||||||
<TextField
|
<TextField
|
||||||
label="Shipment Name"
|
label="Shipment Name"
|
||||||
@ -111,12 +195,9 @@ const ShipmentForm: React.FC<ShipmentFormProps> = ({
|
|||||||
onChange={handleContactPersonChange}
|
onChange={handleContactPersonChange}
|
||||||
displayEmpty
|
displayEmpty
|
||||||
>
|
>
|
||||||
<MenuItem value="">
|
|
||||||
<em>Select a Contact Person</em>
|
|
||||||
</MenuItem>
|
|
||||||
{contactPersons.map((person) => (
|
{contactPersons.map((person) => (
|
||||||
<MenuItem key={person.id} value={person.lastname}>
|
<MenuItem key={person.lastname + person.firstname} value={person.lastname}>
|
||||||
{person.lastname}
|
{`${person.lastname}, ${person.firstname}`}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
<MenuItem value="new">
|
<MenuItem value="new">
|
||||||
@ -124,51 +205,13 @@ const ShipmentForm: React.FC<ShipmentFormProps> = ({
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
</Select>
|
</Select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
{isCreatingContactPerson && (
|
|
||||||
<>
|
|
||||||
<TextField
|
|
||||||
label="First Name"
|
|
||||||
name="firstName"
|
|
||||||
value={newContactPerson.firstName}
|
|
||||||
onChange={(e) => setNewContactPerson({ ...newContactPerson, firstName: e.target.value })}
|
|
||||||
fullWidth
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
label="Last Name"
|
|
||||||
name="lastName"
|
|
||||||
value={newContactPerson.lastName}
|
|
||||||
onChange={(e) => setNewContactPerson({ ...newContactPerson, lastName: e.target.value })}
|
|
||||||
fullWidth
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
label="Phone"
|
|
||||||
name="phone"
|
|
||||||
value={newContactPerson.phone}
|
|
||||||
onChange={(e) => setNewContactPerson({ ...newContactPerson, phone: e.target.value })}
|
|
||||||
fullWidth
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
label="Email"
|
|
||||||
name="email"
|
|
||||||
value={newContactPerson.email}
|
|
||||||
onChange={(e) => setNewContactPerson({ ...newContactPerson, email: e.target.value })}
|
|
||||||
fullWidth
|
|
||||||
/>
|
|
||||||
<Button variant="contained" color="primary" onClick={handleSaveNewContactPerson}>
|
|
||||||
Save New Contact Person
|
|
||||||
</Button>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<FormControl fullWidth>
|
<FormControl fullWidth>
|
||||||
<InputLabel>Proposal Number</InputLabel>
|
<InputLabel>Proposal Number</InputLabel>
|
||||||
<Select
|
<Select
|
||||||
value={newShipment.proposal_number || ''}
|
value={newShipment.proposal_number || ''}
|
||||||
onChange={(e) => setNewShipment({ ...newShipment, proposal_number: e.target.value })}
|
onChange={handleProposalChange}
|
||||||
displayEmpty
|
displayEmpty
|
||||||
>
|
>
|
||||||
<MenuItem value="">
|
|
||||||
<em>Select a Proposal Number</em>
|
|
||||||
</MenuItem>
|
|
||||||
{proposals.map((proposal) => (
|
{proposals.map((proposal) => (
|
||||||
<MenuItem key={proposal.id} value={proposal.number}>
|
<MenuItem key={proposal.id} value={proposal.number}>
|
||||||
{proposal.number}
|
{proposal.number}
|
||||||
@ -179,16 +222,13 @@ const ShipmentForm: React.FC<ShipmentFormProps> = ({
|
|||||||
<FormControl fullWidth>
|
<FormControl fullWidth>
|
||||||
<InputLabel>Return Address</InputLabel>
|
<InputLabel>Return Address</InputLabel>
|
||||||
<Select
|
<Select
|
||||||
value={newShipment.return_address?.[0]?.address || ''} // Access first return address's address
|
value={newShipment.return_address?.[0]?.city || ''}
|
||||||
onChange={handleReturnAddressChange}
|
onChange={handleReturnAddressChange}
|
||||||
displayEmpty
|
displayEmpty
|
||||||
>
|
>
|
||||||
<MenuItem value="">
|
|
||||||
<em>Select a Return Address</em>
|
|
||||||
</MenuItem>
|
|
||||||
{returnAddresses.map((address) => (
|
{returnAddresses.map((address) => (
|
||||||
<MenuItem key={address.id} value={address.address}>
|
<MenuItem key={address.city} value={address.city}>
|
||||||
{address.address}
|
{`${address.street}, ${address.city}, ${address.zipcode}, ${address.country}`}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
<MenuItem value="new">
|
<MenuItem value="new">
|
||||||
@ -199,9 +239,31 @@ const ShipmentForm: React.FC<ShipmentFormProps> = ({
|
|||||||
{isCreatingReturnAddress && (
|
{isCreatingReturnAddress && (
|
||||||
<>
|
<>
|
||||||
<TextField
|
<TextField
|
||||||
label="New Return Address"
|
label="Street"
|
||||||
value={newReturnAddress}
|
name="street"
|
||||||
onChange={(e) => setNewReturnAddress(e.target.value)}
|
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
|
fullWidth
|
||||||
/>
|
/>
|
||||||
<Button variant="contained" color="primary" onClick={handleSaveNewReturnAddress}>
|
<Button variant="contained" color="primary" onClick={handleSaveNewReturnAddress}>
|
@ -5,7 +5,7 @@ import AddIcon from '@mui/icons-material/Add';
|
|||||||
import DeleteIcon from '@mui/icons-material/Delete'; // Import delete icon
|
import DeleteIcon from '@mui/icons-material/Delete'; // Import delete icon
|
||||||
import UploadFileIcon from '@mui/icons-material/UploadFile'; // Import the upload icon
|
import UploadFileIcon from '@mui/icons-material/UploadFile'; // Import the upload icon
|
||||||
import UploadDialog from './UploadDialog.tsx'; // Import the UploadDialog component
|
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 { SxProps } from '@mui/material';
|
||||||
import bottleGrey from '../assets/icons/bottle-svgrepo-com-grey.svg';
|
import bottleGrey from '../assets/icons/bottle-svgrepo-com-grey.svg';
|
||||||
import bottleYellow from '../assets/icons/bottle-svgrepo-com-yellow.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 bottleRed from '../assets/icons/bottle-svgrepo-com-red.svg';
|
||||||
import {Shipment_Input, DefaultService, OpenAPI} from "../../openapi";
|
import {Shipment_Input, DefaultService, OpenAPI} from "../../openapi";
|
||||||
|
|
||||||
interface ShipmentPanelProps {
|
//interface ShipmentPanelProps {
|
||||||
selectedPage: string;
|
// selectedPage: string;
|
||||||
setIsCreatingShipment: Dispatch<SetStateAction<boolean>>;
|
// setIsCreatingShipment: Dispatch<SetStateAction<boolean>>;
|
||||||
newShipment: Shipment; // Ensure this aligns with the Shipment type
|
// newShipment: Shipment; // Ensure this aligns with the Shipment type
|
||||||
setNewShipment: Dispatch<SetStateAction<Shipment>>;
|
// setNewShipment: Dispatch<SetStateAction<Shipment>>;
|
||||||
selectShipment: (shipment: Shipment | null) => void; // Allow null for deselection
|
// selectShipment: (shipment: Shipment | null) => void; // Allow null for deselection
|
||||||
sx?: SxProps; // Optional sx prop for styling
|
// sx?: SxProps; // Optional sx prop for styling
|
||||||
}
|
//}
|
||||||
|
|
||||||
const ShipmentPanel: React.FC<ShipmentPanelProps> = ({
|
const ShipmentPanel: React.FC<ShipmentPanelProps> = ({
|
||||||
//setIsCreatingShipment,
|
setIsCreatingShipment,
|
||||||
//newShipment,
|
//newShipment,
|
||||||
//setNewShipment,
|
//setNewShipment,
|
||||||
//selectedPage,
|
//selectedPage,
|
||||||
@ -53,18 +53,16 @@ const ShipmentPanel: React.FC<ShipmentPanelProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
OpenAPI.BASE='http://127.0.0.1:8000'
|
OpenAPI.BASE = 'http://127.0.0.1:8000';
|
||||||
const fetchShipments = async () => {
|
const fetchShipments = async () => {
|
||||||
console.log('trying to fetch some shipments');
|
console.log('trying to fetch some shipments');
|
||||||
try {
|
try {
|
||||||
DefaultService.getShipmentsShipmentsGet().then((s : Shipment_Input[]) => {
|
// Await the response from the service call
|
||||||
|
const s: Shipment_Input[] = await DefaultService.getShipmentsShipmentsGet();
|
||||||
|
// Set the shipments state with the fetched data
|
||||||
setShipments(s);
|
setShipments(s);
|
||||||
});
|
|
||||||
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
setShipments(data.shipments);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
// If an error occurs, set the error message
|
||||||
console.error('Failed to fetch shipments:', error);
|
console.error('Failed to fetch shipments:', error);
|
||||||
setError("Failed to fetch shipments. Please try again later.");
|
setError("Failed to fetch shipments. Please try again later.");
|
||||||
}
|
}
|
||||||
@ -100,7 +98,7 @@ const ShipmentPanel: React.FC<ShipmentPanelProps> = ({
|
|||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
startIcon={<AddIcon />}
|
startIcon={<AddIcon />}
|
||||||
//onClick={() => {
|
onClick={() => {
|
||||||
// setNewShipment({
|
// setNewShipment({
|
||||||
// shipment_id: '', // Ensure this matches the Shipment type
|
// shipment_id: '', // Ensure this matches the Shipment type
|
||||||
// shipment_name: '',
|
// shipment_name: '',
|
||||||
@ -113,8 +111,8 @@ const ShipmentPanel: React.FC<ShipmentPanelProps> = ({
|
|||||||
// proposal_number: undefined, // Optional property
|
// proposal_number: undefined, // Optional property
|
||||||
// comments: '', // Optional property
|
// comments: '', // Optional property
|
||||||
// });
|
// });
|
||||||
// setIsCreatingShipment(true);
|
setIsCreatingShipment(true);
|
||||||
//}}
|
}}
|
||||||
sx={{ marginBottom: 2, padding: '10px 16px' }}
|
sx={{ marginBottom: 2, padding: '10px 16px' }}
|
||||||
>
|
>
|
||||||
Create Shipment
|
Create Shipment
|
||||||
|
@ -1,41 +1,68 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import ShipmentPanel from '../components/ShipmentPanel';
|
import ShipmentPanel from '../components/ShipmentPanel';
|
||||||
import { Shipment } from '../types';
|
import ShipmentForm from '../components/ShipmentForm'; // Import the ShipmentForm component
|
||||||
|
import { Shipment, ContactPerson, Proposal, Address } from '../types'; // Ensure these types are defined
|
||||||
|
|
||||||
const ShipmentView: React.FC = () => {
|
const ShipmentView: React.FC = () => {
|
||||||
//const [isCreatingShipment, setIsCreatingShipment] = useState(false);
|
const [isCreatingShipment, setIsCreatingShipment] = useState(false); // State to track if the form is open
|
||||||
//const [newShipment, setNewShipment] = useState<Shipment>({
|
const [newShipment, setNewShipment] = useState<Shipment>({
|
||||||
// shipment_id: '',
|
shipment_id: '',
|
||||||
// shipment_name: '',
|
shipment_name: '',
|
||||||
// shipment_status: '',
|
shipment_status: '',
|
||||||
// number_of_dewars: 0,
|
number_of_dewars: 0,
|
||||||
// shipment_date: '',
|
shipment_date: '',
|
||||||
// contact_person: null,
|
contact_person: null,
|
||||||
// dewars: [],
|
dewars: [],
|
||||||
// return_address: [],
|
return_address: [],
|
||||||
// proposal_number: undefined,
|
proposal_number: undefined,
|
||||||
// comments: '',
|
comments: '',
|
||||||
//});
|
});
|
||||||
|
|
||||||
|
// Dummy data for contact persons, proposals, and addresses
|
||||||
|
const contactPersons: ContactPerson[] = [
|
||||||
|
// Populate with contact person objects
|
||||||
|
];
|
||||||
|
const proposals: Proposal[] = [
|
||||||
|
// Populate with proposal objects
|
||||||
|
];
|
||||||
|
const returnAddresses: Address[] = [
|
||||||
|
// Populate with return address objects
|
||||||
|
];
|
||||||
|
|
||||||
const selectShipment = (shipment: Shipment | null) => {
|
const selectShipment = (shipment: Shipment | null) => {
|
||||||
console.log('Selected Shipment:', shipment);
|
console.log('Selected Shipment:', shipment);
|
||||||
// Additional logic for selected shipment
|
// Additional logic for selected shipment
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleSaveShipment = () => {
|
||||||
|
console.log('Saving shipment:', newShipment);
|
||||||
|
setIsCreatingShipment(false); // Close the form after saving
|
||||||
|
// Add logic to save the shipment
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ display: 'flex', padding: '16px' }}>
|
<div style={{ display: 'flex', padding: '16px' }}>
|
||||||
{/* Shipment Panel on the left side */}
|
{/* Shipment Panel on the left side */}
|
||||||
<ShipmentPanel
|
<ShipmentPanel
|
||||||
selectedPage="shipments"
|
selectedPage="shipments"
|
||||||
//setIsCreatingShipment={setIsCreatingShipment}
|
setIsCreatingShipment={setIsCreatingShipment} // Pass the state setter
|
||||||
//newShipment={newShipment}
|
|
||||||
//setNewShipment={setNewShipment}
|
|
||||||
selectShipment={selectShipment}
|
selectShipment={selectShipment}
|
||||||
sx={{ width: '300px' }} // Adjust width as needed
|
sx={{ width: '300px' }} // Adjust width as needed
|
||||||
/>
|
/>
|
||||||
{/* Additional content can go here */}
|
{/* Conditional rendering of the ShipmentForm */}
|
||||||
<div style={{ marginLeft: '16px', flexGrow: 1 }}>
|
<div style={{ marginLeft: '16px', flexGrow: 1 }}>
|
||||||
{/* Other components or information related to selected shipment can go here */}
|
{isCreatingShipment ? (
|
||||||
|
<ShipmentForm
|
||||||
|
newShipment={newShipment}
|
||||||
|
setNewShipment={setNewShipment}
|
||||||
|
handleSaveShipment={handleSaveShipment}
|
||||||
|
contactPersons={contactPersons}
|
||||||
|
proposals={proposals}
|
||||||
|
returnAddresses={returnAddresses}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div> {/* Content when form is not open */} </div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
Reference in New Issue
Block a user