Restore line and subline fields
This commit is contained in:
@@ -99,6 +99,8 @@ const BaseCellContent = React.memo(({
|
||||
(field.fieldType.type === 'input' || field.fieldType.type === 'multi-input') &&
|
||||
field.fieldType.price === true;
|
||||
|
||||
console.log(`BaseCellContent: field.key=${field.key}, fieldType=${fieldType}, disabled=${field.disabled}, options=`, options);
|
||||
|
||||
if (fieldType === 'select') {
|
||||
return (
|
||||
<SelectCell
|
||||
@@ -108,6 +110,7 @@ const BaseCellContent = React.memo(({
|
||||
options={options}
|
||||
hasErrors={hasErrors}
|
||||
className={className}
|
||||
disabled={field.disabled}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -121,6 +124,7 @@ const BaseCellContent = React.memo(({
|
||||
options={options}
|
||||
hasErrors={hasErrors}
|
||||
className={className}
|
||||
disabled={field.disabled}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -133,6 +137,7 @@ const BaseCellContent = React.memo(({
|
||||
hasErrors={hasErrors}
|
||||
isMultiline={isMultiline}
|
||||
isPrice={isPrice}
|
||||
disabled={field.disabled}
|
||||
/>
|
||||
);
|
||||
}, (prev, next) => {
|
||||
@@ -605,6 +610,8 @@ const ValidationCell = ({
|
||||
</div>
|
||||
) : (
|
||||
<div className={`truncate overflow-hidden ${isCopyDownHovered && !copyDownContext.isInCopyDownMode ? 'bg-blue-50/50' : ''}`}>
|
||||
{/* Log options for debugging */}
|
||||
{(() => { console.log(`ValidationCell: fieldKey=${fieldKey}, options=`, options); return null; })()}
|
||||
<BaseCellContent
|
||||
field={field}
|
||||
value={value}
|
||||
|
||||
@@ -119,6 +119,8 @@ const ValidationContainer = <T extends string>({
|
||||
// Only fetch if we have a valid company ID
|
||||
if (!companyId) return;
|
||||
|
||||
console.log(`Fetching product lines for row ${rowIndex}, company ${companyId}`);
|
||||
|
||||
// Set loading state for this row
|
||||
setIsLoadingLines(prev => ({ ...prev, [rowIndex]: true }));
|
||||
|
||||
@@ -129,6 +131,7 @@ const ValidationContainer = <T extends string>({
|
||||
}
|
||||
|
||||
const productLines = await response.json();
|
||||
console.log(`Received product lines for row ${rowIndex}:`, productLines);
|
||||
|
||||
// Store the product lines for this specific row
|
||||
setRowProductLines(prev => ({ ...prev, [rowIndex]: productLines }));
|
||||
@@ -148,6 +151,8 @@ const ValidationContainer = <T extends string>({
|
||||
// Only fetch if we have a valid line ID
|
||||
if (!lineId) return;
|
||||
|
||||
console.log(`Fetching sublines for row ${rowIndex}, line ${lineId}`);
|
||||
|
||||
// Set loading state for this row
|
||||
setIsLoadingSublines(prev => ({ ...prev, [rowIndex]: true }));
|
||||
|
||||
@@ -158,6 +163,7 @@ const ValidationContainer = <T extends string>({
|
||||
}
|
||||
|
||||
const sublines = await response.json();
|
||||
console.log(`Received sublines for row ${rowIndex}:`, sublines);
|
||||
|
||||
// Store the sublines for this specific row
|
||||
setRowSublines(prev => ({ ...prev, [rowIndex]: sublines }));
|
||||
@@ -365,6 +371,7 @@ const ValidationContainer = <T extends string>({
|
||||
// Enhanced updateRow function - memoized
|
||||
const enhancedUpdateRow = useCallback(async (rowIndex: number, fieldKey: T, value: any) => {
|
||||
// Process value before updating data
|
||||
console.log(`enhancedUpdateRow called: rowIndex=${rowIndex}, fieldKey=${fieldKey}, value=`, value);
|
||||
let processedValue = value;
|
||||
|
||||
// Strip dollar signs from price fields
|
||||
@@ -921,9 +928,13 @@ const ValidationContainer = <T extends string>({
|
||||
itemNumbers={itemNumbersMap}
|
||||
isLoadingTemplates={isLoadingTemplates}
|
||||
copyDown={handleCopyDown}
|
||||
rowProductLines={rowProductLines}
|
||||
rowSublines={rowSublines}
|
||||
isLoadingLines={isLoadingLines}
|
||||
isLoadingSublines={isLoadingSublines}
|
||||
/>
|
||||
);
|
||||
}), [validatingUpcRows, itemNumbers, isLoadingTemplates, handleCopyDown, validatingCells]);
|
||||
}), [validatingUpcRows, itemNumbers, isLoadingTemplates, handleCopyDown, validatingCells, rowProductLines, rowSublines, isLoadingLines, isLoadingSublines]);
|
||||
|
||||
// Memoize the rendered validation table
|
||||
const renderValidationTable = useMemo(() => (
|
||||
@@ -945,6 +956,10 @@ const ValidationContainer = <T extends string>({
|
||||
isLoadingTemplates={isLoadingTemplates}
|
||||
copyDown={handleCopyDown}
|
||||
upcValidationResults={new Map()}
|
||||
rowProductLines={rowProductLines}
|
||||
rowSublines={rowSublines}
|
||||
isLoadingLines={isLoadingLines}
|
||||
isLoadingSublines={isLoadingSublines}
|
||||
/>
|
||||
), [
|
||||
EnhancedValidationTable,
|
||||
@@ -961,7 +976,11 @@ const ValidationContainer = <T extends string>({
|
||||
applyTemplate,
|
||||
getTemplateDisplayText,
|
||||
isLoadingTemplates,
|
||||
handleCopyDown
|
||||
handleCopyDown,
|
||||
rowProductLines,
|
||||
rowSublines,
|
||||
isLoadingLines,
|
||||
isLoadingSublines
|
||||
]);
|
||||
|
||||
// Add scroll container ref at the container level
|
||||
|
||||
@@ -166,10 +166,18 @@ const ValidationTable = <T extends string>({
|
||||
validatingCells,
|
||||
itemNumbers,
|
||||
isLoadingTemplates = false,
|
||||
copyDown
|
||||
copyDown,
|
||||
rowProductLines = {},
|
||||
rowSublines = {},
|
||||
isLoadingLines = {},
|
||||
isLoadingSublines = {}
|
||||
}: ValidationTableProps<T>) => {
|
||||
const { translations } = useRsi<T>();
|
||||
|
||||
// Debug logs
|
||||
console.log('ValidationTable rowProductLines:', rowProductLines);
|
||||
console.log('ValidationTable rowSublines:', rowSublines);
|
||||
|
||||
// Add state for copy down selection mode
|
||||
const [isInCopyDownMode, setIsInCopyDownMode] = useState(false);
|
||||
const [sourceRowIndex, setSourceRowIndex] = useState<number | null>(null);
|
||||
@@ -285,7 +293,7 @@ const ValidationTable = <T extends string>({
|
||||
const cache = new Map<string, readonly any[]>();
|
||||
|
||||
fields.forEach((field) => {
|
||||
if (field.disabled) return;
|
||||
// Don't skip disabled fields
|
||||
|
||||
if (field.fieldType.type === 'select' || field.fieldType.type === 'multi-select') {
|
||||
const fieldKey = String(field.key);
|
||||
@@ -308,7 +316,7 @@ const ValidationTable = <T extends string>({
|
||||
|
||||
// Memoize field columns with stable handlers
|
||||
const fieldColumns = useMemo(() => fields.map((field): ColumnDef<RowData<T>, any> | null => {
|
||||
if (field.disabled) return null;
|
||||
// Don't filter out disabled fields, just pass the disabled state to the cell component
|
||||
|
||||
const fieldWidth = field.width || (
|
||||
field.fieldType.type === "checkbox" ? 80 :
|
||||
@@ -327,25 +335,51 @@ const ValidationTable = <T extends string>({
|
||||
accessorKey: fieldKey,
|
||||
header: field.label || fieldKey,
|
||||
size: fieldWidth,
|
||||
cell: ({ row }) => (
|
||||
<MemoizedCell
|
||||
field={field as Field<string>}
|
||||
value={row.original[field.key as keyof typeof row.original]}
|
||||
onChange={(value) => handleFieldUpdate(row.index, field.key as T, value)}
|
||||
errors={validationErrors.get(row.index)?.[fieldKey] || []}
|
||||
isValidating={validatingCells.has(`${row.index}-${field.key}`)}
|
||||
fieldKey={fieldKey}
|
||||
options={fieldOptions}
|
||||
itemNumber={itemNumbers.get(row.index)}
|
||||
width={fieldWidth}
|
||||
rowIndex={row.index}
|
||||
copyDown={(endRowIndex?: number) => handleCopyDown(row.index, field.key as string, endRowIndex)}
|
||||
totalRows={data.length}
|
||||
/>
|
||||
)
|
||||
cell: ({ row }) => {
|
||||
// Get row-specific options for line and subline fields
|
||||
let options = fieldOptions;
|
||||
const rowId = row.original.__index;
|
||||
|
||||
if (fieldKey === 'line' && rowId && rowProductLines[rowId]) {
|
||||
options = rowProductLines[rowId];
|
||||
console.log(`Setting line options for row ${rowId}:`, options);
|
||||
} else if (fieldKey === 'subline' && rowId && rowSublines[rowId]) {
|
||||
options = rowSublines[rowId];
|
||||
console.log(`Setting subline options for row ${rowId}:`, options);
|
||||
}
|
||||
|
||||
// Determine if this cell is in loading state
|
||||
let isLoading = validatingCells.has(`${row.index}-${field.key}`);
|
||||
|
||||
// Add loading state for line/subline fields
|
||||
if (fieldKey === 'line' && rowId && isLoadingLines[rowId]) {
|
||||
isLoading = true;
|
||||
console.log(`Line field for row ${rowId} is loading`);
|
||||
} else if (fieldKey === 'subline' && rowId && isLoadingSublines[rowId]) {
|
||||
isLoading = true;
|
||||
console.log(`Subline field for row ${rowId} is loading`);
|
||||
}
|
||||
|
||||
return (
|
||||
<MemoizedCell
|
||||
field={field as Field<string>}
|
||||
value={row.original[field.key as keyof typeof row.original]}
|
||||
onChange={(value) => handleFieldUpdate(row.index, field.key as T, value)}
|
||||
errors={validationErrors.get(row.index)?.[fieldKey] || []}
|
||||
isValidating={isLoading}
|
||||
fieldKey={fieldKey}
|
||||
options={options}
|
||||
itemNumber={itemNumbers.get(row.index)}
|
||||
width={fieldWidth}
|
||||
rowIndex={row.index}
|
||||
copyDown={(endRowIndex?: number) => handleCopyDown(row.index, field.key as string, endRowIndex)}
|
||||
totalRows={data.length}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
}).filter((col): col is ColumnDef<RowData<T>, any> => col !== null),
|
||||
[fields, validationErrors, validatingCells, itemNumbers, handleFieldUpdate, handleCopyDown, optionsCache, data.length]);
|
||||
[fields, validationErrors, validatingCells, itemNumbers, handleFieldUpdate, handleCopyDown, optionsCache, data.length, rowProductLines, rowSublines, isLoadingLines, isLoadingSublines]);
|
||||
|
||||
// Combine columns
|
||||
const columns = useMemo(() => [selectionColumn, templateColumn, ...fieldColumns], [selectionColumn, templateColumn, fieldColumns]);
|
||||
|
||||
@@ -51,6 +51,8 @@ const SelectCell = <T extends string>({
|
||||
// Add state for hover
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
|
||||
console.log(`SelectCell: field.key=${field.key}, disabled=${disabled}, options=`, options);
|
||||
|
||||
// Helper function to check if a class is present in the className string
|
||||
const hasClass = (cls: string): boolean => {
|
||||
const classNames = className.split(' ');
|
||||
@@ -66,6 +68,7 @@ const SelectCell = <T extends string>({
|
||||
|
||||
// Memoize options processing to avoid recalculation on every render
|
||||
const selectOptions = useMemo(() => {
|
||||
console.log(`Processing options for ${field.key}:`, options);
|
||||
// Fast path check - if we have raw options, just use those
|
||||
if (options && options.length > 0) {
|
||||
// Check if options already have the correct structure to avoid mapping
|
||||
@@ -146,31 +149,95 @@ const SelectCell = <T extends string>({
|
||||
if (disabled) {
|
||||
const displayText = displayValue;
|
||||
|
||||
// For debugging, let's render the Popover component even if disabled
|
||||
// This will help us determine if the issue is with the disabled state
|
||||
return (
|
||||
<div className={cn(
|
||||
"w-full px-3 py-2 h-10 rounded-md text-sm flex items-center",
|
||||
"border",
|
||||
hasErrors ? "border-destructive" : "border-input",
|
||||
isProcessing ? "text-muted-foreground" : "",
|
||||
className
|
||||
)}
|
||||
style={{
|
||||
backgroundColor: hasClass('!bg-blue-100') ? '#dbeafe' :
|
||||
hasClass('!bg-blue-200') ? '#bfdbfe' :
|
||||
hasClass('hover:!bg-blue-100') && isHovered ? '#dbeafe' :
|
||||
undefined,
|
||||
borderColor: hasClass('!border-blue-500') ? '#3b82f6' :
|
||||
hasClass('!border-blue-200') ? '#bfdbfe' :
|
||||
hasClass('!border-blue-200') && isHovered ? '#bfdbfe' :
|
||||
undefined,
|
||||
borderRadius: hasClass('!rounded-md') ? '0.375rem' : undefined,
|
||||
cursor: hasClass('hover:!bg-blue-100') ? 'pointer' : undefined
|
||||
}}
|
||||
onMouseEnter={() => setIsHovered(true)}
|
||||
onMouseLeave={() => setIsHovered(false)}
|
||||
<Popover
|
||||
open={open}
|
||||
onOpenChange={(isOpen) => {
|
||||
setOpen(isOpen);
|
||||
if (isOpen && onStartEdit) onStartEdit();
|
||||
}}
|
||||
>
|
||||
{displayText || ""}
|
||||
</div>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
aria-expanded={open}
|
||||
className={cn(
|
||||
"w-full justify-between font-normal",
|
||||
"border",
|
||||
!internalValue && "text-muted-foreground",
|
||||
isProcessing && "text-muted-foreground",
|
||||
hasErrors ? "border-destructive" : "",
|
||||
className
|
||||
)}
|
||||
style={{
|
||||
backgroundColor: hasClass('!bg-blue-100') ? '#dbeafe' :
|
||||
hasClass('!bg-blue-200') ? '#bfdbfe' :
|
||||
hasClass('hover:!bg-blue-100') && isHovered ? '#dbeafe' :
|
||||
undefined,
|
||||
borderColor: hasClass('!border-blue-500') ? '#3b82f6' :
|
||||
hasClass('!border-blue-200') ? '#bfdbfe' :
|
||||
hasClass('!border-blue-200') && isHovered ? '#bfdbfe' :
|
||||
undefined,
|
||||
borderRadius: hasClass('!rounded-md') ? '0.375rem' : undefined,
|
||||
borderWidth: hasClass('!border-blue-500') || hasClass('!border-blue-200') ? '0px' : undefined,
|
||||
cursor: hasClass('hover:!bg-blue-100') ? 'pointer' : undefined
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setOpen(!open);
|
||||
if (!open && onStartEdit) onStartEdit();
|
||||
}}
|
||||
onMouseEnter={() => setIsHovered(true)}
|
||||
onMouseLeave={() => setIsHovered(false)}
|
||||
>
|
||||
<span className={isProcessing ? "opacity-70" : ""}>
|
||||
{displayValue}
|
||||
</span>
|
||||
<ChevronsUpDown className="mr-1.5 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent
|
||||
className="p-0 w-[var(--radix-popover-trigger-width)]"
|
||||
align="start"
|
||||
sideOffset={4}
|
||||
>
|
||||
<Command shouldFilter={true}>
|
||||
<CommandInput
|
||||
placeholder="Search..."
|
||||
className="h-9"
|
||||
/>
|
||||
<CommandList
|
||||
ref={commandListRef}
|
||||
onWheel={handleWheel}
|
||||
className="max-h-[200px]"
|
||||
>
|
||||
<CommandEmpty>No options found.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
{selectOptions.map((option) => (
|
||||
<CommandItem
|
||||
key={option.value}
|
||||
value={option.value}
|
||||
onSelect={(value) => handleSelect(value)}
|
||||
className="flex w-full"
|
||||
>
|
||||
<Check
|
||||
className={cn(
|
||||
"mr-2 h-4 w-4 flex-shrink-0",
|
||||
internalValue === option.value ? "opacity-100" : "opacity-0"
|
||||
)}
|
||||
/>
|
||||
<span className="truncate w-full">{option.label}</span>
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user