import { useState, useEffect, useCallback } from 'react'; import { audit } from '../services/audit.service'; import { AuditEvent, AuditEventStats } from '../types'; interface UseUserActivityOptions { range?: 'today' | 'last7days' | 'last30days' | 'custom'; startDate?: Date; endDate?: Date; autoLoad?: boolean; } export function useUserActivity(userId: string, options: UseUserActivityOptions = {}) { const { range = 'last30days', startDate, endDate, autoLoad = true } = options; const [activity, setActivity] = useState([]); const [stats, setStats] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const getDateRange = useCallback(() => { const now = new Date(); let start: Date; let end = endDate || now; switch (range) { case 'today': start = new Date(now.getFullYear(), now.getMonth(), now.getDate()); break; case 'last7days': start = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000); break; case 'last30days': start = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000); break; case 'custom': start = startDate || new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000); break; default: start = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000); } return { start, end }; }, [range, startDate, endDate]); const loadActivity = useCallback(async () => { if (!userId) return; setLoading(true); setError(null); try { const { start, end } = getDateRange(); const events = await audit.getUserActivity(userId, start, end); setActivity(events); // Calculate stats const calculatedStats: AuditEventStats = { total: events.length, byAction: {}, byActor: {}, byResource: {}, byResult: {}, byHour: {}, byDay: {}, }; events.forEach(event => { // By action calculatedStats.byAction[event.action] = (calculatedStats.byAction[event.action] || 0) + 1; // By actor const actorKey = `${event.actor.type}:${event.actor.id}`; calculatedStats.byActor[actorKey] = (calculatedStats.byActor[actorKey] || 0) + 1; // By resource calculatedStats.byResource[event.resource.type] = (calculatedStats.byResource[event.resource.type] || 0) + 1; // By result calculatedStats.byResult[event.result] = (calculatedStats.byResult[event.result] || 0) + 1; // By hour const hour = event.timestamp.getHours(); calculatedStats.byHour![hour] = (calculatedStats.byHour![hour] || 0) + 1; // By day const day = event.timestamp.toDateString(); calculatedStats.byDay![day] = (calculatedStats.byDay![day] || 0) + 1; }); setStats(calculatedStats); } catch (err: any) { setError(err); } finally { setLoading(false); } }, [userId, getDateRange]); const refresh = useCallback(() => { loadActivity(); }, [loadActivity]); // Auto-load on mount and when dependencies change useEffect(() => { if (autoLoad) { loadActivity(); } }, [autoLoad, loadActivity]); return { activity, stats, loading, error, refresh, }; }