analytica-frontend-lib
Version:
Repositório público dos componentes utilizados nas plataformas da Analytica Ensino
1 lines • 9.94 kB
Source Map (JSON)
{"version":3,"sources":["../src/components/TimeReport/TimeReport.tsx"],"sourcesContent":["import { type HTMLAttributes, type ReactNode } from 'react';\nimport { TrendUpIcon } from '@phosphor-icons/react/dist/csr/TrendUp';\nimport { TrendDownIcon } from '@phosphor-icons/react/dist/csr/TrendDown';\nimport dayjs from 'dayjs';\nimport duration from 'dayjs/plugin/duration';\nimport Text from '../Text/Text';\nimport { cn } from '../../utils/utils';\nimport { PROFILE_ROLES } from '../../types/chat';\nimport type { StudentsHighlightPeriod } from '../../hooks/useStudentsHighlight';\nimport { ReportLayout } from '../shared/ReportLayout';\n\ndayjs.extend(duration);\n\n/**\n * API types - reusing existing enums/types from the project\n */\nexport { PROFILE_ROLES } from '../../types/chat';\nexport type { StudentsHighlightPeriod as TimeReportPeriod } from '../../hooks/useStudentsHighlight';\n\nexport interface TimeReportRequest {\n period: StudentsHighlightPeriod;\n profile?: PROFILE_ROLES;\n school_group_ids?: string[];\n school_ids?: string[];\n all_school_groups?: boolean;\n}\n\nexport interface TimeMetric {\n hours: number;\n variation_percent: number | null;\n}\n\nexport interface CountMetric {\n count: number;\n variation_percent: number | null;\n}\n\nexport interface TimeReportData {\n total_platform_time: TimeMetric;\n activity_time: TimeMetric;\n exam_simulation_time?: TimeMetric;\n content_time?: TimeMetric;\n questionnaire_time?: TimeMetric;\n recommended_classes_time: TimeMetric;\n total_access_count?: CountMetric;\n}\n\nexport interface TimeReportResponse {\n message: string;\n data: TimeReportData;\n}\n\n/**\n * Format decimal hours to \"Xh Ymin\" display string\n */\nexport const formatHoursToTime = (hours: number): string => {\n const d = dayjs.duration(hours, 'hours');\n const h = Math.floor(d.asHours());\n const min = d.minutes();\n return `${h}h ${min}min`;\n};\n\n/**\n * Get trend direction from variation percentage\n */\nexport const getTrendDirection = (\n variationPercent: number | null\n): TimeCardTrend | undefined => {\n if (variationPercent === null) return undefined;\n return variationPercent >= 0 ? 'up' : 'down';\n};\n\n/**\n * Format variation percentage to display string (e.g., \"+12.3%\", \"-5.2%\")\n */\nexport const formatVariation = (\n variationPercent: number | null\n): string | undefined => {\n if (variationPercent === null) return undefined;\n const sign = variationPercent >= 0 ? '+' : '';\n return `${sign}${variationPercent}%`;\n};\n\n/**\n * Trend direction for time card indicators\n */\nexport type TimeCardTrend = 'up' | 'down';\n\n/**\n * Data for a single time card\n */\nexport interface TimeCardData {\n /** Unique identifier */\n id: string;\n /** Uppercase label (e.g., \"TEMPO NA PLATAFORMA\") */\n label: string;\n /** Formatted time value (e.g., \"12h 20min\") */\n value: string;\n /** Icon element for the card */\n icon: ReactNode;\n /** Trend percentage string (e.g., \"+10%\", \"-5%\") */\n trendValue?: string;\n /** Trend direction - determines color */\n trendDirection?: TimeCardTrend;\n /** Optional footer text shown below the value (e.g., \"de 16.778 escolas\") */\n footer?: ReactNode;\n /**\n * Plain gray line under the value (e.g., \"1 município • 134 escolas\"), for\n * cards whose context is a breakdown rather than a trend. Rendered alongside\n * the trend when both are present.\n */\n subtitle?: string;\n}\n\n/**\n * Tab configuration for the TimeReport component\n */\nexport interface TimeReportTab {\n /** Unique value identifying this tab */\n value: string;\n /** Display label */\n label: string;\n /** Icon element for the tab header */\n icon?: ReactNode;\n /** Cards to display when this tab is active */\n cards: TimeCardData[];\n}\n\n/**\n * Props for the TimeCard component\n */\nexport interface TimeCardProps extends HTMLAttributes<HTMLDivElement> {\n /** Card data */\n data: TimeCardData;\n}\n\n/**\n * Props for the TimeReport component\n */\nexport interface TimeReportProps extends HTMLAttributes<HTMLDivElement> {\n /** Tab configurations with associated card data */\n tabs: TimeReportTab[];\n /** Default active tab value */\n defaultTab?: string;\n /** Controlled active tab value */\n activeTab?: string;\n /** Callback when active tab changes */\n onTabChange?: (value: string) => void;\n}\n\n/**\n * Trend styling configuration\n */\nconst TREND_CONFIG = {\n up: {\n colorClass: 'text-success-500',\n Icon: TrendUpIcon,\n },\n down: {\n colorClass: 'text-error-500',\n Icon: TrendDownIcon,\n },\n} as const;\n\n/**\n * TimeCard component - displays a single time statistic\n */\nexport const TimeCard = ({ data, className, ...props }: TimeCardProps) => {\n const { label, value, icon, trendValue, trendDirection, footer, subtitle } =\n data;\n\n return (\n <div\n className={cn(\n 'flex flex-col gap-3 p-5 bg-background border border-border-50 rounded-xl',\n className\n )}\n data-testid={`time-card-${data.id}`}\n {...props}\n >\n {/* Icon + Label */}\n <div className=\"flex flex-row items-center gap-2\">\n <span className=\"text-text-600 [&>svg]:w-4 [&>svg]:h-4\">{icon}</span>\n <Text\n weight=\"bold\"\n className=\"text-text-600 uppercase text-[8px] leading-[100%]\"\n >\n {label}\n </Text>\n </div>\n\n {/* Time value */}\n <Text\n size=\"2xl\"\n weight=\"bold\"\n className=\"text-primary-800 leading-[100%] tracking-[0.2px]\"\n >\n {value}\n </Text>\n\n {/* Context line (e.g., \"1 município • 134 escolas\") */}\n {subtitle && (\n <Text\n size=\"sm\"\n className=\"text-text-600 leading-[100%]\"\n data-testid={`subtitle-${data.id}`}\n >\n {subtitle}\n </Text>\n )}\n\n {/* Trend indicator */}\n {trendValue && trendDirection && (\n <div\n className={cn(\n 'flex flex-row items-center gap-1',\n TREND_CONFIG[trendDirection].colorClass\n )}\n data-testid={`trend-${data.id}`}\n >\n {(() => {\n const TrendIcon = TREND_CONFIG[trendDirection].Icon;\n return <TrendIcon size={16} weight=\"bold\" />;\n })()}\n <Text\n size=\"xs\"\n weight=\"bold\"\n color=\"inherit\"\n className=\"leading-[100%] uppercase\"\n >\n {trendValue}\n </Text>\n </div>\n )}\n\n {footer !== undefined && footer !== null && footer !== false && (\n <Text as=\"div\" size=\"xs\" className=\"text-text-500 leading-[130%]\">\n {footer}\n </Text>\n )}\n </div>\n );\n};\n\n/**\n * TimeReport component\n *\n * Displays time statistics organized in tabs, each with configurable cards.\n * Used in the manager report page to show platform access time metrics.\n *\n * @example\n * ```tsx\n * <TimeReport\n * tabs={[\n * {\n * value: 'student',\n * label: 'Estudante',\n * icon: <Student size={17} />,\n * cards: [\n * { id: 'platform', label: 'TEMPO NA PLATAFORMA', value: '12h 20min', icon: <Monitor />, trendValue: '+10%', trendDirection: 'up' },\n * ],\n * },\n * ]}\n * onTabChange={(tab) => console.log(tab)}\n * />\n * ```\n */\nexport const TimeReport = ({\n tabs,\n defaultTab,\n activeTab,\n onTabChange,\n className,\n ...props\n}: TimeReportProps) => (\n <ReportLayout\n tabs={tabs}\n defaultTab={defaultTab}\n activeTab={activeTab}\n onTabChange={onTabChange}\n renderCard={(card) => <TimeCard key={card.id} data={card} />}\n gridTestId=\"time-report-cards\"\n className={className}\n {...props}\n />\n);\n\nexport default TimeReport;\n"],"mappings":"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","names":[]}