analytica-frontend-lib 1.4.36 → 1.4.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"useSendActivity.d.ts","sourceRoot":"","sources":["../../src/hooks/useSendActivity.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,OAAO,KAAK,EACV,qBAAqB,EACrB,qBAAqB,EAGtB,MAAM,uBAAuB,CAAC;AA8D/B;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,qBAAqB,GAC5B,qBAAqB,CAuKvB"}
1
+ {"version":3,"file":"useSendActivity.d.ts","sourceRoot":"","sources":["../../src/hooks/useSendActivity.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,OAAO,KAAK,EACV,qBAAqB,EACrB,qBAAqB,EAEtB,MAAM,uBAAuB,CAAC;AAe/B;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,qBAAqB,GAC5B,qBAAqB,CAoJvB"}
@@ -33,87 +33,343 @@ __export(useSendActivity_exports, {
33
33
  useSendActivity: () => useSendActivity
34
34
  });
35
35
  module.exports = __toCommonJS(useSendActivity_exports);
36
- var import_react = require("react");
36
+ var import_react2 = require("react");
37
37
  var import_dayjs = __toESM(require("dayjs"));
38
- function transformToCategoryConfig(data) {
39
- return [
38
+
39
+ // src/utils/categoryDataUtils.ts
40
+ async function fetchStudentsByFilters(apiClient, filters) {
41
+ if ((!filters.schoolIds || filters.schoolIds.length === 0) && (!filters.schoolYearIds || filters.schoolYearIds.length === 0) && (!filters.classIds || filters.classIds.length === 0)) {
42
+ return [];
43
+ }
44
+ const response = await apiClient.post("/students/filters", {
45
+ ...filters.schoolIds && filters.schoolIds.length > 0 && {
46
+ schoolIds: filters.schoolIds
47
+ },
48
+ ...filters.schoolYearIds && filters.schoolYearIds.length > 0 && {
49
+ schoolYearIds: filters.schoolYearIds
50
+ },
51
+ ...filters.classIds && filters.classIds.length > 0 && {
52
+ classIds: filters.classIds
53
+ }
54
+ });
55
+ return response.data.data.students || [];
56
+ }
57
+ async function loadCategoriesData(apiClient, existingCategories) {
58
+ if (existingCategories.length > 0) {
59
+ return existingCategories;
60
+ }
61
+ const [schoolsResponse, schoolYearsResponse, classesResponse] = await Promise.all([
62
+ apiClient.get(
63
+ "/school"
64
+ ),
65
+ apiClient.get("/schoolYear"),
66
+ apiClient.get("/classes")
67
+ ]);
68
+ const schools = schoolsResponse.data.data.schools;
69
+ const schoolYears = schoolYearsResponse.data.data.schoolYears;
70
+ const classes = classesResponse.data.data.classes;
71
+ const transformedCategories = [
40
72
  {
41
73
  key: "escola",
42
74
  label: "Escola",
43
- itens: data.schools,
75
+ itens: schools.map((s) => ({ id: s.id, name: s.companyName })),
44
76
  selectedIds: []
45
77
  },
46
78
  {
47
79
  key: "serie",
48
80
  label: "S\xE9rie",
49
81
  dependsOn: ["escola"],
50
- itens: data.schoolYears,
51
- filteredBy: [{ key: "escola", internalField: "escolaId" }],
82
+ filteredBy: [{ key: "escola", internalField: "schoolId" }],
83
+ itens: schoolYears.map((sy) => ({
84
+ id: sy.id,
85
+ name: sy.name,
86
+ schoolId: sy.schoolId
87
+ })),
52
88
  selectedIds: []
53
89
  },
54
90
  {
55
91
  key: "turma",
56
92
  label: "Turma",
57
- dependsOn: ["escola", "serie"],
58
- itens: data.classes,
59
- filteredBy: [
60
- { key: "escola", internalField: "escolaId" },
61
- { key: "serie", internalField: "serieId" }
62
- ],
93
+ dependsOn: ["serie"],
94
+ filteredBy: [{ key: "serie", internalField: "schoolYearId" }],
95
+ itens: classes.map((c) => ({
96
+ id: c.id,
97
+ name: c.name,
98
+ schoolYearId: c.schoolYearId
99
+ })),
63
100
  selectedIds: []
64
101
  },
65
102
  {
66
103
  key: "students",
67
- label: "Aluno",
68
- dependsOn: ["escola", "serie", "turma"],
69
- itens: data.students,
104
+ label: "Alunos",
105
+ dependsOn: ["turma"],
70
106
  filteredBy: [
71
107
  { key: "escola", internalField: "escolaId" },
72
108
  { key: "serie", internalField: "serieId" },
73
109
  { key: "turma", internalField: "turmaId" }
74
110
  ],
111
+ // Students will be loaded dynamically based on selections
112
+ itens: [],
75
113
  selectedIds: []
76
114
  }
77
115
  ];
116
+ return transformedCategories;
117
+ }
118
+
119
+ // src/utils/useDynamicStudentFetching.ts
120
+ var import_react = require("react");
121
+ function extractSelectedIds(updatedCategories) {
122
+ const escolaCategory = updatedCategories.find((c) => c.key === "escola");
123
+ const serieCategory = updatedCategories.find((c) => c.key === "serie");
124
+ const turmaCategory = updatedCategories.find((c) => c.key === "turma");
125
+ const studentsCategory = updatedCategories.find((c) => c.key === "students");
126
+ return {
127
+ schoolIds: escolaCategory?.selectedIds || [],
128
+ schoolYearIds: serieCategory?.selectedIds || [],
129
+ classIds: turmaCategory?.selectedIds || [],
130
+ studentsCategory
131
+ };
132
+ }
133
+ function detectSelectionChanges(previousSelections, currentSelections) {
134
+ const isInitialState = previousSelections.schoolIds.length === 0 && previousSelections.schoolYearIds.length === 0 && previousSelections.classIds.length === 0;
135
+ const arraysEqual = (a, b) => {
136
+ if (a.length !== b.length) return false;
137
+ return a.every((id) => b.includes(id)) && b.every((id) => a.includes(id));
138
+ };
139
+ const schoolIdsChanged = isInitialState || !arraysEqual(previousSelections.schoolIds, currentSelections.schoolIds);
140
+ const schoolYearIdsChanged = isInitialState || !arraysEqual(
141
+ previousSelections.schoolYearIds,
142
+ currentSelections.schoolYearIds
143
+ );
144
+ const classIdsChanged = isInitialState || !arraysEqual(previousSelections.classIds, currentSelections.classIds);
145
+ const shouldFetchStudents = schoolIdsChanged || schoolYearIdsChanged || classIdsChanged;
146
+ return {
147
+ schoolIdsChanged,
148
+ schoolYearIdsChanged,
149
+ classIdsChanged,
150
+ shouldFetchStudents
151
+ };
78
152
  }
153
+ function transformStudentsToItems(students) {
154
+ return students.map((s) => ({
155
+ id: `${s.userInstitutionId}-${s.class.id}`,
156
+ name: s.name,
157
+ classId: String(s.class.id),
158
+ schoolId: String(s.school.id),
159
+ schoolYearId: String(s.schoolYear.id),
160
+ studentId: s.id,
161
+ userInstitutionId: s.userInstitutionId,
162
+ escolaId: String(s.school.id),
163
+ serieId: String(s.schoolYear.id),
164
+ turmaId: String(s.class.id)
165
+ }));
166
+ }
167
+ function updateCategoriesWithStudents(updatedCategories, studentItems) {
168
+ return updatedCategories.map(
169
+ (cat) => cat.key === "students" ? { ...cat, itens: studentItems } : cat
170
+ );
171
+ }
172
+ function clearStudentsFromCategories(updatedCategories) {
173
+ return updatedCategories.map(
174
+ (cat) => cat.key === "students" ? { ...cat, itens: [] } : cat
175
+ );
176
+ }
177
+ function useDynamicStudentFetching(setCategories, options = {}) {
178
+ const {
179
+ apiClient,
180
+ fetchStudentsByFilters: customFetchStudents,
181
+ onError
182
+ } = options;
183
+ const previousSelectionsRef = (0, import_react.useRef)({
184
+ schoolIds: [],
185
+ schoolYearIds: [],
186
+ classIds: []
187
+ });
188
+ const fetchRequestId = (0, import_react.useRef)(0);
189
+ const buildStudentFilters = (0, import_react.useCallback)(
190
+ (selectedSchoolIds, selectedSchoolYearIds, selectedClassIds) => ({
191
+ schoolIds: selectedSchoolIds.length > 0 ? selectedSchoolIds : void 0,
192
+ schoolYearIds: selectedSchoolYearIds.length > 0 ? selectedSchoolYearIds : void 0,
193
+ classIds: selectedClassIds.length > 0 ? selectedClassIds : void 0
194
+ }),
195
+ []
196
+ );
197
+ const fetchWithCustomFunction = (0, import_react.useCallback)(
198
+ async (selectedSchoolIds, selectedSchoolYearIds, selectedClassIds, localRequestId) => {
199
+ if (!customFetchStudents) {
200
+ return null;
201
+ }
202
+ const filters = buildStudentFilters(
203
+ selectedSchoolIds,
204
+ selectedSchoolYearIds,
205
+ selectedClassIds
206
+ );
207
+ const students = await customFetchStudents(filters);
208
+ if (localRequestId !== fetchRequestId.current) {
209
+ return null;
210
+ }
211
+ return students;
212
+ },
213
+ [customFetchStudents, buildStudentFilters]
214
+ );
215
+ const fetchWithApiClient = (0, import_react.useCallback)(
216
+ async (selectedSchoolIds, selectedSchoolYearIds, selectedClassIds, localRequestId) => {
217
+ if (!apiClient) {
218
+ return null;
219
+ }
220
+ const filters = buildStudentFilters(
221
+ selectedSchoolIds,
222
+ selectedSchoolYearIds,
223
+ selectedClassIds
224
+ );
225
+ const students = await fetchStudentsByFilters(apiClient, filters);
226
+ if (localRequestId !== fetchRequestId.current) {
227
+ return null;
228
+ }
229
+ return students;
230
+ },
231
+ [apiClient, buildStudentFilters]
232
+ );
233
+ const performStudentFetch = (0, import_react.useCallback)(
234
+ async (selectedSchoolIds, selectedSchoolYearIds, selectedClassIds, localRequestId) => {
235
+ const students = await fetchWithCustomFunction(
236
+ selectedSchoolIds,
237
+ selectedSchoolYearIds,
238
+ selectedClassIds,
239
+ localRequestId
240
+ );
241
+ if (students !== null) {
242
+ return students;
243
+ }
244
+ return fetchWithApiClient(
245
+ selectedSchoolIds,
246
+ selectedSchoolYearIds,
247
+ selectedClassIds,
248
+ localRequestId
249
+ );
250
+ },
251
+ [fetchWithCustomFunction, fetchWithApiClient]
252
+ );
253
+ const handleSuccessfulFetch = (0, import_react.useCallback)(
254
+ (students, updatedCategories, localRequestId) => {
255
+ if (localRequestId !== fetchRequestId.current) {
256
+ return false;
257
+ }
258
+ const studentItems = transformStudentsToItems(students);
259
+ const finalCategories = updateCategoriesWithStudents(
260
+ updatedCategories,
261
+ studentItems
262
+ );
263
+ setCategories(finalCategories);
264
+ return true;
265
+ },
266
+ [setCategories]
267
+ );
268
+ const handleFetchError = (0, import_react.useCallback)(
269
+ (error, updatedCategories, localRequestId) => {
270
+ console.error("Error fetching students:", error);
271
+ if (onError && error instanceof Error) {
272
+ onError(error);
273
+ }
274
+ if (localRequestId !== fetchRequestId.current) {
275
+ return false;
276
+ }
277
+ const finalCategories = clearStudentsFromCategories(updatedCategories);
278
+ setCategories(finalCategories);
279
+ return true;
280
+ },
281
+ [onError, setCategories]
282
+ );
283
+ const handleCategoriesChange = (0, import_react.useCallback)(
284
+ async (updatedCategories) => {
285
+ if (!customFetchStudents && !apiClient) {
286
+ setCategories(updatedCategories);
287
+ return;
288
+ }
289
+ const {
290
+ schoolIds: selectedSchoolIds,
291
+ schoolYearIds: selectedSchoolYearIds,
292
+ classIds: selectedClassIds,
293
+ studentsCategory
294
+ } = extractSelectedIds(updatedCategories);
295
+ const previousSelections = previousSelectionsRef.current;
296
+ const { shouldFetchStudents } = detectSelectionChanges(
297
+ previousSelections,
298
+ {
299
+ schoolIds: selectedSchoolIds,
300
+ schoolYearIds: selectedSchoolYearIds,
301
+ classIds: selectedClassIds
302
+ }
303
+ );
304
+ previousSelectionsRef.current = {
305
+ schoolIds: [...selectedSchoolIds],
306
+ schoolYearIds: [...selectedSchoolYearIds],
307
+ classIds: [...selectedClassIds]
308
+ };
309
+ if (shouldFetchStudents && selectedClassIds.length > 0 && studentsCategory) {
310
+ fetchRequestId.current += 1;
311
+ const localRequestId = fetchRequestId.current;
312
+ try {
313
+ const students = await performStudentFetch(
314
+ selectedSchoolIds,
315
+ selectedSchoolYearIds,
316
+ selectedClassIds,
317
+ localRequestId
318
+ );
319
+ if (students === null) {
320
+ return;
321
+ }
322
+ handleSuccessfulFetch(students, updatedCategories, localRequestId);
323
+ } catch (error) {
324
+ handleFetchError(error, updatedCategories, localRequestId);
325
+ }
326
+ } else if (shouldFetchStudents && studentsCategory) {
327
+ fetchRequestId.current += 1;
328
+ const finalCategories = clearStudentsFromCategories(updatedCategories);
329
+ setCategories(finalCategories);
330
+ } else {
331
+ setCategories(updatedCategories);
332
+ }
333
+ },
334
+ [
335
+ apiClient,
336
+ customFetchStudents,
337
+ setCategories,
338
+ performStudentFetch,
339
+ handleSuccessfulFetch,
340
+ handleFetchError
341
+ ]
342
+ );
343
+ return {
344
+ handleCategoriesChange
345
+ };
346
+ }
347
+
348
+ // src/hooks/useSendActivity.ts
79
349
  function toISODateTime(date, time) {
80
350
  return (0, import_dayjs.default)(`${date}T${time}`).toISOString();
81
351
  }
82
352
  function useSendActivity(config) {
83
353
  const { api, onSuccess, onError } = config;
84
- const [isOpen, setIsOpen] = (0, import_react.useState)(false);
85
- const [selectedModel, setSelectedModel] = (0, import_react.useState)(
354
+ const [isOpen, setIsOpen] = (0, import_react2.useState)(false);
355
+ const [selectedModel, setSelectedModel] = (0, import_react2.useState)(
86
356
  null
87
357
  );
88
- const [categories, setCategories] = (0, import_react.useState)([]);
89
- const [isLoading, setIsLoading] = (0, import_react.useState)(false);
90
- const [isCategoriesLoading, setIsCategoriesLoading] = (0, import_react.useState)(false);
91
- const categoriesLoadedRef = (0, import_react.useRef)(false);
92
- const initialData = (0, import_react.useMemo)(() => {
358
+ const [categories, setCategories] = (0, import_react2.useState)([]);
359
+ const [isLoading, setIsLoading] = (0, import_react2.useState)(false);
360
+ const [isCategoriesLoading, setIsCategoriesLoading] = (0, import_react2.useState)(false);
361
+ const categoriesLoadedRef = (0, import_react2.useRef)(false);
362
+ const initialData = (0, import_react2.useMemo)(() => {
93
363
  if (!selectedModel) return void 0;
94
364
  return {
95
365
  title: selectedModel.title
96
366
  };
97
367
  }, [selectedModel]);
98
- const loadCategories = (0, import_react.useCallback)(async () => {
368
+ const loadCategories = (0, import_react2.useCallback)(async () => {
99
369
  if (categoriesLoadedRef.current) return;
100
370
  setIsCategoriesLoading(true);
101
371
  try {
102
- const [schoolsRes, yearsRes, classesRes, studentsRes] = await Promise.all(
103
- [
104
- api.get("/school"),
105
- api.get("/schoolYear"),
106
- api.get("/classes"),
107
- api.get("/students")
108
- ]
109
- );
110
- const data = {
111
- schools: schoolsRes.data.data || [],
112
- schoolYears: yearsRes.data.data || [],
113
- classes: classesRes.data.data || [],
114
- students: studentsRes.data.data || []
115
- };
116
- const categoryConfig = transformToCategoryConfig(data);
372
+ const categoryConfig = await loadCategoriesData(api, []);
117
373
  setCategories(categoryConfig);
118
374
  categoriesLoadedRef.current = true;
119
375
  } catch (error) {
@@ -123,7 +379,7 @@ function useSendActivity(config) {
123
379
  setIsCategoriesLoading(false);
124
380
  }
125
381
  }, [api, onError]);
126
- const openModal = (0, import_react.useCallback)(
382
+ const openModal = (0, import_react2.useCallback)(
127
383
  (model) => {
128
384
  setSelectedModel(model);
129
385
  setIsOpen(true);
@@ -131,17 +387,12 @@ function useSendActivity(config) {
131
387
  },
132
388
  [loadCategories]
133
389
  );
134
- const closeModal = (0, import_react.useCallback)(() => {
390
+ const closeModal = (0, import_react2.useCallback)(() => {
135
391
  setIsOpen(false);
136
392
  setSelectedModel(null);
137
393
  }, []);
138
- const onCategoriesChange = (0, import_react.useCallback)(
139
- (updatedCategories) => {
140
- setCategories(updatedCategories);
141
- },
142
- []
143
- );
144
- const handleSubmit = (0, import_react.useCallback)(
394
+ const { handleCategoriesChange: onCategoriesChange } = useDynamicStudentFetching(setCategories, { apiClient: api });
395
+ const handleSubmit = (0, import_react2.useCallback)(
145
396
  async (data) => {
146
397
  if (!selectedModel) return;
147
398
  setIsLoading(true);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/hooks/useSendActivity.ts"],"sourcesContent":["/**\n * useSendActivity Hook\n *\n * Hook for managing the SendActivityModal state and actions.\n * Uses BaseApiClient for type-safe API calls to backend-monolito endpoints.\n */\n\nimport { useState, useCallback, useMemo, useRef } from 'react';\nimport dayjs from 'dayjs';\nimport type { CategoryConfig } from '../components/CheckBoxGroup/CheckBoxGroup';\nimport {\n ActivityMode,\n ActivitySubtype,\n type SendActivityFormData,\n type SendActivityModalInitialData,\n} from '../components/SendActivityModal/types';\nimport type {\n UseSendActivityConfig,\n UseSendActivityReturn,\n SendActivityCategoriesData,\n ActivityModelItem,\n} from '../types/sendActivity';\n\n/**\n * Transform categories data to CategoryConfig format for CheckboxGroup\n * @param data - Categories data from API\n * @returns Array of CategoryConfig for CheckboxGroup\n */\nfunction transformToCategoryConfig(\n data: SendActivityCategoriesData\n): CategoryConfig[] {\n return [\n {\n key: 'escola',\n label: 'Escola',\n itens: data.schools,\n selectedIds: [],\n },\n {\n key: 'serie',\n label: 'Série',\n dependsOn: ['escola'],\n itens: data.schoolYears,\n filteredBy: [{ key: 'escola', internalField: 'escolaId' }],\n selectedIds: [],\n },\n {\n key: 'turma',\n label: 'Turma',\n dependsOn: ['escola', 'serie'],\n itens: data.classes,\n filteredBy: [\n { key: 'escola', internalField: 'escolaId' },\n { key: 'serie', internalField: 'serieId' },\n ],\n selectedIds: [],\n },\n {\n key: 'students',\n label: 'Aluno',\n dependsOn: ['escola', 'serie', 'turma'],\n itens: data.students,\n filteredBy: [\n { key: 'escola', internalField: 'escolaId' },\n { key: 'serie', internalField: 'serieId' },\n { key: 'turma', internalField: 'turmaId' },\n ],\n selectedIds: [],\n },\n ];\n}\n\n/**\n * Convert date and time to ISO datetime string\n * Uses dayjs for proper timezone conversion\n * @param date - Date string in YYYY-MM-DD format\n * @param time - Time string in HH:MM format\n * @returns ISO datetime string in UTC\n */\nfunction toISODateTime(date: string, time: string): string {\n return dayjs(`${date}T${time}`).toISOString();\n}\n\n/**\n * Hook for managing the SendActivityModal state and actions\n *\n * Pass a BaseApiClient instance and the hook will handle all API calls internally\n * using the backend-monolito endpoints.\n *\n * @param config - Configuration with BaseApiClient instance and optional callbacks\n * @returns Object with modal state, categories, and handlers\n *\n * @example\n * ```tsx\n * import { useSendActivity } from 'analytica-frontend-lib';\n * import api from '@/services/apiService';\n *\n * const sendActivity = useSendActivity({\n * api,\n * onSuccess: (msg) => toast.success(msg),\n * onError: (msg) => toast.error(msg),\n * });\n * ```\n */\nexport function useSendActivity(\n config: UseSendActivityConfig\n): UseSendActivityReturn {\n const { api, onSuccess, onError } = config;\n\n const [isOpen, setIsOpen] = useState(false);\n const [selectedModel, setSelectedModel] = useState<ActivityModelItem | null>(\n null\n );\n const [categories, setCategories] = useState<CategoryConfig[]>([]);\n const [isLoading, setIsLoading] = useState(false);\n const [isCategoriesLoading, setIsCategoriesLoading] = useState(false);\n\n const categoriesLoadedRef = useRef(false);\n\n /**\n * Initial data for pre-filling the modal form\n */\n const initialData = useMemo<SendActivityModalInitialData | undefined>(() => {\n if (!selectedModel) return undefined;\n return {\n title: selectedModel.title,\n };\n }, [selectedModel]);\n\n /**\n * Load categories for recipient selection\n */\n const loadCategories = useCallback(async () => {\n if (categoriesLoadedRef.current) return;\n\n setIsCategoriesLoading(true);\n try {\n const [schoolsRes, yearsRes, classesRes, studentsRes] = await Promise.all(\n [\n api.get<{ data: unknown[] }>('/school'),\n api.get<{ data: unknown[] }>('/schoolYear'),\n api.get<{ data: unknown[] }>('/classes'),\n api.get<{ data: unknown[] }>('/students'),\n ]\n );\n\n const data: SendActivityCategoriesData = {\n schools: (schoolsRes.data.data as []) || [],\n schoolYears: (yearsRes.data.data as []) || [],\n classes: (classesRes.data.data as []) || [],\n students: (studentsRes.data.data as []) || [],\n };\n\n const categoryConfig = transformToCategoryConfig(data);\n setCategories(categoryConfig);\n categoriesLoadedRef.current = true;\n } catch (error) {\n console.error('Error loading categories:', error);\n onError?.('Erro ao carregar destinatários');\n } finally {\n setIsCategoriesLoading(false);\n }\n }, [api, onError]);\n\n /**\n * Open the modal with a selected model\n * @param model - Activity model to send\n */\n const openModal = useCallback(\n (model: ActivityModelItem) => {\n setSelectedModel(model);\n setIsOpen(true);\n void loadCategories();\n },\n [loadCategories]\n );\n\n /**\n * Close the modal and reset state\n */\n const closeModal = useCallback(() => {\n setIsOpen(false);\n setSelectedModel(null);\n }, []);\n\n /**\n * Handle categories change from CheckboxGroup\n * @param updatedCategories - Updated categories array\n */\n const onCategoriesChange = useCallback(\n (updatedCategories: CategoryConfig[]) => {\n setCategories(updatedCategories);\n },\n []\n );\n\n /**\n * Handle form submission\n * @param data - Form data from SendActivityModal\n */\n const handleSubmit = useCallback(\n async (data: SendActivityFormData) => {\n if (!selectedModel) return;\n\n setIsLoading(true);\n\n try {\n // 1. Fetch question IDs from draft/model\n let questionIds: string[] | null = null;\n try {\n const response = await api.get<{\n data: { selectedQuestions?: { id: string }[] };\n }>(`/activity-drafts/${selectedModel.id}`);\n questionIds =\n response.data.data.selectedQuestions?.map((q) => q.id) || null;\n } catch {\n questionIds = null;\n }\n\n if (!questionIds || questionIds.length === 0) {\n throw new Error('Não foi possível obter questões do modelo');\n }\n\n // 2. Create activity\n const createResponse = await api.post<{ data: { id: string } }>(\n '/activities',\n {\n title: data.title,\n subjectId: selectedModel.subjectId,\n questionIds,\n subtype: data.subtype,\n isDigital:\n data.subtype === ActivitySubtype.PROVA\n ? data.mode !== ActivityMode.PRESENCIAL\n : true,\n notification: data.notification,\n startDate: toISODateTime(data.startDate, data.startTime),\n finalDate: toISODateTime(data.finalDate, data.finalTime),\n canRetry: data.canRetry,\n }\n );\n\n // 3. Send to students\n await api.post('/activities/send-to-students', {\n activityId: createResponse.data.data.id,\n students: data.students,\n });\n\n onSuccess?.(`Atividade enviada para ${data.students.length} aluno(s)`);\n\n closeModal();\n } catch (error) {\n console.error('Error sending activity:', error);\n onError?.('Erro ao enviar atividade');\n } finally {\n setIsLoading(false);\n }\n },\n [selectedModel, api, onSuccess, onError, closeModal]\n );\n\n return {\n isOpen,\n openModal,\n closeModal,\n selectedModel,\n initialData,\n categories,\n onCategoriesChange,\n isLoading,\n isCategoriesLoading,\n handleSubmit,\n };\n}\n"],"mappings":"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","names":["dayjs"]}
1
+ {"version":3,"sources":["../../../src/hooks/useSendActivity.ts","../../../src/utils/categoryDataUtils.ts","../../../src/utils/useDynamicStudentFetching.ts"],"sourcesContent":["/**\n * useSendActivity Hook\n *\n * Hook for managing the SendActivityModal state and actions.\n * Uses BaseApiClient for type-safe API calls to backend-monolito endpoints.\n */\n\nimport { useState, useCallback, useMemo, useRef } from 'react';\nimport dayjs from 'dayjs';\nimport type { CategoryConfig } from '../components/CheckBoxGroup/CheckBoxGroup';\nimport {\n ActivityMode,\n ActivitySubtype,\n type SendActivityFormData,\n type SendActivityModalInitialData,\n} from '../components/SendActivityModal/types';\nimport type {\n UseSendActivityConfig,\n UseSendActivityReturn,\n ActivityModelItem,\n} from '../types/sendActivity';\nimport { loadCategoriesData } from '../utils/categoryDataUtils';\nimport { useDynamicStudentFetching } from '../utils/useDynamicStudentFetching';\n\n/**\n * Convert date and time to ISO datetime string\n * Uses dayjs for proper timezone conversion\n * @param date - Date string in YYYY-MM-DD format\n * @param time - Time string in HH:MM format\n * @returns ISO datetime string in UTC\n */\nfunction toISODateTime(date: string, time: string): string {\n return dayjs(`${date}T${time}`).toISOString();\n}\n\n/**\n * Hook for managing the SendActivityModal state and actions\n *\n * Pass a BaseApiClient instance and the hook will handle all API calls internally\n * using the backend-monolito endpoints.\n *\n * @param config - Configuration with BaseApiClient instance and optional callbacks\n * @returns Object with modal state, categories, and handlers\n *\n * @example\n * ```tsx\n * import { useSendActivity } from 'analytica-frontend-lib';\n * import api from '@/services/apiService';\n *\n * const sendActivity = useSendActivity({\n * api,\n * onSuccess: (msg) => toast.success(msg),\n * onError: (msg) => toast.error(msg),\n * });\n * ```\n */\nexport function useSendActivity(\n config: UseSendActivityConfig\n): UseSendActivityReturn {\n const { api, onSuccess, onError } = config;\n\n const [isOpen, setIsOpen] = useState(false);\n const [selectedModel, setSelectedModel] = useState<ActivityModelItem | null>(\n null\n );\n const [categories, setCategories] = useState<CategoryConfig[]>([]);\n const [isLoading, setIsLoading] = useState(false);\n const [isCategoriesLoading, setIsCategoriesLoading] = useState(false);\n\n const categoriesLoadedRef = useRef(false);\n\n /**\n * Initial data for pre-filling the modal form\n */\n const initialData = useMemo<SendActivityModalInitialData | undefined>(() => {\n if (!selectedModel) return undefined;\n return {\n title: selectedModel.title,\n };\n }, [selectedModel]);\n\n /**\n * Load categories for recipient selection\n */\n const loadCategories = useCallback(async () => {\n if (categoriesLoadedRef.current) return;\n\n setIsCategoriesLoading(true);\n try {\n const categoryConfig = await loadCategoriesData(api, []);\n setCategories(categoryConfig);\n categoriesLoadedRef.current = true;\n } catch (error) {\n console.error('Error loading categories:', error);\n onError?.('Erro ao carregar destinatários');\n } finally {\n setIsCategoriesLoading(false);\n }\n }, [api, onError]);\n\n /**\n * Open the modal with a selected model\n * @param model - Activity model to send\n */\n const openModal = useCallback(\n (model: ActivityModelItem) => {\n setSelectedModel(model);\n setIsOpen(true);\n void loadCategories();\n },\n [loadCategories]\n );\n\n /**\n * Close the modal and reset state\n */\n const closeModal = useCallback(() => {\n setIsOpen(false);\n setSelectedModel(null);\n }, []);\n\n /**\n * Handle categories change from CheckboxGroup.\n * Fetches students dynamically via POST /students/filters when the\n * school/série/turma selections change, mirroring the activity creation flow.\n */\n const { handleCategoriesChange: onCategoriesChange } =\n useDynamicStudentFetching(setCategories, { apiClient: api });\n\n /**\n * Handle form submission\n * @param data - Form data from SendActivityModal\n */\n const handleSubmit = useCallback(\n async (data: SendActivityFormData) => {\n if (!selectedModel) return;\n\n setIsLoading(true);\n\n try {\n // 1. Fetch question IDs from draft/model\n let questionIds: string[] | null = null;\n try {\n const response = await api.get<{\n data: { selectedQuestions?: { id: string }[] };\n }>(`/activity-drafts/${selectedModel.id}`);\n questionIds =\n response.data.data.selectedQuestions?.map((q) => q.id) || null;\n } catch {\n questionIds = null;\n }\n\n if (!questionIds || questionIds.length === 0) {\n throw new Error('Não foi possível obter questões do modelo');\n }\n\n // 2. Create activity\n const createResponse = await api.post<{ data: { id: string } }>(\n '/activities',\n {\n title: data.title,\n subjectId: selectedModel.subjectId,\n questionIds,\n subtype: data.subtype,\n isDigital:\n data.subtype === ActivitySubtype.PROVA\n ? data.mode !== ActivityMode.PRESENCIAL\n : true,\n notification: data.notification,\n startDate: toISODateTime(data.startDate, data.startTime),\n finalDate: toISODateTime(data.finalDate, data.finalTime),\n canRetry: data.canRetry,\n }\n );\n\n // 3. Send to students\n await api.post('/activities/send-to-students', {\n activityId: createResponse.data.data.id,\n students: data.students,\n });\n\n onSuccess?.(`Atividade enviada para ${data.students.length} aluno(s)`);\n\n closeModal();\n } catch (error) {\n console.error('Error sending activity:', error);\n onError?.('Erro ao enviar atividade');\n } finally {\n setIsLoading(false);\n }\n },\n [selectedModel, api, onSuccess, onError, closeModal]\n );\n\n return {\n isOpen,\n openModal,\n closeModal,\n selectedModel,\n initialData,\n categories,\n onCategoriesChange,\n isLoading,\n isCategoriesLoading,\n handleSubmit,\n };\n}\n","import type { BaseApiClient } from '../types/api';\nimport type { CategoryConfig } from '../components/CheckBoxGroup/CheckBoxGroup';\n\n/**\n * School type for categories data\n */\nexport interface School {\n id: string;\n companyName: string;\n}\n\n/**\n * SchoolYear type for categories data\n */\nexport interface SchoolYear {\n id: string;\n name: string;\n schoolId: string;\n}\n\n/**\n * Class type for categories data\n */\nexport interface Class {\n id: string;\n name: string;\n schoolYearId: string;\n}\n\n/**\n * Student type for categories data with nested school/schoolYear/class\n */\nexport interface Student {\n id: string;\n email: string;\n name: string;\n active: boolean;\n createdAt: string;\n updatedAt: string;\n userInstitutionId: string;\n institutionId: string;\n profileId: string;\n school: {\n id: string;\n name: string;\n };\n schoolYear: {\n id: string;\n name: string;\n };\n class: {\n id: string;\n name: string;\n };\n}\n\n/**\n * Fetch students using POST /students/filters based on selected schools, schoolYears, and classes\n *\n * @param apiClient - API client instance\n * @param filters - Object with schoolIds, schoolYearIds, and classIds arrays\n * @returns Promise resolving to array of students\n *\n * @example\n * ```ts\n * const students = await fetchStudentsByFilters(apiClient, {\n * schoolIds: ['school-1'],\n * schoolYearIds: ['year-1'],\n * classIds: ['class-1']\n * });\n * ```\n */\nexport async function fetchStudentsByFilters(\n apiClient: BaseApiClient,\n filters: {\n schoolIds?: string[];\n schoolYearIds?: string[];\n classIds?: string[];\n }\n): Promise<Student[]> {\n // Only make request if at least one filter is provided\n if (\n (!filters.schoolIds || filters.schoolIds.length === 0) &&\n (!filters.schoolYearIds || filters.schoolYearIds.length === 0) &&\n (!filters.classIds || filters.classIds.length === 0)\n ) {\n return [];\n }\n\n const response = await apiClient.post<{\n message: string;\n data: {\n students: Student[];\n };\n }>('/students/filters', {\n ...(filters.schoolIds &&\n filters.schoolIds.length > 0 && {\n schoolIds: filters.schoolIds,\n }),\n ...(filters.schoolYearIds &&\n filters.schoolYearIds.length > 0 && {\n schoolYearIds: filters.schoolYearIds,\n }),\n ...(filters.classIds &&\n filters.classIds.length > 0 && {\n classIds: filters.classIds,\n }),\n });\n\n return response.data.data.students || [];\n}\n\n/**\n * Load categories data from API and transform to CategoryConfig format\n *\n * @param apiClient - API client instance\n * @param existingCategories - Current categories array to check if already loaded\n * @returns Promise resolving to array of CategoryConfig\n *\n * @example\n * ```ts\n * const categories = await loadCategoriesData(apiClient, []);\n * ```\n */\nexport async function loadCategoriesData(\n apiClient: BaseApiClient,\n existingCategories: CategoryConfig[]\n): Promise<CategoryConfig[]> {\n if (existingCategories.length > 0) {\n return existingCategories;\n }\n\n const [schoolsResponse, schoolYearsResponse, classesResponse] =\n await Promise.all([\n apiClient.get<{ message: string; data: { schools: School[] } }>(\n '/school'\n ),\n apiClient.get<{\n message: string;\n data: { schoolYears: SchoolYear[] };\n }>('/schoolYear'),\n apiClient.get<{\n message: string;\n data: { classes: Class[] };\n }>('/classes'),\n ]);\n\n const schools = schoolsResponse.data.data.schools;\n const schoolYears = schoolYearsResponse.data.data.schoolYears;\n const classes = classesResponse.data.data.classes;\n\n const transformedCategories: CategoryConfig[] = [\n {\n key: 'escola',\n label: 'Escola',\n itens: schools.map((s) => ({ id: s.id, name: s.companyName })),\n selectedIds: [],\n },\n {\n key: 'serie',\n label: 'Série',\n dependsOn: ['escola'],\n filteredBy: [{ key: 'escola', internalField: 'schoolId' }],\n itens: schoolYears.map((sy) => ({\n id: sy.id,\n name: sy.name,\n schoolId: sy.schoolId,\n })),\n selectedIds: [],\n },\n {\n key: 'turma',\n label: 'Turma',\n dependsOn: ['serie'],\n filteredBy: [{ key: 'serie', internalField: 'schoolYearId' }],\n itens: classes.map((c) => ({\n id: c.id,\n name: c.name,\n schoolYearId: c.schoolYearId,\n })),\n selectedIds: [],\n },\n {\n key: 'students',\n label: 'Alunos',\n dependsOn: ['turma'],\n filteredBy: [\n { key: 'escola', internalField: 'escolaId' },\n { key: 'serie', internalField: 'serieId' },\n { key: 'turma', internalField: 'turmaId' },\n ],\n // Students will be loaded dynamically based on selections\n itens: [],\n selectedIds: [],\n },\n ];\n\n return transformedCategories;\n}\n\n/**\n * Format time for display (HH:mm format)\n *\n * @param date - Date object to format\n * @returns Formatted time string in HH:mm format\n *\n * @example\n * ```ts\n * const time = formatTime(new Date('2025-01-01T14:30:00'));\n * // Returns: '14:30'\n * ```\n */\nexport function formatTime(date: Date): string {\n const hours = date.getHours().toString().padStart(2, '0');\n const minutes = date.getMinutes().toString().padStart(2, '0');\n return `${hours}:${minutes}`;\n}\n","import { useCallback, useRef } from 'react';\nimport type { CategoryConfig } from '../components/CheckBoxGroup/CheckBoxGroup';\nimport type { BaseApiClient } from '../types/api';\nimport { fetchStudentsByFilters } from './categoryDataUtils';\nimport type {\n FetchStudentsByFiltersFunction,\n StudentWithNestedData,\n} from './studentTypes';\n\nexport interface UseDynamicStudentFetchingOptions {\n apiClient?: BaseApiClient;\n fetchStudentsByFilters?: FetchStudentsByFiltersFunction;\n onError?: (error: Error) => void;\n}\n\n/**\n * Extract selected IDs from categories\n */\nfunction extractSelectedIds(updatedCategories: CategoryConfig[]): {\n schoolIds: string[];\n schoolYearIds: string[];\n classIds: string[];\n studentsCategory: CategoryConfig | undefined;\n} {\n const escolaCategory = updatedCategories.find((c) => c.key === 'escola');\n const serieCategory = updatedCategories.find((c) => c.key === 'serie');\n const turmaCategory = updatedCategories.find((c) => c.key === 'turma');\n const studentsCategory = updatedCategories.find((c) => c.key === 'students');\n\n return {\n schoolIds: escolaCategory?.selectedIds || [],\n schoolYearIds: serieCategory?.selectedIds || [],\n classIds: turmaCategory?.selectedIds || [],\n studentsCategory,\n };\n}\n\n/**\n * Detect if selections have changed compared to previous selections\n */\nfunction detectSelectionChanges(\n previousSelections: {\n schoolIds: string[];\n schoolYearIds: string[];\n classIds: string[];\n },\n currentSelections: {\n schoolIds: string[];\n schoolYearIds: string[];\n classIds: string[];\n }\n): {\n schoolIdsChanged: boolean;\n schoolYearIdsChanged: boolean;\n classIdsChanged: boolean;\n shouldFetchStudents: boolean;\n} {\n const isInitialState =\n previousSelections.schoolIds.length === 0 &&\n previousSelections.schoolYearIds.length === 0 &&\n previousSelections.classIds.length === 0;\n\n const arraysEqual = (a: string[], b: string[]) => {\n if (a.length !== b.length) return false;\n return a.every((id) => b.includes(id)) && b.every((id) => a.includes(id));\n };\n\n const schoolIdsChanged =\n isInitialState ||\n !arraysEqual(previousSelections.schoolIds, currentSelections.schoolIds);\n\n const schoolYearIdsChanged =\n isInitialState ||\n !arraysEqual(\n previousSelections.schoolYearIds,\n currentSelections.schoolYearIds\n );\n\n const classIdsChanged =\n isInitialState ||\n !arraysEqual(previousSelections.classIds, currentSelections.classIds);\n\n const shouldFetchStudents =\n schoolIdsChanged || schoolYearIdsChanged || classIdsChanged;\n\n return {\n schoolIdsChanged,\n schoolYearIdsChanged,\n classIdsChanged,\n shouldFetchStudents,\n };\n}\n\n/**\n * Transform students to items format with nested data\n */\nfunction transformStudentsToItems(students: StudentWithNestedData[]): Array<{\n id: string;\n name: string;\n classId: string;\n schoolId: string;\n schoolYearId: string;\n studentId: string;\n userInstitutionId: string;\n escolaId: string;\n serieId: string;\n turmaId: string;\n}> {\n return students.map((s) => ({\n id: `${s.userInstitutionId}-${s.class.id}`,\n name: s.name,\n classId: String(s.class.id),\n schoolId: String(s.school.id),\n schoolYearId: String(s.schoolYear.id),\n studentId: s.id,\n userInstitutionId: s.userInstitutionId,\n escolaId: String(s.school.id),\n serieId: String(s.schoolYear.id),\n turmaId: String(s.class.id),\n }));\n}\n\n/**\n * Update categories with student items\n */\nfunction updateCategoriesWithStudents(\n updatedCategories: CategoryConfig[],\n studentItems: Array<{\n id: string;\n name: string;\n classId: string;\n schoolId: string;\n schoolYearId: string;\n studentId: string;\n userInstitutionId: string;\n escolaId: string;\n serieId: string;\n turmaId: string;\n }>\n): CategoryConfig[] {\n return updatedCategories.map((cat) =>\n cat.key === 'students' ? { ...cat, itens: studentItems } : cat\n );\n}\n\n/**\n * Clear students from categories\n */\nfunction clearStudentsFromCategories(\n updatedCategories: CategoryConfig[]\n): CategoryConfig[] {\n return updatedCategories.map((cat) =>\n cat.key === 'students' ? { ...cat, itens: [] } : cat\n );\n}\n\n/**\n * Hook to handle dynamic student fetching based on category selections.\n *\n * This hook provides a `handleCategoriesChange` function that:\n * - Detects changes in school/series/class selections\n * - Fetches students only when these selections change (not when only students are toggled)\n * - Transforms fetched students into the correct format for CategoryConfig\n * - Handles errors gracefully\n *\n * @param setCategories - Function to update categories state\n * @param options - Configuration options\n * @returns Object with handleCategoriesChange function\n */\nexport function useDynamicStudentFetching(\n setCategories: (categories: CategoryConfig[]) => void,\n options: UseDynamicStudentFetchingOptions = {}\n): {\n handleCategoriesChange: (\n updatedCategories: CategoryConfig[]\n ) => Promise<void>;\n} {\n const {\n apiClient,\n fetchStudentsByFilters: customFetchStudents,\n onError,\n } = options;\n\n // Refs to track previous selections and prevent unnecessary API calls\n const previousSelectionsRef = useRef<{\n schoolIds: string[];\n schoolYearIds: string[];\n classIds: string[];\n }>({\n schoolIds: [],\n schoolYearIds: [],\n classIds: [],\n });\n\n // Ref to track fetch request ID and prevent race conditions\n const fetchRequestId = useRef(0);\n\n /**\n * Build filters object for student fetching\n */\n const buildStudentFilters = useCallback(\n (\n selectedSchoolIds: string[],\n selectedSchoolYearIds: string[],\n selectedClassIds: string[]\n ) => ({\n schoolIds: selectedSchoolIds.length > 0 ? selectedSchoolIds : undefined,\n schoolYearIds:\n selectedSchoolYearIds.length > 0 ? selectedSchoolYearIds : undefined,\n classIds: selectedClassIds.length > 0 ? selectedClassIds : undefined,\n }),\n []\n );\n\n /**\n * Fetch students using custom function\n */\n const fetchWithCustomFunction = useCallback(\n async (\n selectedSchoolIds: string[],\n selectedSchoolYearIds: string[],\n selectedClassIds: string[],\n localRequestId: number\n ): Promise<StudentWithNestedData[] | null> => {\n if (!customFetchStudents) {\n return null;\n }\n\n const filters = buildStudentFilters(\n selectedSchoolIds,\n selectedSchoolYearIds,\n selectedClassIds\n );\n const students = await customFetchStudents(filters);\n\n if (localRequestId !== fetchRequestId.current) {\n return null;\n }\n\n return students;\n },\n [customFetchStudents, buildStudentFilters]\n );\n\n /**\n * Fetch students using API client\n */\n const fetchWithApiClient = useCallback(\n async (\n selectedSchoolIds: string[],\n selectedSchoolYearIds: string[],\n selectedClassIds: string[],\n localRequestId: number\n ): Promise<StudentWithNestedData[] | null> => {\n if (!apiClient) {\n return null;\n }\n\n const filters = buildStudentFilters(\n selectedSchoolIds,\n selectedSchoolYearIds,\n selectedClassIds\n );\n const students = await fetchStudentsByFilters(apiClient, filters);\n\n if (localRequestId !== fetchRequestId.current) {\n return null;\n }\n\n return students;\n },\n [apiClient, buildStudentFilters]\n );\n\n /**\n * Fetch students using the appropriate method (custom function or API client)\n */\n const performStudentFetch = useCallback(\n async (\n selectedSchoolIds: string[],\n selectedSchoolYearIds: string[],\n selectedClassIds: string[],\n localRequestId: number\n ): Promise<StudentWithNestedData[] | null> => {\n const students = await fetchWithCustomFunction(\n selectedSchoolIds,\n selectedSchoolYearIds,\n selectedClassIds,\n localRequestId\n );\n\n if (students !== null) {\n return students;\n }\n\n return fetchWithApiClient(\n selectedSchoolIds,\n selectedSchoolYearIds,\n selectedClassIds,\n localRequestId\n );\n },\n [fetchWithCustomFunction, fetchWithApiClient]\n );\n\n /**\n * Handle successful student fetch\n */\n const handleSuccessfulFetch = useCallback(\n (\n students: StudentWithNestedData[],\n updatedCategories: CategoryConfig[],\n localRequestId: number\n ): boolean => {\n if (localRequestId !== fetchRequestId.current) {\n return false;\n }\n\n const studentItems = transformStudentsToItems(students);\n const finalCategories = updateCategoriesWithStudents(\n updatedCategories,\n studentItems\n );\n setCategories(finalCategories);\n return true;\n },\n [setCategories]\n );\n\n /**\n * Handle error during student fetch\n */\n const handleFetchError = useCallback(\n (\n error: unknown,\n updatedCategories: CategoryConfig[],\n localRequestId: number\n ): boolean => {\n console.error('Error fetching students:', error);\n if (onError && error instanceof Error) {\n onError(error);\n }\n\n if (localRequestId !== fetchRequestId.current) {\n return false;\n }\n\n const finalCategories = clearStudentsFromCategories(updatedCategories);\n setCategories(finalCategories);\n return true;\n },\n [onError, setCategories]\n );\n\n const handleCategoriesChange = useCallback(\n async (updatedCategories: CategoryConfig[]) => {\n // If no fetch function is provided, just update categories\n if (!customFetchStudents && !apiClient) {\n setCategories(updatedCategories);\n return;\n }\n\n // Extract selected IDs from categories\n const {\n schoolIds: selectedSchoolIds,\n schoolYearIds: selectedSchoolYearIds,\n classIds: selectedClassIds,\n studentsCategory,\n } = extractSelectedIds(updatedCategories);\n\n // Detect if selections have changed\n const previousSelections = previousSelectionsRef.current;\n const { shouldFetchStudents } = detectSelectionChanges(\n previousSelections,\n {\n schoolIds: selectedSchoolIds,\n schoolYearIds: selectedSchoolYearIds,\n classIds: selectedClassIds,\n }\n );\n\n // Update previous selections\n previousSelectionsRef.current = {\n schoolIds: [...selectedSchoolIds],\n schoolYearIds: [...selectedSchoolYearIds],\n classIds: [...selectedClassIds],\n };\n\n // Only fetch students if school/series/class selections changed\n if (\n shouldFetchStudents &&\n selectedClassIds.length > 0 &&\n studentsCategory\n ) {\n // Increment request ID to invalidate any in-flight requests\n fetchRequestId.current += 1;\n const localRequestId = fetchRequestId.current;\n\n try {\n const students = await performStudentFetch(\n selectedSchoolIds,\n selectedSchoolYearIds,\n selectedClassIds,\n localRequestId\n );\n\n if (students === null) {\n return; // Request was invalidated\n }\n\n handleSuccessfulFetch(students, updatedCategories, localRequestId);\n } catch (error) {\n handleFetchError(error, updatedCategories, localRequestId);\n }\n } else if (shouldFetchStudents && studentsCategory) {\n // If no classes selected after a change, clear students\n fetchRequestId.current += 1;\n const finalCategories = clearStudentsFromCategories(updatedCategories);\n setCategories(finalCategories);\n } else {\n // No relevant changes (only student selections changed), just update categories as-is\n setCategories(updatedCategories);\n }\n },\n [\n apiClient,\n customFetchStudents,\n setCategories,\n performStudentFetch,\n handleSuccessfulFetch,\n handleFetchError,\n ]\n );\n\n return {\n handleCategoriesChange,\n };\n}\n"],"mappings":"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","names":["import_react","dayjs"]}