241 lines
10 KiB
TypeScript
241 lines
10 KiB
TypeScript
/**
|
|
* Hook for fetching and managing dashboard data
|
|
*/
|
|
|
|
import { useState, useCallback, useRef } from 'react';
|
|
import { dashboardService, type DashboardKPIs, type DateRange, type AIRemarkUtilization, type ApproverPerformance, type DepartmentStats, type PriorityDistribution, type UpcomingDeadline, type RecentActivity, type CriticalRequest } from '@/services/dashboard.service';
|
|
import { ActivityData } from '@/components/dashboard/ActivityFeedItem';
|
|
import type { CriticalAlertData } from '@/components/dashboard/CriticalAlertCard';
|
|
|
|
interface UseDashboardDataOptions {
|
|
isAdmin: boolean;
|
|
viewAsUser?: boolean; // For admin to view as normal user
|
|
userId?: string; // User ID for filtering - needed to fetch user-initiated requests
|
|
dateRange: DateRange;
|
|
customStartDate?: Date;
|
|
customEndDate?: Date;
|
|
onPaginationUpdate: {
|
|
activity: (page: number, totalPages: number, totalRecords: number) => void;
|
|
critical: (page: number, totalPages: number, totalRecords: number) => void;
|
|
deadlines: (page: number, totalPages: number, totalRecords: number) => void;
|
|
approver: (page: number, totalPages: number, totalRecords: number) => void;
|
|
};
|
|
}
|
|
|
|
export function useDashboardData({
|
|
isAdmin,
|
|
viewAsUser = false,
|
|
userId, // User ID for filtering user-initiated requests
|
|
dateRange,
|
|
customStartDate,
|
|
customEndDate,
|
|
onPaginationUpdate,
|
|
}: UseDashboardDataOptions) {
|
|
const [kpis, setKpis] = useState<DashboardKPIs | null>(null);
|
|
const [recentActivity, setRecentActivity] = useState<ActivityData[]>([]);
|
|
const [criticalRequests, setCriticalRequests] = useState<(CriticalRequest | CriticalAlertData)[]>([]);
|
|
const [departmentStats, setDepartmentStats] = useState<DepartmentStats[]>([]);
|
|
const [priorityDistribution, setPriorityDistribution] = useState<PriorityDistribution[]>([]);
|
|
const [upcomingDeadlines, setUpcomingDeadlines] = useState<UpcomingDeadline[]>([]);
|
|
const [aiRemarkUtilization, setAiRemarkUtilization] = useState<AIRemarkUtilization | null>(null);
|
|
const [approverPerformance, setApproverPerformance] = useState<ApproverPerformance[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
const [refreshing, setRefreshing] = useState(false);
|
|
|
|
// Use ref to store latest pagination callbacks to avoid dependency issues
|
|
const paginationCallbacksRef = useRef(onPaginationUpdate);
|
|
paginationCallbacksRef.current = onPaginationUpdate;
|
|
|
|
const fetchDashboardData = useCallback(async (showRefreshing = false) => {
|
|
try {
|
|
if (showRefreshing) {
|
|
setRefreshing(true);
|
|
} else {
|
|
setLoading(true);
|
|
}
|
|
|
|
// Fetch common data for all users
|
|
const commonPromises = [
|
|
dashboardService.getKPIs(dateRange, customStartDate, customEndDate, viewAsUser),
|
|
dashboardService.getRecentActivity(1, 10, viewAsUser),
|
|
dashboardService.getCriticalRequests(1, 10, viewAsUser),
|
|
dashboardService.getUpcomingDeadlines(1, 10, viewAsUser)
|
|
];
|
|
|
|
// For normal users (or admin viewing as user):
|
|
// Fetch user-INITIATED requests stats separately for "My Requests" card
|
|
// This ensures "My Requests" only shows requests they created, not all requests they're involved in
|
|
const userInitiatedPromise = (!isAdmin && userId)
|
|
? dashboardService.getRequestStats(
|
|
dateRange,
|
|
customStartDate?.toISOString(),
|
|
customEndDate?.toISOString(),
|
|
undefined, // status
|
|
undefined, // priority
|
|
undefined, // templateType
|
|
undefined, // department
|
|
userId, // initiator - filter by user's ID to get ONLY their initiated requests
|
|
undefined, // approver
|
|
undefined, // approverType
|
|
undefined, // search
|
|
undefined, // slaCompliance
|
|
viewAsUser // viewAsUser - treat as normal user even if admin
|
|
)
|
|
: null;
|
|
|
|
// Fetch admin-only data if user is admin
|
|
const adminPromises = isAdmin ? [
|
|
dashboardService.getDepartmentStats(dateRange, customStartDate, customEndDate),
|
|
dashboardService.getPriorityDistribution(dateRange, customStartDate, customEndDate),
|
|
dashboardService.getAIRemarkUtilization(dateRange, customStartDate, customEndDate),
|
|
dashboardService.getApproverPerformance(dateRange, 1, 10, customStartDate, customEndDate)
|
|
] : [];
|
|
|
|
// Fetch all data in parallel
|
|
const [commonResults, userInitiatedStats, adminResults] = await Promise.all([
|
|
Promise.all(commonPromises),
|
|
userInitiatedPromise,
|
|
Promise.all(adminPromises)
|
|
]);
|
|
|
|
const kpisData = commonResults[0] as DashboardKPIs;
|
|
const activityResult = commonResults[1] as { activities: RecentActivity[]; pagination: { currentPage: number; totalPages: number; totalRecords: number; limit: number } };
|
|
const criticalResult = commonResults[2] as { criticalRequests: CriticalRequest[]; pagination: { currentPage: number; totalPages: number; totalRecords: number; limit: number } };
|
|
const deadlinesResult = commonResults[3] as { deadlines: UpcomingDeadline[]; pagination: { currentPage: number; totalPages: number; totalRecords: number; limit: number } };
|
|
|
|
// For normal users: Override requestVolume with user-initiated requests only
|
|
// This makes "My Requests" show only requests they created
|
|
// Other KPIs (approverLoad, etc.) remain as-is since they need all involved requests
|
|
if (!isAdmin && userInitiatedStats) {
|
|
kpisData.requestVolume = userInitiatedStats;
|
|
}
|
|
|
|
setKpis(kpisData);
|
|
setRecentActivity(activityResult.activities);
|
|
paginationCallbacksRef.current.activity(
|
|
activityResult.pagination.currentPage,
|
|
activityResult.pagination.totalPages,
|
|
activityResult.pagination.totalRecords
|
|
);
|
|
|
|
setCriticalRequests(criticalResult.criticalRequests);
|
|
paginationCallbacksRef.current.critical(
|
|
criticalResult.pagination.currentPage,
|
|
criticalResult.pagination.totalPages,
|
|
criticalResult.pagination.totalRecords
|
|
);
|
|
|
|
setUpcomingDeadlines(deadlinesResult.deadlines);
|
|
paginationCallbacksRef.current.deadlines(
|
|
deadlinesResult.pagination.currentPage,
|
|
deadlinesResult.pagination.totalPages,
|
|
deadlinesResult.pagination.totalRecords
|
|
);
|
|
|
|
// Only set admin-specific data if user is admin
|
|
if (isAdmin && adminResults.length >= 4) {
|
|
const deptStats = adminResults[0] as DepartmentStats[];
|
|
const priorityDist = adminResults[1] as PriorityDistribution[];
|
|
const aiUtilization = adminResults[2] as AIRemarkUtilization;
|
|
const approverResult = adminResults[3] as { performance: ApproverPerformance[]; pagination: { currentPage: number; totalPages: number; totalRecords: number; limit: number } };
|
|
setDepartmentStats(deptStats);
|
|
setPriorityDistribution(priorityDist);
|
|
setAiRemarkUtilization(aiUtilization);
|
|
setApproverPerformance(approverResult.performance);
|
|
paginationCallbacksRef.current.approver(
|
|
approverResult.pagination.currentPage,
|
|
approverResult.pagination.totalPages,
|
|
approverResult.pagination.totalRecords
|
|
);
|
|
} else if (!isAdmin) {
|
|
// Reset admin-specific data for normal users
|
|
setDepartmentStats([]);
|
|
setPriorityDistribution([]);
|
|
setAiRemarkUtilization(null);
|
|
setApproverPerformance([]);
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to fetch dashboard data:', error);
|
|
} finally {
|
|
setLoading(false);
|
|
setRefreshing(false);
|
|
}
|
|
}, [isAdmin, viewAsUser, userId, dateRange, customStartDate, customEndDate]);
|
|
|
|
// Fetch individual data with pagination
|
|
const fetchRecentActivities = useCallback(async (page: number = 1) => {
|
|
try {
|
|
const result = await dashboardService.getRecentActivity(page, 10, viewAsUser);
|
|
setRecentActivity(result.activities);
|
|
paginationCallbacksRef.current.activity(
|
|
result.pagination.currentPage,
|
|
result.pagination.totalPages,
|
|
result.pagination.totalRecords
|
|
);
|
|
} catch (error) {
|
|
console.error('Failed to fetch recent activities:', error);
|
|
}
|
|
}, [viewAsUser]);
|
|
|
|
const fetchCriticalRequests = useCallback(async (page: number = 1) => {
|
|
try {
|
|
const result = await dashboardService.getCriticalRequests(page, 10, viewAsUser);
|
|
setCriticalRequests(result.criticalRequests);
|
|
paginationCallbacksRef.current.critical(
|
|
result.pagination.currentPage,
|
|
result.pagination.totalPages,
|
|
result.pagination.totalRecords
|
|
);
|
|
} catch (error) {
|
|
console.error('Failed to fetch critical requests:', error);
|
|
}
|
|
}, [viewAsUser]);
|
|
|
|
const fetchUpcomingDeadlines = useCallback(async (page: number = 1) => {
|
|
try {
|
|
const result = await dashboardService.getUpcomingDeadlines(page, 10, viewAsUser);
|
|
setUpcomingDeadlines(result.deadlines);
|
|
paginationCallbacksRef.current.deadlines(
|
|
result.pagination.currentPage,
|
|
result.pagination.totalPages,
|
|
result.pagination.totalRecords
|
|
);
|
|
} catch (error) {
|
|
console.error('Failed to fetch upcoming deadlines:', error);
|
|
}
|
|
}, [viewAsUser]);
|
|
|
|
const fetchApproverPerformance = useCallback(async (page: number = 1) => {
|
|
try {
|
|
const result = await dashboardService.getApproverPerformance(dateRange, page, 10, customStartDate, customEndDate);
|
|
setApproverPerformance(result.performance);
|
|
paginationCallbacksRef.current.approver(
|
|
result.pagination.currentPage,
|
|
result.pagination.totalPages,
|
|
result.pagination.totalRecords
|
|
);
|
|
} catch (error) {
|
|
console.error('Failed to fetch approver performance:', error);
|
|
}
|
|
}, [dateRange, customStartDate, customEndDate]);
|
|
|
|
return {
|
|
kpis,
|
|
recentActivity,
|
|
criticalRequests,
|
|
departmentStats,
|
|
priorityDistribution,
|
|
upcomingDeadlines,
|
|
aiRemarkUtilization,
|
|
approverPerformance,
|
|
loading,
|
|
refreshing,
|
|
fetchDashboardData,
|
|
fetchRecentActivities,
|
|
fetchCriticalRequests,
|
|
fetchUpcomingDeadlines,
|
|
fetchApproverPerformance,
|
|
};
|
|
}
|
|
|