analytica-frontend-lib
Version:
Repositório público dos componentes utilizados nas plataformas da Analytica Ensino
462 lines (460 loc) • 14.8 kB
JavaScript
// src/utils/categoryDataUtils.ts
async function fetchStudentsByFilters(apiClient, filters) {
if ((!filters.schoolIds || filters.schoolIds.length === 0) && (!filters.schoolYearIds || filters.schoolYearIds.length === 0) && (!filters.classIds || filters.classIds.length === 0)) {
return [];
}
const response = await apiClient.post("/students/filters", {
...filters.schoolIds && filters.schoolIds.length > 0 && {
schoolIds: filters.schoolIds
},
...filters.schoolYearIds && filters.schoolYearIds.length > 0 && {
schoolYearIds: filters.schoolYearIds
},
...filters.classIds && filters.classIds.length > 0 && {
classIds: filters.classIds
}
});
return response.data.data.students || [];
}
async function fetchClassesByFilters(apiClient, filters) {
const hasSchools = !!filters.schoolIds && filters.schoolIds.length > 0;
const hasYears = !!filters.schoolYearIds && filters.schoolYearIds.length > 0;
if (!hasSchools && !hasYears) return [];
return fetchAllPages(
apiClient,
"/classes",
(data) => {
const d = data;
return {
items: d.classes ?? [],
totalPages: d.pagination?.totalPages ?? 1
};
},
{
...hasSchools && { schoolId: filters.schoolIds.join(",") },
...hasYears && { schoolYearId: filters.schoolYearIds.join(",") }
}
);
}
async function fetchAllPages(apiClient, url, extract, extraParams = {}) {
const firstResponse = await apiClient.get(
url,
{ params: { ...extraParams, page: 1, limit: 100 } }
);
const first = extract(firstResponse.data.data);
const totalPages = first.totalPages || 1;
const all = [...first.items ?? []];
if (totalPages <= 1) {
return all;
}
const remainingPages = Array.from(
{ length: totalPages - 1 },
(_, i) => i + 2
);
const responses = await Promise.all(
remainingPages.map(
(page) => apiClient.get(url, {
params: { ...extraParams, page, limit: 100 }
})
)
);
for (const response of responses) {
const { items } = extract(response.data.data);
all.push(...items ?? []);
}
return all;
}
async function loadCategoriesData(apiClient, existingCategories) {
if (existingCategories.length > 0) {
return existingCategories;
}
const [schools, schoolYears] = await Promise.all([
fetchAllPages(apiClient, "/school", (data) => {
const d = data;
return { items: d.schools, totalPages: d.pagination?.totalPages ?? 1 };
}),
fetchAllPages(apiClient, "/schoolYear", (data) => {
const d = data;
return {
items: d.schoolYears,
totalPages: d.pagination?.totalPages ?? 1
};
})
]);
const transformedCategories = [
{
key: "escola",
label: "Escola",
itens: schools.map((s) => ({ id: s.id, name: s.companyName })),
selectedIds: []
},
{
key: "serie",
label: "S\xE9rie",
dependsOn: ["escola"],
filteredBy: [{ key: "escola", internalField: "schoolId" }],
itens: schoolYears.map((sy) => ({
id: sy.id,
name: sy.name,
schoolId: sy.schoolId
})),
selectedIds: []
},
{
key: "turma",
label: "Turma",
dependsOn: ["serie"],
filteredBy: [{ key: "serie", internalField: "schoolYearId" }],
// Classes are loaded dynamically based on selected schools/schoolYears
itens: [],
selectedIds: []
},
{
key: "students",
label: "Alunos",
dependsOn: ["turma"],
filteredBy: [
{ key: "escola", internalField: "escolaId" },
{ key: "serie", internalField: "serieId" },
{ key: "turma", internalField: "turmaId" }
],
// Students will be loaded dynamically based on selections
itens: [],
selectedIds: []
}
];
return transformedCategories;
}
function formatTime(date) {
const hours = date.getHours().toString().padStart(2, "0");
const minutes = date.getMinutes().toString().padStart(2, "0");
return `${hours}:${minutes}`;
}
// src/utils/useDynamicStudentFetching.ts
import { useCallback, useRef } from "react";
function extractSelectedIds(updatedCategories) {
const escolaCategory = updatedCategories.find((c) => c.key === "escola");
const serieCategory = updatedCategories.find((c) => c.key === "serie");
const turmaCategory = updatedCategories.find((c) => c.key === "turma");
const studentsCategory = updatedCategories.find((c) => c.key === "students");
return {
schoolIds: escolaCategory?.selectedIds || [],
schoolYearIds: serieCategory?.selectedIds || [],
classIds: turmaCategory?.selectedIds || [],
studentsCategory
};
}
function detectSelectionChanges(previousSelections, currentSelections) {
const isInitialState = previousSelections.schoolIds.length === 0 && previousSelections.schoolYearIds.length === 0 && previousSelections.classIds.length === 0;
const arraysEqual = (a, b) => {
if (a.length !== b.length) return false;
return a.every((id) => b.includes(id)) && b.every((id) => a.includes(id));
};
const schoolIdsChanged = isInitialState || !arraysEqual(previousSelections.schoolIds, currentSelections.schoolIds);
const schoolYearIdsChanged = isInitialState || !arraysEqual(
previousSelections.schoolYearIds,
currentSelections.schoolYearIds
);
const classIdsChanged = isInitialState || !arraysEqual(previousSelections.classIds, currentSelections.classIds);
const shouldFetchStudents = schoolIdsChanged || schoolYearIdsChanged || classIdsChanged;
return {
schoolIdsChanged,
schoolYearIdsChanged,
classIdsChanged,
shouldFetchStudents
};
}
function transformStudentsToItems(students) {
return students.map((s) => ({
id: `${s.userInstitutionId}-${s.class.id}`,
name: s.name,
classId: String(s.class.id),
schoolId: String(s.school.id),
schoolYearId: String(s.schoolYear.id),
studentId: s.id,
userInstitutionId: s.userInstitutionId,
escolaId: String(s.school.id),
serieId: String(s.schoolYear.id),
turmaId: String(s.class.id)
}));
}
function transformClassesToItems(classes) {
return classes.map((c) => ({
id: c.id,
name: c.name,
schoolYearId: c.schoolYearId
}));
}
function setCategoryItems(categories, key, itens) {
return categories.map((cat) => cat.key === key ? { ...cat, itens } : cat);
}
function commitSelectionsPreservingItems(updatedCategories, prev) {
return updatedCategories.map((cat) => {
const prior = prev.find((p) => p.key === cat.key);
return prior ? { ...cat, itens: prior.itens } : cat;
});
}
function useDynamicStudentFetching(setCategories, options = {}) {
const {
apiClient,
fetchStudentsByFilters: customFetchStudents,
fetchClassesByFilters: fetchClasses = fetchClassesByFilters,
onError
} = options;
const previousSelectionsRef = useRef({
schoolIds: [],
schoolYearIds: [],
classIds: []
});
const fetchRequestId = useRef(0);
const fetchClassesRequestId = useRef(0);
const buildStudentFilters = useCallback(
(selectedSchoolIds, selectedSchoolYearIds, selectedClassIds) => ({
schoolIds: selectedSchoolIds.length > 0 ? selectedSchoolIds : void 0,
schoolYearIds: selectedSchoolYearIds.length > 0 ? selectedSchoolYearIds : void 0,
classIds: selectedClassIds.length > 0 ? selectedClassIds : void 0
}),
[]
);
const fetchWithCustomFunction = useCallback(
async (selectedSchoolIds, selectedSchoolYearIds, selectedClassIds, localRequestId) => {
if (!customFetchStudents) {
return null;
}
const filters = buildStudentFilters(
selectedSchoolIds,
selectedSchoolYearIds,
selectedClassIds
);
const students = await customFetchStudents(filters);
if (localRequestId !== fetchRequestId.current) {
return null;
}
return students;
},
[customFetchStudents, buildStudentFilters]
);
const fetchWithApiClient = useCallback(
async (selectedSchoolIds, selectedSchoolYearIds, selectedClassIds, localRequestId) => {
if (!apiClient) {
return null;
}
const filters = buildStudentFilters(
selectedSchoolIds,
selectedSchoolYearIds,
selectedClassIds
);
const students = await fetchStudentsByFilters(apiClient, filters);
if (localRequestId !== fetchRequestId.current) {
return null;
}
return students;
},
[apiClient, buildStudentFilters]
);
const performStudentFetch = useCallback(
async (selectedSchoolIds, selectedSchoolYearIds, selectedClassIds, localRequestId) => {
const students = await fetchWithCustomFunction(
selectedSchoolIds,
selectedSchoolYearIds,
selectedClassIds,
localRequestId
);
if (students !== null) {
return students;
}
return fetchWithApiClient(
selectedSchoolIds,
selectedSchoolYearIds,
selectedClassIds,
localRequestId
);
},
[fetchWithCustomFunction, fetchWithApiClient]
);
const performClassFetch = useCallback(
async (selectedSchoolIds, selectedSchoolYearIds, localRequestId) => {
if (!apiClient) {
return null;
}
const filters = {
schoolIds: selectedSchoolIds.length > 0 ? selectedSchoolIds : void 0,
schoolYearIds: selectedSchoolYearIds.length > 0 ? selectedSchoolYearIds : void 0
};
const classes = await fetchClasses(apiClient, filters);
if (localRequestId !== fetchClassesRequestId.current) {
return null;
}
return classes;
},
[apiClient, fetchClasses]
);
const handleSuccessfulFetch = useCallback(
(students, localRequestId) => {
if (localRequestId !== fetchRequestId.current) {
return false;
}
const studentItems = transformStudentsToItems(students);
setCategories((prev) => setCategoryItems(prev, "students", studentItems));
return true;
},
[setCategories]
);
const handleFetchError = useCallback(
(error, localRequestId) => {
console.error("Error fetching students:", error);
if (onError && error instanceof Error) {
onError(error);
}
if (localRequestId !== fetchRequestId.current) {
return false;
}
setCategories((prev) => setCategoryItems(prev, "students", []));
return true;
},
[onError, setCategories]
);
const handleSuccessfulClassFetch = useCallback(
(classes, localRequestId) => {
if (localRequestId !== fetchClassesRequestId.current) {
return false;
}
const classItems = transformClassesToItems(classes);
setCategories((prev) => setCategoryItems(prev, "turma", classItems));
return true;
},
[setCategories]
);
const handleClassFetchError = useCallback(
(error, localRequestId) => {
console.error("Error fetching classes:", error);
if (onError && error instanceof Error) {
onError(error);
}
if (localRequestId !== fetchClassesRequestId.current) {
return false;
}
setCategories((prev) => setCategoryItems(prev, "turma", []));
return true;
},
[onError, setCategories]
);
const handleClassesChange = useCallback(
async (selectedSchoolIds, selectedSchoolYearIds) => {
if (!apiClient) return;
if (selectedSchoolYearIds.length > 0) {
fetchClassesRequestId.current += 1;
const localRequestId = fetchClassesRequestId.current;
try {
const classes = await performClassFetch(
selectedSchoolIds,
selectedSchoolYearIds,
localRequestId
);
if (classes === null) {
return;
}
handleSuccessfulClassFetch(classes, localRequestId);
} catch (error) {
handleClassFetchError(error, localRequestId);
}
} else {
fetchClassesRequestId.current += 1;
setCategories((prev) => setCategoryItems(prev, "turma", []));
}
},
[
apiClient,
performClassFetch,
handleSuccessfulClassFetch,
handleClassFetchError,
setCategories
]
);
const handleStudentsChange = useCallback(
async (selectedSchoolIds, selectedSchoolYearIds, selectedClassIds, studentsCategory) => {
if (selectedClassIds.length > 0 && studentsCategory) {
fetchRequestId.current += 1;
const localRequestId = fetchRequestId.current;
try {
const students = await performStudentFetch(
selectedSchoolIds,
selectedSchoolYearIds,
selectedClassIds,
localRequestId
);
if (students === null) {
return;
}
handleSuccessfulFetch(students, localRequestId);
} catch (error) {
handleFetchError(error, localRequestId);
}
} else if (studentsCategory) {
fetchRequestId.current += 1;
setCategories((prev) => setCategoryItems(prev, "students", []));
}
},
[
performStudentFetch,
handleSuccessfulFetch,
handleFetchError,
setCategories
]
);
const handleCategoriesChange = useCallback(
async (updatedCategories) => {
if (!customFetchStudents && !apiClient) {
setCategories(updatedCategories);
return;
}
const {
schoolIds: selectedSchoolIds,
schoolYearIds: selectedSchoolYearIds,
classIds: selectedClassIds,
studentsCategory
} = extractSelectedIds(updatedCategories);
const previousSelections = previousSelectionsRef.current;
const { schoolIdsChanged, schoolYearIdsChanged, shouldFetchStudents } = detectSelectionChanges(previousSelections, {
schoolIds: selectedSchoolIds,
schoolYearIds: selectedSchoolYearIds,
classIds: selectedClassIds
});
previousSelectionsRef.current = {
schoolIds: [...selectedSchoolIds],
schoolYearIds: [...selectedSchoolYearIds],
classIds: [...selectedClassIds]
};
setCategories(
(prev) => commitSelectionsPreservingItems(updatedCategories, prev)
);
if (schoolIdsChanged || schoolYearIdsChanged) {
await handleClassesChange(selectedSchoolIds, selectedSchoolYearIds);
}
if (shouldFetchStudents) {
await handleStudentsChange(
selectedSchoolIds,
selectedSchoolYearIds,
selectedClassIds,
studentsCategory
);
}
},
[
apiClient,
customFetchStudents,
setCategories,
handleClassesChange,
handleStudentsChange
]
);
return {
handleCategoriesChange
};
}
export {
loadCategoriesData,
formatTime,
useDynamicStudentFetching
};
//# sourceMappingURL=chunk-5WLR5TLU.mjs.map