// components/modals/EditStockSections.tsx import React from 'react' import axios from 'axios' import { toast } from 'react-hot-toast' import { StockPosition, StockSection } from "@/types" interface Props { onClose: () => void selectedPosition: () => StockPosition } interface EditableSection { // Mirror of StockSection, with local-only flags section_id?: number section_symbol: string section_name: string capacity: number retrievable: boolean markedForDeletion: boolean } const EditStockSections: React.FC = ({ onClose, selectedPosition }) => { // Local state for position capacity and editable sections const [positionCapacity, setPositionCapacity] = React.useState(selectedPosition.capacity) const [sections, setSections] = React.useState([]) const [loading, setLoading] = React.useState(false) const [validationError, setValidationError] = React.useState("") // Initialize sections state whenever the selected position changes React.useEffect(() => { const initialSections: EditableSection[] = selectedPosition.sections.map((sec) => ({ section_id: sec.section_id, section_symbol: sec.section_symbol, section_name: sec.section_name, capacity: sec.capacity, retrievable: sec.retrievable, markedForDeletion: false, })) setSections(initialSections) setPositionCapacity(selectedPosition.capacity) setValidationError("") }, [selectedPosition]) // Handler: change position capacity const handlePositionCapacityChange = (e: React.ChangeEvent) => { const val = parseInt(e.target.value, 10) if (!isNaN(val) && val >= 0) { setPositionCapacity(val) // Clear any existing validation error to re-validate setValidationError("") } } // Handler: change a section's field (by index) const handleSectionChange = ( index: number, field: keyof Omit, value: string | boolean ) => { setSections((prev) => { const updated = [...prev] if (field === "capacity") { const num = parseInt(value as string, 10) updated[index].capacity = isNaN(num) ? 0 : num } else if (field === "retrievable") { updated[index].retrievable = value as boolean } else { updated[index][field] = value as string } return updated }) setValidationError("") } // Handler: add a brand-new empty section const handleAddSection = () => { setSections((prev) => [ ...prev, { section_symbol: `${prev.length + 1}`, section_name: `Section ${prev.length + 1}`, capacity: 0, retrievable: true, markedForDeletion: false, }, ]) setValidationError("") } // Handler: mark a section for deletion (or directly remove if never saved) const handleRemoveSection = (index: number) => { setSections((prev) => { const updated = [...prev] if (updated[index].section_id) { // If it exists on the server, mark for deletion updated[index].markedForDeletion = true } else { // If it's a new unsaved section, just drop it updated.splice(index, 1) } return updated }) setValidationError("") } // Compute total capacity of non-deleted sections const totalSectionsCapacity = sections .filter((s) => !s.markedForDeletion) .reduce((sum, s) => sum + s.capacity, 0) // Validation: total section capacity must not exceed position capacity React.useEffect(() => { if (totalSectionsCapacity > positionCapacity) { setValidationError( `Total section capacity (${totalSectionsCapacity}) exceeds position capacity (${positionCapacity}).` ) } else { setValidationError("") } }, [totalSectionsCapacity, positionCapacity]) // Handler: save all changes (position + sections) const handleSave = async () => { // Prevent saving if there's a validation error if (validationError) { toast.error(validationError) return } setLoading(true) const toastId = toast.loading("Saving changes…") try { // 1) Update the StockPosition's capacity if it has changed if (positionCapacity !== selectedPosition.capacity) { await axios.put( `/api/stockPositions/${selectedPosition.position_id}`, { capacity: positionCapacity, }, { withCredentials: true } ) } // 2) Process each section: create, update, or delete for (const sec of sections) { if (sec.section_id && sec.markedForDeletion) { // DELETE existing section await axios.delete(`/api/stockSections/${sec.section_id}`, { withCredentials: true, }) } else if (sec.section_id) { // UPDATE existing section await axios.put( `/api/stockSections/${sec.section_id}`, { section_name: sec.section_name, capacity: sec.capacity, retrievable: sec.retrievable, }, { withCredentials: true } ) } else if (!sec.section_id && !sec.markedForDeletion) { // CREATE new section await axios.post( `/api/stockSections`, { position_id: selectedPosition.position_id, section_symbol: sec.section_symbol, section_name: sec.section_name, capacity: sec.capacity, retrievable: sec.retrievable, }, { withCredentials: true } ) } // If a new section was added then immediately marked for deletion before save, // we do nothing (skip). } toast.dismiss(toastId) toast.success("Position and sections updated successfully.") onClose() } catch (err: any) { toast.dismiss(toastId) if (err.response && err.response.data && err.response.data.message) { toast.error(`Error: ${err.response.data.message}`) } else { toast.error("Network or server error. Please try again.") } } finally { setLoading(false) } } return (

EditPosition {selectedPosition.storage_address}

{/* Position Capacity Input */}
{/* Sections List */}

Sections

{sections.map((sec, idx) => (
{sec.section_id ? `Section ID: ${sec.section_id}` : `New Section`}
{!sec.markedForDeletion && (
{/* Section Name */}
handleSectionChange(idx, "section_name", e.target.value) } className="input input-bordered w-full" required />
{/* Section Capacity */}
handleSectionChange(idx, "capacity", e.target.value) } className="input input-bordered w-full" min="0" required />
{/* Retrievable Checkbox */}
)} {sec.markedForDeletion && (
This section will be deleted when you save.
)}
))} {sections.length === 0 && (
No sections defined for this position.
)}
{/* Validation Error */} {validationError && (
{validationError}
)}
Total of section capacities: {totalSectionsCapacity}
{/* Action Buttons */}
) } export default EditStockSections