mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 09:33:46 +00:00
fix: scope selector UX, ARIA, and code quality improvements
- removeScope preserves graph state when items remain (only resets on empty) - Extract shared CheckIcon, CloseIcon, Spinner, ScopeListItem components - Unify three handleSelect* into single handleToggle - Fix shared mutable Set in reset state (factory function) - Add MAX_SCOPE_ITEMS UI feedback (disabled button, warning banner) - Correct ARIA: dialog > tablist + listbox > option structure - Event listeners only attached when dropdown is open - isSelected uses Set lookup via useMemo instead of O(n) scan - Clear user search only on add, not on deselect
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { create } from 'zustand';
|
||||
import type { SelectedNode, NetworkFilters, ScopeSelection } from '@/types/referralNetwork';
|
||||
|
||||
const MAX_SCOPE_ITEMS = 50;
|
||||
export const MAX_SCOPE_ITEMS = 50;
|
||||
|
||||
const DEFAULT_FILTERS: NetworkFilters = {
|
||||
campaigns: [],
|
||||
@@ -9,6 +9,15 @@ const DEFAULT_FILTERS: NetworkFilters = {
|
||||
minReferrals: 0,
|
||||
};
|
||||
|
||||
function resetGraphState() {
|
||||
return {
|
||||
selectedNode: null as SelectedNode,
|
||||
hoveredNodeId: null as string | null,
|
||||
highlightedNodes: new Set<string>(),
|
||||
filters: { ...DEFAULT_FILTERS },
|
||||
};
|
||||
}
|
||||
|
||||
interface ReferralNetworkState {
|
||||
selectedNode: SelectedNode;
|
||||
hoveredNodeId: string | null;
|
||||
@@ -51,28 +60,22 @@ export const useReferralNetworkStore = create<ReferralNetworkState>()((set) => (
|
||||
if (state.scope.length >= MAX_SCOPE_ITEMS) return state;
|
||||
return {
|
||||
scope: [...state.scope, item],
|
||||
selectedNode: null,
|
||||
hoveredNodeId: null,
|
||||
highlightedNodes: new Set<string>(),
|
||||
filters: { ...DEFAULT_FILTERS },
|
||||
...resetGraphState(),
|
||||
};
|
||||
}),
|
||||
|
||||
removeScope: (type, id) =>
|
||||
set((state) => ({
|
||||
scope: state.scope.filter((s) => !(s.type === type && s.id === id)),
|
||||
selectedNode: null,
|
||||
hoveredNodeId: null,
|
||||
highlightedNodes: new Set<string>(),
|
||||
filters: { ...DEFAULT_FILTERS },
|
||||
})),
|
||||
set((state) => {
|
||||
const next = state.scope.filter((s) => !(s.type === type && s.id === id));
|
||||
if (next.length === 0) {
|
||||
return { scope: next, ...resetGraphState() };
|
||||
}
|
||||
return { scope: next };
|
||||
}),
|
||||
|
||||
clearScope: () =>
|
||||
set({
|
||||
scope: [],
|
||||
selectedNode: null,
|
||||
hoveredNodeId: null,
|
||||
highlightedNodes: new Set<string>(),
|
||||
filters: { ...DEFAULT_FILTERS },
|
||||
...resetGraphState(),
|
||||
}),
|
||||
}));
|
||||
|
||||
Reference in New Issue
Block a user