added update to comments with characters counter

This commit is contained in:
GotthardG 2024-11-02 21:01:31 +01:00
parent 84f270b647
commit 0becdf9337
3 changed files with 140 additions and 36 deletions

View File

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

View File

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

View File

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