Files
EstiMaker/src/components/estimate-builder/useSelectionManager.ts
T

77 lines
3.0 KiB
TypeScript

import { createSignal } from 'solid-js';
import { appStore } from '../../store/appStore';
import type { EstimateItem } from '../../types';
export function useSelectionManager() {
const [selectedIds, setSelectedIds] = createSignal<string[]>([]);
const [lastSelectedId, setLastSelectedId] = createSignal<string | null>(null);
const getVisualOrderedItems = () => {
const { estimateItems: items, scopes, subScopes } = appStore;
const ordered: EstimateItem[] = [];
ordered.push(...items.filter(i => !i.scopeId));
scopes.forEach(scope => {
ordered.push(...items.filter(i => i.scopeId === scope.id && !i.subScopeId));
subScopes.filter(ss => ss.scopeId === scope.id).forEach(ss => {
ordered.push(...items.filter(i => i.subScopeId === ss.id));
});
});
return ordered;
};
const toggleSelection = (id: string, isMulti: boolean, isShift: boolean = false) => {
if (isShift && lastSelectedId()) {
const orderedItems = getVisualOrderedItems();
const lastIdx = orderedItems.findIndex(i => i.id === lastSelectedId());
const currentIdx = orderedItems.findIndex(i => i.id === id);
if (lastIdx !== -1 && currentIdx !== -1) {
const start = Math.min(lastIdx, currentIdx);
const end = Math.max(lastIdx, currentIdx);
const rangeIds = orderedItems.slice(start, end + 1).map(i => i.id);
setSelectedIds(prev => {
const newSet = new Set(prev);
rangeIds.forEach(rid => newSet.add(rid));
return Array.from(newSet);
});
}
} else if (isMulti) {
setSelectedIds(prev => prev.includes(id)
? prev.filter(i => i !== id)
: [...prev, id]
);
} else {
if (selectedIds().includes(id) && selectedIds().length === 1) {
setSelectedIds([]);
} else {
setSelectedIds([id]);
}
}
setLastSelectedId(id);
};
const clearSelection = (e?: MouseEvent) => {
if (!e || e.target === e.currentTarget) {
setSelectedIds([]);
setLastSelectedId(null);
}
};
const copyColumnSum = (column: 'quantity'|'unitPrice'|'subtotal'|'markup'|'contingency'|'total', val: number, setCopyToast: (msg: string | null) => void) => {
navigator.clipboard.writeText(String(val)).then(() => {
const labels: Record<string, string> = {
quantity: 'Qty', unitPrice: 'Price', subtotal: 'Subtotal',
markup: 'Markup', contingency: 'Contingency', total: 'Total'
};
setCopyToast(`Copied ${labels[column]}: ${val}`);
setTimeout(() => setCopyToast(null), 2500);
});
};
return { selectedIds, setSelectedIds, lastSelectedId, setLastSelectedId, toggleSelection, clearSelection, copyColumnSum };
}