sorting for records in the ui
This commit is contained in:
@@ -84,9 +84,11 @@ export const activityFeedsService = {
|
||||
// Dashboard stats scoped to the logged-in user (org-wide for
|
||||
// ADMIN/MODERATOR): overall workload, today's activity, and the workload
|
||||
// split into batches of 50 in the same order the audit session walks.
|
||||
getUserStats: async (isRectificationEnabled: boolean) => {
|
||||
// sortBy/sortDir keep the batch numbering aligned with the feed/session
|
||||
// order when a custom sort is active (backend mirrors the same whitelist).
|
||||
getUserStats: async (isRectificationEnabled: boolean, sortBy?: string, sortDir?: string) => {
|
||||
const response = await axiosClient.get('/api/audit/anomaly/user-stats', {
|
||||
params: { isRectificationEnabled }
|
||||
params: { isRectificationEnabled, sortBy: sortBy || '', sortDir: sortDir || '' }
|
||||
});
|
||||
return response as unknown as {
|
||||
scoped: boolean;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import React, { useState, useMemo, useCallback, memo } from 'react';
|
||||
import {
|
||||
Box, TextField, Checkbox, FormControlLabel, Button, Typography, Dialog,
|
||||
DialogContent, DialogActions, CircularProgress, Divider, InputAdornment, Chip
|
||||
DialogContent, DialogActions, CircularProgress, Divider, InputAdornment, Chip,
|
||||
Select, MenuItem
|
||||
} from '@mui/material';
|
||||
import SearchIcon from '@mui/icons-material/Search';
|
||||
import { useFeedStore } from '../../store/feedStore';
|
||||
@@ -70,6 +71,7 @@ export const FeedFilters: React.FC = () => {
|
||||
filterFromDate, filterTillDate,
|
||||
filterMinChainage, filterMaxChainage,
|
||||
setFilterMinChainage, setFilterMaxChainage,
|
||||
sortBy, sortDir, setSortBy, setSortDir,
|
||||
} = useFeedStore();
|
||||
|
||||
// ── Use a Set (stored in state) for O(1) has() lookups ────────────────────
|
||||
@@ -77,6 +79,8 @@ export const FeedFilters: React.FC = () => {
|
||||
const [draftSet, setDraftSet] = useState<Set<number>>(() => new Set(selectedAssetIds));
|
||||
const [draftFromDate, setDraftFromDate] = useState('');
|
||||
const [draftTillDate, setDraftTillDate] = useState('');
|
||||
const [draftSortBy, setDraftSortBy] = useState<string>(() => sortBy);
|
||||
const [draftSortDir, setDraftSortDir] = useState<string>(() => sortDir);
|
||||
const [draftMinChainage, setDraftMinChainage] = useState('');
|
||||
const [draftMaxChainage, setDraftMaxChainage] = useState('');
|
||||
const [assetSearch, setAssetSearch] = useState('');
|
||||
@@ -146,6 +150,8 @@ export const FeedFilters: React.FC = () => {
|
||||
setDraftTillDate('');
|
||||
setDraftMinChainage('');
|
||||
setDraftMaxChainage('');
|
||||
setDraftSortBy('');
|
||||
setDraftSortDir('asc');
|
||||
setAssetSearch('');
|
||||
}, []);
|
||||
|
||||
@@ -162,6 +168,8 @@ export const FeedFilters: React.FC = () => {
|
||||
setFilterMinChainage(draftMinChainage); // persist chainage globally
|
||||
setFilterMaxChainage(draftMaxChainage); // persist chainage globally
|
||||
setSelectedAssetIds(draftAssetArr);
|
||||
setSortBy(draftSortBy as any);
|
||||
setSortDir(draftSortDir as any);
|
||||
|
||||
if (selectedTabIndex >= 0) {
|
||||
const activeTab = tabs[selectedTabIndex];
|
||||
@@ -172,7 +180,9 @@ export const FeedFilters: React.FC = () => {
|
||||
const assetIdsKey = draftAssetArr.join(',');
|
||||
|
||||
// Build the correct filter key that will be calculated in GlobalFeed
|
||||
const filterKey = `${selectedSite?.site_id ?? ''}|${auditStatus}|${searchAnomalyId}|${filterPlaza}|${isRectActive}|${activeTab.date}|${draftFromDate}|${draftTillDate}|${draftMinChainage}|${draftMaxChainage}|${assetIdsKey}`;
|
||||
// Must mirror GlobalFeed's filterKey format exactly or the cache
|
||||
// check there misses and double-fetches.
|
||||
const filterKey = `${selectedSite?.site_id ?? ''}|${auditStatus}|${searchAnomalyId}|${filterPlaza}|${isRectActive}|${activeTab.date}|${draftFromDate}|${draftTillDate}|${draftMinChainage}|${draftMaxChainage}|${assetIdsKey}|${draftSortBy}|${draftSortDir}`;
|
||||
|
||||
const historyRes: any = await activityFeedsService.getHistory({
|
||||
date: activeTab.date,
|
||||
@@ -189,6 +199,8 @@ export const FeedFilters: React.FC = () => {
|
||||
fromChainage: draftMinChainage,
|
||||
toChainage: draftMaxChainage,
|
||||
plaza: filterPlaza,
|
||||
sortBy: draftSortBy,
|
||||
sortDir: draftSortDir,
|
||||
});
|
||||
if (historyRes?.anomalies) {
|
||||
updateTab(selectedTabIndex, {
|
||||
@@ -246,6 +258,32 @@ export const FeedFilters: React.FC = () => {
|
||||
)}
|
||||
</Box>
|
||||
|
||||
{/* Sort - drives feed order, session page order and dashboard batch
|
||||
numbering (one source of truth end to end) */}
|
||||
<Box sx={{ display: 'flex', gap: 1, alignItems: 'center', mb: 2 }}>
|
||||
<Typography variant="body2" sx={{ fontWeight: 'bold', color: '#94a3b8', whiteSpace: 'nowrap' }}>Sort by</Typography>
|
||||
<Select
|
||||
size="small"
|
||||
value={draftSortBy}
|
||||
onChange={(e) => setDraftSortBy(String(e.target.value))}
|
||||
displayEmpty
|
||||
sx={{ minWidth: 140, color: '#f8fafc', bgcolor: 'rgba(255,255,255,0.07)', borderRadius: 1, '& fieldset': { borderColor: '#334155' }, '& .MuiSvgIcon-root': { color: '#94a3b8' } }}
|
||||
MenuProps={{ slotProps: { paper: { sx: { bgcolor: '#0f172a', border: '1px solid #1e293b' } } } }}
|
||||
>
|
||||
{[['', 'Default'], ['id', 'ID'], ['date', 'Date'], ['chainage', 'Chainage'], ['latlong', 'Lat/Long']].map(([v, l]) => (
|
||||
<MenuItem key={v} value={v} sx={{ color: '#f8fafc', bgcolor: '#0f172a', '&:hover': { bgcolor: '#1e293b' } }}>{l}</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
<Button
|
||||
size="small"
|
||||
disabled={!draftSortBy}
|
||||
onClick={() => setDraftSortDir(d => (d === 'asc' ? 'desc' : 'asc'))}
|
||||
sx={{ color: '#94a3b8', border: '1px solid #334155', textTransform: 'none', borderRadius: 1, minWidth: 72, '&.Mui-disabled': { color: '#475569', borderColor: '#1e293b' } }}
|
||||
>
|
||||
{draftSortDir === 'asc' ? '↑ Asc' : '↓ Desc'}
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
{/* Date & Chainage */}
|
||||
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 2, mb: 3, alignItems: 'center' }}>
|
||||
<Box sx={{ display: 'flex', gap: 1, alignItems: 'center' }}>
|
||||
|
||||
@@ -16,7 +16,8 @@ export const GlobalFeed: React.FC = () => {
|
||||
filterFromDate, filterTillDate,
|
||||
filterMinChainage, filterMaxChainage,
|
||||
selectedAssetIds,
|
||||
setIsFeedLoading
|
||||
setIsFeedLoading,
|
||||
sortBy, sortDir
|
||||
} = useFeedStore();
|
||||
|
||||
useEffect(() => {
|
||||
@@ -60,7 +61,7 @@ export const GlobalFeed: React.FC = () => {
|
||||
const assetIdsKey = selectedAssetIds.join(',');
|
||||
|
||||
// Build a key for the current filter state on the active tab
|
||||
const filterKey = `${selectedSite?.site_id ?? ''}|${auditStatus}|${searchAnomalyId}|${filterPlaza}|${isRectActive}|${activeTab.date}|${filterFromDate}|${filterTillDate}|${filterMinChainage}|${filterMaxChainage}|${assetIdsKey}`;
|
||||
const filterKey = `${selectedSite?.site_id ?? ''}|${auditStatus}|${searchAnomalyId}|${filterPlaza}|${isRectActive}|${activeTab.date}|${filterFromDate}|${filterTillDate}|${filterMinChainage}|${filterMaxChainage}|${assetIdsKey}|${sortBy}|${sortDir}`;
|
||||
|
||||
// CACHE HIT: This exact tab and filter combo was already fetched
|
||||
if (filterKey === activeTab.filters?.lastFetchedFilterKey && activeTab.anomalies && activeTab.anomalies.length > 0) {
|
||||
@@ -83,6 +84,8 @@ export const GlobalFeed: React.FC = () => {
|
||||
auto_audit: isRectActive ? '' : (auditStatus === 'Auto Audits' ? 'true' : (auditStatus === 'Manual' ? 'false' : '')),
|
||||
isRectificationEnabled: isRectActive,
|
||||
sortByDateAsc: false,
|
||||
sortBy,
|
||||
sortDir,
|
||||
anomalyIds: searchAnomalyId,
|
||||
plaza: filterPlaza,
|
||||
assetsIds: assetIdsKey,
|
||||
@@ -116,7 +119,7 @@ export const GlobalFeed: React.FC = () => {
|
||||
fetchFilteredHistory();
|
||||
}, [
|
||||
selectedSite?.site_id, auditStatus, searchAnomalyId, filterPlaza, isRectificationEnabled, selectedTabIndex, tabs.length,
|
||||
filterFromDate, filterTillDate, filterMinChainage, filterMaxChainage, selectedAssetIds
|
||||
filterFromDate, filterTillDate, filterMinChainage, filterMaxChainage, selectedAssetIds, sortBy, sortDir
|
||||
]);
|
||||
|
||||
const handlePageChange = async (_event: unknown, newPage: number) => {
|
||||
@@ -137,6 +140,8 @@ export const GlobalFeed: React.FC = () => {
|
||||
auto_audit: isRectActive ? '' : (auditStatus === 'Auto Audits' ? 'true' : (auditStatus === 'Manual' ? 'false' : '')),
|
||||
isRectificationEnabled: isRectActive,
|
||||
sortByDateAsc: false,
|
||||
sortBy,
|
||||
sortDir,
|
||||
anomalyIds: searchAnomalyId,
|
||||
plaza: filterPlaza,
|
||||
assetsIds: assetIdsKey,
|
||||
|
||||
@@ -199,7 +199,7 @@ export const AuditSession: React.FC = () => {
|
||||
selectedSite, filterFromDate, filterTillDate,
|
||||
filterMinChainage, filterMaxChainage, selectedAssetIds,
|
||||
searchAnomalyId, auditStatus, isRectificationEnabled, filterPlaza,
|
||||
setDashboardCache
|
||||
setDashboardCache, sortBy, sortDir, setSortBy, setSortDir
|
||||
} = useFeedStore();
|
||||
|
||||
// Call this before every navigate('/dashboard') so the dashboard re-fetches fresh stats
|
||||
@@ -233,6 +233,8 @@ export const AuditSession: React.FC = () => {
|
||||
pageNo: targetPage * 50,
|
||||
pageSize: 50,
|
||||
sortByDateAsc: false, // must match dashboard sort so firstPendingIndex page alignment is correct
|
||||
sortBy, // user sort: same value the dashboard fetch uses, so page alignment holds
|
||||
sortDir,
|
||||
isTrueFalse: isRectActive ? 'both' : (auditStatus === 'False Audits' ? 'true' : 'both'),
|
||||
auditStatus: auditStatus,
|
||||
auto_audit: isRectActive ? '' : (auditStatus === 'Auto Audits' ? 'true' : (auditStatus === 'Manual' ? 'false' : '')),
|
||||
@@ -267,7 +269,7 @@ export const AuditSession: React.FC = () => {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [selectedSite, selectedAssetIds, auditStatus, isRectificationEnabled, filterFromDate, filterTillDate, filterMinChainage, filterMaxChainage, searchAnomalyId, activeDate, isRectActive, location.state, filterPlaza, sessionPageNo, navigate]);
|
||||
}, [selectedSite, selectedAssetIds, auditStatus, isRectificationEnabled, filterFromDate, filterTillDate, filterMinChainage, filterMaxChainage, searchAnomalyId, activeDate, isRectActive, location.state, filterPlaza, sessionPageNo, navigate, sortBy, sortDir]);
|
||||
|
||||
const handleLoadNextFeedPage = useCallback(async () => {
|
||||
try {
|
||||
@@ -282,6 +284,8 @@ export const AuditSession: React.FC = () => {
|
||||
date: activeDate,
|
||||
pageNo: nextPage * feedPageSize,
|
||||
pageSize: feedPageSize,
|
||||
sortBy,
|
||||
sortDir,
|
||||
isTrueFalse: isRectActive ? 'both' : (auditStatus === 'False Audits' ? 'true' : 'both'),
|
||||
auditStatus: auditStatus,
|
||||
auto_audit: isRectActive ? '' : (auditStatus === 'Auto Audits' ? 'true' : (auditStatus === 'Manual' ? 'false' : '')),
|
||||
@@ -323,7 +327,7 @@ export const AuditSession: React.FC = () => {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [selectedSite, selectedAssetIds, auditStatus, isRectificationEnabled, filterFromDate, filterTillDate, filterMinChainage, filterMaxChainage, searchAnomalyId, activeDate, isRectActive, location.state, activeTab, selectedTabIndex, updateTab, navigate]);
|
||||
}, [selectedSite, selectedAssetIds, auditStatus, isRectificationEnabled, filterFromDate, filterTillDate, filterMinChainage, filterMaxChainage, searchAnomalyId, activeDate, isRectActive, location.state, activeTab, selectedTabIndex, updateTab, navigate, sortBy, sortDir]);
|
||||
|
||||
useEffect(() => {
|
||||
if (hasInitializedSession.current) return;
|
||||
@@ -893,6 +897,26 @@ export const AuditSession: React.FC = () => {
|
||||
goToIndex(firstSkipped !== -1 ? firstSkipped : anomalies.length - 1);
|
||||
};
|
||||
|
||||
// Changing sort mid-session reloads page 0 in the new order. Dashboard
|
||||
// sessions only - feed sessions inherit the order of the feed tab they
|
||||
// were opened from (the feed page has its own selector). Staged bulk work
|
||||
// can't survive a reorder, so it's discarded after a confirm.
|
||||
const handleSessionSortChange = (by: string, dir: string) => {
|
||||
if (stagedCount > 0 && !window.confirm(`Changing sort reloads the session and discards ${stagedCount} staged audit(s). Continue?`)) return;
|
||||
setSortBy(by as any);
|
||||
setSortDir(dir as any);
|
||||
};
|
||||
|
||||
const skipSortReload = useRef(true);
|
||||
useEffect(() => {
|
||||
if (skipSortReload.current) { skipSortReload.current = false; return; }
|
||||
if (isFeedSession) return;
|
||||
setShowBatchEndPanel(false);
|
||||
setSessionPageNo(0);
|
||||
loadSessionData(0);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [sortBy, sortDir]);
|
||||
|
||||
// Category 1 nests a sub-category (Plant / Not an Anomaly) - a verdict
|
||||
// without it is incomplete, both for immediate save and for staging.
|
||||
const validateSubCategory = (): boolean => {
|
||||
@@ -1238,6 +1262,31 @@ export const AuditSession: React.FC = () => {
|
||||
)}
|
||||
</Box>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
|
||||
{!isFeedSession && (
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
|
||||
<Select
|
||||
size="small"
|
||||
value={sortBy}
|
||||
onChange={(e) => handleSessionSortChange(String(e.target.value), sortDir)}
|
||||
displayEmpty
|
||||
sx={{ fontSize: '0.75rem', color: '#94a3b8', height: 30, '& fieldset': { borderColor: '#334155' }, '& .MuiSvgIcon-root': { color: '#94a3b8' } }}
|
||||
MenuProps={{ sx: { zIndex: 10001 }, slotProps: { paper: { sx: { bgcolor: '#0f172a', border: '1px solid #1e293b' } } } }}
|
||||
>
|
||||
{[['', 'Sort: Default'], ['id', 'Sort: ID'], ['date', 'Sort: Date'], ['chainage', 'Sort: Chainage'], ['latlong', 'Sort: Lat/Long']].map(([v, l]) => (
|
||||
<MenuItem key={v} value={v} sx={{ fontSize: '0.8rem', color: '#f8fafc', bgcolor: '#0f172a', '&:hover': { bgcolor: '#1e293b' } }}>{l}</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
<Button
|
||||
size="small"
|
||||
disabled={!sortBy}
|
||||
onClick={() => handleSessionSortChange(sortBy, sortDir === 'asc' ? 'desc' : 'asc')}
|
||||
title="Toggle sort direction"
|
||||
sx={{ minWidth: 52, color: '#94a3b8', border: '1px solid #334155', textTransform: 'none', borderRadius: 2, '&.Mui-disabled': { color: '#475569', borderColor: '#1e293b' } }}
|
||||
>
|
||||
{sortDir === 'asc' ? '↑ Asc' : '↓ Desc'}
|
||||
</Button>
|
||||
</Box>
|
||||
)}
|
||||
<Typography sx={{ fontWeight: 'bold', fontSize: '0.9rem' }}>{user?.username || user?.email}</Typography>
|
||||
<Button size="small" onClick={() => setIsShortcutsDialogOpen(true)} sx={{ color: '#94a3b8', border: '1px solid #334155', textTransform: 'none', borderRadius: 2 }}>? Shortcuts</Button>
|
||||
</Box>
|
||||
|
||||
@@ -13,7 +13,7 @@ export const Dashboard: React.FC = () => {
|
||||
filterMinChainage, filterMaxChainage,
|
||||
selectedAssetIds, dashboardCache, setDashboardCache,
|
||||
searchAnomalyId, filterPlaza, isRectificationEnabled,
|
||||
tabs, selectedTabIndex
|
||||
tabs, selectedTabIndex, sortBy, sortDir
|
||||
} = useFeedStore();
|
||||
|
||||
const navigate = useNavigate();
|
||||
@@ -26,7 +26,7 @@ export const Dashboard: React.FC = () => {
|
||||
const isRectActive = isRectificationEnabled || activeTab.isRectificationTab;
|
||||
|
||||
// Build a key that uniquely identifies the current filter state
|
||||
const currentFilterKey = `${selectedSiteId}|${auditStatus}|${filterFromDate}|${filterTillDate}|${assetIdsKey}|${filterMinChainage}|${filterMaxChainage}|${searchAnomalyId}|${filterPlaza}|${isRectActive}|${activeDate}`;
|
||||
const currentFilterKey = `${selectedSiteId}|${auditStatus}|${filterFromDate}|${filterTillDate}|${assetIdsKey}|${filterMinChainage}|${filterMaxChainage}|${searchAnomalyId}|${filterPlaza}|${isRectActive}|${activeDate}|${sortBy}|${sortDir}`;
|
||||
|
||||
// Session-start info (which page the audit session should open on) - still
|
||||
// derived from the filtered feed, same as before. The headline stats below
|
||||
@@ -49,16 +49,18 @@ export const Dashboard: React.FC = () => {
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
setStatsLoading(true);
|
||||
activityFeedsService.getUserStats(isRectActive)
|
||||
activityFeedsService.getUserStats(isRectActive, sortBy, sortDir)
|
||||
.then((s) => { if (!cancelled) setUserStats(s); })
|
||||
.catch((err) => console.error('Failed to load user stats', err))
|
||||
.finally(() => { if (!cancelled) setStatsLoading(false); });
|
||||
return () => { cancelled = true; };
|
||||
}, [isRectActive]);
|
||||
// Batch numbering follows the chosen sort - refetch when it changes so
|
||||
// "batch N" keeps matching the N-th session page.
|
||||
}, [isRectActive, sortBy, sortDir]);
|
||||
|
||||
useEffect(() => {
|
||||
// CACHE HIT: filters unchanged since last fetch — skip API call entirely
|
||||
if (dashboardCache.stats !== null && currentFilterKey === `${dashboardCache.siteId}|${dashboardCache.auditStatus}|${dashboardCache.fromDate}|${dashboardCache.tillDate}|${dashboardCache.assetIds}|${dashboardCache.minChainage}|${dashboardCache.maxChainage}|${dashboardCache.searchAnomalyId}|${dashboardCache.filterPlaza}|${dashboardCache.isRectificationEnabled ?? false}|${dashboardCache.date ?? ''}`) {
|
||||
if (dashboardCache.stats !== null && currentFilterKey === `${dashboardCache.siteId}|${dashboardCache.auditStatus}|${dashboardCache.fromDate}|${dashboardCache.tillDate}|${dashboardCache.assetIds}|${dashboardCache.minChainage}|${dashboardCache.maxChainage}|${dashboardCache.searchAnomalyId}|${dashboardCache.filterPlaza}|${dashboardCache.isRectificationEnabled ?? false}|${dashboardCache.date ?? ''}|${dashboardCache.sortBy ?? ''}|${dashboardCache.sortDir ?? 'asc'}`) {
|
||||
setSessionInfo(dashboardCache.stats);
|
||||
return;
|
||||
}
|
||||
@@ -70,6 +72,8 @@ export const Dashboard: React.FC = () => {
|
||||
pageNo: 0,
|
||||
pageSize: 200,
|
||||
sortByDateAsc: false,
|
||||
sortBy,
|
||||
sortDir,
|
||||
isRectificationEnabled: isRectActive,
|
||||
auditStatus: auditStatus,
|
||||
isTrueFalse: isRectActive ? 'both' : (auditStatus === 'False Audits' ? 'true' : 'both'),
|
||||
@@ -108,6 +112,8 @@ export const Dashboard: React.FC = () => {
|
||||
filterPlaza,
|
||||
isRectificationEnabled: isRectActive,
|
||||
date: activeDate,
|
||||
sortBy,
|
||||
sortDir,
|
||||
stats: newStats,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
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 {
|
||||
date: string;
|
||||
isRectificationTab: boolean;
|
||||
@@ -26,6 +33,8 @@ interface DashboardCache {
|
||||
filterPlaza: string;
|
||||
isRectificationEnabled?: boolean;
|
||||
date?: string;
|
||||
sortBy?: string;
|
||||
sortDir?: string;
|
||||
stats: {
|
||||
globalTotal: number;
|
||||
batchTotal: number;
|
||||
@@ -59,6 +68,8 @@ interface FeedState {
|
||||
searchAnomalyId: string;
|
||||
isRectificationEnabled: boolean;
|
||||
isFeedLoading: boolean;
|
||||
sortBy: FeedSortBy;
|
||||
sortDir: FeedSortDir;
|
||||
|
||||
// Actions
|
||||
setTabs: (tabs: FeedTab[]) => void;
|
||||
@@ -84,6 +95,8 @@ interface FeedState {
|
||||
setSearchAnomalyId: (id: string) => void;
|
||||
setIsRectificationEnabled: (val: boolean) => void;
|
||||
setIsFeedLoading: (val: boolean) => void;
|
||||
setSortBy: (val: FeedSortBy) => void;
|
||||
setSortDir: (val: FeedSortDir) => void;
|
||||
resetStore: () => void;
|
||||
}
|
||||
|
||||
@@ -123,6 +136,8 @@ const initialFeedState = {
|
||||
searchAnomalyId: '',
|
||||
isRectificationEnabled: false,
|
||||
isFeedLoading: false,
|
||||
sortBy: '' as FeedSortBy,
|
||||
sortDir: 'asc' as FeedSortDir,
|
||||
};
|
||||
|
||||
export const useFeedStore = create<FeedState>()(
|
||||
@@ -152,6 +167,8 @@ export const useFeedStore = create<FeedState>()(
|
||||
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];
|
||||
@@ -180,6 +197,8 @@ export const useFeedStore = create<FeedState>()(
|
||||
auditStatus: state.auditStatus,
|
||||
searchAnomalyId: state.searchAnomalyId,
|
||||
isRectificationEnabled: state.isRectificationEnabled,
|
||||
sortBy: state.sortBy,
|
||||
sortDir: state.sortDir,
|
||||
}),
|
||||
}
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user