{"version":3,"sources":["../src/hooks/useSimulations.ts"],"sourcesContent":["import { useCallback, useMemo } from 'react';\nimport type { BaseApiClient } from '../types/api';\nimport type {\n  SimulationsStudentsResponse,\n  SimulationsStudentsPage,\n  SimulationsStudentsFilters,\n  SimulationsListResponse,\n  SimulationsListData,\n  SimulationsListFilters,\n  SimulationDetailResponse,\n  SimulationDetailData,\n  NoteResponse,\n  NoteData,\n} from '../types/simulations';\n\nconst BASE_URL = '/performance/simulations';\n\n/** Encode a value before interpolating it into a request path segment. */\nconst segment = (value: string) => encodeURIComponent(value);\n\n/**\n * Hook return type for the teacher-facing Simulations feature.\n *\n * The hook exposes imperative fetchers (rather than holding everything in\n * state) because the UI loads data lazily across three nested levels:\n * students list -> a student's simulations -> a simulation's questions.\n */\nexport interface UseSimulationsReturn {\n  fetchStudents: (\n    filters?: SimulationsStudentsFilters\n  ) => Promise<SimulationsStudentsPage>;\n  fetchStudentSimulations: (\n    userInstitutionId: string,\n    filters?: SimulationsListFilters\n  ) => Promise<SimulationsListData>;\n  fetchSimulationDetail: (\n    userInstitutionId: string,\n    simulationId: string\n  ) => Promise<SimulationDetailData>;\n  fetchNote: (\n    userInstitutionId: string,\n    simulationId: string\n  ) => Promise<NoteData | null>;\n  saveNote: (\n    userInstitutionId: string,\n    simulationId: string,\n    note: string\n  ) => Promise<NoteData | null>;\n}\n\n/**\n * Factory that binds an API client to the Simulations hook.\n *\n * @example\n * ```tsx\n * const useSimulations = createUseSimulations(api);\n * const { fetchStudents } = useSimulations();\n * ```\n */\nexport const createUseSimulations =\n  (apiClient: BaseApiClient) => (): UseSimulationsReturn => {\n    const fetchStudents = useCallback(\n      async (\n        filters: SimulationsStudentsFilters = {}\n      ): Promise<SimulationsStudentsPage> => {\n        const { page = 1, limit = 20, search, classIds } = filters;\n        const response = await apiClient.get<SimulationsStudentsResponse>(\n          `${BASE_URL}/students`,\n          { params: { page, limit, search, classIds } }\n        );\n        return response.data.data.students;\n      },\n      []\n    );\n\n    const fetchStudentSimulations = useCallback(\n      async (\n        userInstitutionId: string,\n        filters: SimulationsListFilters = {}\n      ): Promise<SimulationsListData> => {\n        const { page = 1, limit = 20 } = filters;\n        const response = await apiClient.get<SimulationsListResponse>(\n          `${BASE_URL}/students/${segment(userInstitutionId)}`,\n          { params: { page, limit } }\n        );\n        return response.data.data;\n      },\n      []\n    );\n\n    const fetchSimulationDetail = useCallback(\n      async (\n        userInstitutionId: string,\n        simulationId: string\n      ): Promise<SimulationDetailData> => {\n        const response = await apiClient.get<SimulationDetailResponse>(\n          `${BASE_URL}/students/${segment(userInstitutionId)}/${segment(simulationId)}`\n        );\n        return response.data.data;\n      },\n      []\n    );\n\n    const fetchNote = useCallback(\n      async (\n        userInstitutionId: string,\n        simulationId: string\n      ): Promise<NoteData | null> => {\n        const response = await apiClient.get<NoteResponse>(\n          `${BASE_URL}/students/${segment(userInstitutionId)}/${segment(simulationId)}/note`\n        );\n        return response.data.data;\n      },\n      []\n    );\n\n    const saveNote = useCallback(\n      async (\n        userInstitutionId: string,\n        simulationId: string,\n        note: string\n      ): Promise<NoteData | null> => {\n        const response = await apiClient.post<NoteResponse>(\n          `${BASE_URL}/students/${segment(userInstitutionId)}/${segment(simulationId)}/note`,\n          { note }\n        );\n        return response.data.data;\n      },\n      []\n    );\n\n    return useMemo(\n      () => ({\n        fetchStudents,\n        fetchStudentSimulations,\n        fetchSimulationDetail,\n        fetchNote,\n        saveNote,\n      }),\n      [\n        fetchStudents,\n        fetchStudentSimulations,\n        fetchSimulationDetail,\n        fetchNote,\n        saveNote,\n      ]\n    );\n  };\n"],"mappings":";AAAA,SAAS,aAAa,eAAe;AAerC,IAAM,WAAW;AAGjB,IAAM,UAAU,CAAC,UAAkB,mBAAmB,KAAK;AAyCpD,IAAM,uBACX,CAAC,cAA6B,MAA4B;AACxD,QAAM,gBAAgB;AAAA,IACpB,OACE,UAAsC,CAAC,MACF;AACrC,YAAM,EAAE,OAAO,GAAG,QAAQ,IAAI,QAAQ,SAAS,IAAI;AACnD,YAAM,WAAW,MAAM,UAAU;AAAA,QAC/B,GAAG,QAAQ;AAAA,QACX,EAAE,QAAQ,EAAE,MAAM,OAAO,QAAQ,SAAS,EAAE;AAAA,MAC9C;AACA,aAAO,SAAS,KAAK,KAAK;AAAA,IAC5B;AAAA,IACA,CAAC;AAAA,EACH;AAEA,QAAM,0BAA0B;AAAA,IAC9B,OACE,mBACA,UAAkC,CAAC,MACF;AACjC,YAAM,EAAE,OAAO,GAAG,QAAQ,GAAG,IAAI;AACjC,YAAM,WAAW,MAAM,UAAU;AAAA,QAC/B,GAAG,QAAQ,aAAa,QAAQ,iBAAiB,CAAC;AAAA,QAClD,EAAE,QAAQ,EAAE,MAAM,MAAM,EAAE;AAAA,MAC5B;AACA,aAAO,SAAS,KAAK;AAAA,IACvB;AAAA,IACA,CAAC;AAAA,EACH;AAEA,QAAM,wBAAwB;AAAA,IAC5B,OACE,mBACA,iBACkC;AAClC,YAAM,WAAW,MAAM,UAAU;AAAA,QAC/B,GAAG,QAAQ,aAAa,QAAQ,iBAAiB,CAAC,IAAI,QAAQ,YAAY,CAAC;AAAA,MAC7E;AACA,aAAO,SAAS,KAAK;AAAA,IACvB;AAAA,IACA,CAAC;AAAA,EACH;AAEA,QAAM,YAAY;AAAA,IAChB,OACE,mBACA,iBAC6B;AAC7B,YAAM,WAAW,MAAM,UAAU;AAAA,QAC/B,GAAG,QAAQ,aAAa,QAAQ,iBAAiB,CAAC,IAAI,QAAQ,YAAY,CAAC;AAAA,MAC7E;AACA,aAAO,SAAS,KAAK;AAAA,IACvB;AAAA,IACA,CAAC;AAAA,EACH;AAEA,QAAM,WAAW;AAAA,IACf,OACE,mBACA,cACA,SAC6B;AAC7B,YAAM,WAAW,MAAM,UAAU;AAAA,QAC/B,GAAG,QAAQ,aAAa,QAAQ,iBAAiB,CAAC,IAAI,QAAQ,YAAY,CAAC;AAAA,QAC3E,EAAE,KAAK;AAAA,MACT;AACA,aAAO,SAAS,KAAK;AAAA,IACvB;AAAA,IACA,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;","names":[]}