{"version":3,"sources":["../src/hooks/useExamDetails.ts","../src/types/examDetails.ts"],"sourcesContent":["import { useState, useCallback } from 'react';\nimport dayjs from 'dayjs';\nimport type { BaseApiClient } from '../types/api';\nimport {\n  StudentAnswerStatus,\n  type ExamDetailsData,\n  type ExamStudentResult,\n  type ExamStats,\n  type ExamDetailsPagination,\n  type ExamDetailsFilters,\n} from '../types/examDetails';\nimport { createFetchErrorHandler } from '../utils/hookErrorHandler';\n\n/**\n * Student activity status from backend\n */\nenum StudentActivityStatus {\n  AGUARDANDO_RESPOSTA = 'AGUARDANDO_RESPOSTA',\n  NAO_ENTREGUE = 'NAO_ENTREGUE',\n  CONCLUIDO = 'CONCLUIDO',\n  AGUARDANDO_CORRECAO = 'AGUARDANDO_CORRECAO',\n}\n\n/**\n * API student type\n */\ninterface ApiExamStudent {\n  studentId: string;\n  studentName: string;\n  answeredAt: string | null;\n  timeSpent: number;\n  score: number | null;\n  status: StudentActivityStatus;\n}\n\n/**\n * API breakdown item type\n */\ninterface ApiBreakdownItem {\n  school: { id: string; name: string } | null;\n  schoolYear: { id: string; name: string } | null;\n  class: { id: string; name: string } | null;\n  totalStudents: number;\n  answeredStudents: number;\n  completionPercentage: number;\n}\n\n/**\n * Exam details API response type\n */\nexport interface ExamDetailsApiResponse {\n  message: string;\n  data: {\n    students: ApiExamStudent[];\n    pagination: {\n      total: number;\n      page: number;\n      limit: number;\n      totalPages: number;\n    };\n    generalStats: {\n      averageScore: number;\n      completionPercentage: number;\n    };\n    questionStats: {\n      mostCorrect: number[];\n      mostIncorrect: number[];\n      notAnswered: number[];\n    };\n    breakdown: ApiBreakdownItem[];\n  };\n}\n\n/**\n * Exam info API response type\n */\nexport interface ExamInfoApiResponse {\n  message: string;\n  data: {\n    id: string;\n    title: string;\n    startDate: string | null;\n    createdAt: string;\n    [key: string]: unknown;\n  };\n}\n\n/**\n * Hook state interface\n */\nexport interface UseExamDetailsState {\n  examData: ExamDetailsData | null;\n  loading: boolean;\n  error: string | null;\n  pagination: ExamDetailsPagination;\n}\n\n/**\n * Hook return type\n */\nexport interface UseExamDetailsReturn extends UseExamDetailsState {\n  fetchExamDetails: (\n    examId: string,\n    filters?: ExamDetailsFilters\n  ) => Promise<void>;\n}\n\n/**\n * Default pagination values\n */\nexport const DEFAULT_EXAM_DETAILS_PAGINATION: ExamDetailsPagination = {\n  total: 0,\n  page: 1,\n  limit: 10,\n  totalPages: 0,\n};\n\n/**\n * Map backend status to frontend status\n */\nexport const mapBackendStatusToFrontend = (\n  status: StudentActivityStatus\n): StudentAnswerStatus => {\n  // If student completed or is awaiting correction, answer sheet was received\n  // If awaiting response or not delivered, still waiting for answer sheet\n  if (\n    status === StudentActivityStatus.CONCLUIDO ||\n    status === StudentActivityStatus.AGUARDANDO_CORRECAO\n  ) {\n    return StudentAnswerStatus.ANSWER_SHEET_RECEIVED;\n  }\n  return StudentAnswerStatus.AWAITING_ANSWER_SHEET;\n};\n\n/**\n * Transform API student to frontend format\n */\nexport const transformStudent = (\n  student: ApiExamStudent\n): ExamStudentResult => ({\n  id: student.studentId,\n  studentId: student.studentId,\n  studentName: student.studentName,\n  status: mapBackendStatusToFrontend(student.status),\n  answerReceivedAt: student.answeredAt\n    ? dayjs(student.answeredAt).format('DD MMM YYYY')\n    : null,\n  score: student.score,\n});\n\n/**\n * Handle errors during exam fetch\n */\nexport const handleExamDetailsFetchError = createFetchErrorHandler(\n  'Erro ao validar dados de detalhes da prova',\n  'Erro ao carregar detalhes da prova'\n);\n\n/**\n * Build query params from filters\n */\nconst buildQueryParams = (\n  filters?: ExamDetailsFilters\n): Record<string, unknown> => {\n  if (!filters) return {};\n\n  const params: Record<string, unknown> = {};\n  for (const key in filters) {\n    const value = filters[key as keyof ExamDetailsFilters];\n    if (value !== undefined && value !== null) {\n      params[key] = value;\n    }\n  }\n  return params;\n};\n\n/**\n * Hook implementation\n */\nconst useExamDetailsImpl = (apiClient: BaseApiClient): UseExamDetailsReturn => {\n  const [state, setState] = useState<UseExamDetailsState>({\n    examData: null,\n    loading: false,\n    error: null,\n    pagination: DEFAULT_EXAM_DETAILS_PAGINATION,\n  });\n\n  /**\n   * Fetch exam details from API\n   */\n  const fetchExamDetails = useCallback(\n    async (examId: string, filters?: ExamDetailsFilters) => {\n      setState((prev) => ({ ...prev, loading: true, error: null }));\n\n      try {\n        const params = buildQueryParams(filters);\n\n        // Fetch exam info and details in parallel using activities endpoints\n        // Use /quiz endpoint instead of /:id to support all user profiles (teachers, managers)\n        const [examInfoResponse, examDetailsResponse] = await Promise.all([\n          apiClient.get<ExamInfoApiResponse>(`/activities/${examId}/quiz`),\n          apiClient.get<ExamDetailsApiResponse>(\n            `/activities/${examId}/details`,\n            {\n              params,\n            }\n          ),\n        ]);\n\n        const examInfo = examInfoResponse.data;\n        const examDetails = examDetailsResponse.data;\n\n        // Transform students\n        const students = examDetails.data.students.map(transformStudent);\n\n        // Build exam stats\n        const stats: ExamStats = {\n          averageScore: examDetails.data.generalStats.averageScore,\n          mostCorrectQuestions: examDetails.data.questionStats.mostCorrect,\n          mostIncorrectQuestions: examDetails.data.questionStats.mostIncorrect,\n          unansweredQuestions: examDetails.data.questionStats.notAnswered,\n        };\n\n        // Extract school and class from breakdown\n        const breakdown = examDetails.data.breakdown;\n\n        // Get unique school names from breakdown\n        const schoolNames = [\n          ...new Set(\n            breakdown\n              .map((b) => b.school?.name)\n              .filter((name): name is string => !!name)\n          ),\n        ];\n\n        // Get unique class names from breakdown\n        const classNames = [\n          ...new Set(\n            breakdown\n              .map((b) => b.class?.name)\n              .filter((name): name is string => !!name)\n          ),\n        ];\n\n        // Build exam data\n        const examData: ExamDetailsData = {\n          id: examInfo.data.id,\n          title: examInfo.data.title,\n          startDate: examInfo.data.startDate\n            ? dayjs(examInfo.data.startDate).format('DD/MM/YYYY')\n            : '-',\n          school: schoolNames.length > 0 ? schoolNames.join(', ') : '-',\n          className: classNames.length > 0 ? classNames.join(', ') : '-',\n          createdAt: dayjs(examInfo.data.createdAt).format('DD/MM/YYYY'),\n          stats,\n          students,\n        };\n\n        setState({\n          examData,\n          loading: false,\n          error: null,\n          pagination: examDetails.data.pagination,\n        });\n      } catch (error) {\n        const errorMessage = handleExamDetailsFetchError(error);\n        setState((prev) => ({\n          ...prev,\n          loading: false,\n          error: errorMessage,\n        }));\n      }\n    },\n    [apiClient]\n  );\n\n  return {\n    ...state,\n    fetchExamDetails,\n  };\n};\n\n/**\n * Factory function to create useExamDetails hook\n *\n * @param apiClient - API client instance (axios, fetch wrapper, etc.)\n * @returns Hook for managing exam details\n *\n * @example\n * ```tsx\n * // In your app setup\n * import { createUseExamDetails } from 'analytica-frontend-lib';\n * import api from '@/services/apiService';\n *\n * export const useExamDetails = createUseExamDetails(api);\n *\n * // In your component\n * const { examData, loading, error, pagination, fetchExamDetails } = useExamDetails();\n *\n * useEffect(() => {\n *   if (examId) {\n *     fetchExamDetails(examId, { page: 1, limit: 10 });\n *   }\n * }, [examId]);\n * ```\n */\nexport const createUseExamDetails = (apiClient: BaseApiClient) => {\n  return (): UseExamDetailsReturn => useExamDetailsImpl(apiClient);\n};\n\n/**\n * Alias for createUseExamDetails\n */\nexport const createExamDetailsHook = createUseExamDetails;\n","/**\n * Exam Details Types\n *\n * This file contains types for the exam details page,\n * including student results, statistics, and status enums.\n */\n\n/**\n * Student answer status enum\n * Represents the state of a student's answer sheet submission\n */\nexport enum StudentAnswerStatus {\n  AWAITING_ANSWER_SHEET = 'AWAITING_ANSWER_SHEET',\n  ANSWER_SHEET_RECEIVED = 'ANSWER_SHEET_RECEIVED',\n}\n\n/**\n * Student answer display status for UI\n */\nexport enum StudentAnswerDisplayStatus {\n  AWAITING_ANSWER_SHEET = 'Aguardando gabarito',\n  ANSWER_SHEET_RECEIVED = 'Gabarito recebido',\n}\n\n/**\n * Student result in exam table\n */\nexport interface ExamStudentResult {\n  id: string;\n  studentId: string;\n  studentName: string;\n  status: StudentAnswerStatus;\n  answerReceivedAt: string | null;\n  score: number | null;\n}\n\n/**\n * Student table item for TableProvider\n * Extends Record<string, unknown> for compatibility with generic table\n */\nexport interface ExamStudentTableItem extends Record<string, unknown> {\n  id: string;\n  studentId: string;\n  studentName: string;\n  status: StudentAnswerStatus;\n  answerReceivedAt: string | null;\n  score: number | null;\n}\n\n/**\n * Exam statistics data\n */\nexport interface ExamStats {\n  averageScore: number;\n  mostCorrectQuestions: number[];\n  mostIncorrectQuestions: number[];\n  unansweredQuestions: number[];\n}\n\n/**\n * Exam details data (used for page display)\n */\nexport interface ExamDetailsData {\n  id: string;\n  title: string;\n  startDate: string;\n  school: string;\n  className: string;\n  createdAt: string;\n  stats: ExamStats;\n  students: ExamStudentResult[];\n}\n\n/**\n * Pagination data for exam details\n */\nexport interface ExamDetailsPagination {\n  total: number;\n  page: number;\n  limit: number;\n  totalPages: number;\n}\n\n/**\n * Query filters for exam details\n */\nexport interface ExamDetailsFilters {\n  page?: number;\n  limit?: number;\n  sortBy?: 'name' | 'score' | 'answeredAt';\n  sortOrder?: 'asc' | 'desc';\n  status?: string;\n}\n"],"mappings":"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","names":["StudentAnswerStatus","StudentAnswerDisplayStatus"]}