analytica-frontend-lib
Version:
Repositório público dos componentes utilizados nas plataformas da Analytica Ensino
1 lines • 7.07 kB
Source Map (JSON)
{"version":3,"sources":["../src/hooks/useMapData.ts"],"sourcesContent":["import { useState, useEffect, useCallback, useRef } from 'react';\nimport type { FeatureCollection, MultiPolygon, Polygon } from 'geojson';\nimport type { RegionData as ChoroplethRegionData } from '../components/ChoroplethMap/ChoroplethMap.types';\nimport type {\n MapFilters,\n MapDataBounds,\n MapDataRegion,\n MapDataApiResponse,\n} from '../types/mapData';\n\n/**\n * Hook return type for useMapData\n */\nexport interface UseMapDataReturn {\n /** Transformed region data for ChoroplethMap */\n data: ChoroplethRegionData[];\n /** Map bounds from API */\n bounds: MapDataBounds | null;\n /** Complete GeoJSON with NRE field for each municipality */\n geoJSON: FeatureCollection<Polygon | MultiPolygon> | null;\n /** Loading state */\n loading: boolean;\n /** Error message if request failed */\n error: string | null;\n /** Refetch data from API */\n refetch: () => Promise<void>;\n}\n\n/**\n * Transform enriched GeoJSON features to ChoroplethMap region data.\n *\n * Each feature is one municipality: `name` is the city and `value`/`accessCount`\n * are its own per-city metric (colored individually). `groupName` carries the\n * NRE label used only to draw the grouping outline.\n *\n * @param geoJSON - Enriched GeoJSON FeatureCollection from backend\n * @returns Array of region data for ChoroplethMap\n */\nfunction transformGeoJSONFeatures(\n geoJSON: FeatureCollection<Polygon | MultiPolygon>\n): ChoroplethRegionData[] {\n return geoJSON.features.map((feature) => ({\n id: feature.properties?.GEOCODIGO || feature.properties?.NOME || '',\n name: feature.properties?.NOME || '',\n groupName: feature.properties?.NRE\n ? `NRE ${feature.properties.NRE}`\n : undefined,\n value: feature.properties?.value ?? 0,\n accessCount: feature.properties?.totalAccess ?? 0,\n geoJson: feature,\n isManagedRegion: feature.properties?.isManagedRegion !== false,\n accessBreakdown: feature.properties?.accessBreakdown,\n }));\n}\n\n/**\n * Transform API region data to ChoroplethMap region data (fallback)\n * @param region - Region data from API\n * @returns Transformed region data for ChoroplethMap or null if no geoJson\n */\nfunction transformRegionData(\n region: MapDataRegion\n): ChoroplethRegionData | null {\n if (!region.geoJson) {\n return null;\n }\n\n return {\n id: region.schoolGroupId,\n name: region.schoolGroupName,\n code: region.schoolGroupCode,\n value: region.value,\n accessCount: region.totalAccess,\n geoJson: region.geoJson,\n isManagedRegion: region.isManagedRegion !== false,\n };\n}\n\n/**\n * Factory function to create useMapData hook\n *\n * @param fetchMapDataApi - Function to fetch map data from API\n * @returns Hook for managing map data with auto-fetch on filter change\n *\n * @example\n * ```tsx\n * // In your app setup\n * const fetchMapDataApi = async (filters: MapFilters) => {\n * const response = await api.post('/access-report/access/map', filters);\n * return response.data;\n * };\n *\n * export const useMapData = createUseMapData(fetchMapDataApi);\n *\n * // In your component\n * const { data, bounds, loading, error } = useMapData(filters);\n * ```\n */\nexport const createUseMapData = (\n fetchMapDataApi: (filters: MapFilters) => Promise<MapDataApiResponse>\n) => {\n return (filters: MapFilters): UseMapDataReturn => {\n const filtersRef = useRef(filters);\n filtersRef.current = filters;\n const filtersKey = JSON.stringify(filters);\n const fetchIdRef = useRef(0);\n\n const [data, setData] = useState<ChoroplethRegionData[]>([]);\n const [bounds, setBounds] = useState<MapDataBounds | null>(null);\n const [geoJSON, setGeoJSON] = useState<FeatureCollection<\n Polygon | MultiPolygon\n > | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n const fetchData = useCallback(async () => {\n const fetchId = ++fetchIdRef.current;\n setLoading(true);\n setError(null);\n\n try {\n const mapData = await fetchMapDataApi(filtersRef.current);\n if (fetchIdRef.current !== fetchId) return;\n\n const transformedRegions = mapData.data.geoJSON\n ? transformGeoJSONFeatures(mapData.data.geoJSON)\n : mapData.data.regions\n .map(transformRegionData)\n .filter((r): r is ChoroplethRegionData => r !== null);\n setData(transformedRegions);\n setBounds(mapData.data.bounds);\n setGeoJSON(mapData.data.geoJSON ?? null);\n } catch (err) {\n if (fetchIdRef.current !== fetchId) return;\n const errorMessage =\n err instanceof Error ? err.message : 'Erro ao carregar dados do mapa';\n setError(errorMessage);\n setData([]);\n setBounds(null);\n setGeoJSON(null);\n } finally {\n if (fetchIdRef.current === fetchId) {\n setLoading(false);\n }\n }\n }, [filtersKey]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n return {\n data,\n bounds,\n geoJSON,\n loading,\n error,\n refetch: fetchData,\n };\n };\n};\n"],"mappings":";AAAA,SAAS,UAAU,WAAW,aAAa,cAAc;AAsCzD,SAAS,yBACP,SACwB;AACxB,SAAO,QAAQ,SAAS,IAAI,CAAC,aAAa;AAAA,IACxC,IAAI,QAAQ,YAAY,aAAa,QAAQ,YAAY,QAAQ;AAAA,IACjE,MAAM,QAAQ,YAAY,QAAQ;AAAA,IAClC,WAAW,QAAQ,YAAY,MAC3B,OAAO,QAAQ,WAAW,GAAG,KAC7B;AAAA,IACJ,OAAO,QAAQ,YAAY,SAAS;AAAA,IACpC,aAAa,QAAQ,YAAY,eAAe;AAAA,IAChD,SAAS;AAAA,IACT,iBAAiB,QAAQ,YAAY,oBAAoB;AAAA,IACzD,iBAAiB,QAAQ,YAAY;AAAA,EACvC,EAAE;AACJ;AAOA,SAAS,oBACP,QAC6B;AAC7B,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,IAAI,OAAO;AAAA,IACX,MAAM,OAAO;AAAA,IACb,MAAM,OAAO;AAAA,IACb,OAAO,OAAO;AAAA,IACd,aAAa,OAAO;AAAA,IACpB,SAAS,OAAO;AAAA,IAChB,iBAAiB,OAAO,oBAAoB;AAAA,EAC9C;AACF;AAsBO,IAAM,mBAAmB,CAC9B,oBACG;AACH,SAAO,CAAC,YAA0C;AAChD,UAAM,aAAa,OAAO,OAAO;AACjC,eAAW,UAAU;AACrB,UAAM,aAAa,KAAK,UAAU,OAAO;AACzC,UAAM,aAAa,OAAO,CAAC;AAE3B,UAAM,CAAC,MAAM,OAAO,IAAI,SAAiC,CAAC,CAAC;AAC3D,UAAM,CAAC,QAAQ,SAAS,IAAI,SAA+B,IAAI;AAC/D,UAAM,CAAC,SAAS,UAAU,IAAI,SAEpB,IAAI;AACd,UAAM,CAAC,SAAS,UAAU,IAAI,SAAS,IAAI;AAC3C,UAAM,CAAC,OAAO,QAAQ,IAAI,SAAwB,IAAI;AAEtD,UAAM,YAAY,YAAY,YAAY;AACxC,YAAM,UAAU,EAAE,WAAW;AAC7B,iBAAW,IAAI;AACf,eAAS,IAAI;AAEb,UAAI;AACF,cAAM,UAAU,MAAM,gBAAgB,WAAW,OAAO;AACxD,YAAI,WAAW,YAAY,QAAS;AAEpC,cAAM,qBAAqB,QAAQ,KAAK,UACpC,yBAAyB,QAAQ,KAAK,OAAO,IAC7C,QAAQ,KAAK,QACV,IAAI,mBAAmB,EACvB,OAAO,CAAC,MAAiC,MAAM,IAAI;AAC1D,gBAAQ,kBAAkB;AAC1B,kBAAU,QAAQ,KAAK,MAAM;AAC7B,mBAAW,QAAQ,KAAK,WAAW,IAAI;AAAA,MACzC,SAAS,KAAK;AACZ,YAAI,WAAW,YAAY,QAAS;AACpC,cAAM,eACJ,eAAe,QAAQ,IAAI,UAAU;AACvC,iBAAS,YAAY;AACrB,gBAAQ,CAAC,CAAC;AACV,kBAAU,IAAI;AACd,mBAAW,IAAI;AAAA,MACjB,UAAE;AACA,YAAI,WAAW,YAAY,SAAS;AAClC,qBAAW,KAAK;AAAA,QAClB;AAAA,MACF;AAAA,IACF,GAAG,CAAC,UAAU,CAAC;AAEf,cAAU,MAAM;AACd,gBAAU;AAAA,IACZ,GAAG,CAAC,SAAS,CAAC;AAEd,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS;AAAA,IACX;AAAA,EACF;AACF;","names":[]}