2026-06-19 16:43:41 +02:00

158 lines
5.9 KiB
TypeScript

import { useState } from 'react';
import { format, startOfMonth, startOfQuarter } from 'date-fns';
import { useFrameEntries } from '@/business/frame/hooks';
import { useSafetyQuizCompliance } from '@/business/safety-quiz/hooks';
import { usePersonalityCompletion } from '@/business/personality/queryHooks';
import { useZoneCheckInCompletion } from '@/business/zone-checkin/hooks';
import {
useStaffAttendanceRecords,
useStaffAttendanceSummary,
} from '@/business/staff-attendance/hooks';
import { usePolicyAcknowledgmentReport } from '@/business/policies/hooks';
import {
buildDirectorAcknowledgmentDocuments,
buildDirectorFramePreviews,
buildDirectorOverviewCards,
buildDirectorQuizResults,
buildDirectorRiskAreas,
} from '@/business/director-dashboard/selectors';
import type { DirectorDashboardPage } from '@/business/director-dashboard/types';
import {
DIRECTOR_DASHBOARD_QUICK_ACTIONS,
DIRECTOR_DASHBOARD_TIME_RANGE_STORAGE_KEY,
DIRECTOR_DASHBOARD_TIME_RANGES,
type DirectorDashboardTimeRange,
} from '@/shared/constants/directorDashboard';
import { useAuth } from '@/shared/app/useAuth';
import { getLeadershipDashboardName } from '@/business/app-shell/selectors';
import { getActiveTenant } from '@/business/scope/selectors';
import { useScopeContext } from '@/shared/app/scope-context';
import { DEFAULT_PRODUCT_ROLE } from '@/shared/constants/roles';
import { getCurrentSafetyQuizWeek } from '@/business/safety-quiz/selectors';
import { getWeekStart } from '@/shared/business/week';
interface DirectorDashboardDateRange {
readonly startDate: string;
readonly endDate: string;
}
function isDirectorDashboardTimeRange(value: string | null): value is DirectorDashboardTimeRange {
return DIRECTOR_DASHBOARD_TIME_RANGES.some((range) => range === value);
}
function readStoredTimeRange(): DirectorDashboardTimeRange {
if (typeof window === 'undefined') {
return 'month';
}
try {
const stored = window.localStorage.getItem(DIRECTOR_DASHBOARD_TIME_RANGE_STORAGE_KEY);
return isDirectorDashboardTimeRange(stored) ? stored : 'month';
} catch {
return 'month';
}
}
export function getDirectorDashboardDateRange(
timeRange: DirectorDashboardTimeRange,
now = new Date(),
): DirectorDashboardDateRange {
const startDate = timeRange === 'week'
? getWeekStart(now)
: timeRange === 'month'
? startOfMonth(now)
: startOfQuarter(now);
return {
startDate: format(startDate, 'yyyy-MM-dd'),
endDate: format(now, 'yyyy-MM-dd'),
};
}
export function useDirectorDashboardPage(): DirectorDashboardPage {
const { user, profile } = useAuth();
const { effectiveTenant } = useScopeContext();
const role = profile?.role ?? DEFAULT_PRODUCT_ROLE;
const title = getLeadershipDashboardName(role);
const activeTenant = effectiveTenant ?? getActiveTenant(user);
const scopeLabel = activeTenant?.name ?? '';
const scopeKey = activeTenant ? `${activeTenant.level}:${activeTenant.id}` : null;
const [timeRange, setTimeRangeState] = useState<DirectorDashboardTimeRange>(readStoredTimeRange);
const periodFilter = getDirectorDashboardDateRange(timeRange);
const safetyQuizWeek = getCurrentSafetyQuizWeek(new Date());
const frameEntriesQuery = useFrameEntries(periodFilter);
const quizCompletionQuery = useSafetyQuizCompliance(safetyQuizWeek, true);
const emotionalIntelligenceCompletionQuery = usePersonalityCompletion(true);
const zoneCheckinCompletionQuery = useZoneCheckInCompletion(true, scopeKey);
const staffAttendanceRecordsQuery = useStaffAttendanceRecords(periodFilter);
const staffAttendanceSummaryQuery = useStaffAttendanceSummary(periodFilter);
const acknowledgmentReportQuery = usePolicyAcknowledgmentReport();
const frameEntries = frameEntriesQuery.data ?? [];
const quizRows = quizCompletionQuery.data?.rows ?? [];
const emotionalIntelligenceCompletion = emotionalIntelligenceCompletionQuery.data ?? null;
const zoneCheckinCompletion = zoneCheckinCompletionQuery.data ?? null;
const acknowledgmentDocuments = buildDirectorAcknowledgmentDocuments(acknowledgmentReportQuery.data);
const quizSummary = quizCompletionQuery.data?.summary ?? {
totalStaff: 0,
completedCount: 0,
pendingCount: 0,
completionRate: 0,
};
const attendanceRecords = staffAttendanceRecordsQuery.data ?? [];
const isLoading = frameEntriesQuery.isLoading
|| quizCompletionQuery.isLoading
|| emotionalIntelligenceCompletionQuery.isLoading
|| zoneCheckinCompletionQuery.isLoading
|| staffAttendanceRecordsQuery.isLoading
|| staffAttendanceSummaryQuery.isLoading
|| acknowledgmentReportQuery.isLoading;
const error = frameEntriesQuery.error
?? quizCompletionQuery.error
?? emotionalIntelligenceCompletionQuery.error
?? zoneCheckinCompletionQuery.error
?? staffAttendanceRecordsQuery.error
?? staffAttendanceSummaryQuery.error
?? acknowledgmentReportQuery.error;
return {
title,
scopeLabel,
timeRange,
overviewCards: buildDirectorOverviewCards(
attendanceRecords,
quizSummary,
frameEntries,
acknowledgmentReportQuery.data?.summary,
),
riskAreas: buildDirectorRiskAreas(
attendanceRecords,
quizSummary,
emotionalIntelligenceCompletion,
zoneCheckinCompletion,
acknowledgmentDocuments,
),
framePreviews: buildDirectorFramePreviews(frameEntries),
quickActions: DIRECTOR_DASHBOARD_QUICK_ACTIONS,
quizResults: buildDirectorQuizResults(
quizRows,
emotionalIntelligenceCompletion,
zoneCheckinCompletion,
scopeLabel,
),
acknowledgmentDocuments,
isLoading,
error,
setTimeRange: (nextTimeRange) => {
setTimeRangeState(nextTimeRange);
if (typeof window !== 'undefined') {
try {
window.localStorage.setItem(DIRECTOR_DASHBOARD_TIME_RANGE_STORAGE_KEY, nextTimeRange);
} catch {
// The selected range still updates in memory when storage is blocked.
}
}
},
};
}