/** * Admin API Hooks * React Query hooks for admin operations */ import type { CreateAnnouncementRequest, CreatePageRequest, CreateUserRequest, UpdatePageRequest, UpdateUserRequest, } from '@/services/admin-api'; import * as adminApi from '@/services/admin-api'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; // ============================================================================ // Query Keys // ============================================================================ export const adminKeys = { all: ['admin'] as const, dashboard: { all: ['admin', 'dashboard'] as const, stats: () => [...adminKeys.dashboard.all, 'stats'] as const, activity: () => [...adminKeys.dashboard.all, 'activity'] as const, }, analytics: { all: ['admin', 'analytics'] as const, organizations: () => [...adminKeys.analytics.all, 'organizations'] as const, users: () => [...adminKeys.analytics.all, 'users'] as const, matching: () => [...adminKeys.analytics.all, 'matching'] as const, }, system: { all: ['admin', 'system'] as const, health: () => [...adminKeys.system.all, 'health'] as const, }, users: { all: ['admin', 'users'] as const, lists: (params?: unknown) => [...adminKeys.users.all, 'list', params] as const, detail: (id: string) => [...adminKeys.users.all, 'detail', id] as const, stats: () => [...adminKeys.users.all, 'stats'] as const, activity: (id: string, params?: unknown) => [...adminKeys.users.all, 'activity', id, params] as const, }, organizations: { all: ['admin', 'organizations'] as const, verificationQueue: (params?: unknown) => [...adminKeys.organizations.all, 'verification-queue', params] as const, stats: () => [...adminKeys.organizations.all, 'stats'] as const, }, i18n: { all: ['admin', 'i18n'] as const, translationKeys: (locale: string) => [...adminKeys.i18n.all, 'translation-keys', locale] as const, }, content: { all: ['admin', 'content'] as const, pages: { all: ['admin', 'content', 'pages'] as const, lists: () => [...adminKeys.content.pages.all, 'list'] as const, detail: (id: string) => [...adminKeys.content.pages.all, 'detail', id] as const, }, announcements: { all: ['admin', 'content', 'announcements'] as const, lists: (params?: unknown) => [...adminKeys.content.announcements.all, 'list', params] as const, detail: (id: string) => [...adminKeys.content.announcements.all, 'detail', id] as const, }, media: { all: ['admin', 'content', 'media'] as const, lists: (params?: unknown) => [...adminKeys.content.media.all, 'list', params] as const, detail: (id: string) => [...adminKeys.content.media.all, 'detail', id] as const, }, }, }; // ============================================================================ // Dashboard & Statistics // ============================================================================ /** * Get dashboard statistics */ export function useDashboardStats() { return useQuery({ queryKey: adminKeys.dashboard.stats(), queryFn: () => adminApi.getDashboardStats(), staleTime: 30000, // 30 seconds retry: (failureCount, error: Error) => { // Don't retry on 403 (Forbidden) or 401 (Unauthorized) errors if (error?.status === 403 || error?.status === 401) { return false; } // Retry up to 2 times for other errors return failureCount < 2; }, retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000), }); } /** * Get recent activity for admin dashboard */ export function useRecentActivity() { return useQuery({ queryKey: adminKeys.dashboard.activity(), queryFn: () => adminApi.getRecentActivity(), staleTime: 30 * 1000, }); } /** * Get organization statistics */ export function useOrganizationStats() { return useQuery({ queryKey: adminKeys.analytics.organizations(), queryFn: () => adminApi.getOrganizationStats(), staleTime: 60000, // 1 minute }); } /** * Get user activity statistics */ export function useUserActivityStats() { return useQuery({ queryKey: adminKeys.analytics.users(), queryFn: () => adminApi.getUserActivityStats(), staleTime: 60000, // 1 minute }); } /** * Get matching statistics */ export function useMatchingStats() { return useQuery({ queryKey: adminKeys.analytics.matching(), queryFn: () => adminApi.getMatchingStats(), staleTime: 60000, // 1 minute }); } /** * Get system health */ export function useSystemHealth() { return useQuery({ queryKey: adminKeys.system.health(), queryFn: () => adminApi.getSystemHealth(), staleTime: 10000, // 10 seconds refetchInterval: 30000, // Refetch every 30 seconds }); } // ============================================================================ // Maintenance // ============================================================================ export const maintenanceKeys = { all: ['admin', 'maintenance'] as const, setting: () => [...maintenanceKeys.all, 'setting'] as const, }; export function useMaintenanceSetting() { return useQuery({ queryKey: maintenanceKeys.setting(), queryFn: () => adminApi.getMaintenance(), staleTime: 5000, retry: false, }); } export function useSetMaintenance() { const qc = useQueryClient(); return useMutation({ mutationFn: (request: adminApi.MaintenanceSetting) => adminApi.setMaintenance(request), onSuccess: () => qc.invalidateQueries({ queryKey: maintenanceKeys.setting() }), }); } // ============================================================================ // User Management // ============================================================================ /** * List users */ export function useUsers(params?: { role?: string; isActive?: boolean; search?: string; limit?: number; offset?: number; }) { return useQuery({ queryKey: adminKeys.users.lists(params), queryFn: () => adminApi.listUsers(params), }); } /** * Get user by ID */ export function useUser(id: string | null | undefined) { return useQuery({ queryKey: adminKeys.users.detail(id!), queryFn: () => adminApi.getUser(id!), enabled: !!id, }); } /** * Create user mutation */ export function useCreateUser() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (request: CreateUserRequest) => adminApi.createUser(request), onSuccess: () => { queryClient.invalidateQueries({ queryKey: adminKeys.users.lists() }); queryClient.invalidateQueries({ queryKey: adminKeys.users.stats() }); }, }); } /** * Update user mutation */ export function useUpdateUser() { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ id, request }: { id: string; request: UpdateUserRequest }) => adminApi.updateUser(id, request), onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: adminKeys.users.lists() }); queryClient.invalidateQueries({ queryKey: adminKeys.users.detail(variables.id) }); queryClient.invalidateQueries({ queryKey: adminKeys.users.stats() }); }, }); } /** * Update user role mutation */ export function useUpdateUserRole() { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ id, role }: { id: string; role: string }) => adminApi.updateUserRole(id, role), onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: adminKeys.users.lists() }); queryClient.invalidateQueries({ queryKey: adminKeys.users.detail(variables.id) }); }, }); } /** * Update user permissions mutation */ export function useUpdateUserPermissions() { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ id, permissions }: { id: string; permissions: string[] }) => adminApi.updateUserPermissions(id, permissions), onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: adminKeys.users.lists() }); queryClient.invalidateQueries({ queryKey: adminKeys.users.detail(variables.id) }); }, }); } /** * Deactivate user mutation */ export function useDeactivateUser() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (id: string) => adminApi.deactivateUser(id), onSuccess: () => { queryClient.invalidateQueries({ queryKey: adminKeys.users.lists() }); queryClient.invalidateQueries({ queryKey: adminKeys.users.stats() }); }, }); } /** * Get user activity log */ export function useUserActivity( id: string | null | undefined, params?: { limit?: number; offset?: number } ) { return useQuery({ queryKey: adminKeys.users.activity(id!, params), queryFn: () => adminApi.getUserActivity(id!, params), enabled: !!id, }); } /** * Get user statistics */ export function useUserStats() { return useQuery({ queryKey: adminKeys.users.stats(), queryFn: () => adminApi.getUserStats(), staleTime: 60000, // 1 minute }); } // ============================================================================ // Organization Verification // ============================================================================ /** * Get verification queue */ export function useVerificationQueue(params?: { status?: string; dataType?: string; organizationId?: string; }) { return useQuery({ queryKey: adminKeys.organizations.verificationQueue(params), queryFn: () => adminApi.getVerificationQueue(params), staleTime: 30000, // 30 seconds }); } /** * Verify organization mutation */ export function useVerifyOrganization() { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ id, notes }: { id: string; notes?: string }) => adminApi.verifyOrganization(id, notes), onSuccess: () => { queryClient.invalidateQueries({ queryKey: adminKeys.organizations.verificationQueue() }); queryClient.invalidateQueries({ queryKey: adminKeys.organizations.stats() }); queryClient.invalidateQueries({ queryKey: ['organizations'] }); }, }); } /** * Reject verification mutation */ export function useRejectVerification() { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ id, reason, notes }: { id: string; reason: string; notes?: string }) => adminApi.rejectVerification(id, reason, notes), onSuccess: () => { queryClient.invalidateQueries({ queryKey: adminKeys.organizations.verificationQueue() }); }, }); } /** * Bulk verify organizations mutation */ export function useBulkVerifyOrganizations() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (organizationIds: string[]) => adminApi.bulkVerifyOrganizations(organizationIds), onSuccess: () => { queryClient.invalidateQueries({ queryKey: adminKeys.organizations.verificationQueue() }); queryClient.invalidateQueries({ queryKey: adminKeys.organizations.stats() }); queryClient.invalidateQueries({ queryKey: ['organizations'] }); }, }); } /** * Get organization statistics (admin) */ export function useOrganizationStatsAdmin() { return useQuery({ queryKey: adminKeys.organizations.stats(), queryFn: () => adminApi.getOrganizationStatsAdmin(), staleTime: 60000, // 1 minute }); } // ============================================================================ // Localization Management // ============================================================================ /** * Get translation keys for a locale */ export function useTranslationKeys(locale: string) { return useQuery({ queryKey: adminKeys.i18n.translationKeys(locale), queryFn: () => adminApi.getTranslationKeys(locale), enabled: !!locale, }); } /** * Update UI translation mutation */ export function useUpdateUITranslation() { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ locale, key, value }: { locale: string; key: string; value: string }) => adminApi.updateUITranslation(locale, key, value), onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: adminKeys.i18n.translationKeys(variables.locale) }); }, }); } /** * Bulk update UI translations mutation */ export function useBulkUpdateUITranslations() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (updates: Array<{ locale: string; key: string; value: string }>) => adminApi.bulkUpdateUITranslations(updates), onSuccess: () => { queryClient.invalidateQueries({ queryKey: adminKeys.i18n.all }); }, }); } /** * Auto-translate missing keys mutation */ export function useAutoTranslateMissing() { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ sourceLocale, targetLocale }: { sourceLocale: string; targetLocale: string }) => adminApi.autoTranslateMissing(sourceLocale, targetLocale), onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: adminKeys.i18n.translationKeys(variables.targetLocale), }); }, }); } /** * Update data translation mutation */ export function useUpdateDataTranslation() { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ entityType, entityID, field, locale, value, }: { entityType: string; entityID: string; field: string; locale: string; value: string; }) => adminApi.updateDataTranslation(entityType, entityID, field, locale, value), onSuccess: () => { queryClient.invalidateQueries({ queryKey: adminKeys.i18n.all }); }, }); } // ============================================================================ // Content Management // ============================================================================ /** * List static pages */ export function usePages() { return useQuery({ queryKey: adminKeys.content.pages.lists(), queryFn: () => adminApi.listPages(), retry: (failureCount, error: Error) => { // Don't retry on 403 (Forbidden) or 401 (Unauthorized) errors if (error?.status === 403 || error?.status === 401) { return false; } // Retry up to 2 times for other errors return failureCount < 2; }, retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000), }); } /** * Get page by ID */ export function usePage(id: string | null | undefined) { return useQuery({ queryKey: adminKeys.content.pages.detail(id!), queryFn: () => adminApi.getPage(id!), enabled: !!id, }); } /** * Create page mutation */ export function useCreatePage() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (request: CreatePageRequest) => adminApi.createPage(request), onSuccess: () => { queryClient.invalidateQueries({ queryKey: adminKeys.content.pages.lists() }); }, }); } /** * Update page mutation */ export function useUpdatePage() { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ id, request }: { id: string; request: UpdatePageRequest }) => adminApi.updatePage(id, request), onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: adminKeys.content.pages.lists() }); queryClient.invalidateQueries({ queryKey: adminKeys.content.pages.detail(variables.id) }); }, }); } /** * Delete page mutation */ export function useDeletePage() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (id: string) => adminApi.deletePage(id), onSuccess: () => { queryClient.invalidateQueries({ queryKey: adminKeys.content.pages.lists() }); }, }); } /** * Publish page mutation */ export function usePublishPage() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (id: string) => adminApi.publishPage(id), onSuccess: (_, id) => { queryClient.invalidateQueries({ queryKey: adminKeys.content.pages.lists() }); queryClient.invalidateQueries({ queryKey: adminKeys.content.pages.detail(id) }); }, }); } /** * List announcements */ export function useAnnouncements(params?: { isActive?: boolean; priority?: string }) { return useQuery({ queryKey: adminKeys.content.announcements.lists(params), queryFn: () => adminApi.listAnnouncements(params), retry: (failureCount, error: Error) => { // Don't retry on 403 (Forbidden) or 401 (Unauthorized) errors if (error?.status === 403 || error?.status === 401) { return false; } // Retry up to 2 times for other errors return failureCount < 2; }, retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000), }); } /** * Get announcement by ID */ export function useAnnouncement(id: string | null | undefined) { return useQuery({ queryKey: adminKeys.content.announcements.detail(id!), queryFn: () => adminApi.getAnnouncement(id!), enabled: !!id, }); } /** * Create announcement mutation */ export function useCreateAnnouncement() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (request: CreateAnnouncementRequest) => adminApi.createAnnouncement(request), onSuccess: () => { queryClient.invalidateQueries({ queryKey: adminKeys.content.announcements.lists() }); }, }); } /** * Update announcement mutation */ export function useUpdateAnnouncement() { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ id, request }: { id: string; request: Partial }) => adminApi.updateAnnouncement(id, request), onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: adminKeys.content.announcements.lists() }); queryClient.invalidateQueries({ queryKey: adminKeys.content.announcements.detail(variables.id), }); }, }); } /** * Delete announcement mutation */ export function useDeleteAnnouncement() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (id: string) => adminApi.deleteAnnouncement(id), onSuccess: () => { queryClient.invalidateQueries({ queryKey: adminKeys.content.announcements.lists() }); }, }); } /** * List media assets */ export function useMediaAssets(params?: { type?: string; tags?: string }) { return useQuery({ queryKey: adminKeys.content.media.lists(params), queryFn: () => adminApi.listMediaAssets(params), retry: (failureCount, error: Error) => { // Don't retry on 403 (Forbidden) or 401 (Unauthorized) errors if (error?.status === 403 || error?.status === 401) { return false; } // Retry up to 2 times for other errors return failureCount < 2; }, retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000), }); } /** * Get media asset by ID */ export function useMediaAsset(id: string | null | undefined) { return useQuery({ queryKey: adminKeys.content.media.detail(id!), queryFn: () => adminApi.getMediaAsset(id!), enabled: !!id, }); } /** * Create media asset mutation */ export function useCreateMediaAsset() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (request: { filename: string; originalName: string; url: string; type: string; mimeType?: string; size?: number; width?: number; height?: number; duration?: number; altText?: string; tags?: string[]; }) => adminApi.createMediaAsset(request), onSuccess: () => { queryClient.invalidateQueries({ queryKey: adminKeys.content.media.lists() }); }, }); } /** * Update media asset mutation */ export function useUpdateMediaAsset() { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ id, request }: { id: string; request: { altText?: string; tags?: string[] } }) => adminApi.updateMediaAsset(id, request), onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: adminKeys.content.media.lists() }); queryClient.invalidateQueries({ queryKey: adminKeys.content.media.detail(variables.id) }); }, }); } /** * Delete media asset mutation */ export function useDeleteMediaAsset() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (id: string) => adminApi.deleteMediaAsset(id), onSuccess: () => { queryClient.invalidateQueries({ queryKey: adminKeys.content.media.lists() }); }, }); }