added pucks and samples
This commit is contained in:
parent
23e7ebb819
commit
9fa499a582
@ -1,20 +1,36 @@
|
|||||||
|
import logging
|
||||||
from sqlalchemy.orm import Session, joinedload
|
from sqlalchemy.orm import Session, joinedload
|
||||||
|
from app.models import Shipment
|
||||||
|
|
||||||
|
|
||||||
def get_shipments(db: Session):
|
def get_shipments(db: Session):
|
||||||
from app.models import Shipment
|
logging.info("Fetching all shipments from the database.")
|
||||||
return db.query(Shipment).options(
|
shipments = db.query(Shipment).options(
|
||||||
joinedload(Shipment.contact_person),
|
joinedload(Shipment.contact_person),
|
||||||
joinedload(Shipment.return_address),
|
joinedload(Shipment.return_address),
|
||||||
joinedload(Shipment.proposal),
|
joinedload(Shipment.proposal),
|
||||||
joinedload(Shipment.dewars)
|
joinedload(Shipment.dewars)
|
||||||
).all()
|
).all()
|
||||||
|
logging.info(f"Total of {len(shipments)} shipments fetched.")
|
||||||
|
for shipment in shipments:
|
||||||
|
if shipment.proposal_id is None:
|
||||||
|
logging.warning(f"Shipment {shipment.shipment_id} is missing proposal ID.")
|
||||||
|
logging.debug(f"Shipment ID: {shipment.shipment_id}, Shipment Name: {shipment.shipment_name}")
|
||||||
|
return shipments
|
||||||
|
|
||||||
|
|
||||||
def get_shipment_by_id(db: Session, shipment_id: str):
|
def get_shipment_by_id(db: Session, shipment_id: str):
|
||||||
from app.models import Shipment
|
logging.info(f"Fetching shipment with ID: {shipment_id}")
|
||||||
shipment = db.query(Shipment).options(
|
shipment = db.query(Shipment).options(
|
||||||
joinedload(Shipment.contact_person),
|
joinedload(Shipment.contact_person),
|
||||||
joinedload(Shipment.return_address),
|
joinedload(Shipment.return_address),
|
||||||
joinedload(Shipment.proposal),
|
joinedload(Shipment.proposal),
|
||||||
joinedload(Shipment.dewars)
|
joinedload(Shipment.dewars)
|
||||||
).filter(Shipment.shipment_id == shipment_id).first()
|
).filter(Shipment.shipment_id == shipment_id).first()
|
||||||
|
if shipment:
|
||||||
|
if shipment.proposal_id is None:
|
||||||
|
logging.warning(f"Shipment {shipment.shipment_id} is missing proposal ID.")
|
||||||
|
logging.info(f"Shipment found: {shipment}")
|
||||||
|
else:
|
||||||
|
logging.warning(f"Shipment with ID {shipment_id} not found.")
|
||||||
return shipment
|
return shipment
|
@ -14,7 +14,7 @@ class Shipment(Base):
|
|||||||
comments = Column(String, nullable=True)
|
comments = Column(String, nullable=True)
|
||||||
contact_person_id = Column(Integer, ForeignKey("contact_persons.id"))
|
contact_person_id = Column(Integer, ForeignKey("contact_persons.id"))
|
||||||
return_address_id = Column(Integer, ForeignKey("addresses.id"))
|
return_address_id = Column(Integer, ForeignKey("addresses.id"))
|
||||||
proposal_id = Column(Integer, ForeignKey("proposals.id"))
|
proposal_id = Column(Integer, ForeignKey('proposals.id'), nullable=True)
|
||||||
|
|
||||||
contact_person = relationship("ContactPerson", back_populates="shipments")
|
contact_person = relationship("ContactPerson", back_populates="shipments")
|
||||||
return_address = relationship("Address", back_populates="shipments")
|
return_address = relationship("Address", back_populates="shipments")
|
||||||
@ -97,6 +97,7 @@ class Puck(Base):
|
|||||||
positions = relationship("Sample", back_populates="puck")
|
positions = relationship("Sample", back_populates="puck")
|
||||||
dewar = relationship("Dewar", back_populates="pucks")
|
dewar = relationship("Dewar", back_populates="pucks")
|
||||||
|
|
||||||
|
|
||||||
class Sample(Base):
|
class Sample(Base):
|
||||||
__tablename__ = 'samples'
|
__tablename__ = 'samples'
|
||||||
|
|
||||||
|
@ -11,7 +11,8 @@ router = APIRouter()
|
|||||||
|
|
||||||
@router.get("/", response_model=List[DewarSchema])
|
@router.get("/", response_model=List[DewarSchema])
|
||||||
async def get_dewars(db: Session = Depends(get_db)):
|
async def get_dewars(db: Session = Depends(get_db)):
|
||||||
return db.query(DewarModel).all()
|
dewars = db.query(DewarModel).options(joinedload(DewarModel.pucks)).all()
|
||||||
|
return dewars
|
||||||
|
|
||||||
|
|
||||||
@router.post("/", response_model=DewarSchema, status_code=status.HTTP_201_CREATED)
|
@router.post("/", response_model=DewarSchema, status_code=status.HTTP_201_CREATED)
|
||||||
@ -22,8 +23,6 @@ async def create_dewar(dewar: DewarCreate, db: Session = Depends(get_db)) -> Dew
|
|||||||
id=dewar_id,
|
id=dewar_id,
|
||||||
dewar_name=dewar.dewar_name,
|
dewar_name=dewar.dewar_name,
|
||||||
tracking_number=dewar.tracking_number,
|
tracking_number=dewar.tracking_number,
|
||||||
number_of_pucks=dewar.number_of_pucks,
|
|
||||||
number_of_samples=dewar.number_of_samples,
|
|
||||||
status=dewar.status,
|
status=dewar.status,
|
||||||
ready_date=dewar.ready_date,
|
ready_date=dewar.ready_date,
|
||||||
shipping_date=dewar.shipping_date,
|
shipping_date=dewar.shipping_date,
|
||||||
@ -37,6 +36,7 @@ async def create_dewar(dewar: DewarCreate, db: Session = Depends(get_db)) -> Dew
|
|||||||
db.add(db_dewar)
|
db.add(db_dewar)
|
||||||
db.commit()
|
db.commit()
|
||||||
db.refresh(db_dewar)
|
db.refresh(db_dewar)
|
||||||
|
|
||||||
return db_dewar
|
return db_dewar
|
||||||
|
|
||||||
|
|
||||||
@ -49,7 +49,12 @@ async def get_dewar(dewar_id: str, db: Session = Depends(get_db)):
|
|||||||
if not dewar:
|
if not dewar:
|
||||||
raise HTTPException(status_code=404, detail="Dewar not found")
|
raise HTTPException(status_code=404, detail="Dewar not found")
|
||||||
|
|
||||||
return dewar
|
# Ensure dewar.pucks is an empty list if there are no pucks
|
||||||
|
dewar_dict = dewar.__dict__
|
||||||
|
if dewar_dict.get("pucks") is None:
|
||||||
|
dewar_dict["pucks"] = []
|
||||||
|
|
||||||
|
return DewarSchema.from_orm(dewar)
|
||||||
|
|
||||||
|
|
||||||
@router.put("/{dewar_id}", response_model=DewarSchema)
|
@router.put("/{dewar_id}", response_model=DewarSchema)
|
||||||
@ -60,7 +65,9 @@ async def update_dewar(dewar_id: str, dewar_update: DewarUpdate, db: Session = D
|
|||||||
raise HTTPException(status_code=404, detail="Dewar not found")
|
raise HTTPException(status_code=404, detail="Dewar not found")
|
||||||
|
|
||||||
for key, value in dewar_update.dict(exclude_unset=True).items():
|
for key, value in dewar_update.dict(exclude_unset=True).items():
|
||||||
setattr(dewar, key, value)
|
# Ensure we're only setting directly settable attributes
|
||||||
|
if hasattr(dewar, key):
|
||||||
|
setattr(dewar, key, value)
|
||||||
|
|
||||||
db.commit()
|
db.commit()
|
||||||
db.refresh(dewar)
|
db.refresh(dewar)
|
||||||
|
@ -4,9 +4,10 @@ from typing import List, Optional
|
|||||||
import uuid
|
import uuid
|
||||||
import json
|
import json
|
||||||
from datetime import date
|
from datetime import date
|
||||||
|
import logging
|
||||||
|
|
||||||
from app.models import Shipment as ShipmentModel, ContactPerson as ContactPersonModel, Address as AddressModel, Proposal as ProposalModel, Dewar as DewarModel
|
from app.models import Shipment as ShipmentModel, ContactPerson as ContactPersonModel, Address as AddressModel, Proposal as ProposalModel, Dewar as DewarModel
|
||||||
from app.schemas import ShipmentCreate, Shipment as ShipmentSchema, DewarUpdate, ContactPerson as ContactPersonSchema
|
from app.schemas import ShipmentCreate, UpdateShipmentComments, Shipment as ShipmentSchema, DewarUpdate, ContactPerson as ContactPersonSchema
|
||||||
from app.schemas import Sample as SampleSchema
|
from app.schemas import Sample as SampleSchema
|
||||||
from app.database import get_db
|
from app.database import get_db
|
||||||
from app.crud import get_shipments, get_shipment_by_id
|
from app.crud import get_shipments, get_shipment_by_id
|
||||||
@ -23,9 +24,16 @@ async def fetch_shipments(shipment_id: Optional[str] = Query(None), db: Session
|
|||||||
if shipment_id:
|
if shipment_id:
|
||||||
shipment = get_shipment_by_id(db, shipment_id)
|
shipment = get_shipment_by_id(db, shipment_id)
|
||||||
if not shipment:
|
if not shipment:
|
||||||
|
logging.error(f"Shipment with ID {shipment_id} not found")
|
||||||
raise HTTPException(status_code=404, detail="Shipment not found")
|
raise HTTPException(status_code=404, detail="Shipment not found")
|
||||||
|
logging.info(f"Shipment found: {shipment}")
|
||||||
return [shipment]
|
return [shipment]
|
||||||
return get_shipments(db)
|
|
||||||
|
shipments = get_shipments(db)
|
||||||
|
logging.info(f"Total shipments fetched: {len(shipments)}")
|
||||||
|
for shipment in shipments:
|
||||||
|
logging.info(f"Shipment ID: {shipment.shipment_id}, Shipment Name: {shipment.shipment_name}")
|
||||||
|
return shipments
|
||||||
|
|
||||||
@router.post("", response_model=ShipmentSchema, status_code=status.HTTP_201_CREATED)
|
@router.post("", response_model=ShipmentSchema, status_code=status.HTTP_201_CREATED)
|
||||||
async def create_shipment(shipment: ShipmentCreate, db: Session = Depends(get_db)):
|
async def create_shipment(shipment: ShipmentCreate, db: Session = Depends(get_db)):
|
||||||
@ -80,7 +88,8 @@ async def update_shipment(shipment_id: str, updated_shipment: ShipmentCreate, db
|
|||||||
raise HTTPException(status_code=404, detail="Shipment not found")
|
raise HTTPException(status_code=404, detail="Shipment not found")
|
||||||
|
|
||||||
# Validate relationships by IDs
|
# Validate relationships by IDs
|
||||||
contact_person = db.query(ContactPersonModel).filter(ContactPersonModel.id == updated_shipment.contact_person_id).first()
|
contact_person = db.query(ContactPersonModel).filter(
|
||||||
|
ContactPersonModel.id == updated_shipment.contact_person_id).first()
|
||||||
return_address = db.query(AddressModel).filter(AddressModel.id == updated_shipment.return_address_id).first()
|
return_address = db.query(AddressModel).filter(AddressModel.id == updated_shipment.return_address_id).first()
|
||||||
if not contact_person:
|
if not contact_person:
|
||||||
raise HTTPException(status_code=404, detail="Contact person not found")
|
raise HTTPException(status_code=404, detail="Contact person not found")
|
||||||
@ -101,17 +110,18 @@ async def update_shipment(shipment_id: str, updated_shipment: ShipmentCreate, db
|
|||||||
if not dewar:
|
if not dewar:
|
||||||
raise HTTPException(status_code=404, detail=f"Dewar with ID {dewar_data.dewar_id} not found")
|
raise HTTPException(status_code=404, detail=f"Dewar with ID {dewar_data.dewar_id} not found")
|
||||||
|
|
||||||
# Dynamically update the dewar fields based on provided input
|
|
||||||
update_fields = dewar_data.dict(exclude_unset=True)
|
update_fields = dewar_data.dict(exclude_unset=True)
|
||||||
for key, value in update_fields.items():
|
for key, value in update_fields.items():
|
||||||
if key == 'contact_person_id':
|
if key == 'contact_person_id':
|
||||||
contact_person = db.query(ContactPersonModel).filter(ContactPersonModel.id == value).first()
|
contact_person = db.query(ContactPersonModel).filter(ContactPersonModel.id == value).first()
|
||||||
if not contact_person:
|
if not contact_person:
|
||||||
raise HTTPException(status_code=404, detail=f"Contact person with ID {value} for Dewar {dewar_data.dewar_id} not found")
|
raise HTTPException(status_code=404,
|
||||||
|
detail=f"Contact person with ID {value} for Dewar {dewar_data.dewar_id} not found")
|
||||||
if key == 'return_address_id':
|
if key == 'return_address_id':
|
||||||
address = db.query(AddressModel).filter(AddressModel.id == value).first()
|
address = db.query(AddressModel).filter(AddressModel.id == value).first()
|
||||||
if not address:
|
if not address:
|
||||||
raise HTTPException(status_code=404, detail=f"Address with ID {value} for Dewar {dewar_data.dewar_id} not found")
|
raise HTTPException(status_code=404,
|
||||||
|
detail=f"Address with ID {value} for Dewar {dewar_data.dewar_id} not found")
|
||||||
|
|
||||||
for key, value in update_fields.items():
|
for key, value in update_fields.items():
|
||||||
if key != 'dewar_id':
|
if key != 'dewar_id':
|
||||||
@ -121,6 +131,7 @@ async def update_shipment(shipment_id: str, updated_shipment: ShipmentCreate, db
|
|||||||
db.refresh(shipment)
|
db.refresh(shipment)
|
||||||
return shipment
|
return shipment
|
||||||
|
|
||||||
|
|
||||||
@router.post("/{shipment_id}/add_dewar", response_model=ShipmentSchema)
|
@router.post("/{shipment_id}/add_dewar", response_model=ShipmentSchema)
|
||||||
async def add_dewar_to_shipment(shipment_id: str, dewar_id: str, db: Session = Depends(get_db)):
|
async def add_dewar_to_shipment(shipment_id: str, dewar_id: str, db: Session = Depends(get_db)):
|
||||||
shipment = db.query(ShipmentModel).filter(ShipmentModel.shipment_id == shipment_id).first()
|
shipment = db.query(ShipmentModel).filter(ShipmentModel.shipment_id == shipment_id).first()
|
||||||
@ -179,4 +190,16 @@ def get_samples_in_dewar(shipment_id: str, dewar_id: str, db: Session = Depends(
|
|||||||
for puck in dewar.pucks:
|
for puck in dewar.pucks:
|
||||||
samples.extend(puck.positions)
|
samples.extend(puck.positions)
|
||||||
|
|
||||||
return samples
|
return samples
|
||||||
|
|
||||||
|
|
||||||
|
@router.put("/{shipment_id}/comments", response_model=ShipmentSchema)
|
||||||
|
async def update_shipment_comments(shipment_id: str, comments_data: UpdateShipmentComments, db: Session = Depends(get_db)):
|
||||||
|
shipment = db.query(ShipmentModel).filter(ShipmentModel.shipment_id == shipment_id).first()
|
||||||
|
if not shipment:
|
||||||
|
raise HTTPException(status_code=404, detail="Shipment not found")
|
||||||
|
|
||||||
|
shipment.comments = comments_data.comments
|
||||||
|
db.commit()
|
||||||
|
db.refresh(shipment)
|
||||||
|
return shipment
|
@ -107,8 +107,6 @@ class Dewar(DewarBase):
|
|||||||
class DewarUpdate(BaseModel):
|
class DewarUpdate(BaseModel):
|
||||||
dewar_name: Optional[str] = None
|
dewar_name: Optional[str] = None
|
||||||
tracking_number: Optional[str] = None
|
tracking_number: Optional[str] = None
|
||||||
number_of_pucks: Optional[int] = None
|
|
||||||
number_of_samples: Optional[int] = None
|
|
||||||
status: Optional[str] = None
|
status: Optional[str] = None
|
||||||
ready_date: Optional[date] = None
|
ready_date: Optional[date] = None
|
||||||
shipping_date: Optional[date] = None
|
shipping_date: Optional[date] = None
|
||||||
@ -156,3 +154,7 @@ class ShipmentCreate(BaseModel):
|
|||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
from_attributes = True
|
from_attributes = True
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateShipmentComments(BaseModel):
|
||||||
|
comments: str
|
BIN
backend/test.db
BIN
backend/test.db
Binary file not shown.
@ -1,20 +1,20 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Box, Typography, TextField, Button, Select, MenuItem, Snackbar } from '@mui/material';
|
import { Box, Typography, TextField, Button, Select, MenuItem, Snackbar } from '@mui/material';
|
||||||
import QRCode from 'react-qr-code';
|
import QRCode from 'react-qr-code';
|
||||||
import { ContactPerson, Address, Dewar, ContactsService, AddressesService, ShipmentsService, Puck, Sample } from '../../openapi';
|
import { ContactPerson, Address, Dewar, ContactsService, AddressesService, DewarsService, ShipmentsService } from '../../openapi';
|
||||||
import Unipuck from '../components/Unipuck';
|
import Unipuck from '../components/Unipuck';
|
||||||
|
|
||||||
interface DewarDetailsProps {
|
interface DewarDetailsProps {
|
||||||
dewar: Dewar;
|
dewar: Dewar;
|
||||||
trackingNumber: string;
|
trackingNumber: string;
|
||||||
setTrackingNumber: React.Dispatch<React.SetStateAction<string>>;
|
setTrackingNumber: (trackingNumber: string) => void;
|
||||||
initialContactPersons: ContactPerson[];
|
initialContactPersons?: ContactPerson[];
|
||||||
initialReturnAddresses: Address[];
|
initialReturnAddresses?: Address[];
|
||||||
defaultContactPerson?: ContactPerson;
|
defaultContactPerson?: ContactPerson;
|
||||||
defaultReturnAddress?: Address;
|
defaultReturnAddress?: Address;
|
||||||
shipmentId: string;
|
shipmentId: string;
|
||||||
refreshShipments: () => void;
|
refreshShipments: () => void;
|
||||||
selectedShipment: any;
|
selectedShipment?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DewarDetails: React.FC<DewarDetailsProps> = ({
|
const DewarDetails: React.FC<DewarDetailsProps> = ({
|
||||||
@ -27,61 +27,48 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
|
|||||||
defaultReturnAddress,
|
defaultReturnAddress,
|
||||||
shipmentId,
|
shipmentId,
|
||||||
refreshShipments,
|
refreshShipments,
|
||||||
selectedShipment
|
selectedShipment,
|
||||||
}) => {
|
}) => {
|
||||||
const [localTrackingNumber, setLocalTrackingNumber] = useState(trackingNumber);
|
const [localTrackingNumber, setLocalTrackingNumber] = useState(trackingNumber);
|
||||||
const [contactPersons, setContactPersons] = useState<ContactPerson[]>(initialContactPersons);
|
const [contactPersons, setContactPersons] = useState(initialContactPersons);
|
||||||
const [returnAddresses, setReturnAddresses] = useState<Address[]>(initialReturnAddresses);
|
const [returnAddresses, setReturnAddresses] = useState(initialReturnAddresses);
|
||||||
const [selectedContactPerson, setSelectedContactPerson] = useState<string>('');
|
const [selectedContactPerson, setSelectedContactPerson] = useState('');
|
||||||
const [selectedReturnAddress, setSelectedReturnAddress] = useState<string>('');
|
const [selectedReturnAddress, setSelectedReturnAddress] = useState('');
|
||||||
const [isCreatingContactPerson, setIsCreatingContactPerson] = useState(false);
|
const [isCreatingContactPerson, setIsCreatingContactPerson] = useState(false);
|
||||||
const [isCreatingReturnAddress, setIsCreatingReturnAddress] = useState(false);
|
const [isCreatingReturnAddress, setIsCreatingReturnAddress] = useState(false);
|
||||||
const [puckStatuses, setPuckStatuses] = useState<string[][]>(dewar.pucks.map(() => Array(16).fill('empty')));
|
const [puckStatuses, setPuckStatuses] = useState<string[][]>([]);
|
||||||
const [newContactPerson, setNewContactPerson] = useState({
|
const [newContactPerson, setNewContactPerson] = useState({ id: 0, firstName: '', lastName: '', phone_number: '', email: '' });
|
||||||
id: 0,
|
const [newReturnAddress, setNewReturnAddress] = useState({ id: 0, street: '', city: '', zipcode: '', country: '' });
|
||||||
firstName: '',
|
const [changesMade, setChangesMade] = useState(false);
|
||||||
lastName: '',
|
const [feedbackMessage, setFeedbackMessage] = useState('');
|
||||||
phone_number: '',
|
const [openSnackbar, setOpenSnackbar] = useState(false);
|
||||||
email: '',
|
|
||||||
});
|
|
||||||
const [newReturnAddress, setNewReturnAddress] = useState<Address>({
|
|
||||||
id: 0,
|
|
||||||
street: '',
|
|
||||||
city: '',
|
|
||||||
zipcode: '',
|
|
||||||
country: '',
|
|
||||||
});
|
|
||||||
const [changesMade, setChangesMade] = useState<boolean>(false);
|
|
||||||
const [feedbackMessage, setFeedbackMessage] = useState<string>('');
|
|
||||||
const [openSnackbar, setOpenSnackbar] = useState<boolean>(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const setInitialContactPerson = () => {
|
const setInitialContactPerson = () => {
|
||||||
const contactPersonId =
|
setSelectedContactPerson(
|
||||||
selectedShipment?.contact_person?.id?.toString() ||
|
|
||||||
dewar.contact_person?.id?.toString() ||
|
dewar.contact_person?.id?.toString() ||
|
||||||
defaultContactPerson?.id?.toString() ||
|
defaultContactPerson?.id?.toString() ||
|
||||||
'';
|
''
|
||||||
setSelectedContactPerson(contactPersonId);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const setInitialReturnAddress = () => {
|
const setInitialReturnAddress = () => {
|
||||||
const returnAddressId =
|
setSelectedReturnAddress(
|
||||||
dewar.return_address?.id?.toString() ||
|
dewar.return_address?.id?.toString() ||
|
||||||
defaultReturnAddress?.id?.toString() ||
|
defaultReturnAddress?.id?.toString() ||
|
||||||
'';
|
''
|
||||||
setSelectedReturnAddress(returnAddressId);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
setLocalTrackingNumber(dewar.tracking_number || '');
|
setLocalTrackingNumber(dewar.tracking_number || '');
|
||||||
setInitialContactPerson();
|
setInitialContactPerson();
|
||||||
setInitialReturnAddress();
|
setInitialReturnAddress();
|
||||||
}, [dewar, defaultContactPerson, defaultReturnAddress, selectedShipment]);
|
}, [dewar, defaultContactPerson, defaultReturnAddress]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const getContacts = async () => {
|
const getContacts = async () => {
|
||||||
try {
|
try {
|
||||||
const c: ContactPerson[] = await ContactsService.getContactsContactsGet();
|
const c = await ContactsService.getContactsContactsGet();
|
||||||
setContactPersons(c);
|
setContactPersons(c);
|
||||||
} catch {
|
} catch {
|
||||||
setFeedbackMessage('Failed to load contact persons. Please try again later.');
|
setFeedbackMessage('Failed to load contact persons. Please try again later.');
|
||||||
@ -91,7 +78,7 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
|
|||||||
|
|
||||||
const getReturnAddresses = async () => {
|
const getReturnAddresses = async () => {
|
||||||
try {
|
try {
|
||||||
const a: Address[] = await AddressesService.getReturnAddressesAddressesGet();
|
const a = await AddressesService.getReturnAddressesAddressesGet();
|
||||||
setReturnAddresses(a);
|
setReturnAddresses(a);
|
||||||
} catch {
|
} catch {
|
||||||
setFeedbackMessage('Failed to load return addresses. Please try again later.');
|
setFeedbackMessage('Failed to load return addresses. Please try again later.');
|
||||||
@ -105,17 +92,20 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchSamples = async () => {
|
const fetchSamples = async () => {
|
||||||
if (dewar.id) {
|
if (dewar.id && Array.isArray(dewar.pucks)) {
|
||||||
try {
|
try {
|
||||||
const samples: Sample[] = await ShipmentsService.getSamplesInDewarShipmentsShipmentIdDewarsDewarIdSamplesGet(shipmentId, dewar.id);
|
const samples = await ShipmentsService.getSamplesInDewarShipmentsShipmentIdDewarsDewarIdSamplesGet(shipmentId, dewar.id);
|
||||||
|
|
||||||
const updatedPuckStatuses = dewar.pucks.map(puck => {
|
const updatedPuckStatuses = dewar.pucks.map(puck => {
|
||||||
|
if (!Array.isArray(puck.positions)) return [];
|
||||||
return puck.positions.map(position => {
|
return puck.positions.map(position => {
|
||||||
const isOccupied = samples.some(sample => sample.id === position.id);
|
const isOccupied = samples.some(sample => sample.id === position.id);
|
||||||
return isOccupied ? 'filled' : 'empty';
|
return isOccupied ? 'filled' : 'empty';
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
setPuckStatuses(updatedPuckStatuses);
|
setPuckStatuses(updatedPuckStatuses);
|
||||||
} catch {
|
} catch (error) {
|
||||||
setFeedbackMessage('Failed to load samples. Please try again later.');
|
setFeedbackMessage('Failed to load samples. Please try again later.');
|
||||||
setOpenSnackbar(true);
|
setOpenSnackbar(true);
|
||||||
}
|
}
|
||||||
@ -129,9 +119,7 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
|
|||||||
const validatePhoneNumber = (phone: string) => /^\+?[1-9]\d{1,14}$/.test(phone);
|
const validatePhoneNumber = (phone: string) => /^\+?[1-9]\d{1,14}$/.test(phone);
|
||||||
const validateZipCode = (zipcode: string) => /^\d{5}(?:[-\s]\d{4})?$/.test(zipcode);
|
const validateZipCode = (zipcode: string) => /^\d{5}(?:[-\s]\d{4})?$/.test(zipcode);
|
||||||
|
|
||||||
if (!dewar) {
|
if (!dewar) return <Typography>No dewar selected.</Typography>;
|
||||||
return <Typography>No dewar selected.</Typography>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleAddContact = async () => {
|
const handleAddContact = async () => {
|
||||||
if (!validateEmail(newContactPerson.email) || !validatePhoneNumber(newContactPerson.phone_number) ||
|
if (!validateEmail(newContactPerson.email) || !validatePhoneNumber(newContactPerson.phone_number) ||
|
||||||
@ -149,7 +137,7 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const c: ContactPerson = await ContactsService.createContactContactsPost(payload);
|
const c = await ContactsService.createContactContactsPost(payload);
|
||||||
setContactPersons([...contactPersons, c]);
|
setContactPersons([...contactPersons, c]);
|
||||||
setFeedbackMessage('Contact person added successfully.');
|
setFeedbackMessage('Contact person added successfully.');
|
||||||
setNewContactPerson({ id: 0, firstName: '', lastName: '', phone_number: '', email: '' });
|
setNewContactPerson({ id: 0, firstName: '', lastName: '', phone_number: '', email: '' });
|
||||||
@ -178,7 +166,7 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const a: Address = await AddressesService.createReturnAddressAddressesPost(payload);
|
const a = await AddressesService.createReturnAddressAddressesPost(payload);
|
||||||
setReturnAddresses([...returnAddresses, a]);
|
setReturnAddresses([...returnAddresses, a]);
|
||||||
setFeedbackMessage('Return address added successfully.');
|
setFeedbackMessage('Return address added successfully.');
|
||||||
setNewReturnAddress({ id: 0, street: '', city: '', zipcode: '', country: '' });
|
setNewReturnAddress({ id: 0, street: '', city: '', zipcode: '', country: '' });
|
||||||
@ -192,20 +180,8 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
|
|||||||
setChangesMade(true);
|
setChangesMade(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getShipmentById = async (shipmentId: string) => {
|
|
||||||
try {
|
|
||||||
const response = await ShipmentsService.fetchShipmentsShipmentsGet(shipmentId);
|
|
||||||
if (response && response.length > 0) {
|
|
||||||
return response[0];
|
|
||||||
}
|
|
||||||
throw new Error('Shipment not found');
|
|
||||||
} catch (error) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSaveChanges = async () => {
|
const handleSaveChanges = async () => {
|
||||||
const formatDate = (dateString: string | undefined): string | null => {
|
const formatDate = (dateString: string) => {
|
||||||
if (!dateString) return null;
|
if (!dateString) return null;
|
||||||
const date = new Date(dateString);
|
const date = new Date(dateString);
|
||||||
if (isNaN(date.getTime())) return null;
|
if (isNaN(date.getTime())) return null;
|
||||||
@ -213,59 +189,42 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (!selectedContactPerson || !selectedReturnAddress) {
|
if (!selectedContactPerson || !selectedReturnAddress) {
|
||||||
setFeedbackMessage('Please ensure all required fields are filled.');
|
setFeedbackMessage("Please ensure all required fields are filled.");
|
||||||
setOpenSnackbar(true);
|
setOpenSnackbar(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let existingShipment;
|
const dewarId = dewar.id;
|
||||||
try {
|
|
||||||
existingShipment = await getShipmentById(shipmentId);
|
if (!dewarId) {
|
||||||
} catch {
|
setFeedbackMessage("Invalid Dewar ID. Please ensure Dewar ID is provided.");
|
||||||
setFeedbackMessage('Failed to fetch existing shipment data. Please try again later.');
|
|
||||||
setOpenSnackbar(true);
|
setOpenSnackbar(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedDewar = {
|
|
||||||
dewar_id: dewar.id,
|
|
||||||
dewar_name: dewar.dewar_name,
|
|
||||||
tracking_number: localTrackingNumber,
|
|
||||||
number_of_pucks: dewar.number_of_pucks,
|
|
||||||
number_of_samples: dewar.number_of_samples,
|
|
||||||
status: dewar.status,
|
|
||||||
ready_date: formatDate(dewar.ready_date ?? undefined),
|
|
||||||
shipping_date: formatDate(dewar.shipping_date ?? undefined),
|
|
||||||
arrival_date: dewar.arrival_date,
|
|
||||||
returning_date: dewar.returning_date,
|
|
||||||
qrcode: dewar.qrcode,
|
|
||||||
return_address_id: selectedReturnAddress,
|
|
||||||
contact_person_id: selectedContactPerson,
|
|
||||||
};
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
shipment_id: existingShipment.shipment_id,
|
|
||||||
shipment_name: existingShipment.shipment_name,
|
|
||||||
shipment_date: existingShipment.shipment_date,
|
|
||||||
shipment_status: existingShipment.shipment_status,
|
|
||||||
comments: existingShipment.comments,
|
|
||||||
contact_person_id: existingShipment.contact_person.id,
|
|
||||||
return_address_id: selectedReturnAddress,
|
|
||||||
proposal_id: existingShipment.proposal?.id,
|
|
||||||
dewars: [updatedDewar],
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await ShipmentsService.updateShipmentShipmentsShipmentIdPut(shipmentId, payload);
|
const payload = {
|
||||||
setFeedbackMessage('Changes saved successfully.');
|
dewar_id: dewarId,
|
||||||
|
dewar_name: dewar.dewar_name,
|
||||||
|
tracking_number: localTrackingNumber,
|
||||||
|
number_of_pucks: dewar.number_of_pucks,
|
||||||
|
number_of_samples: dewar.number_of_samples,
|
||||||
|
status: dewar.status,
|
||||||
|
ready_date: formatDate(dewar.ready_date),
|
||||||
|
shipping_date: formatDate(dewar.shipping_date),
|
||||||
|
arrival_date: dewar.arrival_date,
|
||||||
|
returning_date: dewar.returning_date,
|
||||||
|
qrcode: dewar.qrcode,
|
||||||
|
return_address_id: selectedReturnAddress,
|
||||||
|
contact_person_id: selectedContactPerson,
|
||||||
|
};
|
||||||
|
|
||||||
|
await DewarsService.updateDewarDewarsDewarIdPut(dewarId, payload);
|
||||||
|
setFeedbackMessage("Changes saved successfully.");
|
||||||
setChangesMade(false);
|
setChangesMade(false);
|
||||||
refreshShipments();
|
refreshShipments();
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
if (error.response && error.response.data) {
|
setFeedbackMessage("Failed to save changes. Please try again later.");
|
||||||
setFeedbackMessage(`Failed to save shipment. Validation errors: ${JSON.stringify(error.response.data)}`);
|
|
||||||
} else {
|
|
||||||
setFeedbackMessage('Failed to save changes. Please try again later.');
|
|
||||||
}
|
|
||||||
setOpenSnackbar(true);
|
setOpenSnackbar(true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -276,7 +235,7 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
|
|||||||
<TextField
|
<TextField
|
||||||
label="Tracking Number"
|
label="Tracking Number"
|
||||||
value={localTrackingNumber}
|
value={localTrackingNumber}
|
||||||
onChange={(e) => {
|
onChange={e => {
|
||||||
setLocalTrackingNumber(e.target.value);
|
setLocalTrackingNumber(e.target.value);
|
||||||
setTrackingNumber(e.target.value);
|
setTrackingNumber(e.target.value);
|
||||||
setChangesMade(true);
|
setChangesMade(true);
|
||||||
@ -296,23 +255,15 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
|
|||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
<Typography variant="body1">Number of Pucks: {dewar.number_of_pucks}</Typography>
|
|
||||||
<Box sx={{ marginTop: 2 }}>
|
<Box sx={{ marginTop: 2 }}>
|
||||||
{/* Other inputs and elements */}
|
|
||||||
|
|
||||||
<Typography variant="body1">Number of Pucks: {dewar.number_of_pucks}</Typography>
|
<Typography variant="body1">Number of Pucks: {dewar.number_of_pucks}</Typography>
|
||||||
|
{dewar.number_of_pucks > 0 ? <Unipuck pucks={dewar.number_of_pucks} samples={puckStatuses} /> : <Typography>No pucks attached to the dewar.</Typography>}
|
||||||
{/* Here we integrate the Unipuck component with puck data */}
|
|
||||||
{puckStatuses && <Unipuck pucks={puckStatuses.length} samples={puckStatuses} />}
|
|
||||||
|
|
||||||
<Typography variant="body1">Number of Samples: {dewar.number_of_samples}</Typography>
|
<Typography variant="body1">Number of Samples: {dewar.number_of_samples}</Typography>
|
||||||
{/* Rest of DewarDetails component */}
|
|
||||||
</Box>
|
</Box>
|
||||||
<Typography variant="body1">Number of Samples: {dewar.number_of_samples}</Typography>
|
|
||||||
<Typography variant="body1">Current Contact Person:</Typography>
|
<Typography variant="body1">Current Contact Person:</Typography>
|
||||||
<Select
|
<Select
|
||||||
value={selectedContactPerson}
|
value={selectedContactPerson}
|
||||||
onChange={(e) => {
|
onChange={e => {
|
||||||
const value = e.target.value;
|
const value = e.target.value;
|
||||||
setSelectedContactPerson(value);
|
setSelectedContactPerson(value);
|
||||||
setIsCreatingContactPerson(value === 'add');
|
setIsCreatingContactPerson(value === 'add');
|
||||||
@ -323,7 +274,7 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
|
|||||||
variant="outlined"
|
variant="outlined"
|
||||||
displayEmpty
|
displayEmpty
|
||||||
>
|
>
|
||||||
{Array.isArray(contactPersons) && contactPersons.map((person) => (
|
{contactPersons.map(person => (
|
||||||
<MenuItem key={person.id?.toString()} value={person.id?.toString() || ''}>
|
<MenuItem key={person.id?.toString()} value={person.id?.toString() || ''}>
|
||||||
{person.firstname} {person.lastname}
|
{person.firstname} {person.lastname}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
@ -335,7 +286,7 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
|
|||||||
<TextField
|
<TextField
|
||||||
label="First Name"
|
label="First Name"
|
||||||
value={newContactPerson.firstName}
|
value={newContactPerson.firstName}
|
||||||
onChange={(e) => setNewContactPerson({ ...newContactPerson, firstName: e.target.value })}
|
onChange={e => setNewContactPerson({ ...newContactPerson, firstName: e.target.value })}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
fullWidth
|
fullWidth
|
||||||
sx={{ marginBottom: 1 }}
|
sx={{ marginBottom: 1 }}
|
||||||
@ -343,7 +294,7 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
|
|||||||
<TextField
|
<TextField
|
||||||
label="Last Name"
|
label="Last Name"
|
||||||
value={newContactPerson.lastName}
|
value={newContactPerson.lastName}
|
||||||
onChange={(e) => setNewContactPerson({ ...newContactPerson, lastName: e.target.value })}
|
onChange={e => setNewContactPerson({ ...newContactPerson, lastName: e.target.value })}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
fullWidth
|
fullWidth
|
||||||
sx={{ marginBottom: 1 }}
|
sx={{ marginBottom: 1 }}
|
||||||
@ -351,7 +302,7 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
|
|||||||
<TextField
|
<TextField
|
||||||
label="Phone"
|
label="Phone"
|
||||||
value={newContactPerson.phone_number}
|
value={newContactPerson.phone_number}
|
||||||
onChange={(e) => setNewContactPerson({ ...newContactPerson, phone_number: e.target.value })}
|
onChange={e => setNewContactPerson({ ...newContactPerson, phone_number: e.target.value })}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
fullWidth
|
fullWidth
|
||||||
sx={{ marginBottom: 1 }}
|
sx={{ marginBottom: 1 }}
|
||||||
@ -361,7 +312,7 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
|
|||||||
<TextField
|
<TextField
|
||||||
label="Email"
|
label="Email"
|
||||||
value={newContactPerson.email}
|
value={newContactPerson.email}
|
||||||
onChange={(e) => setNewContactPerson({ ...newContactPerson, email: e.target.value })}
|
onChange={e => setNewContactPerson({ ...newContactPerson, email: e.target.value })}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
fullWidth
|
fullWidth
|
||||||
sx={{ marginBottom: 1 }}
|
sx={{ marginBottom: 1 }}
|
||||||
@ -376,7 +327,7 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
|
|||||||
<Typography variant="body1">Current Return Address:</Typography>
|
<Typography variant="body1">Current Return Address:</Typography>
|
||||||
<Select
|
<Select
|
||||||
value={selectedReturnAddress}
|
value={selectedReturnAddress}
|
||||||
onChange={(e) => {
|
onChange={e => {
|
||||||
const value = e.target.value;
|
const value = e.target.value;
|
||||||
setSelectedReturnAddress(value);
|
setSelectedReturnAddress(value);
|
||||||
setIsCreatingReturnAddress(value === 'add');
|
setIsCreatingReturnAddress(value === 'add');
|
||||||
@ -387,7 +338,7 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
|
|||||||
variant="outlined"
|
variant="outlined"
|
||||||
displayEmpty
|
displayEmpty
|
||||||
>
|
>
|
||||||
{Array.isArray(returnAddresses) && returnAddresses.map((address) => (
|
{returnAddresses.map(address => (
|
||||||
<MenuItem key={address.id?.toString()} value={address.id?.toString() || ''}>
|
<MenuItem key={address.id?.toString()} value={address.id?.toString() || ''}>
|
||||||
{address.street}, {address.city}
|
{address.street}, {address.city}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
@ -399,7 +350,7 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
|
|||||||
<TextField
|
<TextField
|
||||||
label="Street"
|
label="Street"
|
||||||
value={newReturnAddress.street}
|
value={newReturnAddress.street}
|
||||||
onChange={(e) => setNewReturnAddress({ ...newReturnAddress, street: e.target.value })}
|
onChange={e => setNewReturnAddress({ ...newReturnAddress, street: e.target.value })}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
fullWidth
|
fullWidth
|
||||||
sx={{ marginBottom: 1 }}
|
sx={{ marginBottom: 1 }}
|
||||||
@ -407,7 +358,7 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
|
|||||||
<TextField
|
<TextField
|
||||||
label="City"
|
label="City"
|
||||||
value={newReturnAddress.city}
|
value={newReturnAddress.city}
|
||||||
onChange={(e) => setNewReturnAddress({ ...newReturnAddress, city: e.target.value })}
|
onChange={e => setNewReturnAddress({ ...newReturnAddress, city: e.target.value })}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
fullWidth
|
fullWidth
|
||||||
sx={{ marginBottom: 1 }}
|
sx={{ marginBottom: 1 }}
|
||||||
@ -415,7 +366,7 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
|
|||||||
<TextField
|
<TextField
|
||||||
label="Zip Code"
|
label="Zip Code"
|
||||||
value={newReturnAddress.zipcode}
|
value={newReturnAddress.zipcode}
|
||||||
onChange={(e) => setNewReturnAddress({ ...newReturnAddress, zipcode: e.target.value })}
|
onChange={e => setNewReturnAddress({ ...newReturnAddress, zipcode: e.target.value })}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
fullWidth
|
fullWidth
|
||||||
sx={{ marginBottom: 1 }}
|
sx={{ marginBottom: 1 }}
|
||||||
@ -425,7 +376,7 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
|
|||||||
<TextField
|
<TextField
|
||||||
label="Country"
|
label="Country"
|
||||||
value={newReturnAddress.country}
|
value={newReturnAddress.country}
|
||||||
onChange={(e) => setNewReturnAddress({ ...newReturnAddress, country: e.target.value })}
|
onChange={e => setNewReturnAddress({ ...newReturnAddress, country: e.target.value })}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
fullWidth
|
fullWidth
|
||||||
sx={{ marginBottom: 1 }}
|
sx={{ marginBottom: 1 }}
|
||||||
@ -436,7 +387,7 @@ const DewarDetails: React.FC<DewarDetailsProps> = ({
|
|||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
{changesMade && (
|
{changesMade && (
|
||||||
<Button variant="contained" color="primary" onClick={handleSaveChanges}>
|
<Button variant="contained" color="primary" onClick={handleSaveChanges} sx={{ marginTop: 2 }}>
|
||||||
Save Changes
|
Save Changes
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
@ -44,13 +44,21 @@ const ShipmentDetails: React.FC<ShipmentDetailsProps> = ({
|
|||||||
shipping_date: null,
|
shipping_date: null,
|
||||||
arrival_date: null,
|
arrival_date: null,
|
||||||
returning_date: null,
|
returning_date: null,
|
||||||
qrcode: 'N/A'
|
qrcode: 'N/A',
|
||||||
|
contact_person_id: selectedShipment?.contact_person?.id,
|
||||||
|
return_address_id: selectedShipment?.return_address?.id,
|
||||||
};
|
};
|
||||||
|
|
||||||
const [newDewar, setNewDewar] = useState<Partial<Dewar>>(initialNewDewarState);
|
const [newDewar, setNewDewar] = useState<Partial<Dewar>>(initialNewDewarState);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setLocalSelectedDewar(null);
|
setLocalSelectedDewar(null);
|
||||||
|
// Ensure to update the default contact person and return address when the shipment changes
|
||||||
|
setNewDewar((prev) => ({
|
||||||
|
...prev,
|
||||||
|
contact_person_id: selectedShipment?.contact_person?.id,
|
||||||
|
return_address_id: selectedShipment?.return_address?.id
|
||||||
|
}));
|
||||||
}, [selectedShipment]);
|
}, [selectedShipment]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -97,12 +105,14 @@ const ShipmentDetails: React.FC<ShipmentDetailsProps> = ({
|
|||||||
...initialNewDewarState,
|
...initialNewDewarState,
|
||||||
...newDewar,
|
...newDewar,
|
||||||
dewar_name: newDewar.dewar_name.trim(),
|
dewar_name: newDewar.dewar_name.trim(),
|
||||||
contact_person: selectedShipment?.contact_person,
|
|
||||||
contact_person_id: selectedShipment?.contact_person?.id,
|
contact_person_id: selectedShipment?.contact_person?.id,
|
||||||
return_address: selectedShipment?.return_address,
|
return_address_id: selectedShipment?.return_address?.id
|
||||||
return_address_id: selectedShipment?.return_address?.id,
|
|
||||||
} as Dewar;
|
} as Dewar;
|
||||||
|
|
||||||
|
if (!newDewarToPost.dewar_name || !newDewarToPost.status) {
|
||||||
|
throw new Error('Missing required fields');
|
||||||
|
}
|
||||||
|
|
||||||
const createdDewar = await DewarsService.createDewarDewarsPost(newDewarToPost);
|
const createdDewar = await DewarsService.createDewarDewarsPost(newDewarToPost);
|
||||||
|
|
||||||
if (createdDewar && selectedShipment) {
|
if (createdDewar && selectedShipment) {
|
||||||
@ -127,27 +137,14 @@ const ShipmentDetails: React.FC<ShipmentDetailsProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSaveComments = async () => {
|
const handleSaveComments = async () => {
|
||||||
if (selectedShipment) {
|
if (selectedShipment && selectedShipment.shipment_id) {
|
||||||
try {
|
try {
|
||||||
const updatedShipmentPayload = {
|
const payload = { comments };
|
||||||
shipment_id: selectedShipment.shipment_id,
|
|
||||||
shipment_name: selectedShipment.shipment_name,
|
|
||||||
shipment_date: selectedShipment.shipment_date,
|
|
||||||
shipment_status: selectedShipment.shipment_status,
|
|
||||||
comments: comments,
|
|
||||||
contact_person_id: selectedShipment.contact_person?.id,
|
|
||||||
return_address_id: selectedShipment.return_address?.id,
|
|
||||||
proposal_id: selectedShipment.proposal?.id,
|
|
||||||
dewars: selectedShipment.dewars?.map(dewar => ({
|
|
||||||
...dewar,
|
|
||||||
dewar_id: dewar.id,
|
|
||||||
contact_person_id: dewar.contact_person?.id,
|
|
||||||
return_address_id: dewar.return_address?.id
|
|
||||||
}))
|
|
||||||
};
|
|
||||||
|
|
||||||
const updatedShipment = await ShipmentsService.updateShipmentShipmentsShipmentIdPut(selectedShipment.shipment_id, updatedShipmentPayload);
|
// Assuming `updateShipmentCommentsShipmentsShipmentIdCommentsPut` only needs the shipment ID
|
||||||
setSelectedShipment(updatedShipment);
|
const updatedShipment = await ShipmentsService.updateShipmentCommentsShipmentsShipmentIdCommentsPut(selectedShipment.shipment_id, payload);
|
||||||
|
|
||||||
|
setSelectedShipment({ ...selectedShipment, comments: updatedShipment.comments });
|
||||||
setInitialComments(comments);
|
setInitialComments(comments);
|
||||||
refreshShipments();
|
refreshShipments();
|
||||||
alert('Comments updated successfully.');
|
alert('Comments updated successfully.');
|
||||||
@ -155,6 +152,8 @@ const ShipmentDetails: React.FC<ShipmentDetailsProps> = ({
|
|||||||
console.error('Failed to update comments:', error);
|
console.error('Failed to update comments:', error);
|
||||||
alert('Failed to update comments. Please try again.');
|
alert('Failed to update comments. Please try again.');
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
console.error("Selected shipment or shipment ID is undefined");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -188,10 +187,19 @@ const ShipmentDetails: React.FC<ShipmentDetailsProps> = ({
|
|||||||
fullWidth
|
fullWidth
|
||||||
sx={{ marginBottom: 2 }}
|
sx={{ marginBottom: 2 }}
|
||||||
/>
|
/>
|
||||||
<Button variant="contained" color="primary" onClick={handleAddDewar} sx={{ marginRight: 2 }}>
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
onClick={handleAddDewar}
|
||||||
|
sx={{ marginRight: 2 }}
|
||||||
|
>
|
||||||
Save Dewar
|
Save Dewar
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="outlined" color="secondary" onClick={() => setIsAddingDewar(false)}>
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
color="secondary"
|
||||||
|
onClick={() => setIsAddingDewar(false)}
|
||||||
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
@ -333,10 +341,10 @@ const ShipmentDetails: React.FC<ShipmentDetailsProps> = ({
|
|||||||
setTrackingNumber={(value) => {
|
setTrackingNumber={(value) => {
|
||||||
setLocalSelectedDewar((prev) => (prev ? { ...prev, tracking_number: value as string } : prev));
|
setLocalSelectedDewar((prev) => (prev ? { ...prev, tracking_number: value as string } : prev));
|
||||||
}}
|
}}
|
||||||
initialContactPersons={selectedShipment?.contact_person ? [selectedShipment.contact_person] : []}
|
initialContactPersons={localSelectedDewar?.contact_person ? [localSelectedDewar.contact_person] : []} // Focus on dewar contact person
|
||||||
initialReturnAddresses={selectedShipment?.return_address ? [selectedShipment.return_address] : []}
|
initialReturnAddresses={localSelectedDewar?.return_address ? [localSelectedDewar.return_address] : []} // Focus on dewar return address
|
||||||
defaultContactPerson={contactPerson}
|
defaultContactPerson={localSelectedDewar?.contact_person}
|
||||||
defaultReturnAddress={selectedShipment?.return_address}
|
defaultReturnAddress={localSelectedDewar?.return_address}
|
||||||
shipmentId={selectedShipment?.shipment_id || ''}
|
shipmentId={selectedShipment?.shipment_id || ''}
|
||||||
refreshShipments={refreshShipments}
|
refreshShipments={refreshShipments}
|
||||||
/>
|
/>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Box } from '@mui/material';
|
import { Box, Typography } from '@mui/material';
|
||||||
|
|
||||||
interface UnipuckProps {
|
interface UnipuckProps {
|
||||||
pucks: number; // Number of pucks
|
pucks: number; // Number of pucks
|
||||||
@ -8,6 +8,10 @@ interface UnipuckProps {
|
|||||||
|
|
||||||
const Unipuck: React.FC<UnipuckProps> = ({ pucks, samples }) => {
|
const Unipuck: React.FC<UnipuckProps> = ({ pucks, samples }) => {
|
||||||
const renderPuck = (sampleStatus: string[]) => {
|
const renderPuck = (sampleStatus: string[]) => {
|
||||||
|
if (!sampleStatus) {
|
||||||
|
sampleStatus = Array(16).fill('empty');
|
||||||
|
}
|
||||||
|
|
||||||
const puckSVG = (
|
const puckSVG = (
|
||||||
<svg width="100" height="100" viewBox="0 0 100 100">
|
<svg width="100" height="100" viewBox="0 0 100 100">
|
||||||
<circle cx="50" cy="50" r="45" stroke="black" strokeWidth="2" fill="none" />
|
<circle cx="50" cy="50" r="45" stroke="black" strokeWidth="2" fill="none" />
|
||||||
@ -28,11 +32,15 @@ const Unipuck: React.FC<UnipuckProps> = ({ pucks, samples }) => {
|
|||||||
return puckSVG;
|
return puckSVG;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (pucks === 0) {
|
||||||
|
return <Typography variant="body1">No pucks attached to the dewar.</Typography>;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ display: 'flex', flexWrap: 'wrap', justifyContent: 'center', gap: 2 }}>
|
<Box sx={{ display: 'flex', flexWrap: 'wrap', justifyContent: 'center', gap: 2 }}>
|
||||||
{[...Array(pucks)].map((_, index) => (
|
{[...Array(pucks)].map((_, index) => (
|
||||||
<Box key={index} sx={{ margin: 1 }}>
|
<Box key={index} sx={{ margin: 1 }}>
|
||||||
{renderPuck(samples ? samples[index] : Array(16).fill('empty'))}
|
{renderPuck(samples && samples[index] ? samples[index] : Array(16).fill('empty'))}
|
||||||
</Box>
|
</Box>
|
||||||
))}
|
))}
|
||||||
</Box>
|
</Box>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user