analytica-frontend-lib
Version:
Repositório público dos componentes utilizados nas plataformas da Analytica Ensino
1 lines • 17.4 kB
Source Map (JSON)
{"version":3,"sources":["../src/components/Filter/useTableFilter.ts","../src/components/CheckBoxGroup/CheckBoxGroup.helpers.ts"],"sourcesContent":["import { useEffect, useState, useCallback, useMemo } from 'react';\nimport type { CategoryConfig } from '../CheckBoxGroup/CheckBoxGroup';\nimport { calculateFormattedItemsForAutoSelection } from '../CheckBoxGroup/CheckBoxGroup.helpers';\n\nexport type FilterConfig = {\n key: string;\n label: string;\n categories: CategoryConfig[];\n};\n\n/**\n * Merge new filter configs with previous state, preserving user selections\n */\nconst mergeConfigsWithSelections = (\n newConfigs: FilterConfig[],\n prevConfigs: FilterConfig[]\n): FilterConfig[] => {\n let changed = false;\n\n const result = newConfigs.map((newConfig, i) => ({\n ...newConfig,\n categories: newConfig.categories.map((newCat, j) => {\n const prevCat = prevConfigs[i]?.categories[j];\n const prevItems = prevCat?.itens ?? [];\n const newItems = newCat.itens ?? [];\n\n if (prevItems.length !== newItems.length) {\n changed = true;\n }\n\n if (prevCat?.key === newCat.key && prevCat?.selectedIds?.length) {\n const availableIds = new Set(newItems.map((item) => item.id));\n const selectedIds = prevCat.selectedIds.filter((id) =>\n availableIds.has(id)\n );\n if (selectedIds.length !== prevCat.selectedIds.length) {\n changed = true;\n }\n return { ...newCat, selectedIds };\n }\n return newCat;\n }),\n }));\n\n return changed ? result : prevConfigs;\n};\n\nexport type UseTableFilterOptions = {\n syncWithUrl?: boolean;\n};\n\nexport type UseTableFilterReturn = {\n filterConfigs: FilterConfig[];\n activeFilters: Record<string, string[]>;\n hasActiveFilters: boolean;\n activeFiltersCount: number;\n updateFilters: (configs: FilterConfig[]) => void;\n applyFilters: () => void;\n clearFilters: () => void;\n};\n\n/**\n * Hook for managing table filters with URL synchronization\n *\n * @param initialConfigs - Initial filter configurations\n * @param options - Hook options including URL sync\n * @returns Filter state and management functions\n *\n * @example\n * ```tsx\n * const { filterConfigs, activeFilters, updateFilters, applyFilters } = useTableFilter(\n * [\n * {\n * key: 'academic',\n * label: 'Dados Acadêmicos',\n * categories: [...]\n * }\n * ],\n * { syncWithUrl: true }\n * );\n * ```\n */\nexport const useTableFilter = (\n initialConfigs: FilterConfig[],\n options: UseTableFilterOptions = {}\n): UseTableFilterReturn => {\n const { syncWithUrl = false } = options;\n\n // Get initial state from URL if syncWithUrl is enabled\n const getInitialState = useCallback((): FilterConfig[] => {\n if (!syncWithUrl || globalThis.window === undefined) {\n return initialConfigs;\n }\n\n const params = new URLSearchParams(globalThis.window.location.search);\n const configsWithUrlState = initialConfigs.map((config) => ({\n ...config,\n categories: config.categories.map((category) => {\n const urlValue = params.get(`filter_${category.key}`);\n const selectedIds = urlValue ? urlValue.split(',').filter(Boolean) : [];\n return {\n ...category,\n selectedIds,\n };\n }),\n }));\n\n return configsWithUrlState;\n }, [initialConfigs, syncWithUrl]);\n\n const [filterConfigs, setFilterConfigs] =\n useState<FilterConfig[]>(getInitialState);\n\n // Calculate active filters (only categories with selections)\n // Memoize to prevent creating new object reference on every render\n const activeFilters = useMemo(() => {\n const filters: Record<string, string[]> = {};\n\n for (const config of filterConfigs) {\n for (const category of config.categories) {\n if (category.selectedIds && category.selectedIds.length > 0) {\n filters[category.key] = category.selectedIds;\n }\n }\n }\n\n return filters;\n }, [filterConfigs]);\n\n const hasActiveFilters = Object.keys(activeFilters).length > 0;\n\n // Count only filters that were manually selected by the user,\n // excluding categories that were auto-selected because they have only 1 available item\n const activeFiltersCount = useMemo(() => {\n const allCategories = filterConfigs.flatMap((config) => config.categories);\n\n let count = 0;\n for (const category of allCategories) {\n if (!category.selectedIds || category.selectedIds.length === 0) continue;\n\n const availableItems = calculateFormattedItemsForAutoSelection(\n category,\n allCategories\n );\n\n const isAutoSelected =\n availableItems.length === 1 &&\n category.selectedIds.length === 1 &&\n category.selectedIds[0] === availableItems[0]?.id;\n\n if (!isAutoSelected) {\n count++;\n }\n }\n\n return count;\n }, [filterConfigs]);\n\n /**\n * Update filter configs (temporary state, not applied to URL yet)\n */\n const updateFilters = useCallback((configs: FilterConfig[]) => {\n setFilterConfigs(configs);\n }, []);\n\n /**\n * Apply filters to URL (commit the changes)\n */\n const applyFilters = useCallback(() => {\n if (!syncWithUrl || globalThis.window === undefined) {\n return;\n }\n\n const url = new URL(globalThis.window.location.href);\n const params = url.searchParams;\n\n // Update URL parameters for each category\n for (const config of filterConfigs) {\n for (const category of config.categories) {\n const paramKey = `filter_${category.key}`;\n\n if (category.selectedIds && category.selectedIds.length > 0) {\n params.set(paramKey, category.selectedIds.join(','));\n } else {\n params.delete(paramKey);\n }\n }\n }\n\n // Update URL without page reload\n globalThis.window.history.replaceState({}, '', url.toString());\n }, [filterConfigs, syncWithUrl]);\n\n /**\n * Clear all filters\n */\n const clearFilters = useCallback(() => {\n const clearedConfigs = filterConfigs.map((config) => ({\n ...config,\n categories: config.categories.map((category) => ({\n ...category,\n selectedIds: [],\n })),\n }));\n\n setFilterConfigs(clearedConfigs);\n\n // If syncWithUrl, also clear URL parameters\n if (syncWithUrl && globalThis.window !== undefined) {\n const url = new URL(globalThis.window.location.href);\n const params = url.searchParams;\n\n for (const config of filterConfigs) {\n for (const category of config.categories) {\n params.delete(`filter_${category.key}`);\n }\n }\n\n globalThis.window.history.replaceState({}, '', url.toString());\n }\n }, [filterConfigs, syncWithUrl]);\n\n // Sync filter configs when initialConfigs items change (e.g., async data loaded)\n useEffect(() => {\n setFilterConfigs((prev) =>\n mergeConfigsWithSelections(initialConfigs, prev)\n );\n }, [initialConfigs]);\n\n // Sync with URL on mount and when URL changes externally\n useEffect(() => {\n if (!syncWithUrl || globalThis.window === undefined) {\n return;\n }\n\n const handlePopState = () => {\n setFilterConfigs(getInitialState());\n };\n\n globalThis.window.addEventListener('popstate', handlePopState);\n return () =>\n globalThis.window.removeEventListener('popstate', handlePopState);\n }, [syncWithUrl, getInitialState]);\n\n return {\n filterConfigs,\n activeFilters,\n hasActiveFilters,\n activeFiltersCount,\n updateFilters,\n applyFilters,\n clearFilters,\n };\n};\n","import type { CategoryConfig, Item } from './CheckBoxGroup';\n\n/**\n * Helper function to efficiently compare selectedIds arrays\n */\nexport const areSelectedIdsEqual = (\n ids1?: string[],\n ids2?: string[]\n): boolean => {\n if (ids1 === ids2) return true;\n if (!ids1 || !ids2) return ids1 === ids2;\n if (ids1.length !== ids2.length) return false;\n\n for (let i = 0; i < ids1.length; i++) {\n if (ids1[i] !== ids2[i]) return false;\n }\n return true;\n};\n\n/**\n * Helper function to check if category is enabled based on dependencies\n */\nexport const isCategoryEnabled = (\n category: CategoryConfig,\n allCategories: CategoryConfig[]\n): boolean => {\n if (!category.dependsOn || category.dependsOn.length === 0) {\n return true;\n }\n return category.dependsOn.every((depKey) => {\n const depCat = allCategories.find((c) => c.key === depKey);\n return depCat?.selectedIds && depCat.selectedIds.length > 0;\n });\n};\n\n/**\n * Helper function to check if an item matches a filter\n */\nexport const isItemMatchingFilter = (\n item: Item,\n filter: { key: string; internalField: string },\n allCategories: CategoryConfig[]\n): boolean => {\n const parentCat = allCategories.find((c) => c.key === filter.key);\n const parentSelectedIds = parentCat?.selectedIds || [];\n const itemFieldValue = item[filter.internalField];\n return parentSelectedIds.includes(String(itemFieldValue));\n};\n\n/**\n * Helper function to get badge text for category\n */\nexport const getBadgeText = (\n category: CategoryConfig,\n formattedItems: { groupLabel?: string; itens: Item[] }[]\n): string => {\n const visibleIds = formattedItems\n .flatMap((group) => group.itens || [])\n .map((i) => i.id);\n const selectedVisibleCount = visibleIds.filter((id) =>\n category.selectedIds?.includes(id)\n ).length;\n const totalVisible = visibleIds.length;\n return `${selectedVisibleCount} de ${totalVisible} ${\n selectedVisibleCount === 1 ? 'selecionado' : 'selecionados'\n }`;\n};\n\n/**\n * Helper function to handle accordion value change logic\n * Returns the new accordion value or null if should not change\n */\nexport const handleAccordionValueChange = (\n value: string | string[] | undefined,\n categories: CategoryConfig[],\n isCategoryEnabledFn: (category: CategoryConfig) => boolean\n): string | null => {\n if (typeof value !== 'string') {\n if (!value) {\n return '';\n }\n return null; // Don't change for array values\n }\n\n if (!value) {\n return '';\n }\n\n // Prevent opening disabled categories\n const category = categories.find((c) => c.key === value);\n if (!category) {\n return null; // Category not found, don't change\n }\n\n const isEnabled = isCategoryEnabledFn(category);\n if (!isEnabled) {\n return null; // Don't allow opening disabled accordions\n }\n\n return value;\n};\n\n/**\n * Helper function to calculate filtered items for auto-selection\n * This function determines which items are visible/filtered for a category\n */\nexport const calculateFormattedItemsForAutoSelection = (\n category: CategoryConfig,\n allCategories: CategoryConfig[]\n): Item[] => {\n if (!category?.dependsOn || category.dependsOn.length === 0) {\n return category?.itens || [];\n }\n\n // Check if category is enabled based on dependencies\n const isEnabled = isCategoryEnabled(category, allCategories);\n\n // If category is disabled, return empty items array\n if (!isEnabled) {\n return [];\n }\n\n const filters =\n (category.filteredBy as {\n key: string;\n internalField: string;\n label?: string;\n }[]) || [];\n\n if (filters.length === 0) {\n return category?.itens || [];\n }\n\n const selectedIdsArr = filters.map((f) => {\n const parentCat = allCategories.find((c) => c.key === f.key);\n if (!parentCat?.selectedIds?.length) {\n return [];\n }\n return parentCat.selectedIds;\n });\n\n if (selectedIdsArr.some((arr) => arr.length === 0)) {\n return [];\n }\n\n // Filter items based on selected parent IDs\n const filteredItems = (category.itens || []).filter((item) =>\n filters.every((filter) => isItemMatchingFilter(item, filter, allCategories))\n );\n\n return filteredItems;\n};\n"],"mappings":"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","names":[]}