added update to comments with characters counter
This commit is contained in:
parent
84f270b647
commit
0becdf9337
@ -1,5 +1,5 @@
|
||||
from typing import List, Optional
|
||||
from pydantic import BaseModel, EmailStr
|
||||
from pydantic import BaseModel, EmailStr, constr
|
||||
from datetime import date
|
||||
|
||||
|
||||
@ -120,7 +120,7 @@ class ShipmentCreate(BaseModel):
|
||||
shipment_name: str
|
||||
shipment_date: date
|
||||
shipment_status: str
|
||||
comments: Optional[str] = ""
|
||||
comments: Optional[constr(max_length=500)]
|
||||
contact_person_id: int
|
||||
return_address_id: int
|
||||
proposal_id: int
|
||||
|
@ -1,12 +1,16 @@
|
||||
import React from 'react';
|
||||
import { Box, Typography, Button, Stack, TextField } from '@mui/material';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Box, Typography, Button, Stack, TextField, IconButton, Grid } from '@mui/material';
|
||||
import QRCode from 'react-qr-code';
|
||||
import DeleteIcon from "@mui/icons-material/Delete";
|
||||
import { Dewar, DewarsService, ShipmentsService, ContactPerson, ApiError } from "../../openapi"; // Ensure ApiError is imported here
|
||||
import CheckIcon from '@mui/icons-material/Check';
|
||||
import CloseIcon from '@mui/icons-material/Close';
|
||||
import { Dewar, DewarsService, ShipmentsService, ContactPerson, ApiError } from "../../openapi";
|
||||
import { SxProps } from "@mui/system";
|
||||
import CustomStepper from "./DewarStepper";
|
||||
import DewarDetails from './DewarDetails';
|
||||
|
||||
const MAX_COMMENTS_LENGTH = 200;
|
||||
|
||||
interface ShipmentDetailsProps {
|
||||
isCreatingShipment: boolean;
|
||||
sx?: SxProps;
|
||||
@ -28,8 +32,10 @@ const ShipmentDetails: React.FC<ShipmentDetailsProps> = ({
|
||||
refreshShipments,
|
||||
defaultContactPerson
|
||||
}) => {
|
||||
const [localSelectedDewar, setLocalSelectedDewar] = React.useState<Dewar | null>(null);
|
||||
const [isAddingDewar, setIsAddingDewar] = React.useState<boolean>(false);
|
||||
const [localSelectedDewar, setLocalSelectedDewar] = useState<Dewar | null>(null);
|
||||
const [isAddingDewar, setIsAddingDewar] = useState<boolean>(false);
|
||||
const [comments, setComments] = useState<string>(selectedShipment?.comments || '');
|
||||
const [initialComments, setInitialComments] = useState<string>(selectedShipment?.comments || '');
|
||||
|
||||
const initialNewDewarState: Partial<Dewar> = {
|
||||
dewar_name: '',
|
||||
@ -44,14 +50,15 @@ const ShipmentDetails: React.FC<ShipmentDetailsProps> = ({
|
||||
qrcode: 'N/A'
|
||||
};
|
||||
|
||||
const [newDewar, setNewDewar] = React.useState<Partial<Dewar>>(initialNewDewarState);
|
||||
const [newDewar, setNewDewar] = useState<Partial<Dewar>>(initialNewDewarState);
|
||||
|
||||
React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
setLocalSelectedDewar(null);
|
||||
}, [selectedShipment]);
|
||||
|
||||
React.useEffect(() => {
|
||||
console.log('ShipmentDetails - selectedShipment updated:', selectedShipment);
|
||||
useEffect(() => {
|
||||
setComments(selectedShipment?.comments || '');
|
||||
setInitialComments(selectedShipment?.comments || '');
|
||||
}, [selectedShipment]);
|
||||
|
||||
const totalPucks = selectedShipment?.dewars?.reduce((acc, dewar) => acc + (dewar.number_of_pucks || 0), 0) || 0;
|
||||
@ -94,12 +101,13 @@ const ShipmentDetails: React.FC<ShipmentDetailsProps> = ({
|
||||
...newDewar,
|
||||
dewar_name: newDewar.dewar_name.trim(),
|
||||
contact_person: selectedShipment?.contact_person,
|
||||
contact_person_id: selectedShipment?.contact_person?.id, // Adding contact_person_id
|
||||
contact_person_id: selectedShipment?.contact_person?.id,
|
||||
return_address: selectedShipment?.return_address,
|
||||
return_address_id: selectedShipment?.return_address?.id, // Adding return_address_id
|
||||
return_address_id: selectedShipment?.return_address?.id,
|
||||
} as Dewar;
|
||||
|
||||
const createdDewar = await DewarsService.createDewarDewarsPost(newDewarToPost);
|
||||
|
||||
if (createdDewar && selectedShipment) {
|
||||
const updatedShipment = await ShipmentsService.addDewarToShipmentShipmentsShipmentIdAddDewarPost(selectedShipment.shipment_id, createdDewar.id);
|
||||
setSelectedShipment(updatedShipment);
|
||||
@ -110,7 +118,7 @@ const ShipmentDetails: React.FC<ShipmentDetailsProps> = ({
|
||||
} catch (error) {
|
||||
console.error('Error adding dewar or updating shipment:', error);
|
||||
if (error instanceof ApiError && error.body) {
|
||||
console.error('Validation errors:', error.body.detail); // Log specific validation errors
|
||||
console.error('Validation errors:', error.body.detail);
|
||||
} else {
|
||||
console.error('Unexpected error:', error);
|
||||
}
|
||||
@ -121,6 +129,43 @@ const ShipmentDetails: React.FC<ShipmentDetailsProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
const handleSaveComments = async () => {
|
||||
if (selectedShipment) {
|
||||
try {
|
||||
const updatedShipmentPayload = {
|
||||
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);
|
||||
setSelectedShipment(updatedShipment);
|
||||
setInitialComments(comments);
|
||||
refreshShipments();
|
||||
alert('Comments updated successfully.');
|
||||
} catch (error) {
|
||||
console.error('Failed to update comments:', error);
|
||||
alert('Failed to update comments. Please try again.');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleCancelEdit = () => {
|
||||
setComments(initialComments);
|
||||
};
|
||||
|
||||
const isCommentsEdited = comments !== initialComments;
|
||||
const contactPerson = selectedShipment?.contact_person;
|
||||
|
||||
return (
|
||||
@ -155,19 +200,57 @@ const ShipmentDetails: React.FC<ShipmentDetailsProps> = ({
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{selectedShipment ? (
|
||||
<>
|
||||
<Typography variant="h5">{selectedShipment.shipment_name}</Typography>
|
||||
<Typography variant="body1" color="textSecondary">
|
||||
Main contact person: {contactPerson ? `${contactPerson.firstname} ${contactPerson.lastname}` : 'N/A'}
|
||||
</Typography>
|
||||
<Typography variant="body1">Number of Pucks: {totalPucks}</Typography>
|
||||
<Typography variant="body1">Number of Samples: {totalSamples}</Typography>
|
||||
<Typography variant="body1">Shipment Date: {selectedShipment.shipment_date}</Typography>
|
||||
</>
|
||||
) : (
|
||||
<Typography variant="h5" color="error">No shipment selected</Typography>
|
||||
)}
|
||||
{
|
||||
selectedShipment
|
||||
? (
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Box sx={{ marginTop: 2, marginBottom: 2 }}>
|
||||
<Typography variant="h5">{selectedShipment.shipment_name}</Typography>
|
||||
<Typography variant="body1" color="textSecondary">
|
||||
Main contact person: {contactPerson ? `${contactPerson.firstname} ${contactPerson.lastname}` : 'N/A'}
|
||||
</Typography>
|
||||
<Typography variant="body1">Number of Pucks: {totalPucks}</Typography>
|
||||
<Typography variant="body1">Number of Samples: {totalSamples}</Typography>
|
||||
<Typography variant="body1">Shipment Date: {selectedShipment.shipment_date}</Typography>
|
||||
</Box>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Box sx={{ position: 'relative' }}>
|
||||
<TextField
|
||||
label="Comments"
|
||||
fullWidth
|
||||
multiline
|
||||
rows={4}
|
||||
value={comments}
|
||||
onChange={(e) => setComments(e.target.value)}
|
||||
sx={{
|
||||
marginBottom: 2,
|
||||
'& .MuiInputBase-root': {
|
||||
color: isCommentsEdited ? 'inherit' : 'rgba(0, 0, 0, 0.6)',
|
||||
},
|
||||
}}
|
||||
helperText={`${MAX_COMMENTS_LENGTH - comments.length} characters remaining`}
|
||||
error={comments.length > MAX_COMMENTS_LENGTH}
|
||||
/>
|
||||
<Box sx={{ position: 'absolute', bottom: 8, right: 8, display: 'flex', gap: 1 }}>
|
||||
<IconButton
|
||||
color="primary"
|
||||
onClick={handleSaveComments}
|
||||
disabled={comments.length > MAX_COMMENTS_LENGTH}
|
||||
>
|
||||
<CheckIcon />
|
||||
</IconButton>
|
||||
<IconButton color="secondary" onClick={handleCancelEdit}>
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
</Box>
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
: <Typography variant="h5" color="error">No shipment selected</Typography>
|
||||
}
|
||||
|
||||
{localSelectedDewar && !isAddingDewar && (
|
||||
<DewarDetails
|
||||
|
@ -10,6 +10,8 @@ import {
|
||||
} from '../../openapi';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
const MAX_COMMENTS_LENGTH = 200;
|
||||
|
||||
interface ShipmentFormProps {
|
||||
sx?: SxProps;
|
||||
onCancel: () => void;
|
||||
@ -396,21 +398,40 @@ const ShipmentForm: React.FC<ShipmentFormProps> = ({ sx = {}, onCancel, refreshS
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
<TextField
|
||||
label="Comments"
|
||||
name="comments"
|
||||
fullWidth
|
||||
multiline
|
||||
rows={4}
|
||||
value={newShipment.comments || ''}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<Box
|
||||
sx={{
|
||||
position: 'relative',
|
||||
}}
|
||||
>
|
||||
<TextField
|
||||
label="Comments"
|
||||
name="comments"
|
||||
fullWidth
|
||||
multiline
|
||||
rows={4}
|
||||
value={newShipment.comments || ''}
|
||||
onChange={handleChange}
|
||||
inputProps={{ maxLength: MAX_COMMENTS_LENGTH }}
|
||||
/>
|
||||
<Typography
|
||||
variant="caption"
|
||||
color={newShipment.comments && newShipment.comments.length > MAX_COMMENTS_LENGTH ? 'error' : 'textSecondary'}
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
bottom: 8,
|
||||
right: 8,
|
||||
}}
|
||||
>
|
||||
{MAX_COMMENTS_LENGTH - (newShipment.comments?.length || 0)} characters remaining
|
||||
</Typography>
|
||||
</Box>
|
||||
<Stack direction="row" spacing={2} justifyContent="flex-end">
|
||||
<Button variant="outlined" color="error" onClick={onCancel}>Cancel</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={handleSaveShipment}
|
||||
disabled={newShipment.comments?.length > MAX_COMMENTS_LENGTH}
|
||||
>
|
||||
Save Shipment
|
||||
</Button>
|
||||
|
Loading…
x
Reference in New Issue
Block a user