UNPKG

analytica-frontend-lib

Version:

Repositório público dos componentes utilizados nas plataformas da Analytica Ensino

1 lines 10.1 kB
{"version":3,"sources":["../src/components/StatisticsCard/StatisticsCard.tsx"],"sourcesContent":["import Text from '../Text/Text';\nimport Button from '../Button/Button';\nimport Select, {\n SelectTrigger,\n SelectValue,\n SelectContent,\n SelectItem,\n} from '../Select/Select';\nimport { PlusIcon } from '@phosphor-icons/react/dist/csr/Plus';\n\n/**\n * Statistics data item\n */\ninterface StatItem {\n /** Statistic label */\n label: string;\n /** Statistic value */\n value: string | number;\n /** Color variant */\n variant: 'high' | 'medium' | 'low' | 'total';\n}\n\n/**\n * Props for StatisticsCard component\n */\ninterface StatisticsCardProps {\n /** Title displayed at the top of the card */\n title: string;\n /** Optional description displayed below the title */\n description?: string;\n /** Statistics data to display */\n data?: StatItem[];\n /** Show placeholder \"-\" in values when true (for created items without data yet) */\n showPlaceholder?: boolean;\n /** Message shown in empty state */\n emptyStateMessage?: string;\n /** Text for the empty state button */\n emptyStateButtonText?: string;\n /** Callback when empty state button is clicked */\n onEmptyStateButtonClick?: () => void;\n /** Optional dropdown options for filtering */\n dropdownOptions?: Array<{\n label: string;\n value: string;\n }>;\n /** Currently selected dropdown value */\n selectedDropdownValue?: string;\n /** Callback when dropdown value changes */\n onDropdownChange?: (value: string) => void;\n /** Placeholder text for the dropdown select */\n selectPlaceholder?: string;\n /** Accessible label for the dropdown select */\n dropdownAriaLabel?: string;\n /** Additional CSS classes */\n className?: string;\n}\n\n/**\n * Variant styles mapping\n */\nconst VARIANT_STYLES = {\n high: 'bg-success-background',\n medium: 'bg-warning-background',\n low: 'bg-error-background',\n total: 'bg-info-background',\n} as const;\n\n/**\n * Value text colors mapping\n */\nconst VALUE_TEXT_COLORS = {\n high: 'text-success-700',\n medium: 'text-warning-600',\n low: 'text-error-700',\n total: 'text-info-700',\n} as const;\n\n/**\n * Internal StatCard component\n */\ninterface StatCardProps {\n item: StatItem;\n showPlaceholder?: boolean;\n}\n\nconst StatCard = ({ item, showPlaceholder = false }: StatCardProps) => {\n return (\n <div\n className={`rounded-xl py-[17px] px-6 min-h-[105px] flex flex-col justify-center items-start gap-1 ${VARIANT_STYLES[item.variant]}`}\n >\n <Text\n size=\"4xl\"\n weight=\"bold\"\n className={`${VALUE_TEXT_COLORS[item.variant]} leading-[42px] tracking-[0.2px] self-stretch`}\n >\n {showPlaceholder ? '-' : item.value}\n </Text>\n <Text\n size=\"xs\"\n weight=\"bold\"\n className=\"uppercase text-[8px] leading-[9px] text-text-800 whitespace-nowrap\"\n >\n {item.label}\n </Text>\n </div>\n );\n};\n\n/**\n * Get grid column class based on number of items\n */\nconst getGridColumnsClass = (itemCount: number): string => {\n if (itemCount === 6) return 'lg:grid-cols-6';\n if (itemCount === 5) return 'lg:grid-cols-5';\n if (itemCount === 4) return 'lg:grid-cols-4';\n if (itemCount === 3) return 'lg:grid-cols-3';\n if (itemCount === 2) return 'lg:grid-cols-2';\n return 'lg:grid-cols-1';\n};\n\n/**\n * StatisticsCard component - displays statistics with empty state support\n *\n * @example\n * ```tsx\n * // With data\n * <StatisticsCard\n * title=\"Estatística das atividades\"\n * data={[\n * { label: 'Acertos', value: '85%', variant: 'high' },\n * { label: 'Em andamento', value: 12, variant: 'medium' },\n * { label: 'Erros', value: '15%', variant: 'low' },\n * { label: 'Concluídas', value: 24, variant: 'total' }\n * ]}\n * dropdownOptions={[\n * { label: '1 ano', value: '1year' },\n * { label: '6 meses', value: '6months' }\n * ]}\n * selectedDropdownValue=\"1year\"\n * onDropdownChange={(value) => console.log(value)}\n * />\n *\n * // Empty state\n * <StatisticsCard\n * title=\"Estatística das atividades\"\n * emptyStateMessage=\"Sem dados por enquanto. Crie uma atividade para que os resultados apareçam aqui.\"\n * emptyStateButtonText=\"Criar atividade\"\n * onEmptyStateButtonClick={() => console.log('Create activity')}\n * />\n * ```\n */\nexport const StatisticsCard = ({\n title,\n description,\n data,\n showPlaceholder = false,\n emptyStateMessage,\n emptyStateButtonText,\n onEmptyStateButtonClick,\n dropdownOptions,\n selectedDropdownValue,\n onDropdownChange,\n selectPlaceholder = 'Selecione um período',\n dropdownAriaLabel = 'Filtro de período',\n className = '',\n}: StatisticsCardProps) => {\n const hasData = data && data.length > 0;\n const gridColumnsClass = hasData ? getGridColumnsClass(data.length) : '';\n\n return (\n <div\n className={`bg-background rounded-xl p-4 h-auto lg:min-h-[185px] flex flex-col gap-2 ${className}`}\n >\n {/* Header with title and optional dropdown */}\n <div className=\"flex flex-row justify-between items-center gap-4\">\n <div className=\"flex-1 min-w-0 flex flex-col gap-1\">\n <Text as=\"h3\" size=\"lg\" weight=\"bold\" color=\"text-text-950\">\n {title}\n </Text>\n {description && (\n <Text size=\"sm\" color=\"text-text-700\">\n {description}\n </Text>\n )}\n </div>\n\n {dropdownOptions && dropdownOptions.length > 0 && (\n <div className=\"w-[120px] min-w-[90px] sm:shrink-0\">\n <Select\n value={selectedDropdownValue}\n onValueChange={onDropdownChange}\n size=\"medium\"\n >\n <SelectTrigger\n className=\"border border-border-300 rounded [&>span]:whitespace-nowrap [&>span]:overflow-hidden [&>span]:text-ellipsis\"\n aria-label={dropdownAriaLabel}\n >\n <SelectValue placeholder={selectPlaceholder} />\n </SelectTrigger>\n <SelectContent className=\"min-w-[120px]\">\n {dropdownOptions.map((option) => (\n <SelectItem\n key={option.value}\n value={option.value}\n className=\"whitespace-nowrap\"\n >\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n )}\n </div>\n\n {/* Content: Data Grid or Empty State */}\n {hasData ? (\n <div\n className={`grid grid-cols-1 sm:grid-cols-2 gap-[13px] ${gridColumnsClass}`}\n >\n {data.map((item, index) => (\n <StatCard\n key={`${item.variant}-${item.label}-${index}`}\n item={item}\n showPlaceholder={showPlaceholder}\n />\n ))}\n </div>\n ) : (\n <div className=\"border border-dashed border-border-300 rounded-lg p-6 min-h-[105px] flex flex-col items-center justify-center gap-2\">\n <Text\n size=\"sm\"\n color=\"text-text-600\"\n className=\"text-center max-w-md\"\n >\n {emptyStateMessage}\n </Text>\n\n {onEmptyStateButtonClick && (\n <Button\n variant=\"outline\"\n action=\"primary\"\n size=\"small\"\n onClick={onEmptyStateButtonClick}\n iconLeft={<PlusIcon size={16} weight=\"bold\" />}\n >\n {emptyStateButtonText}\n </Button>\n )}\n </div>\n )}\n </div>\n );\n};\n"],"mappings":"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","names":[]}