mirror of
https://github.com/christianvidalwolf-prog/Craze-Data-check.git
synced 2026-08-03 11:05:24 +02:00
feat: standardize Weight Issues filter to use ColumnFilterPopover
This commit is contained in:
@@ -1,14 +0,0 @@
|
||||
|
||||
> react-example@0.0.0 lint
|
||||
> tsc --noEmit
|
||||
|
||||
src/components/PricingView.tsx(200,25): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.
|
||||
src/components/PricingView.tsx(201,26): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.
|
||||
src/components/PricingView.tsx(203,23): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.
|
||||
src/components/PricingView.tsx(1042,16): error TS2741: Property 'triggerId' is missing in type '{ value: { terms: string[]; op: "and" | "or"; }; onChange: (value: { terms: string[]; op: "and" | "or"; } | ((prev: { terms: string[]; op: "and" | "or"; }) => { terms: string[]; op: "and" | "or"; })) => void; onClose: () => any; }' but required in type '{ value: { terms: string[]; op: "and" | "or"; }; onChange: (v: { terms: string[]; op: "and" | "or"; }) => void; onClose: () => void; triggerId: string; }'.
|
||||
src/components/PricingView.tsx(1304,23): error TS2322: Type '{ triggerId: string; value: { terms: string[]; op: "and" | "or"; }; onChange: (value: { terms: string[]; op: "and" | "or"; } | ((prev: { terms: string[]; op: "and" | "or"; }) => { terms: string[]; op: "and" | "or"; })) => void; onClose: () => any; zIndex: number; }' is not assignable to type '{ value: { terms: string[]; op: "and" | "or"; }; onChange: (v: { terms: string[]; op: "and" | "or"; }) => void; onClose: () => void; triggerId: string; }'.
|
||||
Property 'zIndex' does not exist on type '{ value: { terms: string[]; op: "and" | "or"; }; onChange: (v: { terms: string[]; op: "and" | "or"; }) => void; onClose: () => void; triggerId: string; }'.
|
||||
src/components/PricingView.tsx(1339,23): error TS2322: Type '{ triggerId: string; value: { terms: string[]; op: "and" | "or"; }; onChange: (value: { terms: string[]; op: "and" | "or"; } | ((prev: { terms: string[]; op: "and" | "or"; }) => { terms: string[]; op: "and" | "or"; })) => void; onClose: () => any; zIndex: number; }' is not assignable to type '{ value: { terms: string[]; op: "and" | "or"; }; onChange: (v: { terms: string[]; op: "and" | "or"; }) => void; onClose: () => void; triggerId: string; }'.
|
||||
Property 'zIndex' does not exist on type '{ value: { terms: string[]; op: "and" | "or"; }; onChange: (v: { terms: string[]; op: "and" | "or"; }) => void; onClose: () => void; triggerId: string; }'.
|
||||
src/components/ProductDescriptions.tsx(205,21): error TS2304: Cannot find name 'TabType'.
|
||||
src/types.ts(50,14): error TS2740: Type '{ ARTICLE_NO: string[]; ARTICLE_NAME: string[]; LINE: string[]; LICENSE: string[]; DETAILS_EN: string[]; DETAILS_DE: string[]; BARCODE: string[]; TARIFF_CODE: string[]; COUNTRY_ORIGIN: string[]; LONG_DE: string[]; ... 15 more ...; OUTER_H: string[]; }' is missing the following properties from type 'Record<"ASIN" | "ARTICLE_NO" | "ARTICLE_NAME" | "LINE" | "LICENSE" | "DETAILS_EN" | "DETAILS_DE" | "BARCODE" | "TARIFF_CODE" | "COUNTRY_ORIGIN" | "LONG_DE" | "LONG_EN" | "SHORT_DE" | ... 19 more ... | "ANNA_NOTE", string[]>': VERIFIED_DIMS, VALIDATED_CHECK, VALIDATED_NOTE, PRODUCT_TYPE, and 3 more.
|
||||
@@ -105,7 +105,7 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
||||
const [checkYingFilter, setCheckYingFilter] = usePersistentState<string[]>('pricing-checkYingFilter', []);
|
||||
const [checkAnnaFilter, setCheckAnnaFilter] = usePersistentState<string[]>('pricing-checkAnnaFilter', []);
|
||||
const [dynamicColFilters, setDynamicColFilters] = usePersistentState<Record<number, string[]>>('pricing-dynamicColFilters', {});
|
||||
const [weightIssueFilter, setWeightIssueFilter] = usePersistentState<'all' | 'with' | 'without'>('pricing-weightIssueFilter', 'all');
|
||||
const [weightIssueFilter, setWeightIssueFilter] = usePersistentState<string[]>('pricing-weightIssueFilter', []);
|
||||
const [selectedSearchItems, setSelectedSearchItems] = usePersistentState<Set<string>>('pricing-selectedSearchItems', new Set());
|
||||
const [openFilter, setOpenFilter] = useState<string | null>(null);
|
||||
const [isSearchOpen, setIsSearchOpen] = useState(false);
|
||||
@@ -115,15 +115,12 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
||||
const [pinnedColumns, setPinnedColumns] = usePersistentState<Set<string>>('pricing-pinnedColumns', new Set(['articleNo', 'articleName']));
|
||||
const [showPinPanel, setShowPinPanel] = useState(false);
|
||||
|
||||
// Drag-to-check state (Excel-style drag to toggle Check Ying)
|
||||
// Drag-to-select state (Excel-style row selection)
|
||||
const [dragSelectedRows, setDragSelectedRows] = useState<Set<number>>(new Set());
|
||||
const isDraggingRef = useRef(false);
|
||||
const dragStartIndexRef = useRef<number | null>(null);
|
||||
const dragCheckValueRef = useRef<boolean>(true); // what value to set on mouseup
|
||||
const lastDragIndexRef = useRef<number | null>(null);
|
||||
const visibleDataIndexesRef = useRef<number[]>([]);
|
||||
const dataRef = useRef(data);
|
||||
dataRef.current = data;
|
||||
|
||||
const handleRowMouseDown = useCallback((e: React.MouseEvent, dataIndex: number) => {
|
||||
if ((e.target as HTMLElement).closest('input, button, a')) return;
|
||||
@@ -131,10 +128,8 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
||||
isDraggingRef.current = true;
|
||||
dragStartIndexRef.current = dataIndex;
|
||||
lastDragIndexRef.current = dataIndex;
|
||||
// Toggle based on current state of the first row touched
|
||||
dragCheckValueRef.current = !dataRef.current[dataIndex]?.[COLUMNS.VALIDATED_CHECK];
|
||||
setDragSelectedRows(new Set([dataIndex]));
|
||||
}, [COLUMNS.VALIDATED_CHECK]);
|
||||
}, []);
|
||||
|
||||
const handleRowMouseEnter = useCallback((dataIndex: number) => {
|
||||
if (!isDraggingRef.current || dragStartIndexRef.current === null) return;
|
||||
@@ -155,19 +150,18 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const handleMouseUp = async () => {
|
||||
if (!isDraggingRef.current) return;
|
||||
isDraggingRef.current = false;
|
||||
const rows = new Set(dragSelectedRows);
|
||||
if (rows.size === 0) return;
|
||||
setDragSelectedRows(new Set());
|
||||
const targetValue = dragCheckValueRef.current;
|
||||
for (const idx of Array.from(rows)) {
|
||||
await handleToggleCheck(idx as number, targetValue);
|
||||
}
|
||||
};
|
||||
const handleMouseUp = () => { isDraggingRef.current = false; };
|
||||
document.addEventListener('mouseup', handleMouseUp);
|
||||
return () => document.removeEventListener('mouseup', handleMouseUp);
|
||||
}, []);
|
||||
|
||||
const applyCheckToSelection = useCallback(async (column: 'ying' | 'anna', value: boolean) => {
|
||||
const rows = Array.from(dragSelectedRows) as number[];
|
||||
setDragSelectedRows(new Set());
|
||||
for (const idx of rows) {
|
||||
if (column === 'ying') await handleToggleCheck(idx, value);
|
||||
else await handleToggleAnnaCheck(idx, value);
|
||||
}
|
||||
}, [dragSelectedRows]);
|
||||
|
||||
// Close search dropdown on click outside
|
||||
@@ -499,10 +493,13 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
||||
});
|
||||
|
||||
// Weight issue filter
|
||||
if (weightIssueFilter === 'with') {
|
||||
result = result.filter(r => r.unitErrors.some(e => e.startsWith('NW')));
|
||||
} else if (weightIssueFilter === 'without') {
|
||||
result = result.filter(r => !r.unitErrors.some(e => e.startsWith('NW')));
|
||||
if ((weightIssueFilter || []).length > 0) {
|
||||
result = result.filter(r => {
|
||||
const hasWeightError = r.unitErrors.some(e => e.startsWith('NW'));
|
||||
if (weightIssueFilter.includes('with') && hasWeightError) return true;
|
||||
if (weightIssueFilter.includes('without') && !hasWeightError) return true;
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -1792,30 +1789,27 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
||||
<div className="flex items-center gap-1">
|
||||
<span>Weight Issues</span>
|
||||
<button
|
||||
onClick={() => setOpenFilter(openFilter === 'weightIssue' ? null : 'weightIssue')}
|
||||
id="filter-trigger-weightIssue"
|
||||
onClick={(e) => { e.stopPropagation(); setOpenFilter(openFilter === 'weightIssue' ? null : 'weightIssue'); }}
|
||||
className={cn(
|
||||
'p-0.5 rounded hover:bg-slate-700 transition-colors shrink-0',
|
||||
weightIssueFilter !== 'all' ? 'text-red-400 bg-red-400/10' : 'text-slate-500 opacity-0 group-hover:opacity-100'
|
||||
'p-0.5 rounded hover:bg-slate-700 transition-colors shrink-0 filter-trigger-btn',
|
||||
(weightIssueFilter || []).length > 0 ? 'text-red-400 bg-red-400/10' : 'text-slate-500 opacity-0 group-hover:opacity-100'
|
||||
)}
|
||||
>
|
||||
<Filter className="w-3 h-3" />
|
||||
</button>
|
||||
</div>
|
||||
{openFilter === 'weightIssue' && (
|
||||
<div className="absolute top-full left-0 mt-1 w-44 bg-slate-800 border border-slate-700 rounded-lg shadow-2xl z-50 p-1 flex flex-col gap-0.5 animate-in fade-in zoom-in-95 duration-100">
|
||||
{(['all', 'with', 'without'] as const).map(opt => (
|
||||
<button
|
||||
key={opt}
|
||||
onClick={() => { setWeightIssueFilter(opt); setOpenFilter(null); }}
|
||||
className={cn(
|
||||
'w-full text-left px-3 py-1.5 rounded text-xs transition-colors',
|
||||
weightIssueFilter === opt ? 'bg-red-500/20 text-red-400' : 'text-slate-300 hover:bg-slate-700'
|
||||
)}
|
||||
>
|
||||
{opt === 'all' ? 'All' : opt === 'with' ? 'With weight issue' : 'No weight issue'}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<ColumnFilterPopover
|
||||
triggerId="filter-trigger-weightIssue"
|
||||
uniqueValues={['with', 'without']}
|
||||
selectedValues={weightIssueFilter || []}
|
||||
onToggle={val => setWeightIssueFilter(prev => (prev || []).includes(val) ? (prev || []).filter(v => v !== val) : [...(prev || []), val])}
|
||||
onSelectAll={vals => setWeightIssueFilter(vals || [])}
|
||||
onClear={() => { setWeightIssueFilter([]); setOpenFilter(null); }}
|
||||
onClose={() => setOpenFilter(null)}
|
||||
zIndex={50}
|
||||
/>
|
||||
)}
|
||||
</th>
|
||||
|
||||
@@ -1833,6 +1827,17 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
||||
<Filter className="w-3 h-3" />
|
||||
</button>
|
||||
</div>
|
||||
{dragSelectedRows.size > 0 && (
|
||||
<div className="flex items-center gap-1 mt-1" onClick={(e: React.MouseEvent) => e.stopPropagation()}>
|
||||
<input
|
||||
type="checkbox"
|
||||
title={`Marcar Check Ying en ${dragSelectedRows.size} filas`}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => applyCheckToSelection('ying', e.target.checked)}
|
||||
className="w-3.5 h-3.5 rounded border-blue-500 bg-slate-900 text-blue-600 cursor-pointer"
|
||||
/>
|
||||
<span className="text-[10px] text-blue-300 whitespace-nowrap">{dragSelectedRows.size} filas</span>
|
||||
</div>
|
||||
)}
|
||||
{openFilter === 'check' && (
|
||||
<ColumnFilterPopover
|
||||
triggerId="filter-trigger-check"
|
||||
@@ -1862,6 +1867,17 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
||||
<Filter className="w-3 h-3" />
|
||||
</button>
|
||||
</div>
|
||||
{dragSelectedRows.size > 0 && (
|
||||
<div className="flex items-center gap-1 mt-1" onClick={(e: React.MouseEvent) => e.stopPropagation()}>
|
||||
<input
|
||||
type="checkbox"
|
||||
title={`Marcar Check Anna en ${dragSelectedRows.size} filas`}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => applyCheckToSelection('anna', e.target.checked)}
|
||||
className="w-3.5 h-3.5 rounded border-pink-500 bg-slate-900 text-pink-600 cursor-pointer"
|
||||
/>
|
||||
<span className="text-[10px] text-pink-300 whitespace-nowrap">{dragSelectedRows.size} filas</span>
|
||||
</div>
|
||||
)}
|
||||
{openFilter === 'checkAnna' && (
|
||||
<ColumnFilterPopover
|
||||
triggerId="filter-trigger-checkAnna"
|
||||
|
||||
Reference in New Issue
Block a user