analytica-frontend-lib
Version:
Repositório público dos componentes utilizados nas plataformas da Analytica Ensino
1 lines • 13.3 kB
Source Map (JSON)
{"version":3,"sources":["../src/utils/filterHelpers.ts"],"sourcesContent":["import type { ActivityFilterOption } from '../types/activitiesHistory';\n\n/**\n * Generic user institution data structure\n * Matches the structure from GET /user/me endpoint\n */\nexport interface UserInstitutionData {\n school?: { id: string; name: string };\n schoolYear?: { id: string; name: string };\n class?: { id: string; name: string };\n}\n\n/**\n * Generic subject teacher topic class structure\n */\nexport interface SubTeacherTopicClassData {\n subject?: { id: string; name: string };\n class?: { id: string; name: string };\n}\n\n/**\n * Generic user data structure for filter extraction\n * Can be extended by consuming projects\n */\nexport interface UserFilterSourceData {\n userInstitutions?: UserInstitutionData[];\n subTeacherTopicClasses?: SubTeacherTopicClassData[];\n}\n\n/**\n * Extract unique school options from user data\n * Uses Map for deduplication to handle multiple institutions with same school\n *\n * @param userData - User data from /user/me endpoint\n * @returns Array of unique schools sorted by name\n *\n * @example\n * ```typescript\n * const userData = useUserStore(state => state.data);\n * const schools = getSchoolOptionsFromUserData(userData);\n * // Returns: [{ id: '1', name: 'Escola A' }, { id: '2', name: 'Escola B' }]\n * ```\n */\nexport const getSchoolOptionsFromUserData = (\n userData: UserFilterSourceData | null | undefined\n): ActivityFilterOption[] => {\n if (!userData?.userInstitutions) {\n return [];\n }\n\n const schoolsMap = new Map<string, ActivityFilterOption>();\n\n for (const userInst of userData.userInstitutions) {\n if (userInst.school?.id && userInst.school?.name) {\n schoolsMap.set(userInst.school.id, {\n id: userInst.school.id,\n name: userInst.school.name,\n });\n }\n }\n\n return Array.from(schoolsMap.values()).sort((a, b) =>\n a.name.localeCompare(b.name, 'pt-BR')\n );\n};\n\n/**\n * Extract unique subject options from user data\n * Uses Map for deduplication\n *\n * @param userData - User data from /user/me endpoint\n * @returns Array of unique subjects sorted by name\n *\n * @example\n * ```typescript\n * const userData = useUserStore(state => state.data);\n * const subjects = getSubjectOptionsFromUserData(userData);\n * // Returns: [{ id: '1', name: 'Matemática' }, { id: '2', name: 'Português' }]\n * ```\n */\nexport const getSubjectOptionsFromUserData = (\n userData: UserFilterSourceData | null | undefined\n): ActivityFilterOption[] => {\n if (!userData?.subTeacherTopicClasses) {\n return [];\n }\n\n const subjectsMap = new Map<string, ActivityFilterOption>();\n\n for (const subTeacher of userData.subTeacherTopicClasses) {\n if (subTeacher.subject?.id && subTeacher.subject?.name) {\n subjectsMap.set(subTeacher.subject.id, {\n id: subTeacher.subject.id,\n name: subTeacher.subject.name,\n });\n }\n }\n\n return Array.from(subjectsMap.values()).sort((a, b) =>\n a.name.localeCompare(b.name, 'pt-BR')\n );\n};\n\n/**\n * Extract unique school year (série) options from user data\n *\n * @param userData - User data from /user/me endpoint\n * @returns Array of unique school years sorted by name\n */\nexport const getSchoolYearOptionsFromUserData = (\n userData: UserFilterSourceData | null | undefined\n): ActivityFilterOption[] => {\n if (!userData?.userInstitutions) {\n return [];\n }\n\n const schoolYearsMap = new Map<string, ActivityFilterOption>();\n\n for (const userInst of userData.userInstitutions) {\n if (userInst.schoolYear?.id && userInst.schoolYear?.name) {\n schoolYearsMap.set(userInst.schoolYear.id, {\n id: userInst.schoolYear.id,\n name: userInst.schoolYear.name,\n });\n }\n }\n\n return Array.from(schoolYearsMap.values()).sort((a, b) =>\n a.name.localeCompare(b.name, 'pt-BR')\n );\n};\n\n/**\n * Extract unique class (turma) options from user data\n * Combines classes from userInstitutions and subTeacherTopicClasses\n *\n * @param userData - User data from /user/me endpoint\n * @returns Array of unique classes sorted by name\n */\nexport const getClassOptionsFromUserData = (\n userData: UserFilterSourceData | null | undefined\n): ActivityFilterOption[] => {\n if (!userData) {\n return [];\n }\n\n const classesMap = new Map<string, ActivityFilterOption>();\n\n if (userData.userInstitutions) {\n for (const userInst of userData.userInstitutions) {\n if (userInst.class?.id && userInst.class?.name) {\n classesMap.set(userInst.class.id, {\n id: userInst.class.id,\n name: userInst.class.name,\n });\n }\n }\n }\n\n if (userData.subTeacherTopicClasses) {\n for (const subTeacher of userData.subTeacherTopicClasses) {\n if (subTeacher.class?.id && subTeacher.class?.name) {\n classesMap.set(subTeacher.class.id, {\n id: subTeacher.class.id,\n name: subTeacher.class.name,\n });\n }\n }\n }\n\n return Array.from(classesMap.values()).sort((a, b) =>\n a.name.localeCompare(b.name, 'pt-BR')\n );\n};\n\n/**\n * Build user filter data object from user data\n * Convenience function to create ActivityUserFilterData\n *\n * @param userData - User data from /user/me endpoint\n * @returns Object with schools and subjects arrays\n *\n * @example\n * ```typescript\n * const userData = useUserStore(state => state.data);\n * const userFilterData = buildUserFilterData(userData);\n * // Use with ActivitiesHistory component:\n * <ActivitiesHistory userFilterData={userFilterData} ... />\n * ```\n */\nexport const buildUserFilterData = (\n userData: UserFilterSourceData | null | undefined\n): { schools: ActivityFilterOption[]; subjects: ActivityFilterOption[] } => ({\n schools: getSchoolOptionsFromUserData(userData),\n subjects: getSubjectOptionsFromUserData(userData),\n});\n\n/**\n * Merge two filter option arrays, deduplicating by ID.\n * Returns the base array unchanged if extra adds no new items.\n *\n * @param base - Base filter options array\n * @param extra - Additional filter options to merge\n * @returns Merged and sorted array of unique filter options\n *\n * @example\n * ```typescript\n * const userSubjects = getSubjectOptionsFromUserData(userData);\n * const apiSubjects = [{ id: '3', name: 'História' }];\n * const allSubjects = mergeFilterOptions(userSubjects, apiSubjects);\n * // Returns deduplicated and sorted array\n * ```\n */\nexport const mergeFilterOptions = (\n base: ActivityFilterOption[],\n extra: ActivityFilterOption[]\n): ActivityFilterOption[] => {\n if (extra.length === 0) return base;\n const baseIds = new Set(base.map((item) => item.id));\n const hasNew = extra.some((item) => !baseIds.has(item.id));\n if (!hasNew) return base;\n const map = new Map(base.map((item) => [item.id, item.name] as const));\n extra.forEach((item) => {\n if (!map.has(item.id)) map.set(item.id, item.name);\n });\n return Array.from(map.entries())\n .map(([id, name]) => ({ id, name }))\n .sort((a, b) => a.name.localeCompare(b.name, 'pt-BR'));\n};\n\n/**\n * Generic entity reference with id and name.\n * Used internally for structural typing in extractBreakdownFilterOptions.\n */\ninterface EntityRefLike {\n id: string;\n name: string;\n}\n\n/**\n * Structural shape of a single breakdown entry (school/class/schoolYear).\n * Matches both ActivityBreakdownItem and ExamBreakdownItem.\n */\ninterface BreakdownLike {\n school?: EntityRefLike | null;\n schoolYear?: EntityRefLike | null;\n class?: EntityRefLike | null;\n}\n\n/**\n * Structural shape of a history item that carries subject and breakdown data.\n * Matches both ActivityHistoryResponse and ExamHistoryResponse.\n */\ninterface BreakdownHistoryItem {\n subject?: EntityRefLike | null;\n breakdown?: BreakdownLike[];\n}\n\n/**\n * Filter options extracted from a list of history items with breakdown data.\n */\nexport interface BreakdownFilterOptions {\n schools: ActivityFilterOption[];\n classes: ActivityFilterOption[];\n subjects: ActivityFilterOption[];\n schoolYears: ActivityFilterOption[];\n}\n\n/**\n * Extract unique filter options (schools, classes, subjects, schoolYears)\n * from a list of history items that carry subject and breakdown data.\n *\n * Used by both useActivitiesHistory and useExamsHistory to avoid duplication.\n *\n * @param items - Array of history items (activities or exams) from the API\n * @returns Deduplicated, sorted filter options grouped by dimension\n *\n * @example\n * ```typescript\n * const options = extractBreakdownFilterOptions(data.activities);\n * // Returns: { schools: [...], classes: [...], subjects: [...], schoolYears: [...] }\n * ```\n */\nexport const extractBreakdownFilterOptions = (\n items: BreakdownHistoryItem[]\n): BreakdownFilterOptions => {\n const schoolsMap = new Map<string, string>();\n const classesMap = new Map<string, string>();\n const subjectsMap = new Map<string, string>();\n const schoolYearsMap = new Map<string, string>();\n\n const setIfPresent = (\n map: Map<string, string>,\n ref: EntityRefLike | null | undefined\n ): void => {\n if (ref?.id && ref?.name) map.set(ref.id, ref.name);\n };\n\n for (const item of items) {\n setIfPresent(subjectsMap, item.subject);\n item.breakdown?.forEach((b) => {\n setIfPresent(schoolsMap, b.school);\n setIfPresent(classesMap, b.class);\n setIfPresent(schoolYearsMap, b.schoolYear);\n });\n }\n\n const toOptions = (map: Map<string, string>): ActivityFilterOption[] =>\n Array.from(map.entries())\n .map(([id, name]) => ({ id, name }))\n .sort((a, b) => a.name.localeCompare(b.name, 'pt-BR'));\n\n return {\n schools: toOptions(schoolsMap),\n classes: toOptions(classesMap),\n subjects: toOptions(subjectsMap),\n schoolYears: toOptions(schoolYearsMap),\n };\n};\n"],"mappings":"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","names":[]}