analytica-frontend-lib
Version:
Repositório público dos componentes utilizados nas plataformas da Analytica Ensino
1 lines • 13.1 kB
Source Map (JSON)
{"version":3,"sources":["../src/hooks/useActivitiesHistory.ts"],"sourcesContent":["import { useState, useCallback } from 'react';\nimport dayjs from 'dayjs';\nimport type { BaseApiClient } from '../types/api';\nimport { mapApiStatusToDisplay } from '../types/common';\nimport type {\n ActivityHistoryResponse,\n ActivityTableItem,\n ActivitiesHistoryApiResponse,\n ActivityHistoryFilters,\n ActivityPagination,\n ActivityFilterOption,\n} from '../types/activitiesHistory';\nimport {\n mergeFilterOptions,\n extractBreakdownFilterOptions,\n} from '../utils/filterHelpers';\n\n/**\n * Options for configuring the useActivitiesHistory hook\n */\nexport interface UseActivitiesHistoryOptions {\n /** Filter by activity category (PROVA, ATIVIDADE, etc.) */\n activityCategory?: 'PROVA' | 'ATIVIDADE';\n}\n\n/**\n * API filter options extracted from response\n */\nexport interface ActivityApiFilterOptions {\n schools: ActivityFilterOption[];\n classes: ActivityFilterOption[];\n subjects: ActivityFilterOption[];\n schoolYears: ActivityFilterOption[];\n}\n\n/**\n * Hook state interface\n */\nexport interface UseActivitiesHistoryState {\n activities: ActivityTableItem[];\n loading: boolean;\n error: string | null;\n pagination: ActivityPagination;\n apiFilterOptions: ActivityApiFilterOptions;\n}\n\n/**\n * Hook return type\n */\nexport interface UseActivitiesHistoryReturn extends UseActivitiesHistoryState {\n fetchActivities: (filters?: ActivityHistoryFilters) => Promise<void>;\n}\n\n/**\n * Default pagination values\n */\nexport const DEFAULT_ACTIVITIES_PAGINATION: ActivityPagination = {\n total: 0,\n page: 1,\n limit: 10,\n totalPages: 0,\n};\n\n/**\n * Default API filter options\n */\nexport const DEFAULT_ACTIVITY_FILTER_OPTIONS: ActivityApiFilterOptions = {\n schools: [],\n classes: [],\n subjects: [],\n schoolYears: [],\n};\n\n/**\n * Transform API response to table item format\n * @param activity - Activity from API response\n * @returns Formatted activity for table display\n */\nexport const transformActivityToTableItem = (\n activity: ActivityHistoryResponse\n): ActivityTableItem => {\n const firstBreakdown = activity.breakdown?.[0];\n return {\n id: activity.id,\n startDate: activity.startDate\n ? dayjs(activity.startDate).format('DD/MM')\n : '-',\n deadline: activity.finalDate\n ? dayjs(activity.finalDate).format('DD/MM')\n : '-',\n creator: activity.creator?.name?.trim() ? activity.creator.name : '-',\n creatorId: activity.creator?.id ?? null,\n title: activity.title,\n school: firstBreakdown?.school?.name ?? '-',\n year: firstBreakdown?.schoolYear?.name ?? '-',\n subject: activity.subject?.name ?? '-',\n class: firstBreakdown?.class?.name ?? '-',\n status: mapApiStatusToDisplay(activity.status),\n completionPercentage: activity.completionPercentage,\n };\n};\n\n/**\n * Extract unique filter options from activities API response.\n * Delegates to the shared extractBreakdownFilterOptions helper.\n */\nexport const extractActivityFilterOptions = (\n activities: ActivityHistoryResponse[]\n): ActivityApiFilterOptions => extractBreakdownFilterOptions(activities);\n\n/**\n * Join an array of selected ids into the backend's comma-separated convention\n * (e.g. `schoolIds=a,b,c`). Returns undefined for empty / non-array input so the\n * query param is omitted entirely.\n */\nconst toCsv = (value: unknown): string | undefined => {\n if (Array.isArray(value) && value.length > 0) {\n return value.map(String).join(',');\n }\n return undefined;\n};\n\n/**\n * Collapse a single-select filter (emitted as an array by TableProvider) to its\n * first value. Also tolerates a bare string. Returns undefined when empty.\n */\nconst toSingle = (value: unknown): string | undefined => {\n if (Array.isArray(value)) {\n return value.length > 0 ? String(value[0]) : undefined;\n }\n if (typeof value === 'string' && value.length > 0) {\n return value;\n }\n return undefined;\n};\n\n/**\n * Assign a resolved string value onto the params object only when it is present.\n * Keeps the builder free of repetitive `if (value) params[key] = value` blocks.\n */\nconst assignIf = (\n params: Record<string, unknown>,\n key: string,\n value: string | undefined\n): void => {\n if (value) {\n params[key] = value;\n }\n};\n\n/**\n * Raw scalar keys forwarded to the backend untouched (pagination, text search,\n * date range and sorting). Copied verbatim when present and non-empty.\n */\nconst PASSTHROUGH_KEYS = [\n 'page',\n 'limit',\n 'search',\n 'startDate',\n 'finalDate',\n 'sortBy',\n 'sortOrder',\n] as const;\n\n/**\n * Build the `/activities/history` query params from the raw TableProvider filter\n * keys. TableProvider emits UI-category keys (`subject`, `school`, `class`,\n * `schoolYear`, `status`, `creatorType`) as arrays; the backend expects a\n * different, mostly single-value contract. This adapter renames each key and\n * collapses/serializes to what the backend actually reads. Mirrors\n * `buildFiltersFromParams` in RecommendedLessonsHistory.\n *\n * @param filters - Raw table params (arrays under UI keys) plus page/limit/search/sort\n * @param activityCategory - Optional value forwarded as the `type` param\n */\nexport const buildActivityHistoryQueryParams = (\n filters?: Record<string, unknown>,\n activityCategory?: string\n): Record<string, unknown> => {\n const params: Record<string, unknown> = {};\n assignIf(params, 'type', activityCategory);\n\n if (!filters) {\n return params;\n }\n\n for (const key of PASSTHROUGH_KEYS) {\n const value = filters[key];\n if (value !== undefined && value !== null && value !== '') {\n params[key] = value;\n }\n }\n\n // Multi-select filters serialized as comma-separated ids. School and class each\n // fall back to their legacy singular key when the raw multi-select key is absent.\n assignIf(params, 'schoolIds', toCsv(filters.school));\n assignIf(params, 'classIds', toCsv(filters.class));\n assignIf(params, 'schoolYearIds', toCsv(filters.schoolYear));\n if (!params.schoolIds) {\n assignIf(params, 'schoolId', toSingle(filters.schoolId));\n }\n if (!params.classIds) {\n assignIf(params, 'classId', toSingle(filters.classId));\n }\n\n // Single-select filters (subject also honors the legacy singular key).\n assignIf(params, 'status', toSingle(filters.status));\n assignIf(\n params,\n 'subjectId',\n toSingle(filters.subject) ?? toSingle(filters.subjectId)\n );\n assignIf(params, 'creatorType', toSingle(filters.creatorType));\n\n return params;\n};\n\n/**\n * Hook implementation\n */\nconst useActivitiesHistoryImpl = (\n apiClient: BaseApiClient,\n options?: UseActivitiesHistoryOptions\n): UseActivitiesHistoryReturn => {\n const [state, setState] = useState<UseActivitiesHistoryState>({\n activities: [],\n loading: false,\n error: null,\n pagination: DEFAULT_ACTIVITIES_PAGINATION,\n apiFilterOptions: DEFAULT_ACTIVITY_FILTER_OPTIONS,\n });\n\n const fetchActivities = useCallback(\n async (filters?: ActivityHistoryFilters) => {\n setState((prev) => ({ ...prev, loading: true, error: null }));\n\n try {\n const params = buildActivityHistoryQueryParams(\n filters as Record<string, unknown>,\n options?.activityCategory\n );\n const response = await apiClient.get<ActivitiesHistoryApiResponse>(\n '/activities/history',\n { params }\n );\n\n const { data } = response.data;\n\n const tableItems = data.activities.map(transformActivityToTableItem);\n const extracted = extractActivityFilterOptions(data.activities);\n\n setState((prev) => ({\n activities: tableItems,\n loading: false,\n error: null,\n pagination: data.pagination,\n apiFilterOptions: {\n schools: mergeFilterOptions(\n prev.apiFilterOptions.schools,\n extracted.schools\n ),\n classes: mergeFilterOptions(\n prev.apiFilterOptions.classes,\n extracted.classes\n ),\n subjects: mergeFilterOptions(\n prev.apiFilterOptions.subjects,\n extracted.subjects\n ),\n schoolYears: mergeFilterOptions(\n prev.apiFilterOptions.schoolYears,\n extracted.schoolYears\n ),\n },\n }));\n } catch (error) {\n console.error('Erro ao carregar histórico:', error);\n setState((prev) => ({\n ...prev,\n loading: false,\n error: 'Erro ao carregar histórico de atividades',\n }));\n }\n },\n [apiClient, options?.activityCategory]\n );\n\n return { ...state, fetchActivities };\n};\n\n/**\n * Factory function to create useActivitiesHistory hook\n *\n * @param apiClient - API client instance (axios, fetch wrapper, etc.)\n * @param options - Hook configuration options\n * @returns Hook for managing activities history\n *\n * @example\n * ```tsx\n * import { createUseActivitiesHistory } from 'analytica-frontend-lib';\n * import api from '@/services/apiService';\n *\n * const useActivitiesHistory = createUseActivitiesHistory(api, { activityCategory: 'ATIVIDADE' });\n *\n * // In your component\n * const { activities, loading, fetchActivities, apiFilterOptions } = useActivitiesHistory();\n * ```\n */\nexport const createUseActivitiesHistory = (\n apiClient: BaseApiClient,\n options?: UseActivitiesHistoryOptions\n) => {\n return (): UseActivitiesHistoryReturn =>\n useActivitiesHistoryImpl(apiClient, options);\n};\n\n/**\n * Alias for createUseActivitiesHistory\n */\nexport const createActivitiesHistoryHook = createUseActivitiesHistory;\n"],"mappings":"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","names":[]}