import { create } from 'zustand'; import type { SelectedNode, NetworkFilters, ScopeSelection } from '@/types/referralNetwork'; export const MAX_SCOPE_ITEMS = 50; const DEFAULT_FILTERS: NetworkFilters = { campaigns: [], partnersOnly: false, minReferrals: 0, }; function resetGraphState() { return { selectedNode: null as SelectedNode, hoveredNodeId: null as string | null, highlightedNodes: new Set(), filters: { ...DEFAULT_FILTERS }, }; } interface ReferralNetworkState { selectedNode: SelectedNode; hoveredNodeId: string | null; highlightedNodes: Set; filters: NetworkFilters; scope: ScopeSelection[]; isFullNetwork: boolean; setSelectedNode: (node: SelectedNode) => void; setHoveredNode: (id: string | null) => void; setHighlightedNodes: (nodes: Set) => void; updateFilters: (filters: Partial) => void; resetFilters: () => void; setFullNetwork: (enabled: boolean) => void; addScope: (item: ScopeSelection) => void; removeScope: (type: ScopeSelection['type'], id: number) => void; clearScope: () => void; } export const useReferralNetworkStore = create()((set) => ({ selectedNode: null, hoveredNodeId: null, highlightedNodes: new Set(), filters: { ...DEFAULT_FILTERS }, scope: [], isFullNetwork: false, setSelectedNode: (node) => set({ selectedNode: node }), setHoveredNode: (id) => set({ hoveredNodeId: id }), setHighlightedNodes: (nodes) => set({ highlightedNodes: nodes }), updateFilters: (partial) => set((state) => ({ filters: { ...state.filters, ...partial }, })), resetFilters: () => set({ filters: { ...DEFAULT_FILTERS } }), // Full network and a scope selection are mutually exclusive: the whole graph // already contains every campaign, partner and user, so narrowing it by chips // would be meaningless. Each mode therefore drops the other. setFullNetwork: (enabled) => set({ isFullNetwork: enabled, scope: [], ...resetGraphState(), }), addScope: (item) => set((state) => { const exists = state.scope.some((s) => s.type === item.type && s.id === item.id); if (exists) return state; if (state.scope.length >= MAX_SCOPE_ITEMS) return state; return { scope: [...state.scope, item], isFullNetwork: false, ...resetGraphState(), }; }), removeScope: (type, id) => 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: [], isFullNetwork: false, ...resetGraphState(), }), }));