diff --git a/docs/validate-table-changes.md b/docs/validate-table-changes.md index cdf123c..470ac3b 100644 --- a/docs/validate-table-changes.md +++ b/docs/validate-table-changes.md @@ -4,12 +4,11 @@ * Red outline + alert circle icon with tooltip if cell is NOT empty and isn't valid 5. Description column needs to have an expanded view of some sort, maybe a popover to allow for easier editing * Don't distort table to make it happen -7. The template select cell is expanding, needs to be fixed size and truncate 8. When you enter a value in 2+ cells before validation finishes, contents from all edited cells get erased when validation finishes 9. Import dialog state not fully reset when closing? (validate data step appears scrolled to the middle of the table where I left it) 10. UPC column doesn't need to show loading state when Item Number is being processed, only show on item number column 11. Copy down needs to show a loading state on the cells that it will copy to -12. Shipping restrictions/tax category should default to ID 0 if we didn't get it elsewhere +15. Enhance copy down feature by allowing user to choose the last cell to copy to, instead of going all the way to the bottom @@ -23,6 +22,8 @@ ✅FIXED 2. Columns alignment with header is slightly off, gets worse the further right you go ✅FIXED 3. The copy down button is in the way of the validation error icon and the select open trigger - all three need to be in unique locations ✅FIXED 6. Need to ensure all cell's contents don't overflow the input (truncate). COO does this currently, probably more +✅FIXED 7. The template select cell is expanding, needs to be fixed size and truncate +✅FIXED 12. Shipping restrictions/tax category should default to ID 0 if we didn't get it elsewhere ✅FIXED 13. Header row should be sticky (both up/down and left/right) ✅FIXED 14. Need a way to scroll around table if user doesn't have mouse wheel for left/right diff --git a/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/SearchableTemplateSelect.tsx b/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/SearchableTemplateSelect.tsx index b3ba9f1..1e5583c 100644 --- a/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/SearchableTemplateSelect.tsx +++ b/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/SearchableTemplateSelect.tsx @@ -172,7 +172,19 @@ const SearchableTemplateSelect: React.FC = ({ if (!value) return placeholder; const template = templates.find(t => t.id.toString() === value); if (!template) return placeholder; - return getTemplateDisplayText(value); + + // Get the original display text + const originalText = getTemplateDisplayText(value); + + // Check if it has the expected format "Brand - Product Type" + if (originalText.includes(' - ')) { + const [brand, productType] = originalText.split(' - ', 2); + // Reverse the order to "Product Type - Brand" + return `${productType} - ${brand}`; + } + + // If it doesn't match the expected format, return the original text + return originalText; } catch (err) { console.error('Error getting display text:', err); return placeholder; @@ -218,10 +230,10 @@ const SearchableTemplateSelect: React.FC = ({ variant="outline" role="combobox" aria-expanded={open} - className={cn("w-full justify-between", triggerClassName)} + className={cn("w-full justify-between overflow-hidden", triggerClassName)} > - {getDisplayText()} - + {getDisplayText()} + diff --git a/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationCell.tsx b/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationCell.tsx index fe50dbe..b290124 100644 --- a/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationCell.tsx +++ b/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationCell.tsx @@ -9,7 +9,7 @@ import { } from '@/components/ui/tooltip' import InputCell from './cells/InputCell' import SelectCell from './cells/SelectCell' -import MultiInputCell from './cells/MultiInputCell' +import MultiSelectCell from './cells/MultiSelectCell' import { TableCell } from '@/components/ui/table' // Define error object type @@ -88,7 +88,7 @@ const BaseCellContent = React.memo(({ if (fieldType === 'multi-select' || fieldType === 'multi-input') { return ( - { if (isLoading) { return ( - ); } @@ -217,15 +217,17 @@ const ValidationTable = ({ const rowIndex = data.findIndex(r => r === row.original); return ( - - handleTemplateChange(value, rowIndex)} - getTemplateDisplayText={getTemplateDisplayText} - defaultBrand={defaultBrand} - isLoading={isLoadingTemplates} - /> + +
+ handleTemplateChange(value, rowIndex)} + getTemplateDisplayText={getTemplateDisplayText} + defaultBrand={defaultBrand} + isLoading={isLoadingTemplates} + /> +
); } diff --git a/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/InputCell.tsx b/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/InputCell.tsx index b3eca85..8cdc9f9 100644 --- a/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/InputCell.tsx +++ b/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/cells/InputCell.tsx @@ -1,8 +1,8 @@ -import React, { useState, useCallback, useDeferredValue, useTransition, useRef, useEffect } from 'react' +import React, { useState, useCallback, useDeferredValue, useTransition, useRef, useEffect, useMemo } from 'react' import { Field } from '../../../../types' import { Input } from '@/components/ui/input' -import { Textarea } from '@/components/ui/textarea' import { cn } from '@/lib/utils' +import MultilineInput from './MultilineInput' interface InputCellProps { field: Field @@ -31,6 +31,7 @@ const formatPrice = (value: string): string => { }; const InputCell = ({ + field, value, onChange, onStartEdit, @@ -48,6 +49,18 @@ const InputCell = ({ // Use a ref to track if we need to process the value const needsProcessingRef = useRef(false); + // Track local display value to avoid waiting for validation + const [localDisplayValue, setLocalDisplayValue] = useState(null); + + // Initialize localDisplayValue on mount and when value changes externally + useEffect(() => { + if (localDisplayValue === null || + (typeof value === 'string' && typeof localDisplayValue === 'string' && + value.trim() !== localDisplayValue.trim())) { + setLocalDisplayValue(value); + } + }, [value, localDisplayValue]); + // Efficiently handle price formatting without multiple rerenders useEffect(() => { if (isPrice && needsProcessingRef.current && !isEditing) { @@ -93,6 +106,9 @@ const InputCell = ({ needsProcessingRef.current = true; } + // Update local display value immediately + setLocalDisplayValue(processedValue); + onChange(processedValue); onEndEdit?.(); }); @@ -104,14 +120,30 @@ const InputCell = ({ setEditValue(newValue); }, [isPrice]); - // Display value with efficient memoization - const displayValue = useDeferredValue( - isPrice && value ? - typeof value === 'number' ? value.toFixed(2) : - typeof value === 'string' && /^-?\d+(\.\d+)?$/.test(value) ? parseFloat(value).toFixed(2) : - value : - value ?? '' - ); + // Get the display value - prioritize local display value + const displayValue = useMemo(() => { + // First priority: local display value (for immediate updates) + if (localDisplayValue !== null) { + if (isPrice) { + // Format price value + const numValue = parseFloat(localDisplayValue); + return !isNaN(numValue) ? numValue.toFixed(2) : localDisplayValue; + } + return localDisplayValue; + } + + // Second priority: handle price formatting for the actual value + if (isPrice && value) { + if (typeof value === 'number') { + return value.toFixed(2); + } else if (typeof value === 'string' && /^-?\d+(\.\d+)?$/.test(value)) { + return parseFloat(value).toFixed(2); + } + } + + // Default: use the actual value or empty string + return value ?? ''; + }, [isPrice, value, localDisplayValue]); // Add outline even when not in focus const outlineClass = "border focus-visible:ring-0 focus-visible:ring-offset-0"; @@ -128,48 +160,48 @@ const InputCell = ({ ); } + + // Render multiline fields using the dedicated MultilineInput component + if (isMultiline) { + return ( + + ); + } + // Original component for non-multiline fields return (
- {isMultiline ? ( -