209 lines
7.0 KiB
TypeScript
209 lines
7.0 KiB
TypeScript
import { create } from 'zustand';
|
|
import { persist } from 'zustand/middleware';
|
|
|
|
// Feed/session sort. '' = backend default order (id DESC on the pending
|
|
// feed). One choice drives the whole chain: feed table, session pages,
|
|
// dashboard batch numbering and the "continue auditing" start page - they
|
|
// must all use the same order or batch N stops matching session page N.
|
|
export type FeedSortBy = '' | 'id' | 'date' | 'chainage' | 'latlong';
|
|
export type FeedSortDir = 'asc' | 'desc';
|
|
|
|
export interface FeedTab {
|
|
// '' = pending tab; 'YYYY-MM-DD' or 'YYYY-MM-DD_YYYY-MM-DD' (range) = history tab
|
|
date: string;
|
|
isRectificationTab: boolean;
|
|
// History tabs only: show records audited BY the logged-in user
|
|
auditedByMe?: boolean;
|
|
totalAnomalyCount: number;
|
|
anomalies: any[];
|
|
anomaliesCopy: any[];
|
|
selectedAnomalyIndex: number;
|
|
filters: any;
|
|
page: number;
|
|
rowsPerPage: number;
|
|
}
|
|
|
|
// Tracks what filter params were last used to fetch dashboard stats
|
|
interface DashboardCache {
|
|
siteId: string;
|
|
auditStatus: string;
|
|
fromDate: string;
|
|
tillDate: string;
|
|
assetIds: string;
|
|
minChainage: string;
|
|
maxChainage: string;
|
|
searchAnomalyId: string;
|
|
filterPlaza: string;
|
|
isRectificationEnabled?: boolean;
|
|
date?: string;
|
|
sortBy?: string;
|
|
sortDir?: string;
|
|
stats: {
|
|
globalTotal: number;
|
|
batchTotal: number;
|
|
batchAudited: number;
|
|
batchPending: number;
|
|
batchAnomaliesFound: number;
|
|
firstPendingIndex: number;
|
|
} | null;
|
|
}
|
|
|
|
interface FeedState {
|
|
tabs: FeedTab[];
|
|
selectedTabIndex: number;
|
|
assets: any[];
|
|
assetTypes: any[];
|
|
filterFromDate: string;
|
|
filterTillDate: string;
|
|
filterMinChainage: string;
|
|
filterMaxChainage: string;
|
|
filterPlaza: string;
|
|
selectedAssetIds: number[];
|
|
sites: any[];
|
|
auditStatus: string;
|
|
selectedSite: any;
|
|
isFiltersModalOpen: boolean;
|
|
isInitialized: boolean;
|
|
// Cache: last filter key used for the second GlobalFeed effect
|
|
lastFetchedFilterKey: string;
|
|
// Dashboard stats cache
|
|
dashboardCache: DashboardCache;
|
|
searchAnomalyId: string;
|
|
isRectificationEnabled: boolean;
|
|
isFeedLoading: boolean;
|
|
sortBy: FeedSortBy;
|
|
sortDir: FeedSortDir;
|
|
|
|
// Actions
|
|
setTabs: (tabs: FeedTab[]) => void;
|
|
setSelectedTabIndex: (index: number) => void;
|
|
setAssets: (assets: any[]) => void;
|
|
setAssetTypes: (assetTypes: any[]) => void;
|
|
setSelectedAssetIds: (ids: number[]) => void;
|
|
setSites: (sites: any[]) => void;
|
|
setSelectedSite: (site: any) => void;
|
|
setAuditStatus: (status: string) => void;
|
|
setIsFiltersModalOpen: (isOpen: boolean) => void;
|
|
setIsInitialized: (val: boolean) => void;
|
|
setLastFetchedFilterKey: (key: string) => void;
|
|
setDashboardCache: (cache: DashboardCache) => void;
|
|
addTab: (tab: FeedTab) => void;
|
|
closeTab: (index: number) => void;
|
|
updateTab: (index: number, partialTab: Partial<FeedTab>) => void;
|
|
setFilterFromDate: (date: string) => void;
|
|
setFilterTillDate: (date: string) => void;
|
|
setFilterMinChainage: (val: string) => void;
|
|
setFilterMaxChainage: (val: string) => void;
|
|
setFilterPlaza: (val: string) => void;
|
|
setSearchAnomalyId: (id: string) => void;
|
|
setIsRectificationEnabled: (val: boolean) => void;
|
|
setIsFeedLoading: (val: boolean) => void;
|
|
setSortBy: (val: FeedSortBy) => void;
|
|
setSortDir: (val: FeedSortDir) => void;
|
|
resetStore: () => void;
|
|
}
|
|
|
|
const EMPTY_DASHBOARD_CACHE: DashboardCache = {
|
|
siteId: '__unset__',
|
|
auditStatus: '__unset__',
|
|
fromDate: '__unset__',
|
|
tillDate: '__unset__',
|
|
assetIds: '__unset__',
|
|
minChainage: '__unset__',
|
|
maxChainage: '__unset__',
|
|
searchAnomalyId: '__unset__',
|
|
filterPlaza: '__unset__',
|
|
isRectificationEnabled: false,
|
|
date: '',
|
|
stats: null,
|
|
};
|
|
|
|
const initialFeedState = {
|
|
tabs: [],
|
|
selectedTabIndex: -1,
|
|
assets: [],
|
|
assetTypes: [],
|
|
filterFromDate: '',
|
|
filterTillDate: '',
|
|
filterMinChainage: '',
|
|
filterMaxChainage: '',
|
|
filterPlaza: '',
|
|
selectedAssetIds: [],
|
|
selectedSite: null,
|
|
sites: [],
|
|
auditStatus: 'Manual',
|
|
isFiltersModalOpen: false,
|
|
isInitialized: false,
|
|
lastFetchedFilterKey: '',
|
|
dashboardCache: EMPTY_DASHBOARD_CACHE,
|
|
searchAnomalyId: '',
|
|
isRectificationEnabled: false,
|
|
isFeedLoading: false,
|
|
sortBy: '' as FeedSortBy,
|
|
sortDir: 'asc' as FeedSortDir,
|
|
};
|
|
|
|
export const useFeedStore = create<FeedState>()(
|
|
persist(
|
|
(set) => ({
|
|
...initialFeedState,
|
|
|
|
resetStore: () => set(initialFeedState),
|
|
|
|
setTabs: (tabs) => set({ tabs }),
|
|
setSelectedTabIndex: (index) => set({ selectedTabIndex: index }),
|
|
setAssets: (assets) => set({ assets }),
|
|
setAssetTypes: (assetTypes) => set({ assetTypes }),
|
|
setSelectedAssetIds: (selectedAssetIds) => set({ selectedAssetIds }),
|
|
setSites: (sites) => set({ sites }),
|
|
setSelectedSite: (selectedSite) => set({ selectedSite }),
|
|
setAuditStatus: (auditStatus) => set({ auditStatus }),
|
|
setIsFiltersModalOpen: (isFiltersModalOpen) => set({ isFiltersModalOpen }),
|
|
setIsInitialized: (isInitialized) => set({ isInitialized }),
|
|
setLastFetchedFilterKey: (lastFetchedFilterKey) => set({ lastFetchedFilterKey }),
|
|
setDashboardCache: (dashboardCache) => set({ dashboardCache }),
|
|
setFilterFromDate: (filterFromDate) => set({ filterFromDate }),
|
|
setFilterTillDate: (filterTillDate) => set({ filterTillDate }),
|
|
setFilterMinChainage: (filterMinChainage) => set({ filterMinChainage }),
|
|
setFilterMaxChainage: (filterMaxChainage) => set({ filterMaxChainage }),
|
|
setFilterPlaza: (filterPlaza) => set({ filterPlaza }),
|
|
setSearchAnomalyId: (searchAnomalyId) => set({ searchAnomalyId }),
|
|
setIsRectificationEnabled: (isRectificationEnabled) => set({ isRectificationEnabled }),
|
|
setIsFeedLoading: (isFeedLoading) => set({ isFeedLoading }),
|
|
setSortBy: (sortBy) => set({ sortBy }),
|
|
setSortDir: (sortDir) => set({ sortDir }),
|
|
addTab: (tab) => set((state) => ({ tabs: [...state.tabs, tab], selectedTabIndex: state.tabs.length })),
|
|
closeTab: (index) => set((state) => {
|
|
const newTabs = [...state.tabs];
|
|
newTabs.splice(index, 1);
|
|
const newIndex = state.selectedTabIndex >= newTabs.length ? newTabs.length - 1 : state.selectedTabIndex;
|
|
return { tabs: newTabs, selectedTabIndex: newIndex };
|
|
}),
|
|
updateTab: (index, partialTab) => set((state) => {
|
|
const newTabs = [...state.tabs];
|
|
newTabs[index] = { ...newTabs[index], ...partialTab };
|
|
return { tabs: newTabs };
|
|
})
|
|
}),
|
|
{
|
|
name: 'feed-store-storage',
|
|
partialize: (state) => ({
|
|
tabs: state.tabs,
|
|
selectedTabIndex: state.selectedTabIndex,
|
|
filterFromDate: state.filterFromDate,
|
|
filterTillDate: state.filterTillDate,
|
|
filterMinChainage: state.filterMinChainage,
|
|
filterMaxChainage: state.filterMaxChainage,
|
|
filterPlaza: state.filterPlaza,
|
|
selectedAssetIds: state.selectedAssetIds,
|
|
selectedSite: state.selectedSite,
|
|
auditStatus: state.auditStatus,
|
|
searchAnomalyId: state.searchAnomalyId,
|
|
isRectificationEnabled: state.isRectificationEnabled,
|
|
sortBy: state.sortBy,
|
|
sortDir: state.sortDir,
|
|
}),
|
|
}
|
|
)
|
|
);
|