diff --git a/src/frontend/src/forms/ReturnOrderForms.tsx b/src/frontend/src/forms/ReturnOrderForms.tsx index 3377ff1f22..0fe1866b7b 100644 --- a/src/frontend/src/forms/ReturnOrderForms.tsx +++ b/src/frontend/src/forms/ReturnOrderForms.tsx @@ -199,7 +199,7 @@ function ReturnOrderLineItemFormRow({ label: t`Status`, choices: statusOptions, onValueChange: (value) => { - props.changeFn(props.idx, 'status', value); + props.changeFn(props.rowId, 'status', value); } }} defaultValue={record.item_detail?.status} @@ -207,7 +207,7 @@ function ReturnOrderLineItemFormRow({ /> - props.removeFn(props.idx)} /> + props.removeFn(props.rowId)} /> @@ -226,6 +226,7 @@ export function useReceiveReturnOrderLineItems( field_type: 'table', value: props.items.map((item: any) => { return { + id: item.pk, item: item.pk }; }), @@ -236,7 +237,7 @@ export function useReceiveReturnOrderLineItems( ); }, diff --git a/src/frontend/src/forms/SalesOrderForms.tsx b/src/frontend/src/forms/SalesOrderForms.tsx index c6f81f2ffb..af5a73d467 100644 --- a/src/frontend/src/forms/SalesOrderForms.tsx +++ b/src/frontend/src/forms/SalesOrderForms.tsx @@ -26,6 +26,7 @@ import type { } from '@lib/types/Forms'; import dayjs from 'dayjs'; import type { TableFieldRowProps } from '../components/forms/fields/TableField'; +import { useWhyDidYouUpdate } from '../functions/debug'; import useBackgroundTask from '../hooks/UseBackgroundTask'; import { useCreateApiFormModal, useEditApiFormModal } from '../hooks/UseForm'; import { useGlobalSettingsState } from '../states/SettingsStates'; @@ -310,6 +311,12 @@ function SalesOrderAllocateLineRow({ record: any; sourceLocation?: number | null; }>) { + useWhyDidYouUpdate('SalesOrderAllocateLineRow', { + props, + record, + sourceLocation + }); + // Statically defined field for selecting the stock item const stockItemField: ApiFormFieldType = useMemo(() => { return { @@ -328,28 +335,33 @@ function SalesOrderAllocateLineRow({ value: props.item.stock_item, name: 'stock_item', onValueChange: (value: any, instance: any) => { - props.changeFn(props.idx, 'stock_item', value); + props.changeFn(props.rowId, 'stock_item', value); // Update the allocated quantity based on the selected stock item if (instance) { const available = instance.quantity - instance.allocated; const required = record.quantity - record.allocated; - let quantity = props.item?.quantity ?? 0; + let q = props.item?.quantity ?? 0; - quantity = Math.max(quantity, required); - quantity = Math.min(quantity, available); + q = Math.max(q, required); + q = Math.min(q, available); - if (quantity != props.item.quantity) { - props.changeFn(props.idx, 'quantity', quantity); + if (q != props.item?.quantity) { + setQuantity(q); + props.changeFn(props.rowId, 'quantity', q); } } } }; }, [sourceLocation, record, props]); + const [quantity, setQuantity] = useState( + props.item?.quantity ?? '' + ); + return ( - + @@ -373,7 +385,7 @@ function SalesOrderAllocateLineRow({ min={0} step={1} decimalScale={10} - value={props.item.quantity ?? ''} + value={quantity} onChange={(value: number | string) => { let nextValue: number | '' = ''; @@ -384,13 +396,14 @@ function SalesOrderAllocateLineRow({ nextValue = Number.isFinite(parsed) ? parsed : ''; } - props.changeFn(props.idx, 'quantity', nextValue); + setQuantity(nextValue); + props.changeFn(props.rowId, 'quantity', nextValue); }} error={props.rowErrors?.quantity?.message} /> - props.removeFn(props.idx)} /> + props.removeFn(props.rowId)} /> ); @@ -445,7 +458,7 @@ export function useAllocateToSalesOrderForm({ return ( { return { + id: item.pk, line_item: item.pk, quantity: 0, stock_item: null diff --git a/src/frontend/src/forms/StockForms.tsx b/src/frontend/src/forms/StockForms.tsx index 9660c3ee6c..3bdc6a0a7b 100644 --- a/src/frontend/src/forms/StockForms.tsx +++ b/src/frontend/src/forms/StockForms.tsx @@ -39,7 +39,6 @@ import dayjs from 'dayjs'; import { type JSX, Suspense, - memo, useCallback, useEffect, useMemo, @@ -57,6 +56,7 @@ import { import { Thumbnail } from '../components/images/Thumbnail'; import { StatusRenderer } from '../components/render/StatusRenderer'; import { RenderStockLocation } from '../components/render/Stock'; +import { useWhyDidYouUpdate } from '../functions/debug'; import { InvenTreeIcon } from '../functions/icons'; import { useApiFormModal, @@ -636,6 +636,18 @@ function StockOperationsRow({ }) { const rowId = props.rowId; + useWhyDidYouUpdate('StockOperationsRow', { + props, + transfer, + changeStatus, + add, + setMax, + merge, + transferMerge, + returnStock, + record + }); + const statusOptions: ApiFormFieldChoice[] = useMemo(() => { return ( StatusFilterOptions(ModelType.stockitem)()?.map((choice) => { @@ -878,39 +890,6 @@ function StockOperationsRow({ ); } -// Memoize each stock operations row, so that we don't re-render the entire table when a single row is updated -const MemoizedStockOperationsRow = memo( - StockOperationsRow, - (previousProps, nextProps) => { - const prevItem = previousProps.props.item; - const nextItem = nextProps.props.item; - - const itemUnchanged = - prevItem === nextItem || - (prevItem?.pk === nextItem?.pk && - prevItem?.quantity === nextItem?.quantity && - prevItem?.status === nextItem?.status && - prevItem?.packaging === nextItem?.packaging && - prevItem?.merge === nextItem?.merge); - - return ( - previousProps.props.rowId === nextProps.props.rowId && - itemUnchanged && - previousProps.props.rowErrors === nextProps.props.rowErrors && - previousProps.props.changeFn === nextProps.props.changeFn && - previousProps.props.removeFn === nextProps.props.removeFn && - previousProps.record === nextProps.record && - previousProps.transfer === nextProps.transfer && - previousProps.changeStatus === nextProps.changeStatus && - previousProps.add === nextProps.add && - previousProps.setMax === nextProps.setMax && - previousProps.merge === nextProps.merge && - previousProps.transferMerge === nextProps.transferMerge && - previousProps.returnStock === nextProps.returnStock - ); - } -); - type StockItemQuantity = number | '' | undefined; type StockAdjustmentItem = { @@ -959,7 +938,7 @@ function stockTransferFields( const record = records[row.item.pk]; return ( - ); @@ -1146,16 +1125,14 @@ function stockAddFields(items: any[]): ApiFormFieldSet { } function stockCountFields(items: any[]): ApiFormFieldSet { - if (!items) { - return {}; - } + const records = Object.fromEntries( + items?.map((item) => [item.pk, item]) ?? [] + ); - const records = Object.fromEntries(items.map((item) => [item.pk, item])); - - const initialValue = mapAdjustmentItems(items); + const initialValue = items ? mapAdjustmentItems(items) : []; // Extract all location values from the items - const locations = [...new Set(items.map((item) => item.location))]; + const locations = [...new Set(items?.map((item) => item.location))]; const fields: ApiFormFieldSet = { items: { @@ -1163,11 +1140,11 @@ function stockCountFields(items: any[]): ApiFormFieldSet { value: initialValue, modelRenderer: (row: TableFieldRowProps) => { return ( - ); }, @@ -1212,7 +1189,7 @@ function stockChangeStatusFields(items: any[]): ApiFormFieldSet { }), modelRenderer: (row: TableFieldRowProps) => { return ( - { return ( - { return ( - { return lineItems.map((item) => { - console.log('line:', item); return { id: item.pk, ...item