"use client"; /** * Client-only state for database UI. * * Owns (per frontend-architecture §4): * - active view per database (`?view=` is the source of truth when present; * this store persists the last choice so deep links work after reload), * - per-view ad-hoc filter/sort/group overrides (persisted to localStorage), * - selected record ids (bulk operations), * - the right-hand record panel (open record + origin). * * Server state (records, properties, views) lives in TanStack Query — never here. */ import { create } from "zustand"; import { persist, createJSONStorage } from "zustand/middleware"; export interface ViewOverrides { filter?: unknown | null; sort?: unknown[] | null; group?: unknown[] | null; searchText?: string; } interface DatabaseState { /** databaseId -> last active viewId */ activeViews: Record; /** `dbId:viewId` -> ad-hoc overrides on top of the saved view */ overrides: Record; /** Record ids selected in the active table/board (cleared on view/db change) */ selectedRecordIds: string[]; /** Record panel: open record id + where it was opened from (for "back") */ panelRecordId: string | null; panelDatabaseId: string | null; panelOpen: boolean; setActiveView: (databaseId: string, viewId: string) => void; setOverrides: (databaseId: string, viewId: string, patch: Partial) => void; clearOverrides: (databaseId: string, viewId: string) => void; toggleSelectedRecord: (recordId: string) => void; setSelectedRecords: (recordIds: string[]) => void; clearSelection: () => void; openPanel: (databaseId: string, recordId: string) => void; closePanel: () => void; } const key = (databaseId: string, viewId: string) => `${databaseId}:${viewId}`; export const useDatabaseStore = create()( persist( (set) => ({ activeViews: {}, overrides: {}, selectedRecordIds: [], panelRecordId: null, panelDatabaseId: null, panelOpen: false, setActiveView: (databaseId, viewId) => set((s) => ({ activeViews: { ...s.activeViews, [databaseId]: viewId } })), setOverrides: (databaseId, viewId, patch) => set((s) => { const k = key(databaseId, viewId); return { overrides: { ...s.overrides, [k]: { ...s.overrides[k], ...patch } } }; }), clearOverrides: (databaseId, viewId) => set((s) => { const k = key(databaseId, viewId); if (!s.overrides[k]) return s; const next = { ...s.overrides }; delete next[k]; return { overrides: next }; }), toggleSelectedRecord: (recordId) => set((s) => ({ selectedRecordIds: s.selectedRecordIds.includes(recordId) ? s.selectedRecordIds.filter((id) => id !== recordId) : [...s.selectedRecordIds, recordId] })), setSelectedRecords: (recordIds) => set({ selectedRecordIds: recordIds }), clearSelection: () => set({ selectedRecordIds: [] }), openPanel: (databaseId, recordId) => set({ panelDatabaseId: databaseId, panelRecordId: recordId, panelOpen: true }), closePanel: () => set({ panelOpen: false, panelRecordId: null, panelDatabaseId: null }) }), { name: "factory-database-store", storage: createJSONStorage(() => localStorage), // Only persist things that must survive a reload; selection/panel are transient. partialize: (s) => ({ activeViews: s.activeViews, overrides: s.overrides }) } ) );