/** * Store types for @siesa/master-pattern-view * * Defines the combined state shape for the Zustand store factory. * Each interface corresponds to one slice of the store. * * @internal * @module store/types */ import type { StoreApi } from 'zustand'; import type { MasterPatternViewEntity } from '../types/service.types'; import type { FormMode, PendingAction } from '../types/internal.types'; export interface SearchParams { page: number; pageSize: number; search: string; sortBy: string; sortOrder: 'asc' | 'desc'; filters: ActiveFilter[]; } export interface ListState { searchParams: SearchParams; /** Column-level filters (written by ListTable header inputs). Kept separate from * FilterPanel filters so each mechanism is independent — FilterPanel "Buscar" * no longer wipes active column filters, and column inputs survive FilterPanel * searches. Both are merged in useMasterList before calling service.getAll(). */ columnFilters: ActiveFilter[]; /** Quick-filter values written by the inline toolbar QuickFilters inputs. * Stored as { fieldName: rawStringValue }. Converted to ActiveFilter[] with * operator 'contains' in useMasterList before merging with the other filter * channels. Cleared by clearFilters() alongside columnFilters. */ quickFilterValues: Record; data: T[]; total: number; isLoading: boolean; selectedIds: string[]; hasSearched: boolean; setSearchParams: (params: Partial) => void; setColumnFilters: (filters: ActiveFilter[]) => void; clearColumnFilters: () => void; setQuickFilterValues: (values: Record) => void; clearQuickFilters: () => void; setData: (data: T[], total: number) => void; setIsLoading: (isLoading: boolean) => void; toggleSelection: (id: string) => void; clearSelection: () => void; setHasSearched: (hasSearched: boolean) => void; } export interface FormState { mode: FormMode; activeRecord: T | null; values: Record; errors: Record; isDirty: boolean; isSaving: boolean; activeTabKey: string; /** True while getById is in-flight after opening edit/view — blocks form interaction. */ isLoadingRecord: boolean; /** True when getById failed — Guardar is disabled and an error banner is shown. */ recordLoadFailed: boolean; /** * Snapshot of the auto-seeded defaults (boolean fields defaulting to `true`, plus * `defaultCreateValues`) at the moment `openCreate()` ran — the "nothing touched yet" * baseline for a brand-new record. Used as the dirty-check's `original` instead of `{}` * while `mode === 'creating'`, so a field that merely carries its own default doesn't * register as a user change the instant the create form opens. */ initialCreateValues: Record; openCreate: () => void; openEdit: (record: T) => void; openView: (record: T) => void; closeForm: () => void; /** Update activeRecord in place (e.g. after async getById resolves with company-context entity). */ updateActiveRecord: (record: T) => void; setValues: (values: Record | ((prev: Record) => Record)) => void; /** * Merges into the `initialCreateValues` baseline without touching `values` — used when a * `defaultCreateValues` field arrives asynchronously (e.g. company → plan → currency) after * `openCreate()` already ran with an empty snapshot. Without this, that late default still * gets written to `values` (so the field visibly shows it) but never to the baseline, so the * dirty-check compares "has the default" against "baseline never had it" and reports a false * unsaved change the instant the async default lands — even though the user touched nothing. */ setInitialCreateValues: (values: Record) => void; setErrors: (errors: Record) => void; setIsDirty: (isDirty: boolean) => void; setIsSaving: (isSaving: boolean) => void; setActiveTabKey: (key: string) => void; setIsLoadingRecord: (loading: boolean) => void; setRecordLoadFailed: (failed: boolean) => void; } export interface ActiveFilter { field: string; operator: string; value: unknown; } export interface FilterState { isFilterPanelOpen: boolean; activeFilters: ActiveFilter[]; activeFilterCount: number; toggleFilterPanel: () => void; setFilterPanelOpen: (open: boolean) => void; setActiveFilters: (filters: ActiveFilter[]) => void; clearFilters: () => void; } export interface UIState { isChangeStatusModalOpen: boolean; isCompanyEnableModalOpen: boolean; isNotEnabledModalOpen: boolean; isDirtyStateDialogOpen: boolean; isImportModalOpen: boolean; isConflictDialogOpen: boolean; pendingAction: PendingAction | null; openChangeStatusModal: () => void; closeChangeStatusModal: () => void; openCompanyEnableModal: () => void; closeCompanyEnableModal: () => void; openNotEnabledModal: () => void; closeNotEnabledModal: () => void; openDirtyStateDialog: () => void; closeDirtyStateDialog: () => void; openImportModal: () => void; closeImportModal: () => void; openConflictDialog: () => void; closeConflictDialog: () => void; setPendingAction: (action: PendingAction) => void; clearPendingAction: () => void; viewMode: 'table' | 'cards'; setViewMode: (mode: 'table' | 'cards') => void; } export interface OverrideState { activeCompanyContext: string | undefined; overrides: Record; globalValues: Record; isShowGlobalValuesEnabled: boolean; /** Fields the user explicitly reverted to global in this editing session. */ revertedFields: string[]; setActiveCompanyContext: (context: string | undefined) => void; setOverrides: (overrides: Record) => void; setGlobalValues: (values: Record) => void; toggleShowGlobalValues: () => void; setRevertedFields: (fields: string[]) => void; } export interface MasterViewState extends ListState, FormState, FilterState, UIState, OverrideState { } export type MasterViewStore = StoreApi>; //# sourceMappingURL=types.d.ts.map