analytica-frontend-lib 1.2.86 → 1.2.88
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ActivitiesHistory/index.js.map +1 -1
- package/dist/ActivitiesHistory/index.mjs.map +1 -1
- package/dist/NotificationCard/index.js +1 -1
- package/dist/NotificationCard/index.js.map +1 -1
- package/dist/NotificationCard/index.mjs +1 -1
- package/dist/NotificationCard/index.mjs.map +1 -1
- package/dist/QuestionsData/index.d.ts +26 -1
- package/dist/QuestionsData/index.d.ts.map +1 -1
- package/dist/QuestionsData/index.js.map +1 -1
- package/dist/QuestionsData/index.mjs.map +1 -1
- package/dist/RecommendedLessonsHistory/index.d.ts +1 -1
- package/dist/RecommendedLessonsHistory/index.d.ts.map +1 -1
- package/dist/RecommendedLessonsHistory/index.js +148 -142
- package/dist/RecommendedLessonsHistory/index.js.map +1 -1
- package/dist/RecommendedLessonsHistory/index.mjs +147 -141
- package/dist/RecommendedLessonsHistory/index.mjs.map +1 -1
- package/dist/StudentRanking/index.d.ts +33 -9
- package/dist/StudentRanking/index.d.ts.map +1 -1
- package/dist/StudentRanking/index.js.map +1 -1
- package/dist/StudentRanking/index.mjs.map +1 -1
- package/dist/hooks/useActivitiesHistory/index.js.map +1 -1
- package/dist/hooks/useActivitiesHistory/index.mjs.map +1 -1
- package/dist/hooks/useNotifications.d.ts +2 -2
- package/dist/hooks/useNotifications.d.ts.map +1 -1
- package/dist/hooks/useQuestionsData.d.ts +218 -0
- package/dist/hooks/useQuestionsData.d.ts.map +1 -0
- package/dist/hooks/useRecommendedClassDrafts/index.d.ts +57 -0
- package/dist/hooks/useRecommendedClassDrafts/index.d.ts.map +1 -0
- package/dist/hooks/{useGoalDrafts → useRecommendedClassDrafts}/index.js +40 -40
- package/dist/hooks/useRecommendedClassDrafts/index.js.map +1 -0
- package/dist/hooks/{useGoalDrafts → useRecommendedClassDrafts}/index.mjs +33 -33
- package/dist/hooks/useRecommendedClassDrafts/index.mjs.map +1 -0
- package/dist/hooks/useRecommendedClassDrafts.d.ts +57 -0
- package/dist/hooks/useRecommendedClassDrafts.d.ts.map +1 -0
- package/dist/hooks/{useGoalModels.d.ts → useRecommendedClassModels.d.ts} +32 -32
- package/dist/hooks/useRecommendedClassModels.d.ts.map +1 -0
- package/dist/hooks/useRecommendedLessonDetails.d.ts +44 -44
- package/dist/hooks/useRecommendedLessonDetails.d.ts.map +1 -1
- package/dist/hooks/useRecommendedLessons/index.d.ts +35 -35
- package/dist/hooks/useRecommendedLessons/index.d.ts.map +1 -1
- package/dist/hooks/useRecommendedLessons/index.js +41 -41
- package/dist/hooks/useRecommendedLessons/index.js.map +1 -1
- package/dist/hooks/useRecommendedLessons/index.mjs +37 -37
- package/dist/hooks/useRecommendedLessons/index.mjs.map +1 -1
- package/dist/hooks/useRecommendedLessons.d.ts +35 -35
- package/dist/hooks/useRecommendedLessons.d.ts.map +1 -1
- package/dist/hooks/useRecommendedLessonsPage/index.d.ts +21 -21
- package/dist/hooks/useRecommendedLessonsPage/index.d.ts.map +1 -1
- package/dist/hooks/useRecommendedLessonsPage/index.js +39 -33
- package/dist/hooks/useRecommendedLessonsPage/index.js.map +1 -1
- package/dist/hooks/useRecommendedLessonsPage/index.mjs +39 -33
- package/dist/hooks/useRecommendedLessonsPage/index.mjs.map +1 -1
- package/dist/hooks/useRecommendedLessonsPage.d.ts +21 -21
- package/dist/hooks/useRecommendedLessonsPage.d.ts.map +1 -1
- package/dist/hooks/useStudentsHighlight.d.ts +275 -0
- package/dist/hooks/useStudentsHighlight.d.ts.map +1 -0
- package/dist/index.d.ts +15 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +570 -351
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +516 -308
- package/dist/index.mjs.map +1 -1
- package/dist/store/notificationStore.d.ts.map +1 -1
- package/dist/types/activitiesHistory/index.js.map +1 -1
- package/dist/types/activitiesHistory/index.mjs.map +1 -1
- package/dist/types/common.d.ts +2 -2
- package/dist/types/notifications.d.ts +5 -5
- package/dist/types/notifications.d.ts.map +1 -1
- package/dist/types/recommendedLessons/index.d.ts +112 -112
- package/dist/types/recommendedLessons/index.d.ts.map +1 -1
- package/dist/types/recommendedLessons/index.js +25 -25
- package/dist/types/recommendedLessons/index.js.map +1 -1
- package/dist/types/recommendedLessons/index.mjs +17 -17
- package/dist/types/recommendedLessons/index.mjs.map +1 -1
- package/dist/types/recommendedLessons.d.ts +112 -112
- package/dist/types/recommendedLessons.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/hooks/useGoalDrafts/index.d.ts +0 -57
- package/dist/hooks/useGoalDrafts/index.d.ts.map +0 -1
- package/dist/hooks/useGoalDrafts/index.js.map +0 -1
- package/dist/hooks/useGoalDrafts/index.mjs.map +0 -1
- package/dist/hooks/useGoalDrafts.d.ts +0 -57
- package/dist/hooks/useGoalDrafts.d.ts.map +0 -1
- package/dist/hooks/useGoalModels.d.ts.map +0 -1
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
import { HTMLAttributes } from 'react';
|
|
2
|
+
import type { StudentHighlightItem } from '../../hooks/useStudentsHighlight';
|
|
2
3
|
/**
|
|
3
|
-
*
|
|
4
|
+
* Re-export StudentHighlightItem as StudentRankingItem for backwards compatibility
|
|
5
|
+
* and direct usage with the component
|
|
4
6
|
*/
|
|
5
|
-
export
|
|
6
|
-
/** Student position in the ranking */
|
|
7
|
-
position: number;
|
|
8
|
-
/** Student name */
|
|
9
|
-
name: string;
|
|
10
|
-
/** Performance percentage (0-100) */
|
|
11
|
-
percentage: number;
|
|
12
|
-
}
|
|
7
|
+
export type StudentRankingItem = Pick<StudentHighlightItem, 'position' | 'name' | 'percentage'>;
|
|
13
8
|
/**
|
|
14
9
|
* Card variant type
|
|
15
10
|
*/
|
|
@@ -48,6 +43,7 @@ export interface StudentRankingProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
48
43
|
*
|
|
49
44
|
* @example
|
|
50
45
|
* ```tsx
|
|
46
|
+
* // Basic usage with static data
|
|
51
47
|
* <StudentRanking
|
|
52
48
|
* highlightTitle="Estudantes em destaque"
|
|
53
49
|
* attentionTitle="Estudantes precisando de atenção"
|
|
@@ -63,6 +59,34 @@ export interface StudentRankingProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
63
59
|
* ]}
|
|
64
60
|
* />
|
|
65
61
|
* ```
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```tsx
|
|
65
|
+
* // Usage with useStudentsHighlight hook (direct usage - no transformation needed)
|
|
66
|
+
* const fetchStudentsHighlight = async (filters) => {
|
|
67
|
+
* const response = await api.get('/performance/students-highlight', { params: filters });
|
|
68
|
+
* return response.data;
|
|
69
|
+
* };
|
|
70
|
+
*
|
|
71
|
+
* const useStudentsHighlight = createUseStudentsHighlight(fetchStudentsHighlight);
|
|
72
|
+
*
|
|
73
|
+
* function MyComponent() {
|
|
74
|
+
* const { topStudents, bottomStudents, loading, fetchStudentsHighlight } = useStudentsHighlight();
|
|
75
|
+
*
|
|
76
|
+
* useEffect(() => {
|
|
77
|
+
* fetchStudentsHighlight({ period: '30_DAYS' });
|
|
78
|
+
* }, [fetchStudentsHighlight]);
|
|
79
|
+
*
|
|
80
|
+
* if (loading) return <Skeleton />;
|
|
81
|
+
*
|
|
82
|
+
* return (
|
|
83
|
+
* <StudentRanking
|
|
84
|
+
* highlightStudents={topStudents}
|
|
85
|
+
* attentionStudents={bottomStudents}
|
|
86
|
+
* />
|
|
87
|
+
* );
|
|
88
|
+
* }
|
|
89
|
+
* ```
|
|
66
90
|
*/
|
|
67
91
|
export declare const StudentRanking: ({ highlightTitle, attentionTitle, highlightStudents, attentionStudents, className, ...props }: StudentRankingProps) => import("react/jsx-runtime").JSX.Element;
|
|
68
92
|
export default StudentRanking;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StudentRanking.d.ts","sourceRoot":"","sources":["../../../src/components/StudentRanking/StudentRanking.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"StudentRanking.d.ts","sourceRoot":"","sources":["../../../src/components/StudentRanking/StudentRanking.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAIvC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AAE7E;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG,IAAI,CACnC,oBAAoB,EACpB,UAAU,GAAG,MAAM,GAAG,YAAY,CACnC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG,WAAW,GAAG,WAAW,CAAC;AAmH9D;;GAEG;AACH,MAAM,WAAW,gBAAiB,SAAQ,cAAc,CAAC,cAAc,CAAC;IACtE,iBAAiB;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,6EAA6E;IAC7E,OAAO,EAAE,qBAAqB,CAAC;IAC/B,kCAAkC;IAClC,QAAQ,EAAE,kBAAkB,EAAE,CAAC;CAChC;AAED;;GAEG;AACH,eAAO,MAAM,WAAW,GAAI,mDAMzB,gBAAgB,4CAiDlB,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,mBAAoB,SAAQ,cAAc,CAAC,cAAc,CAAC;IACzE,mDAAmD;IACnD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qDAAqD;IACrD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qDAAqD;IACrD,iBAAiB,EAAE,kBAAkB,EAAE,CAAC;IACxC,6DAA6D;IAC7D,iBAAiB,EAAE,kBAAkB,EAAE,CAAC;CACzC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,eAAO,MAAM,cAAc,GAAI,+FAO5B,mBAAmB,4CAkBrB,CAAC;AAEF,eAAe,cAAc,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/StudentRanking/StudentRanking.tsx","../../src/utils/utils.ts","../../src/components/Text/Text.tsx"],"sourcesContent":["import { HTMLAttributes } from 'react';\nimport { Trophy, Warning, TrendUp, TrendDown } from 'phosphor-react';\nimport Text from '../Text/Text';\nimport { cn } from '../../utils/utils';\n\n/**\n * Student data item for the ranking\n */\nexport interface StudentRankingItem {\n /** Student position in the ranking */\n position: number;\n /** Student name */\n name: string;\n /** Performance percentage (0-100) */\n percentage: number;\n}\n\n/**\n * Card variant type\n */\nexport type StudentRankingVariant = 'highlight' | 'attention';\n\n/**\n * Props for individual student card\n */\ninterface StudentCardProps {\n student: StudentRankingItem;\n variant: StudentRankingVariant;\n}\n\n/**\n * Lookup table for card background colors by position\n * Position 1 = most intense, Position 3+ = lightest\n */\nconst CARD_BACKGROUND_CLASSES = {\n highlight: {\n 1: 'bg-success-200',\n 2: 'bg-success-100',\n 3: 'bg-success-background',\n },\n attention: {\n 1: 'bg-error-200',\n 2: 'bg-error-100',\n 3: 'bg-error-background',\n },\n} as const;\n\n/**\n * Lookup table for badge background colors\n */\nconst BADGE_BACKGROUND_CLASSES = {\n highlight: 'bg-indicator-positive',\n attention: 'bg-indicator-negative',\n} as const;\n\n/**\n * Lookup table for percentage badge background colors\n */\nconst PERCENTAGE_BADGE_CLASSES = {\n highlight: 'bg-success-700',\n attention: 'bg-indicator-negative',\n} as const;\n\n/**\n * Lookup table for header badge background colors\n */\nconst HEADER_BADGE_CLASSES = {\n highlight: 'bg-indicator-positive',\n attention: 'bg-indicator-negative',\n} as const;\n\n/**\n * Get background class based on position (1, 2, or 3+)\n */\nconst getPositionBackgroundClass = (\n variant: StudentRankingVariant,\n position: number\n): string => {\n const positionKey = Math.max(1, Math.min(position, 3)) as 1 | 2 | 3;\n return CARD_BACKGROUND_CLASSES[variant][positionKey];\n};\n\n/**\n * Individual student card component\n */\nconst StudentCard = ({ student, variant }: StudentCardProps) => {\n const TrendIcon = variant === 'highlight' ? TrendUp : TrendDown;\n const backgroundClass = getPositionBackgroundClass(variant, student.position);\n\n return (\n <div\n className={cn(\n 'flex flex-row items-center w-full p-4 gap-2 rounded-xl',\n backgroundClass\n )}\n >\n {/* Position badge */}\n <Text\n size=\"xs\"\n weight=\"bold\"\n aria-label={`Posição ${student.position}`}\n className={cn(\n 'w-5 h-5 rounded-full flex items-center justify-center text-text',\n BADGE_BACKGROUND_CLASSES[variant]\n )}\n >\n {student.position}\n </Text>\n\n {/* Student name */}\n <Text\n size=\"sm\"\n weight=\"bold\"\n className=\"flex-1 min-w-0 text-text-950 tracking-[0.2px] truncate\"\n >\n {student.name}\n </Text>\n\n {/* Percentage badge */}\n <Text\n size=\"xs\"\n weight=\"bold\"\n aria-label={`Desempenho ${student.percentage}%`}\n className={cn(\n 'flex flex-row items-center h-[22px] px-2 gap-1 rounded text-text',\n PERCENTAGE_BADGE_CLASSES[variant]\n )}\n >\n <TrendIcon size={16} weight=\"bold\" aria-hidden=\"true\" />\n {student.percentage}%\n </Text>\n </div>\n );\n};\n\n/**\n * Props for a single ranking card\n */\nexport interface RankingCardProps extends HTMLAttributes<HTMLDivElement> {\n /** Card title */\n title: string;\n /** Card variant: highlight (best students) or attention (needs attention) */\n variant: StudentRankingVariant;\n /** List of students to display */\n students: StudentRankingItem[];\n}\n\n/**\n * Single ranking card component (can be used independently)\n */\nexport const RankingCard = ({\n title,\n variant,\n students,\n className,\n ...props\n}: RankingCardProps) => {\n const HeaderIcon = variant === 'highlight' ? Trophy : Warning;\n\n return (\n <div\n className={cn(\n 'flex flex-col flex-1 min-h-[254px] p-5 gap-4 bg-background border border-border-50 rounded-xl',\n className\n )}\n {...props}\n >\n {/* Header */}\n <div className=\"flex flex-row justify-between items-center h-6 gap-4\">\n <Text\n as=\"h3\"\n size=\"lg\"\n weight=\"bold\"\n className=\"text-text-950 tracking-[0.2px]\"\n >\n {title}\n </Text>\n\n {/* Header badge with icon */}\n <span\n className={cn(\n 'w-6 h-6 rounded-full flex items-center justify-center',\n HEADER_BADGE_CLASSES[variant]\n )}\n >\n <HeaderIcon\n size={14}\n weight=\"fill\"\n className={variant === 'highlight' ? 'text-text-950' : 'text-text'}\n />\n </span>\n </div>\n\n {/* Students list */}\n <div className=\"flex flex-col gap-2\">\n {students.map((student, index) => (\n <StudentCard\n key={`${variant}-${index}-${student.position}`}\n student={student}\n variant={variant}\n />\n ))}\n </div>\n </div>\n );\n};\n\n/**\n * Props for the StudentRanking component\n */\nexport interface StudentRankingProps extends HTMLAttributes<HTMLDivElement> {\n /** Title for the highlight (best students) card */\n highlightTitle?: string;\n /** Title for the attention (needs attention) card */\n attentionTitle?: string;\n /** List of highlighted (best performing) students */\n highlightStudents: StudentRankingItem[];\n /** List of students needing attention (lowest performing) */\n attentionStudents: StudentRankingItem[];\n}\n\n/**\n * StudentRanking component - displays two cards side by side showing\n * the best performing students and students that need attention.\n *\n * @example\n * ```tsx\n * <StudentRanking\n * highlightTitle=\"Estudantes em destaque\"\n * attentionTitle=\"Estudantes precisando de atenção\"\n * highlightStudents={[\n * { position: 1, name: 'Valentina Ribeiro', percentage: 100 },\n * { position: 2, name: 'Lucas Almeida', percentage: 100 },\n * { position: 3, name: 'Fernanda Costa', percentage: 100 },\n * ]}\n * attentionStudents={[\n * { position: 1, name: 'Ricardo Silva', percentage: 80 },\n * { position: 2, name: 'Juliana Santos', percentage: 50 },\n * { position: 3, name: 'Gabriel Oliveira', percentage: 40 },\n * ]}\n * />\n * ```\n */\nexport const StudentRanking = ({\n highlightTitle = 'Estudantes em destaque',\n attentionTitle = 'Estudantes precisando de atenção',\n highlightStudents,\n attentionStudents,\n className,\n ...props\n}: StudentRankingProps) => {\n return (\n <div\n className={cn('flex flex-col md:flex-row w-full gap-4', className)}\n {...props}\n >\n <RankingCard\n title={highlightTitle}\n variant=\"highlight\"\n students={highlightStudents}\n />\n <RankingCard\n title={attentionTitle}\n variant=\"attention\"\n students={attentionStudents}\n />\n </div>\n );\n};\n\nexport default StudentRanking;\n","import { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport { syncDropdownState } from './dropdown';\nexport {\n getSelectedIdsFromCategories,\n toggleArrayItem,\n toggleSingleValue,\n areFiltersEqual,\n} from './activityFilters';\nexport {\n mapQuestionTypeToEnum,\n mapQuestionTypeToEnumRequired,\n} from './questionTypeUtils';\nexport {\n getStatusBadgeConfig,\n formatTimeSpent,\n formatQuestionNumbers,\n formatDateToBrazilian,\n} from './activityDetailsUtils';\n\n/**\n * Retorna a cor hexadecimal com opacidade 0.3 (4d) se não estiver em dark mode.\n * Se estiver em dark mode, retorna a cor original.\n *\n * @param hexColor - Cor hexadecimal (ex: \"#0066b8\" ou \"0066b8\")\n * @param isDark - booleano indicando se está em dark mode\n * @returns string - cor hexadecimal com opacidade se necessário\n */\nexport function getSubjectColorWithOpacity(\n hexColor: string | undefined,\n isDark: boolean\n): string | undefined {\n if (!hexColor) return undefined;\n // Remove o '#' se existir\n let color = hexColor.replace(/^#/, '').toLowerCase();\n\n if (isDark) {\n // Se está em dark mode, sempre remove opacidade se existir\n if (color.length === 8) {\n color = color.slice(0, 6);\n }\n return `#${color}`;\n } else {\n // Se não está em dark mode (light mode)\n let resultColor: string;\n if (color.length === 6) {\n // Adiciona opacidade 0.3 (4D) para cores de 6 dígitos\n resultColor = `#${color}4d`;\n } else if (color.length === 8) {\n // Já tem opacidade, retorna como está\n resultColor = `#${color}`;\n } else {\n // Para outros tamanhos (3, 4, 5 dígitos), retorna como está\n resultColor = `#${color}`;\n }\n return resultColor;\n }\n}\n","import { ComponentPropsWithoutRef, ElementType, ReactNode } from 'react';\nimport { cn } from '../../utils/utils';\n\n/**\n * Base text component props\n */\ntype BaseTextProps = {\n /** Content to be displayed */\n children?: ReactNode;\n /** Text size variant */\n size?:\n | '2xs'\n | 'xs'\n | 'sm'\n | 'md'\n | 'lg'\n | 'xl'\n | '2xl'\n | '3xl'\n | '4xl'\n | '5xl'\n | '6xl';\n /** Font weight variant */\n weight?:\n | 'hairline'\n | 'light'\n | 'normal'\n | 'medium'\n | 'semibold'\n | 'bold'\n | 'extrabold'\n | 'black';\n /** Color variant - white for light backgrounds, black for dark backgrounds */\n color?: string;\n /** Additional CSS classes to apply */\n className?: string;\n};\n\n/**\n * Polymorphic text component props that ensures type safety based on the 'as' prop\n */\ntype TextProps<T extends ElementType = 'p'> = BaseTextProps & {\n /** HTML tag to render */\n as?: T;\n} & Omit<ComponentPropsWithoutRef<T>, keyof BaseTextProps>;\n\n/**\n * Text component for Analytica Ensino platforms\n *\n * A flexible polymorphic text component with multiple sizes, weights, and colors.\n * Automatically adapts to dark and light themes with full type safety.\n *\n * @param children - The content to display\n * @param size - The text size variant (2xs, xs, sm, md, lg, xl, 2xl, 3xl, 4xl, 5xl, 6xl)\n * @param weight - The font weight variant (hairline, light, normal, medium, semibold, bold, extrabold, black)\n * @param color - The color variant - adapts to theme\n * @param as - The HTML tag to render - determines allowed attributes via TypeScript\n * @param className - Additional CSS classes\n * @param props - HTML attributes valid for the chosen tag only\n * @returns A styled text element with type-safe attributes\n *\n * @example\n * ```tsx\n * <Text size=\"lg\" weight=\"bold\" color=\"text-info-800\">\n * This is a large, bold text\n * </Text>\n *\n * <Text as=\"a\" href=\"/link\" target=\"_blank\">\n * Link with type-safe anchor attributes\n * </Text>\n *\n * <Text as=\"button\" onClick={handleClick} disabled>\n * Button with type-safe button attributes\n * </Text>\n * ```\n */\nconst Text = <T extends ElementType = 'p'>({\n children,\n size = 'md',\n weight = 'normal',\n color = 'text-text-950',\n as,\n className = '',\n ...props\n}: TextProps<T>) => {\n let sizeClasses = '';\n let weightClasses = '';\n\n // Text size classes mapping\n const sizeClassMap = {\n '2xs': 'text-2xs',\n xs: 'text-xs',\n sm: 'text-sm',\n md: 'text-md',\n lg: 'text-lg',\n xl: 'text-xl',\n '2xl': 'text-2xl',\n '3xl': 'text-3xl',\n '4xl': 'text-4xl',\n '5xl': 'text-5xl',\n '6xl': 'text-6xl',\n } as const;\n\n sizeClasses = sizeClassMap[size] ?? sizeClassMap.md;\n\n // Font weight classes mapping\n const weightClassMap = {\n hairline: 'font-hairline',\n light: 'font-light',\n normal: 'font-normal',\n medium: 'font-medium',\n semibold: 'font-semibold',\n bold: 'font-bold',\n extrabold: 'font-extrabold',\n black: 'font-black',\n } as const;\n\n weightClasses = weightClassMap[weight] ?? weightClassMap.normal;\n\n const baseClasses = 'font-primary';\n const Component = as ?? ('p' as ElementType);\n\n return (\n <Component\n className={cn(baseClasses, sizeClasses, weightClasses, color, className)}\n {...props}\n >\n {children}\n </Component>\n );\n};\n\nexport default Text;\n"],"mappings":"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","names":["import_jsx_runtime"]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/StudentRanking/StudentRanking.tsx","../../src/utils/utils.ts","../../src/components/Text/Text.tsx"],"sourcesContent":["import { HTMLAttributes } from 'react';\nimport { Trophy, Warning, TrendUp, TrendDown } from 'phosphor-react';\nimport Text from '../Text/Text';\nimport { cn } from '../../utils/utils';\nimport type { StudentHighlightItem } from '../../hooks/useStudentsHighlight';\n\n/**\n * Re-export StudentHighlightItem as StudentRankingItem for backwards compatibility\n * and direct usage with the component\n */\nexport type StudentRankingItem = Pick<\n StudentHighlightItem,\n 'position' | 'name' | 'percentage'\n>;\n\n/**\n * Card variant type\n */\nexport type StudentRankingVariant = 'highlight' | 'attention';\n\n/**\n * Props for individual student card\n */\ninterface StudentCardProps {\n student: StudentRankingItem;\n variant: StudentRankingVariant;\n}\n\n/**\n * Lookup table for card background colors by position\n * Position 1 = most intense, Position 3+ = lightest\n */\nconst CARD_BACKGROUND_CLASSES = {\n highlight: {\n 1: 'bg-success-200',\n 2: 'bg-success-100',\n 3: 'bg-success-background',\n },\n attention: {\n 1: 'bg-error-200',\n 2: 'bg-error-100',\n 3: 'bg-error-background',\n },\n} as const;\n\n/**\n * Lookup table for badge background colors\n */\nconst BADGE_BACKGROUND_CLASSES = {\n highlight: 'bg-indicator-positive',\n attention: 'bg-indicator-negative',\n} as const;\n\n/**\n * Lookup table for percentage badge background colors\n */\nconst PERCENTAGE_BADGE_CLASSES = {\n highlight: 'bg-success-700',\n attention: 'bg-indicator-negative',\n} as const;\n\n/**\n * Lookup table for header badge background colors\n */\nconst HEADER_BADGE_CLASSES = {\n highlight: 'bg-indicator-positive',\n attention: 'bg-indicator-negative',\n} as const;\n\n/**\n * Get background class based on position (1, 2, or 3+)\n */\nconst getPositionBackgroundClass = (\n variant: StudentRankingVariant,\n position: number\n): string => {\n const positionKey = Math.max(1, Math.min(position, 3)) as 1 | 2 | 3;\n return CARD_BACKGROUND_CLASSES[variant][positionKey];\n};\n\n/**\n * Individual student card component\n */\nconst StudentCard = ({ student, variant }: StudentCardProps) => {\n const TrendIcon = variant === 'highlight' ? TrendUp : TrendDown;\n const backgroundClass = getPositionBackgroundClass(variant, student.position);\n\n return (\n <div\n className={cn(\n 'flex flex-row items-center w-full p-4 gap-2 rounded-xl',\n backgroundClass\n )}\n >\n {/* Position badge */}\n <Text\n size=\"xs\"\n weight=\"bold\"\n aria-label={`Posição ${student.position}`}\n className={cn(\n 'w-5 h-5 rounded-full flex items-center justify-center text-text',\n BADGE_BACKGROUND_CLASSES[variant]\n )}\n >\n {student.position}\n </Text>\n\n {/* Student name */}\n <Text\n size=\"sm\"\n weight=\"bold\"\n className=\"flex-1 min-w-0 text-text-950 tracking-[0.2px] truncate\"\n >\n {student.name}\n </Text>\n\n {/* Percentage badge */}\n <Text\n size=\"xs\"\n weight=\"bold\"\n aria-label={`Desempenho ${student.percentage}%`}\n className={cn(\n 'flex flex-row items-center h-[22px] px-2 gap-1 rounded text-text',\n PERCENTAGE_BADGE_CLASSES[variant]\n )}\n >\n <TrendIcon size={16} weight=\"bold\" aria-hidden=\"true\" />\n {student.percentage}%\n </Text>\n </div>\n );\n};\n\n/**\n * Props for a single ranking card\n */\nexport interface RankingCardProps extends HTMLAttributes<HTMLDivElement> {\n /** Card title */\n title: string;\n /** Card variant: highlight (best students) or attention (needs attention) */\n variant: StudentRankingVariant;\n /** List of students to display */\n students: StudentRankingItem[];\n}\n\n/**\n * Single ranking card component (can be used independently)\n */\nexport const RankingCard = ({\n title,\n variant,\n students,\n className,\n ...props\n}: RankingCardProps) => {\n const HeaderIcon = variant === 'highlight' ? Trophy : Warning;\n\n return (\n <div\n className={cn(\n 'flex flex-col flex-1 min-h-[254px] p-5 gap-4 bg-background border border-border-50 rounded-xl',\n className\n )}\n {...props}\n >\n {/* Header */}\n <div className=\"flex flex-row justify-between items-center h-6 gap-4\">\n <Text\n as=\"h3\"\n size=\"lg\"\n weight=\"bold\"\n className=\"text-text-950 tracking-[0.2px]\"\n >\n {title}\n </Text>\n\n {/* Header badge with icon */}\n <span\n className={cn(\n 'w-6 h-6 rounded-full flex items-center justify-center',\n HEADER_BADGE_CLASSES[variant]\n )}\n >\n <HeaderIcon\n size={14}\n weight=\"fill\"\n className={variant === 'highlight' ? 'text-text-950' : 'text-text'}\n />\n </span>\n </div>\n\n {/* Students list */}\n <div className=\"flex flex-col gap-2\">\n {students.map((student, index) => (\n <StudentCard\n key={`${variant}-${index}-${student.position}`}\n student={student}\n variant={variant}\n />\n ))}\n </div>\n </div>\n );\n};\n\n/**\n * Props for the StudentRanking component\n */\nexport interface StudentRankingProps extends HTMLAttributes<HTMLDivElement> {\n /** Title for the highlight (best students) card */\n highlightTitle?: string;\n /** Title for the attention (needs attention) card */\n attentionTitle?: string;\n /** List of highlighted (best performing) students */\n highlightStudents: StudentRankingItem[];\n /** List of students needing attention (lowest performing) */\n attentionStudents: StudentRankingItem[];\n}\n\n/**\n * StudentRanking component - displays two cards side by side showing\n * the best performing students and students that need attention.\n *\n * @example\n * ```tsx\n * // Basic usage with static data\n * <StudentRanking\n * highlightTitle=\"Estudantes em destaque\"\n * attentionTitle=\"Estudantes precisando de atenção\"\n * highlightStudents={[\n * { position: 1, name: 'Valentina Ribeiro', percentage: 100 },\n * { position: 2, name: 'Lucas Almeida', percentage: 100 },\n * { position: 3, name: 'Fernanda Costa', percentage: 100 },\n * ]}\n * attentionStudents={[\n * { position: 1, name: 'Ricardo Silva', percentage: 80 },\n * { position: 2, name: 'Juliana Santos', percentage: 50 },\n * { position: 3, name: 'Gabriel Oliveira', percentage: 40 },\n * ]}\n * />\n * ```\n *\n * @example\n * ```tsx\n * // Usage with useStudentsHighlight hook (direct usage - no transformation needed)\n * const fetchStudentsHighlight = async (filters) => {\n * const response = await api.get('/performance/students-highlight', { params: filters });\n * return response.data;\n * };\n *\n * const useStudentsHighlight = createUseStudentsHighlight(fetchStudentsHighlight);\n *\n * function MyComponent() {\n * const { topStudents, bottomStudents, loading, fetchStudentsHighlight } = useStudentsHighlight();\n *\n * useEffect(() => {\n * fetchStudentsHighlight({ period: '30_DAYS' });\n * }, [fetchStudentsHighlight]);\n *\n * if (loading) return <Skeleton />;\n *\n * return (\n * <StudentRanking\n * highlightStudents={topStudents}\n * attentionStudents={bottomStudents}\n * />\n * );\n * }\n * ```\n */\nexport const StudentRanking = ({\n highlightTitle = 'Estudantes em destaque',\n attentionTitle = 'Estudantes precisando de atenção',\n highlightStudents,\n attentionStudents,\n className,\n ...props\n}: StudentRankingProps) => {\n return (\n <div\n className={cn('flex flex-col md:flex-row w-full gap-4', className)}\n {...props}\n >\n <RankingCard\n title={highlightTitle}\n variant=\"highlight\"\n students={highlightStudents}\n />\n <RankingCard\n title={attentionTitle}\n variant=\"attention\"\n students={attentionStudents}\n />\n </div>\n );\n};\n\nexport default StudentRanking;\n","import { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport { syncDropdownState } from './dropdown';\nexport {\n getSelectedIdsFromCategories,\n toggleArrayItem,\n toggleSingleValue,\n areFiltersEqual,\n} from './activityFilters';\nexport {\n mapQuestionTypeToEnum,\n mapQuestionTypeToEnumRequired,\n} from './questionTypeUtils';\nexport {\n getStatusBadgeConfig,\n formatTimeSpent,\n formatQuestionNumbers,\n formatDateToBrazilian,\n} from './activityDetailsUtils';\n\n/**\n * Retorna a cor hexadecimal com opacidade 0.3 (4d) se não estiver em dark mode.\n * Se estiver em dark mode, retorna a cor original.\n *\n * @param hexColor - Cor hexadecimal (ex: \"#0066b8\" ou \"0066b8\")\n * @param isDark - booleano indicando se está em dark mode\n * @returns string - cor hexadecimal com opacidade se necessário\n */\nexport function getSubjectColorWithOpacity(\n hexColor: string | undefined,\n isDark: boolean\n): string | undefined {\n if (!hexColor) return undefined;\n // Remove o '#' se existir\n let color = hexColor.replace(/^#/, '').toLowerCase();\n\n if (isDark) {\n // Se está em dark mode, sempre remove opacidade se existir\n if (color.length === 8) {\n color = color.slice(0, 6);\n }\n return `#${color}`;\n } else {\n // Se não está em dark mode (light mode)\n let resultColor: string;\n if (color.length === 6) {\n // Adiciona opacidade 0.3 (4D) para cores de 6 dígitos\n resultColor = `#${color}4d`;\n } else if (color.length === 8) {\n // Já tem opacidade, retorna como está\n resultColor = `#${color}`;\n } else {\n // Para outros tamanhos (3, 4, 5 dígitos), retorna como está\n resultColor = `#${color}`;\n }\n return resultColor;\n }\n}\n","import { ComponentPropsWithoutRef, ElementType, ReactNode } from 'react';\nimport { cn } from '../../utils/utils';\n\n/**\n * Base text component props\n */\ntype BaseTextProps = {\n /** Content to be displayed */\n children?: ReactNode;\n /** Text size variant */\n size?:\n | '2xs'\n | 'xs'\n | 'sm'\n | 'md'\n | 'lg'\n | 'xl'\n | '2xl'\n | '3xl'\n | '4xl'\n | '5xl'\n | '6xl';\n /** Font weight variant */\n weight?:\n | 'hairline'\n | 'light'\n | 'normal'\n | 'medium'\n | 'semibold'\n | 'bold'\n | 'extrabold'\n | 'black';\n /** Color variant - white for light backgrounds, black for dark backgrounds */\n color?: string;\n /** Additional CSS classes to apply */\n className?: string;\n};\n\n/**\n * Polymorphic text component props that ensures type safety based on the 'as' prop\n */\ntype TextProps<T extends ElementType = 'p'> = BaseTextProps & {\n /** HTML tag to render */\n as?: T;\n} & Omit<ComponentPropsWithoutRef<T>, keyof BaseTextProps>;\n\n/**\n * Text component for Analytica Ensino platforms\n *\n * A flexible polymorphic text component with multiple sizes, weights, and colors.\n * Automatically adapts to dark and light themes with full type safety.\n *\n * @param children - The content to display\n * @param size - The text size variant (2xs, xs, sm, md, lg, xl, 2xl, 3xl, 4xl, 5xl, 6xl)\n * @param weight - The font weight variant (hairline, light, normal, medium, semibold, bold, extrabold, black)\n * @param color - The color variant - adapts to theme\n * @param as - The HTML tag to render - determines allowed attributes via TypeScript\n * @param className - Additional CSS classes\n * @param props - HTML attributes valid for the chosen tag only\n * @returns A styled text element with type-safe attributes\n *\n * @example\n * ```tsx\n * <Text size=\"lg\" weight=\"bold\" color=\"text-info-800\">\n * This is a large, bold text\n * </Text>\n *\n * <Text as=\"a\" href=\"/link\" target=\"_blank\">\n * Link with type-safe anchor attributes\n * </Text>\n *\n * <Text as=\"button\" onClick={handleClick} disabled>\n * Button with type-safe button attributes\n * </Text>\n * ```\n */\nconst Text = <T extends ElementType = 'p'>({\n children,\n size = 'md',\n weight = 'normal',\n color = 'text-text-950',\n as,\n className = '',\n ...props\n}: TextProps<T>) => {\n let sizeClasses = '';\n let weightClasses = '';\n\n // Text size classes mapping\n const sizeClassMap = {\n '2xs': 'text-2xs',\n xs: 'text-xs',\n sm: 'text-sm',\n md: 'text-md',\n lg: 'text-lg',\n xl: 'text-xl',\n '2xl': 'text-2xl',\n '3xl': 'text-3xl',\n '4xl': 'text-4xl',\n '5xl': 'text-5xl',\n '6xl': 'text-6xl',\n } as const;\n\n sizeClasses = sizeClassMap[size] ?? sizeClassMap.md;\n\n // Font weight classes mapping\n const weightClassMap = {\n hairline: 'font-hairline',\n light: 'font-light',\n normal: 'font-normal',\n medium: 'font-medium',\n semibold: 'font-semibold',\n bold: 'font-bold',\n extrabold: 'font-extrabold',\n black: 'font-black',\n } as const;\n\n weightClasses = weightClassMap[weight] ?? weightClassMap.normal;\n\n const baseClasses = 'font-primary';\n const Component = as ?? ('p' as ElementType);\n\n return (\n <Component\n className={cn(baseClasses, sizeClasses, weightClasses, color, className)}\n {...props}\n >\n {children}\n </Component>\n );\n};\n\nexport default Text;\n"],"mappings":"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","names":["import_jsx_runtime"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/StudentRanking/StudentRanking.tsx","../../src/utils/utils.ts","../../src/components/Text/Text.tsx"],"sourcesContent":["import { HTMLAttributes } from 'react';\nimport { Trophy, Warning, TrendUp, TrendDown } from 'phosphor-react';\nimport Text from '../Text/Text';\nimport { cn } from '../../utils/utils';\n\n/**\n * Student data item for the ranking\n */\nexport interface StudentRankingItem {\n /** Student position in the ranking */\n position: number;\n /** Student name */\n name: string;\n /** Performance percentage (0-100) */\n percentage: number;\n}\n\n/**\n * Card variant type\n */\nexport type StudentRankingVariant = 'highlight' | 'attention';\n\n/**\n * Props for individual student card\n */\ninterface StudentCardProps {\n student: StudentRankingItem;\n variant: StudentRankingVariant;\n}\n\n/**\n * Lookup table for card background colors by position\n * Position 1 = most intense, Position 3+ = lightest\n */\nconst CARD_BACKGROUND_CLASSES = {\n highlight: {\n 1: 'bg-success-200',\n 2: 'bg-success-100',\n 3: 'bg-success-background',\n },\n attention: {\n 1: 'bg-error-200',\n 2: 'bg-error-100',\n 3: 'bg-error-background',\n },\n} as const;\n\n/**\n * Lookup table for badge background colors\n */\nconst BADGE_BACKGROUND_CLASSES = {\n highlight: 'bg-indicator-positive',\n attention: 'bg-indicator-negative',\n} as const;\n\n/**\n * Lookup table for percentage badge background colors\n */\nconst PERCENTAGE_BADGE_CLASSES = {\n highlight: 'bg-success-700',\n attention: 'bg-indicator-negative',\n} as const;\n\n/**\n * Lookup table for header badge background colors\n */\nconst HEADER_BADGE_CLASSES = {\n highlight: 'bg-indicator-positive',\n attention: 'bg-indicator-negative',\n} as const;\n\n/**\n * Get background class based on position (1, 2, or 3+)\n */\nconst getPositionBackgroundClass = (\n variant: StudentRankingVariant,\n position: number\n): string => {\n const positionKey = Math.max(1, Math.min(position, 3)) as 1 | 2 | 3;\n return CARD_BACKGROUND_CLASSES[variant][positionKey];\n};\n\n/**\n * Individual student card component\n */\nconst StudentCard = ({ student, variant }: StudentCardProps) => {\n const TrendIcon = variant === 'highlight' ? TrendUp : TrendDown;\n const backgroundClass = getPositionBackgroundClass(variant, student.position);\n\n return (\n <div\n className={cn(\n 'flex flex-row items-center w-full p-4 gap-2 rounded-xl',\n backgroundClass\n )}\n >\n {/* Position badge */}\n <Text\n size=\"xs\"\n weight=\"bold\"\n aria-label={`Posição ${student.position}`}\n className={cn(\n 'w-5 h-5 rounded-full flex items-center justify-center text-text',\n BADGE_BACKGROUND_CLASSES[variant]\n )}\n >\n {student.position}\n </Text>\n\n {/* Student name */}\n <Text\n size=\"sm\"\n weight=\"bold\"\n className=\"flex-1 min-w-0 text-text-950 tracking-[0.2px] truncate\"\n >\n {student.name}\n </Text>\n\n {/* Percentage badge */}\n <Text\n size=\"xs\"\n weight=\"bold\"\n aria-label={`Desempenho ${student.percentage}%`}\n className={cn(\n 'flex flex-row items-center h-[22px] px-2 gap-1 rounded text-text',\n PERCENTAGE_BADGE_CLASSES[variant]\n )}\n >\n <TrendIcon size={16} weight=\"bold\" aria-hidden=\"true\" />\n {student.percentage}%\n </Text>\n </div>\n );\n};\n\n/**\n * Props for a single ranking card\n */\nexport interface RankingCardProps extends HTMLAttributes<HTMLDivElement> {\n /** Card title */\n title: string;\n /** Card variant: highlight (best students) or attention (needs attention) */\n variant: StudentRankingVariant;\n /** List of students to display */\n students: StudentRankingItem[];\n}\n\n/**\n * Single ranking card component (can be used independently)\n */\nexport const RankingCard = ({\n title,\n variant,\n students,\n className,\n ...props\n}: RankingCardProps) => {\n const HeaderIcon = variant === 'highlight' ? Trophy : Warning;\n\n return (\n <div\n className={cn(\n 'flex flex-col flex-1 min-h-[254px] p-5 gap-4 bg-background border border-border-50 rounded-xl',\n className\n )}\n {...props}\n >\n {/* Header */}\n <div className=\"flex flex-row justify-between items-center h-6 gap-4\">\n <Text\n as=\"h3\"\n size=\"lg\"\n weight=\"bold\"\n className=\"text-text-950 tracking-[0.2px]\"\n >\n {title}\n </Text>\n\n {/* Header badge with icon */}\n <span\n className={cn(\n 'w-6 h-6 rounded-full flex items-center justify-center',\n HEADER_BADGE_CLASSES[variant]\n )}\n >\n <HeaderIcon\n size={14}\n weight=\"fill\"\n className={variant === 'highlight' ? 'text-text-950' : 'text-text'}\n />\n </span>\n </div>\n\n {/* Students list */}\n <div className=\"flex flex-col gap-2\">\n {students.map((student, index) => (\n <StudentCard\n key={`${variant}-${index}-${student.position}`}\n student={student}\n variant={variant}\n />\n ))}\n </div>\n </div>\n );\n};\n\n/**\n * Props for the StudentRanking component\n */\nexport interface StudentRankingProps extends HTMLAttributes<HTMLDivElement> {\n /** Title for the highlight (best students) card */\n highlightTitle?: string;\n /** Title for the attention (needs attention) card */\n attentionTitle?: string;\n /** List of highlighted (best performing) students */\n highlightStudents: StudentRankingItem[];\n /** List of students needing attention (lowest performing) */\n attentionStudents: StudentRankingItem[];\n}\n\n/**\n * StudentRanking component - displays two cards side by side showing\n * the best performing students and students that need attention.\n *\n * @example\n * ```tsx\n * <StudentRanking\n * highlightTitle=\"Estudantes em destaque\"\n * attentionTitle=\"Estudantes precisando de atenção\"\n * highlightStudents={[\n * { position: 1, name: 'Valentina Ribeiro', percentage: 100 },\n * { position: 2, name: 'Lucas Almeida', percentage: 100 },\n * { position: 3, name: 'Fernanda Costa', percentage: 100 },\n * ]}\n * attentionStudents={[\n * { position: 1, name: 'Ricardo Silva', percentage: 80 },\n * { position: 2, name: 'Juliana Santos', percentage: 50 },\n * { position: 3, name: 'Gabriel Oliveira', percentage: 40 },\n * ]}\n * />\n * ```\n */\nexport const StudentRanking = ({\n highlightTitle = 'Estudantes em destaque',\n attentionTitle = 'Estudantes precisando de atenção',\n highlightStudents,\n attentionStudents,\n className,\n ...props\n}: StudentRankingProps) => {\n return (\n <div\n className={cn('flex flex-col md:flex-row w-full gap-4', className)}\n {...props}\n >\n <RankingCard\n title={highlightTitle}\n variant=\"highlight\"\n students={highlightStudents}\n />\n <RankingCard\n title={attentionTitle}\n variant=\"attention\"\n students={attentionStudents}\n />\n </div>\n );\n};\n\nexport default StudentRanking;\n","import { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport { syncDropdownState } from './dropdown';\nexport {\n getSelectedIdsFromCategories,\n toggleArrayItem,\n toggleSingleValue,\n areFiltersEqual,\n} from './activityFilters';\nexport {\n mapQuestionTypeToEnum,\n mapQuestionTypeToEnumRequired,\n} from './questionTypeUtils';\nexport {\n getStatusBadgeConfig,\n formatTimeSpent,\n formatQuestionNumbers,\n formatDateToBrazilian,\n} from './activityDetailsUtils';\n\n/**\n * Retorna a cor hexadecimal com opacidade 0.3 (4d) se não estiver em dark mode.\n * Se estiver em dark mode, retorna a cor original.\n *\n * @param hexColor - Cor hexadecimal (ex: \"#0066b8\" ou \"0066b8\")\n * @param isDark - booleano indicando se está em dark mode\n * @returns string - cor hexadecimal com opacidade se necessário\n */\nexport function getSubjectColorWithOpacity(\n hexColor: string | undefined,\n isDark: boolean\n): string | undefined {\n if (!hexColor) return undefined;\n // Remove o '#' se existir\n let color = hexColor.replace(/^#/, '').toLowerCase();\n\n if (isDark) {\n // Se está em dark mode, sempre remove opacidade se existir\n if (color.length === 8) {\n color = color.slice(0, 6);\n }\n return `#${color}`;\n } else {\n // Se não está em dark mode (light mode)\n let resultColor: string;\n if (color.length === 6) {\n // Adiciona opacidade 0.3 (4D) para cores de 6 dígitos\n resultColor = `#${color}4d`;\n } else if (color.length === 8) {\n // Já tem opacidade, retorna como está\n resultColor = `#${color}`;\n } else {\n // Para outros tamanhos (3, 4, 5 dígitos), retorna como está\n resultColor = `#${color}`;\n }\n return resultColor;\n }\n}\n","import { ComponentPropsWithoutRef, ElementType, ReactNode } from 'react';\nimport { cn } from '../../utils/utils';\n\n/**\n * Base text component props\n */\ntype BaseTextProps = {\n /** Content to be displayed */\n children?: ReactNode;\n /** Text size variant */\n size?:\n | '2xs'\n | 'xs'\n | 'sm'\n | 'md'\n | 'lg'\n | 'xl'\n | '2xl'\n | '3xl'\n | '4xl'\n | '5xl'\n | '6xl';\n /** Font weight variant */\n weight?:\n | 'hairline'\n | 'light'\n | 'normal'\n | 'medium'\n | 'semibold'\n | 'bold'\n | 'extrabold'\n | 'black';\n /** Color variant - white for light backgrounds, black for dark backgrounds */\n color?: string;\n /** Additional CSS classes to apply */\n className?: string;\n};\n\n/**\n * Polymorphic text component props that ensures type safety based on the 'as' prop\n */\ntype TextProps<T extends ElementType = 'p'> = BaseTextProps & {\n /** HTML tag to render */\n as?: T;\n} & Omit<ComponentPropsWithoutRef<T>, keyof BaseTextProps>;\n\n/**\n * Text component for Analytica Ensino platforms\n *\n * A flexible polymorphic text component with multiple sizes, weights, and colors.\n * Automatically adapts to dark and light themes with full type safety.\n *\n * @param children - The content to display\n * @param size - The text size variant (2xs, xs, sm, md, lg, xl, 2xl, 3xl, 4xl, 5xl, 6xl)\n * @param weight - The font weight variant (hairline, light, normal, medium, semibold, bold, extrabold, black)\n * @param color - The color variant - adapts to theme\n * @param as - The HTML tag to render - determines allowed attributes via TypeScript\n * @param className - Additional CSS classes\n * @param props - HTML attributes valid for the chosen tag only\n * @returns A styled text element with type-safe attributes\n *\n * @example\n * ```tsx\n * <Text size=\"lg\" weight=\"bold\" color=\"text-info-800\">\n * This is a large, bold text\n * </Text>\n *\n * <Text as=\"a\" href=\"/link\" target=\"_blank\">\n * Link with type-safe anchor attributes\n * </Text>\n *\n * <Text as=\"button\" onClick={handleClick} disabled>\n * Button with type-safe button attributes\n * </Text>\n * ```\n */\nconst Text = <T extends ElementType = 'p'>({\n children,\n size = 'md',\n weight = 'normal',\n color = 'text-text-950',\n as,\n className = '',\n ...props\n}: TextProps<T>) => {\n let sizeClasses = '';\n let weightClasses = '';\n\n // Text size classes mapping\n const sizeClassMap = {\n '2xs': 'text-2xs',\n xs: 'text-xs',\n sm: 'text-sm',\n md: 'text-md',\n lg: 'text-lg',\n xl: 'text-xl',\n '2xl': 'text-2xl',\n '3xl': 'text-3xl',\n '4xl': 'text-4xl',\n '5xl': 'text-5xl',\n '6xl': 'text-6xl',\n } as const;\n\n sizeClasses = sizeClassMap[size] ?? sizeClassMap.md;\n\n // Font weight classes mapping\n const weightClassMap = {\n hairline: 'font-hairline',\n light: 'font-light',\n normal: 'font-normal',\n medium: 'font-medium',\n semibold: 'font-semibold',\n bold: 'font-bold',\n extrabold: 'font-extrabold',\n black: 'font-black',\n } as const;\n\n weightClasses = weightClassMap[weight] ?? weightClassMap.normal;\n\n const baseClasses = 'font-primary';\n const Component = as ?? ('p' as ElementType);\n\n return (\n <Component\n className={cn(baseClasses, sizeClasses, weightClasses, color, className)}\n {...props}\n >\n {children}\n </Component>\n );\n};\n\nexport default Text;\n"],"mappings":"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","names":["jsx"]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/StudentRanking/StudentRanking.tsx","../../src/utils/utils.ts","../../src/components/Text/Text.tsx"],"sourcesContent":["import { HTMLAttributes } from 'react';\nimport { Trophy, Warning, TrendUp, TrendDown } from 'phosphor-react';\nimport Text from '../Text/Text';\nimport { cn } from '../../utils/utils';\nimport type { StudentHighlightItem } from '../../hooks/useStudentsHighlight';\n\n/**\n * Re-export StudentHighlightItem as StudentRankingItem for backwards compatibility\n * and direct usage with the component\n */\nexport type StudentRankingItem = Pick<\n StudentHighlightItem,\n 'position' | 'name' | 'percentage'\n>;\n\n/**\n * Card variant type\n */\nexport type StudentRankingVariant = 'highlight' | 'attention';\n\n/**\n * Props for individual student card\n */\ninterface StudentCardProps {\n student: StudentRankingItem;\n variant: StudentRankingVariant;\n}\n\n/**\n * Lookup table for card background colors by position\n * Position 1 = most intense, Position 3+ = lightest\n */\nconst CARD_BACKGROUND_CLASSES = {\n highlight: {\n 1: 'bg-success-200',\n 2: 'bg-success-100',\n 3: 'bg-success-background',\n },\n attention: {\n 1: 'bg-error-200',\n 2: 'bg-error-100',\n 3: 'bg-error-background',\n },\n} as const;\n\n/**\n * Lookup table for badge background colors\n */\nconst BADGE_BACKGROUND_CLASSES = {\n highlight: 'bg-indicator-positive',\n attention: 'bg-indicator-negative',\n} as const;\n\n/**\n * Lookup table for percentage badge background colors\n */\nconst PERCENTAGE_BADGE_CLASSES = {\n highlight: 'bg-success-700',\n attention: 'bg-indicator-negative',\n} as const;\n\n/**\n * Lookup table for header badge background colors\n */\nconst HEADER_BADGE_CLASSES = {\n highlight: 'bg-indicator-positive',\n attention: 'bg-indicator-negative',\n} as const;\n\n/**\n * Get background class based on position (1, 2, or 3+)\n */\nconst getPositionBackgroundClass = (\n variant: StudentRankingVariant,\n position: number\n): string => {\n const positionKey = Math.max(1, Math.min(position, 3)) as 1 | 2 | 3;\n return CARD_BACKGROUND_CLASSES[variant][positionKey];\n};\n\n/**\n * Individual student card component\n */\nconst StudentCard = ({ student, variant }: StudentCardProps) => {\n const TrendIcon = variant === 'highlight' ? TrendUp : TrendDown;\n const backgroundClass = getPositionBackgroundClass(variant, student.position);\n\n return (\n <div\n className={cn(\n 'flex flex-row items-center w-full p-4 gap-2 rounded-xl',\n backgroundClass\n )}\n >\n {/* Position badge */}\n <Text\n size=\"xs\"\n weight=\"bold\"\n aria-label={`Posição ${student.position}`}\n className={cn(\n 'w-5 h-5 rounded-full flex items-center justify-center text-text',\n BADGE_BACKGROUND_CLASSES[variant]\n )}\n >\n {student.position}\n </Text>\n\n {/* Student name */}\n <Text\n size=\"sm\"\n weight=\"bold\"\n className=\"flex-1 min-w-0 text-text-950 tracking-[0.2px] truncate\"\n >\n {student.name}\n </Text>\n\n {/* Percentage badge */}\n <Text\n size=\"xs\"\n weight=\"bold\"\n aria-label={`Desempenho ${student.percentage}%`}\n className={cn(\n 'flex flex-row items-center h-[22px] px-2 gap-1 rounded text-text',\n PERCENTAGE_BADGE_CLASSES[variant]\n )}\n >\n <TrendIcon size={16} weight=\"bold\" aria-hidden=\"true\" />\n {student.percentage}%\n </Text>\n </div>\n );\n};\n\n/**\n * Props for a single ranking card\n */\nexport interface RankingCardProps extends HTMLAttributes<HTMLDivElement> {\n /** Card title */\n title: string;\n /** Card variant: highlight (best students) or attention (needs attention) */\n variant: StudentRankingVariant;\n /** List of students to display */\n students: StudentRankingItem[];\n}\n\n/**\n * Single ranking card component (can be used independently)\n */\nexport const RankingCard = ({\n title,\n variant,\n students,\n className,\n ...props\n}: RankingCardProps) => {\n const HeaderIcon = variant === 'highlight' ? Trophy : Warning;\n\n return (\n <div\n className={cn(\n 'flex flex-col flex-1 min-h-[254px] p-5 gap-4 bg-background border border-border-50 rounded-xl',\n className\n )}\n {...props}\n >\n {/* Header */}\n <div className=\"flex flex-row justify-between items-center h-6 gap-4\">\n <Text\n as=\"h3\"\n size=\"lg\"\n weight=\"bold\"\n className=\"text-text-950 tracking-[0.2px]\"\n >\n {title}\n </Text>\n\n {/* Header badge with icon */}\n <span\n className={cn(\n 'w-6 h-6 rounded-full flex items-center justify-center',\n HEADER_BADGE_CLASSES[variant]\n )}\n >\n <HeaderIcon\n size={14}\n weight=\"fill\"\n className={variant === 'highlight' ? 'text-text-950' : 'text-text'}\n />\n </span>\n </div>\n\n {/* Students list */}\n <div className=\"flex flex-col gap-2\">\n {students.map((student, index) => (\n <StudentCard\n key={`${variant}-${index}-${student.position}`}\n student={student}\n variant={variant}\n />\n ))}\n </div>\n </div>\n );\n};\n\n/**\n * Props for the StudentRanking component\n */\nexport interface StudentRankingProps extends HTMLAttributes<HTMLDivElement> {\n /** Title for the highlight (best students) card */\n highlightTitle?: string;\n /** Title for the attention (needs attention) card */\n attentionTitle?: string;\n /** List of highlighted (best performing) students */\n highlightStudents: StudentRankingItem[];\n /** List of students needing attention (lowest performing) */\n attentionStudents: StudentRankingItem[];\n}\n\n/**\n * StudentRanking component - displays two cards side by side showing\n * the best performing students and students that need attention.\n *\n * @example\n * ```tsx\n * // Basic usage with static data\n * <StudentRanking\n * highlightTitle=\"Estudantes em destaque\"\n * attentionTitle=\"Estudantes precisando de atenção\"\n * highlightStudents={[\n * { position: 1, name: 'Valentina Ribeiro', percentage: 100 },\n * { position: 2, name: 'Lucas Almeida', percentage: 100 },\n * { position: 3, name: 'Fernanda Costa', percentage: 100 },\n * ]}\n * attentionStudents={[\n * { position: 1, name: 'Ricardo Silva', percentage: 80 },\n * { position: 2, name: 'Juliana Santos', percentage: 50 },\n * { position: 3, name: 'Gabriel Oliveira', percentage: 40 },\n * ]}\n * />\n * ```\n *\n * @example\n * ```tsx\n * // Usage with useStudentsHighlight hook (direct usage - no transformation needed)\n * const fetchStudentsHighlight = async (filters) => {\n * const response = await api.get('/performance/students-highlight', { params: filters });\n * return response.data;\n * };\n *\n * const useStudentsHighlight = createUseStudentsHighlight(fetchStudentsHighlight);\n *\n * function MyComponent() {\n * const { topStudents, bottomStudents, loading, fetchStudentsHighlight } = useStudentsHighlight();\n *\n * useEffect(() => {\n * fetchStudentsHighlight({ period: '30_DAYS' });\n * }, [fetchStudentsHighlight]);\n *\n * if (loading) return <Skeleton />;\n *\n * return (\n * <StudentRanking\n * highlightStudents={topStudents}\n * attentionStudents={bottomStudents}\n * />\n * );\n * }\n * ```\n */\nexport const StudentRanking = ({\n highlightTitle = 'Estudantes em destaque',\n attentionTitle = 'Estudantes precisando de atenção',\n highlightStudents,\n attentionStudents,\n className,\n ...props\n}: StudentRankingProps) => {\n return (\n <div\n className={cn('flex flex-col md:flex-row w-full gap-4', className)}\n {...props}\n >\n <RankingCard\n title={highlightTitle}\n variant=\"highlight\"\n students={highlightStudents}\n />\n <RankingCard\n title={attentionTitle}\n variant=\"attention\"\n students={attentionStudents}\n />\n </div>\n );\n};\n\nexport default StudentRanking;\n","import { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport { syncDropdownState } from './dropdown';\nexport {\n getSelectedIdsFromCategories,\n toggleArrayItem,\n toggleSingleValue,\n areFiltersEqual,\n} from './activityFilters';\nexport {\n mapQuestionTypeToEnum,\n mapQuestionTypeToEnumRequired,\n} from './questionTypeUtils';\nexport {\n getStatusBadgeConfig,\n formatTimeSpent,\n formatQuestionNumbers,\n formatDateToBrazilian,\n} from './activityDetailsUtils';\n\n/**\n * Retorna a cor hexadecimal com opacidade 0.3 (4d) se não estiver em dark mode.\n * Se estiver em dark mode, retorna a cor original.\n *\n * @param hexColor - Cor hexadecimal (ex: \"#0066b8\" ou \"0066b8\")\n * @param isDark - booleano indicando se está em dark mode\n * @returns string - cor hexadecimal com opacidade se necessário\n */\nexport function getSubjectColorWithOpacity(\n hexColor: string | undefined,\n isDark: boolean\n): string | undefined {\n if (!hexColor) return undefined;\n // Remove o '#' se existir\n let color = hexColor.replace(/^#/, '').toLowerCase();\n\n if (isDark) {\n // Se está em dark mode, sempre remove opacidade se existir\n if (color.length === 8) {\n color = color.slice(0, 6);\n }\n return `#${color}`;\n } else {\n // Se não está em dark mode (light mode)\n let resultColor: string;\n if (color.length === 6) {\n // Adiciona opacidade 0.3 (4D) para cores de 6 dígitos\n resultColor = `#${color}4d`;\n } else if (color.length === 8) {\n // Já tem opacidade, retorna como está\n resultColor = `#${color}`;\n } else {\n // Para outros tamanhos (3, 4, 5 dígitos), retorna como está\n resultColor = `#${color}`;\n }\n return resultColor;\n }\n}\n","import { ComponentPropsWithoutRef, ElementType, ReactNode } from 'react';\nimport { cn } from '../../utils/utils';\n\n/**\n * Base text component props\n */\ntype BaseTextProps = {\n /** Content to be displayed */\n children?: ReactNode;\n /** Text size variant */\n size?:\n | '2xs'\n | 'xs'\n | 'sm'\n | 'md'\n | 'lg'\n | 'xl'\n | '2xl'\n | '3xl'\n | '4xl'\n | '5xl'\n | '6xl';\n /** Font weight variant */\n weight?:\n | 'hairline'\n | 'light'\n | 'normal'\n | 'medium'\n | 'semibold'\n | 'bold'\n | 'extrabold'\n | 'black';\n /** Color variant - white for light backgrounds, black for dark backgrounds */\n color?: string;\n /** Additional CSS classes to apply */\n className?: string;\n};\n\n/**\n * Polymorphic text component props that ensures type safety based on the 'as' prop\n */\ntype TextProps<T extends ElementType = 'p'> = BaseTextProps & {\n /** HTML tag to render */\n as?: T;\n} & Omit<ComponentPropsWithoutRef<T>, keyof BaseTextProps>;\n\n/**\n * Text component for Analytica Ensino platforms\n *\n * A flexible polymorphic text component with multiple sizes, weights, and colors.\n * Automatically adapts to dark and light themes with full type safety.\n *\n * @param children - The content to display\n * @param size - The text size variant (2xs, xs, sm, md, lg, xl, 2xl, 3xl, 4xl, 5xl, 6xl)\n * @param weight - The font weight variant (hairline, light, normal, medium, semibold, bold, extrabold, black)\n * @param color - The color variant - adapts to theme\n * @param as - The HTML tag to render - determines allowed attributes via TypeScript\n * @param className - Additional CSS classes\n * @param props - HTML attributes valid for the chosen tag only\n * @returns A styled text element with type-safe attributes\n *\n * @example\n * ```tsx\n * <Text size=\"lg\" weight=\"bold\" color=\"text-info-800\">\n * This is a large, bold text\n * </Text>\n *\n * <Text as=\"a\" href=\"/link\" target=\"_blank\">\n * Link with type-safe anchor attributes\n * </Text>\n *\n * <Text as=\"button\" onClick={handleClick} disabled>\n * Button with type-safe button attributes\n * </Text>\n * ```\n */\nconst Text = <T extends ElementType = 'p'>({\n children,\n size = 'md',\n weight = 'normal',\n color = 'text-text-950',\n as,\n className = '',\n ...props\n}: TextProps<T>) => {\n let sizeClasses = '';\n let weightClasses = '';\n\n // Text size classes mapping\n const sizeClassMap = {\n '2xs': 'text-2xs',\n xs: 'text-xs',\n sm: 'text-sm',\n md: 'text-md',\n lg: 'text-lg',\n xl: 'text-xl',\n '2xl': 'text-2xl',\n '3xl': 'text-3xl',\n '4xl': 'text-4xl',\n '5xl': 'text-5xl',\n '6xl': 'text-6xl',\n } as const;\n\n sizeClasses = sizeClassMap[size] ?? sizeClassMap.md;\n\n // Font weight classes mapping\n const weightClassMap = {\n hairline: 'font-hairline',\n light: 'font-light',\n normal: 'font-normal',\n medium: 'font-medium',\n semibold: 'font-semibold',\n bold: 'font-bold',\n extrabold: 'font-extrabold',\n black: 'font-black',\n } as const;\n\n weightClasses = weightClassMap[weight] ?? weightClassMap.normal;\n\n const baseClasses = 'font-primary';\n const Component = as ?? ('p' as ElementType);\n\n return (\n <Component\n className={cn(baseClasses, sizeClasses, weightClasses, color, className)}\n {...props}\n >\n {children}\n </Component>\n );\n};\n\nexport default Text;\n"],"mappings":"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","names":["jsx"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/hooks/useActivitiesHistory.ts","../../../src/types/common.ts","../../../src/types/activitiesHistory.ts","../../../src/utils/hookErrorHandler.ts"],"sourcesContent":["import { useState, useCallback } from 'react';\nimport { z } from 'zod';\nimport dayjs from 'dayjs';\nimport {\n ActivityApiStatus,\n mapActivityStatusToDisplay,\n} from '../types/activitiesHistory';\nimport type {\n ActivityHistoryResponse,\n ActivityTableItem,\n ActivitiesHistoryApiResponse,\n ActivityHistoryFilters,\n ActivityPagination,\n} from '../types/activitiesHistory';\nimport { createFetchErrorHandler } from '../utils/hookErrorHandler';\n\n/**\n * Zod schema for activity history API response validation\n * Based on /activities/history endpoint\n */\nconst activityHistoryResponseSchema = z.object({\n id: z.string().uuid(),\n title: z.string(),\n startDate: z.string().nullable(),\n finalDate: z.string().nullable(),\n status: z.nativeEnum(ActivityApiStatus),\n completionPercentage: z.number().min(0).max(100).optional().default(0),\n subjectId: z.string().uuid().optional().nullable(),\n schoolId: z.string().optional(),\n schoolName: z.string().optional(),\n year: z.string().optional(),\n className: z.string().optional(),\n subjectName: z.string().optional(),\n});\n\nexport const activitiesHistoryApiResponseSchema = z.object({\n message: z.string(),\n data: z.object({\n activities: z.array(z.unknown()).transform((items) =>\n items\n .map((item) => activityHistoryResponseSchema.safeParse(item))\n .filter(\n (\n result\n ): result is {\n success: true;\n data: z.infer<typeof activityHistoryResponseSchema>;\n } => result.success\n )\n .map((result) => result.data)\n ),\n pagination: z.object({\n total: z.number(),\n page: z.number(),\n limit: z.number(),\n totalPages: z.number(),\n }),\n }),\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}\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 * 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 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 title: activity.title,\n school: activity.schoolName || '-',\n year: activity.year || '-',\n subject: activity.subjectName || '-',\n class: activity.className || '-',\n status: mapActivityStatusToDisplay(activity.status),\n completionPercentage: activity.completionPercentage,\n };\n};\n\n/**\n * Handle errors during activity fetch\n * Uses the generic error handler factory to reduce code duplication\n */\nexport const handleActivityFetchError = createFetchErrorHandler(\n 'Erro ao validar dados de histórico de atividades',\n 'Erro ao carregar histórico de atividades'\n);\n\n/**\n * Factory function to create useActivitiesHistory hook\n *\n * @param fetchActivitiesHistory - Function to fetch activities from API\n * @returns Hook for managing activities history\n *\n * @example\n * ```tsx\n * // In your app setup\n * const fetchActivitiesHistory = async (filters) => {\n * const response = await api.get('/activities/history', { params: filters });\n * return response.data;\n * };\n *\n * const useActivitiesHistory = createUseActivitiesHistory(fetchActivitiesHistory);\n *\n * // In your component\n * const { activities, loading, error, pagination, fetchActivities } = useActivitiesHistory();\n * ```\n */\nexport const createUseActivitiesHistory = (\n fetchActivitiesHistory: (\n filters?: ActivityHistoryFilters\n ) => Promise<ActivitiesHistoryApiResponse>\n) => {\n return (): UseActivitiesHistoryReturn => {\n const [state, setState] = useState<UseActivitiesHistoryState>({\n activities: [],\n loading: false,\n error: null,\n pagination: DEFAULT_ACTIVITIES_PAGINATION,\n });\n\n /**\n * Fetch activities history from API\n * @param filters - Optional filters for pagination, search, sorting, etc.\n */\n const fetchActivities = useCallback(\n async (filters?: ActivityHistoryFilters) => {\n setState((prev) => ({ ...prev, loading: true, error: null }));\n\n try {\n // Fetch data from API\n const responseData = await fetchActivitiesHistory(filters);\n\n // Validate response with Zod\n const validatedData =\n activitiesHistoryApiResponseSchema.parse(responseData);\n\n // Transform activities to table format\n const tableItems = validatedData.data.activities.map(\n transformActivityToTableItem\n );\n\n // Update state with validated and transformed data\n setState({\n activities: tableItems,\n loading: false,\n error: null,\n pagination: validatedData.data.pagination,\n });\n } catch (error) {\n const errorMessage = handleActivityFetchError(error);\n setState((prev) => ({\n ...prev,\n loading: false,\n error: errorMessage,\n }));\n }\n },\n [fetchActivitiesHistory]\n );\n\n return {\n ...state,\n fetchActivities,\n };\n };\n};\n\n/**\n * Alias for createUseActivitiesHistory\n */\nexport const createActivitiesHistoryHook = createUseActivitiesHistory;\n","/**\n * Common Type Definitions\n * Shared types used across multiple features (activities, goals, etc.)\n */\n\n/**\n * Generic API status for activities and goals\n * Used by backend endpoints for status filtering\n */\nexport enum GenericApiStatus {\n A_VENCER = 'A_VENCER',\n VENCIDA = 'VENCIDA',\n CONCLUIDA = 'CONCLUIDA',\n}\n\n/**\n * Generic display status for UI components\n * Used for Badge and status display in tables\n */\nexport enum GenericDisplayStatus {\n ATIVA = 'ATIVA',\n VENCIDA = 'VENCIDA',\n CONCLUIDA = 'CONCLUÍDA',\n}\n\n/**\n * Badge action types for status visualization\n * Maps to Badge component action prop\n */\nexport enum BadgeActionType {\n SUCCESS = 'success',\n WARNING = 'warning',\n ERROR = 'error',\n}\n\n/**\n * Get badge action based on display status\n * @param status - Display status value\n * @returns Badge action type for styling\n */\nexport const getStatusBadgeAction = (\n status: GenericDisplayStatus\n): BadgeActionType => {\n const actionMap: Record<GenericDisplayStatus, BadgeActionType> = {\n [GenericDisplayStatus.CONCLUIDA]: BadgeActionType.SUCCESS,\n [GenericDisplayStatus.ATIVA]: BadgeActionType.WARNING,\n [GenericDisplayStatus.VENCIDA]: BadgeActionType.ERROR,\n };\n return actionMap[status] ?? BadgeActionType.WARNING;\n};\n\n/**\n * Map API status to display status\n * @param apiStatus - Status from backend API\n * @returns Formatted status for UI display\n */\nexport const mapApiStatusToDisplay = (\n apiStatus: GenericApiStatus\n): GenericDisplayStatus => {\n const statusMap: Record<GenericApiStatus, GenericDisplayStatus> = {\n [GenericApiStatus.A_VENCER]: GenericDisplayStatus.ATIVA,\n [GenericApiStatus.VENCIDA]: GenericDisplayStatus.VENCIDA,\n [GenericApiStatus.CONCLUIDA]: GenericDisplayStatus.CONCLUIDA,\n };\n return statusMap[apiStatus];\n};\n","/**\n * Activities History Type Definitions\n * Types and interfaces for activities history and models functionality\n * Based on /activities/history and /activity-drafts endpoints\n */\n\nimport {\n GenericApiStatus,\n GenericDisplayStatus,\n BadgeActionType,\n getStatusBadgeAction,\n mapApiStatusToDisplay,\n} from './common';\n\n/**\n * Activity status from backend API /activities/history\n * Re-exported from common for backward compatibility\n */\nexport { GenericApiStatus as ActivityApiStatus } from './common';\n\n/**\n * Activity status for display in UI (Badge component)\n * Re-exported from common for backward compatibility\n */\nexport { GenericDisplayStatus as ActivityDisplayStatus } from './common';\n\n/**\n * Badge action types for activity status visualization\n * Re-exported from common for backward compatibility\n */\nexport { BadgeActionType as ActivityBadgeActionType } from './common';\n\n/**\n * Activity draft type enum (matches backend ACTIVITY_DRAFT_TYPE)\n */\nexport enum ActivityDraftType {\n MODELO = 'MODELO',\n RASCUNHO = 'RASCUNHO',\n}\n\n/**\n * Activity history response from backend API /activities/history\n */\nexport interface ActivityHistoryResponse {\n id: string;\n title: string;\n startDate: string | null;\n finalDate: string | null;\n status: GenericApiStatus;\n completionPercentage: number;\n subjectId?: string | null;\n schoolId?: string;\n schoolName?: string;\n year?: string;\n className?: string;\n subjectName?: string;\n}\n\n/**\n * Activity table item interface for activities list table\n */\nexport interface ActivityTableItem extends Record<string, unknown> {\n id: string;\n startDate: string | null;\n deadline: string | null;\n title: string;\n school: string;\n year: string;\n subject: string;\n class: string;\n status: GenericDisplayStatus;\n completionPercentage: number;\n}\n\n/**\n * Pagination info from API\n */\nexport interface ActivityPagination {\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n}\n\n/**\n * Activities history API complete response\n */\nexport interface ActivitiesHistoryApiResponse {\n message: string;\n data: {\n activities: ActivityHistoryResponse[];\n pagination: ActivityPagination;\n };\n}\n\n/**\n * Activity history filters for API query parameters\n */\nexport interface ActivityHistoryFilters {\n page?: number;\n limit?: number;\n status?: GenericApiStatus;\n search?: string;\n startDate?: string;\n finalDate?: string;\n subjectId?: string;\n schoolId?: string;\n sortBy?: 'finalDate' | 'title' | 'completionPercentage';\n sortOrder?: 'asc' | 'desc';\n}\n\n/**\n * Activity draft filters object from backend\n */\nexport interface ActivityDraftFilters {\n questionTypes?: string[];\n questionBanks?: string[];\n subjects?: string[];\n topics?: string[];\n subtopics?: string[];\n contents?: string[];\n}\n\n/**\n * Subject object with icon and color information\n */\nexport interface SubjectData {\n id: string;\n subjectName: string;\n subjectIcon: string;\n subjectColor: string;\n}\n\n/**\n * Activity model response from backend API (/activity-drafts)\n */\nexport interface ActivityModelResponse {\n id: string;\n type: ActivityDraftType;\n title: string | null;\n creatorUserInstitutionId: string | null;\n subjectId: string | null;\n subject?: SubjectData | null;\n filters: ActivityDraftFilters | null;\n createdAt: string;\n updatedAt: string;\n}\n\n/**\n * Activity model table item for display\n */\nexport interface ActivityModelTableItem extends Record<string, unknown> {\n id: string;\n title: string;\n savedAt: string;\n subject: SubjectData | null;\n subjectId: string | null;\n}\n\n/**\n * Activity models API response\n */\nexport interface ActivityModelsApiResponse {\n message: string;\n data: {\n activityDrafts: ActivityModelResponse[];\n total: number;\n };\n}\n\n/**\n * Activity model filters for API query\n */\nexport interface ActivityModelFilters {\n page?: number;\n limit?: number;\n search?: string;\n subjectId?: string;\n type?: ActivityDraftType;\n}\n\n/**\n * Filter option for dropdowns\n * Extends with index signature to be compatible with CheckBoxGroup Item type\n */\nexport interface ActivityFilterOption {\n id: string;\n name: string;\n [key: string]: unknown;\n}\n\n/**\n * User data for filter options (schools, classes, subjects)\n */\nexport interface ActivityUserFilterData {\n schools?: Array<{ id: string; name: string }>;\n classes?: Array<{ id: string; name: string; schoolId?: string }>;\n subjects?: Array<{ id: string; name: string }>;\n schoolYears?: Array<{ id: string; name: string }>;\n}\n\n/**\n * Get status badge action based on activity display status\n * @param status - Activity display status\n * @returns Badge action type for styling\n */\nexport const getActivityStatusBadgeAction = (\n status: GenericDisplayStatus\n): BadgeActionType => getStatusBadgeAction(status);\n\n/**\n * Activity status options for filter\n */\nexport const ACTIVITY_FILTER_STATUS_OPTIONS: ActivityFilterOption[] = [\n { id: GenericApiStatus.A_VENCER, name: 'A Vencer' },\n { id: GenericApiStatus.VENCIDA, name: 'Vencida' },\n { id: GenericApiStatus.CONCLUIDA, name: 'Concluída' },\n];\n\n/**\n * Map API status to display status\n * @param apiStatus - Status from backend API\n * @returns Formatted status for UI display\n */\nexport const mapActivityStatusToDisplay = (\n apiStatus: GenericApiStatus\n): GenericDisplayStatus => mapApiStatusToDisplay(apiStatus);\n","import { z } from 'zod';\n\n/**\n * Factory function to create a fetch error handler\n * This reduces code duplication across data fetching hooks\n *\n * @param validationErrorMessage - Message to display for Zod validation errors\n * @param genericErrorMessage - Message to display for other errors\n * @returns Error handler function that returns appropriate error message\n *\n * @example\n * ```typescript\n * const handleFetchError = createFetchErrorHandler(\n * 'Erro ao validar dados',\n * 'Erro ao carregar dados'\n * );\n *\n * try {\n * // fetch data\n * } catch (error) {\n * const errorMessage = handleFetchError(error);\n * }\n * ```\n */\nexport const createFetchErrorHandler =\n (validationErrorMessage: string, genericErrorMessage: string) =>\n (error: unknown): string => {\n if (error instanceof z.ZodError) {\n console.error(validationErrorMessage, error);\n return validationErrorMessage;\n }\n\n console.error(genericErrorMessage, error);\n return genericErrorMessage;\n };\n"],"mappings":"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","names":["import_zod","GenericApiStatus","dayjs"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/hooks/useActivitiesHistory.ts","../../../src/types/common.ts","../../../src/types/activitiesHistory.ts","../../../src/utils/hookErrorHandler.ts"],"sourcesContent":["import { useState, useCallback } from 'react';\nimport { z } from 'zod';\nimport dayjs from 'dayjs';\nimport {\n ActivityApiStatus,\n mapActivityStatusToDisplay,\n} from '../types/activitiesHistory';\nimport type {\n ActivityHistoryResponse,\n ActivityTableItem,\n ActivitiesHistoryApiResponse,\n ActivityHistoryFilters,\n ActivityPagination,\n} from '../types/activitiesHistory';\nimport { createFetchErrorHandler } from '../utils/hookErrorHandler';\n\n/**\n * Zod schema for activity history API response validation\n * Based on /activities/history endpoint\n */\nconst activityHistoryResponseSchema = z.object({\n id: z.string().uuid(),\n title: z.string(),\n startDate: z.string().nullable(),\n finalDate: z.string().nullable(),\n status: z.nativeEnum(ActivityApiStatus),\n completionPercentage: z.number().min(0).max(100).optional().default(0),\n subjectId: z.string().uuid().optional().nullable(),\n schoolId: z.string().optional(),\n schoolName: z.string().optional(),\n year: z.string().optional(),\n className: z.string().optional(),\n subjectName: z.string().optional(),\n});\n\nexport const activitiesHistoryApiResponseSchema = z.object({\n message: z.string(),\n data: z.object({\n activities: z.array(z.unknown()).transform((items) =>\n items\n .map((item) => activityHistoryResponseSchema.safeParse(item))\n .filter(\n (\n result\n ): result is {\n success: true;\n data: z.infer<typeof activityHistoryResponseSchema>;\n } => result.success\n )\n .map((result) => result.data)\n ),\n pagination: z.object({\n total: z.number(),\n page: z.number(),\n limit: z.number(),\n totalPages: z.number(),\n }),\n }),\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}\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 * 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 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 title: activity.title,\n school: activity.schoolName || '-',\n year: activity.year || '-',\n subject: activity.subjectName || '-',\n class: activity.className || '-',\n status: mapActivityStatusToDisplay(activity.status),\n completionPercentage: activity.completionPercentage,\n };\n};\n\n/**\n * Handle errors during activity fetch\n * Uses the generic error handler factory to reduce code duplication\n */\nexport const handleActivityFetchError = createFetchErrorHandler(\n 'Erro ao validar dados de histórico de atividades',\n 'Erro ao carregar histórico de atividades'\n);\n\n/**\n * Factory function to create useActivitiesHistory hook\n *\n * @param fetchActivitiesHistory - Function to fetch activities from API\n * @returns Hook for managing activities history\n *\n * @example\n * ```tsx\n * // In your app setup\n * const fetchActivitiesHistory = async (filters) => {\n * const response = await api.get('/activities/history', { params: filters });\n * return response.data;\n * };\n *\n * const useActivitiesHistory = createUseActivitiesHistory(fetchActivitiesHistory);\n *\n * // In your component\n * const { activities, loading, error, pagination, fetchActivities } = useActivitiesHistory();\n * ```\n */\nexport const createUseActivitiesHistory = (\n fetchActivitiesHistory: (\n filters?: ActivityHistoryFilters\n ) => Promise<ActivitiesHistoryApiResponse>\n) => {\n return (): UseActivitiesHistoryReturn => {\n const [state, setState] = useState<UseActivitiesHistoryState>({\n activities: [],\n loading: false,\n error: null,\n pagination: DEFAULT_ACTIVITIES_PAGINATION,\n });\n\n /**\n * Fetch activities history from API\n * @param filters - Optional filters for pagination, search, sorting, etc.\n */\n const fetchActivities = useCallback(\n async (filters?: ActivityHistoryFilters) => {\n setState((prev) => ({ ...prev, loading: true, error: null }));\n\n try {\n // Fetch data from API\n const responseData = await fetchActivitiesHistory(filters);\n\n // Validate response with Zod\n const validatedData =\n activitiesHistoryApiResponseSchema.parse(responseData);\n\n // Transform activities to table format\n const tableItems = validatedData.data.activities.map(\n transformActivityToTableItem\n );\n\n // Update state with validated and transformed data\n setState({\n activities: tableItems,\n loading: false,\n error: null,\n pagination: validatedData.data.pagination,\n });\n } catch (error) {\n const errorMessage = handleActivityFetchError(error);\n setState((prev) => ({\n ...prev,\n loading: false,\n error: errorMessage,\n }));\n }\n },\n [fetchActivitiesHistory]\n );\n\n return {\n ...state,\n fetchActivities,\n };\n };\n};\n\n/**\n * Alias for createUseActivitiesHistory\n */\nexport const createActivitiesHistoryHook = createUseActivitiesHistory;\n","/**\n * Common Type Definitions\n * Shared types used across multiple features (activities, recommendedClass, etc.)\n */\n\n/**\n * Generic API status for activities and recommendedClass\n * Used by backend endpoints for status filtering\n */\nexport enum GenericApiStatus {\n A_VENCER = 'A_VENCER',\n VENCIDA = 'VENCIDA',\n CONCLUIDA = 'CONCLUIDA',\n}\n\n/**\n * Generic display status for UI components\n * Used for Badge and status display in tables\n */\nexport enum GenericDisplayStatus {\n ATIVA = 'ATIVA',\n VENCIDA = 'VENCIDA',\n CONCLUIDA = 'CONCLUÍDA',\n}\n\n/**\n * Badge action types for status visualization\n * Maps to Badge component action prop\n */\nexport enum BadgeActionType {\n SUCCESS = 'success',\n WARNING = 'warning',\n ERROR = 'error',\n}\n\n/**\n * Get badge action based on display status\n * @param status - Display status value\n * @returns Badge action type for styling\n */\nexport const getStatusBadgeAction = (\n status: GenericDisplayStatus\n): BadgeActionType => {\n const actionMap: Record<GenericDisplayStatus, BadgeActionType> = {\n [GenericDisplayStatus.CONCLUIDA]: BadgeActionType.SUCCESS,\n [GenericDisplayStatus.ATIVA]: BadgeActionType.WARNING,\n [GenericDisplayStatus.VENCIDA]: BadgeActionType.ERROR,\n };\n return actionMap[status] ?? BadgeActionType.WARNING;\n};\n\n/**\n * Map API status to display status\n * @param apiStatus - Status from backend API\n * @returns Formatted status for UI display\n */\nexport const mapApiStatusToDisplay = (\n apiStatus: GenericApiStatus\n): GenericDisplayStatus => {\n const statusMap: Record<GenericApiStatus, GenericDisplayStatus> = {\n [GenericApiStatus.A_VENCER]: GenericDisplayStatus.ATIVA,\n [GenericApiStatus.VENCIDA]: GenericDisplayStatus.VENCIDA,\n [GenericApiStatus.CONCLUIDA]: GenericDisplayStatus.CONCLUIDA,\n };\n return statusMap[apiStatus];\n};\n","/**\n * Activities History Type Definitions\n * Types and interfaces for activities history and models functionality\n * Based on /activities/history and /activity-drafts endpoints\n */\n\nimport {\n GenericApiStatus,\n GenericDisplayStatus,\n BadgeActionType,\n getStatusBadgeAction,\n mapApiStatusToDisplay,\n} from './common';\n\n/**\n * Activity status from backend API /activities/history\n * Re-exported from common for backward compatibility\n */\nexport { GenericApiStatus as ActivityApiStatus } from './common';\n\n/**\n * Activity status for display in UI (Badge component)\n * Re-exported from common for backward compatibility\n */\nexport { GenericDisplayStatus as ActivityDisplayStatus } from './common';\n\n/**\n * Badge action types for activity status visualization\n * Re-exported from common for backward compatibility\n */\nexport { BadgeActionType as ActivityBadgeActionType } from './common';\n\n/**\n * Activity draft type enum (matches backend ACTIVITY_DRAFT_TYPE)\n */\nexport enum ActivityDraftType {\n MODELO = 'MODELO',\n RASCUNHO = 'RASCUNHO',\n}\n\n/**\n * Activity history response from backend API /activities/history\n */\nexport interface ActivityHistoryResponse {\n id: string;\n title: string;\n startDate: string | null;\n finalDate: string | null;\n status: GenericApiStatus;\n completionPercentage: number;\n subjectId?: string | null;\n schoolId?: string;\n schoolName?: string;\n year?: string;\n className?: string;\n subjectName?: string;\n}\n\n/**\n * Activity table item interface for activities list table\n */\nexport interface ActivityTableItem extends Record<string, unknown> {\n id: string;\n startDate: string | null;\n deadline: string | null;\n title: string;\n school: string;\n year: string;\n subject: string;\n class: string;\n status: GenericDisplayStatus;\n completionPercentage: number;\n}\n\n/**\n * Pagination info from API\n */\nexport interface ActivityPagination {\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n}\n\n/**\n * Activities history API complete response\n */\nexport interface ActivitiesHistoryApiResponse {\n message: string;\n data: {\n activities: ActivityHistoryResponse[];\n pagination: ActivityPagination;\n };\n}\n\n/**\n * Activity history filters for API query parameters\n */\nexport interface ActivityHistoryFilters {\n page?: number;\n limit?: number;\n status?: GenericApiStatus;\n search?: string;\n startDate?: string;\n finalDate?: string;\n subjectId?: string;\n schoolId?: string;\n sortBy?: 'finalDate' | 'title' | 'completionPercentage';\n sortOrder?: 'asc' | 'desc';\n}\n\n/**\n * Activity draft filters object from backend\n */\nexport interface ActivityDraftFilters {\n questionTypes?: string[];\n questionBanks?: string[];\n subjects?: string[];\n topics?: string[];\n subtopics?: string[];\n contents?: string[];\n}\n\n/**\n * Subject object with icon and color information\n */\nexport interface SubjectData {\n id: string;\n subjectName: string;\n subjectIcon: string;\n subjectColor: string;\n}\n\n/**\n * Activity model response from backend API (/activity-drafts)\n */\nexport interface ActivityModelResponse {\n id: string;\n type: ActivityDraftType;\n title: string | null;\n creatorUserInstitutionId: string | null;\n subjectId: string | null;\n subject?: SubjectData | null;\n filters: ActivityDraftFilters | null;\n createdAt: string;\n updatedAt: string;\n}\n\n/**\n * Activity model table item for display\n */\nexport interface ActivityModelTableItem extends Record<string, unknown> {\n id: string;\n title: string;\n savedAt: string;\n subject: SubjectData | null;\n subjectId: string | null;\n}\n\n/**\n * Activity models API response\n */\nexport interface ActivityModelsApiResponse {\n message: string;\n data: {\n activityDrafts: ActivityModelResponse[];\n total: number;\n };\n}\n\n/**\n * Activity model filters for API query\n */\nexport interface ActivityModelFilters {\n page?: number;\n limit?: number;\n search?: string;\n subjectId?: string;\n type?: ActivityDraftType;\n}\n\n/**\n * Filter option for dropdowns\n * Extends with index signature to be compatible with CheckBoxGroup Item type\n */\nexport interface ActivityFilterOption {\n id: string;\n name: string;\n [key: string]: unknown;\n}\n\n/**\n * User data for filter options (schools, classes, subjects)\n */\nexport interface ActivityUserFilterData {\n schools?: Array<{ id: string; name: string }>;\n classes?: Array<{ id: string; name: string; schoolId?: string }>;\n subjects?: Array<{ id: string; name: string }>;\n schoolYears?: Array<{ id: string; name: string }>;\n}\n\n/**\n * Get status badge action based on activity display status\n * @param status - Activity display status\n * @returns Badge action type for styling\n */\nexport const getActivityStatusBadgeAction = (\n status: GenericDisplayStatus\n): BadgeActionType => getStatusBadgeAction(status);\n\n/**\n * Activity status options for filter\n */\nexport const ACTIVITY_FILTER_STATUS_OPTIONS: ActivityFilterOption[] = [\n { id: GenericApiStatus.A_VENCER, name: 'A Vencer' },\n { id: GenericApiStatus.VENCIDA, name: 'Vencida' },\n { id: GenericApiStatus.CONCLUIDA, name: 'Concluída' },\n];\n\n/**\n * Map API status to display status\n * @param apiStatus - Status from backend API\n * @returns Formatted status for UI display\n */\nexport const mapActivityStatusToDisplay = (\n apiStatus: GenericApiStatus\n): GenericDisplayStatus => mapApiStatusToDisplay(apiStatus);\n","import { z } from 'zod';\n\n/**\n * Factory function to create a fetch error handler\n * This reduces code duplication across data fetching hooks\n *\n * @param validationErrorMessage - Message to display for Zod validation errors\n * @param genericErrorMessage - Message to display for other errors\n * @returns Error handler function that returns appropriate error message\n *\n * @example\n * ```typescript\n * const handleFetchError = createFetchErrorHandler(\n * 'Erro ao validar dados',\n * 'Erro ao carregar dados'\n * );\n *\n * try {\n * // fetch data\n * } catch (error) {\n * const errorMessage = handleFetchError(error);\n * }\n * ```\n */\nexport const createFetchErrorHandler =\n (validationErrorMessage: string, genericErrorMessage: string) =>\n (error: unknown): string => {\n if (error instanceof z.ZodError) {\n console.error(validationErrorMessage, error);\n return validationErrorMessage;\n }\n\n console.error(genericErrorMessage, error);\n return genericErrorMessage;\n };\n"],"mappings":"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","names":["import_zod","GenericApiStatus","dayjs"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/hooks/useActivitiesHistory.ts","../../../src/types/common.ts","../../../src/types/activitiesHistory.ts","../../../src/utils/hookErrorHandler.ts"],"sourcesContent":["import { useState, useCallback } from 'react';\nimport { z } from 'zod';\nimport dayjs from 'dayjs';\nimport {\n ActivityApiStatus,\n mapActivityStatusToDisplay,\n} from '../types/activitiesHistory';\nimport type {\n ActivityHistoryResponse,\n ActivityTableItem,\n ActivitiesHistoryApiResponse,\n ActivityHistoryFilters,\n ActivityPagination,\n} from '../types/activitiesHistory';\nimport { createFetchErrorHandler } from '../utils/hookErrorHandler';\n\n/**\n * Zod schema for activity history API response validation\n * Based on /activities/history endpoint\n */\nconst activityHistoryResponseSchema = z.object({\n id: z.string().uuid(),\n title: z.string(),\n startDate: z.string().nullable(),\n finalDate: z.string().nullable(),\n status: z.nativeEnum(ActivityApiStatus),\n completionPercentage: z.number().min(0).max(100).optional().default(0),\n subjectId: z.string().uuid().optional().nullable(),\n schoolId: z.string().optional(),\n schoolName: z.string().optional(),\n year: z.string().optional(),\n className: z.string().optional(),\n subjectName: z.string().optional(),\n});\n\nexport const activitiesHistoryApiResponseSchema = z.object({\n message: z.string(),\n data: z.object({\n activities: z.array(z.unknown()).transform((items) =>\n items\n .map((item) => activityHistoryResponseSchema.safeParse(item))\n .filter(\n (\n result\n ): result is {\n success: true;\n data: z.infer<typeof activityHistoryResponseSchema>;\n } => result.success\n )\n .map((result) => result.data)\n ),\n pagination: z.object({\n total: z.number(),\n page: z.number(),\n limit: z.number(),\n totalPages: z.number(),\n }),\n }),\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}\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 * 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 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 title: activity.title,\n school: activity.schoolName || '-',\n year: activity.year || '-',\n subject: activity.subjectName || '-',\n class: activity.className || '-',\n status: mapActivityStatusToDisplay(activity.status),\n completionPercentage: activity.completionPercentage,\n };\n};\n\n/**\n * Handle errors during activity fetch\n * Uses the generic error handler factory to reduce code duplication\n */\nexport const handleActivityFetchError = createFetchErrorHandler(\n 'Erro ao validar dados de histórico de atividades',\n 'Erro ao carregar histórico de atividades'\n);\n\n/**\n * Factory function to create useActivitiesHistory hook\n *\n * @param fetchActivitiesHistory - Function to fetch activities from API\n * @returns Hook for managing activities history\n *\n * @example\n * ```tsx\n * // In your app setup\n * const fetchActivitiesHistory = async (filters) => {\n * const response = await api.get('/activities/history', { params: filters });\n * return response.data;\n * };\n *\n * const useActivitiesHistory = createUseActivitiesHistory(fetchActivitiesHistory);\n *\n * // In your component\n * const { activities, loading, error, pagination, fetchActivities } = useActivitiesHistory();\n * ```\n */\nexport const createUseActivitiesHistory = (\n fetchActivitiesHistory: (\n filters?: ActivityHistoryFilters\n ) => Promise<ActivitiesHistoryApiResponse>\n) => {\n return (): UseActivitiesHistoryReturn => {\n const [state, setState] = useState<UseActivitiesHistoryState>({\n activities: [],\n loading: false,\n error: null,\n pagination: DEFAULT_ACTIVITIES_PAGINATION,\n });\n\n /**\n * Fetch activities history from API\n * @param filters - Optional filters for pagination, search, sorting, etc.\n */\n const fetchActivities = useCallback(\n async (filters?: ActivityHistoryFilters) => {\n setState((prev) => ({ ...prev, loading: true, error: null }));\n\n try {\n // Fetch data from API\n const responseData = await fetchActivitiesHistory(filters);\n\n // Validate response with Zod\n const validatedData =\n activitiesHistoryApiResponseSchema.parse(responseData);\n\n // Transform activities to table format\n const tableItems = validatedData.data.activities.map(\n transformActivityToTableItem\n );\n\n // Update state with validated and transformed data\n setState({\n activities: tableItems,\n loading: false,\n error: null,\n pagination: validatedData.data.pagination,\n });\n } catch (error) {\n const errorMessage = handleActivityFetchError(error);\n setState((prev) => ({\n ...prev,\n loading: false,\n error: errorMessage,\n }));\n }\n },\n [fetchActivitiesHistory]\n );\n\n return {\n ...state,\n fetchActivities,\n };\n };\n};\n\n/**\n * Alias for createUseActivitiesHistory\n */\nexport const createActivitiesHistoryHook = createUseActivitiesHistory;\n","/**\n * Common Type Definitions\n * Shared types used across multiple features (activities, goals, etc.)\n */\n\n/**\n * Generic API status for activities and goals\n * Used by backend endpoints for status filtering\n */\nexport enum GenericApiStatus {\n A_VENCER = 'A_VENCER',\n VENCIDA = 'VENCIDA',\n CONCLUIDA = 'CONCLUIDA',\n}\n\n/**\n * Generic display status for UI components\n * Used for Badge and status display in tables\n */\nexport enum GenericDisplayStatus {\n ATIVA = 'ATIVA',\n VENCIDA = 'VENCIDA',\n CONCLUIDA = 'CONCLUÍDA',\n}\n\n/**\n * Badge action types for status visualization\n * Maps to Badge component action prop\n */\nexport enum BadgeActionType {\n SUCCESS = 'success',\n WARNING = 'warning',\n ERROR = 'error',\n}\n\n/**\n * Get badge action based on display status\n * @param status - Display status value\n * @returns Badge action type for styling\n */\nexport const getStatusBadgeAction = (\n status: GenericDisplayStatus\n): BadgeActionType => {\n const actionMap: Record<GenericDisplayStatus, BadgeActionType> = {\n [GenericDisplayStatus.CONCLUIDA]: BadgeActionType.SUCCESS,\n [GenericDisplayStatus.ATIVA]: BadgeActionType.WARNING,\n [GenericDisplayStatus.VENCIDA]: BadgeActionType.ERROR,\n };\n return actionMap[status] ?? BadgeActionType.WARNING;\n};\n\n/**\n * Map API status to display status\n * @param apiStatus - Status from backend API\n * @returns Formatted status for UI display\n */\nexport const mapApiStatusToDisplay = (\n apiStatus: GenericApiStatus\n): GenericDisplayStatus => {\n const statusMap: Record<GenericApiStatus, GenericDisplayStatus> = {\n [GenericApiStatus.A_VENCER]: GenericDisplayStatus.ATIVA,\n [GenericApiStatus.VENCIDA]: GenericDisplayStatus.VENCIDA,\n [GenericApiStatus.CONCLUIDA]: GenericDisplayStatus.CONCLUIDA,\n };\n return statusMap[apiStatus];\n};\n","/**\n * Activities History Type Definitions\n * Types and interfaces for activities history and models functionality\n * Based on /activities/history and /activity-drafts endpoints\n */\n\nimport {\n GenericApiStatus,\n GenericDisplayStatus,\n BadgeActionType,\n getStatusBadgeAction,\n mapApiStatusToDisplay,\n} from './common';\n\n/**\n * Activity status from backend API /activities/history\n * Re-exported from common for backward compatibility\n */\nexport { GenericApiStatus as ActivityApiStatus } from './common';\n\n/**\n * Activity status for display in UI (Badge component)\n * Re-exported from common for backward compatibility\n */\nexport { GenericDisplayStatus as ActivityDisplayStatus } from './common';\n\n/**\n * Badge action types for activity status visualization\n * Re-exported from common for backward compatibility\n */\nexport { BadgeActionType as ActivityBadgeActionType } from './common';\n\n/**\n * Activity draft type enum (matches backend ACTIVITY_DRAFT_TYPE)\n */\nexport enum ActivityDraftType {\n MODELO = 'MODELO',\n RASCUNHO = 'RASCUNHO',\n}\n\n/**\n * Activity history response from backend API /activities/history\n */\nexport interface ActivityHistoryResponse {\n id: string;\n title: string;\n startDate: string | null;\n finalDate: string | null;\n status: GenericApiStatus;\n completionPercentage: number;\n subjectId?: string | null;\n schoolId?: string;\n schoolName?: string;\n year?: string;\n className?: string;\n subjectName?: string;\n}\n\n/**\n * Activity table item interface for activities list table\n */\nexport interface ActivityTableItem extends Record<string, unknown> {\n id: string;\n startDate: string | null;\n deadline: string | null;\n title: string;\n school: string;\n year: string;\n subject: string;\n class: string;\n status: GenericDisplayStatus;\n completionPercentage: number;\n}\n\n/**\n * Pagination info from API\n */\nexport interface ActivityPagination {\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n}\n\n/**\n * Activities history API complete response\n */\nexport interface ActivitiesHistoryApiResponse {\n message: string;\n data: {\n activities: ActivityHistoryResponse[];\n pagination: ActivityPagination;\n };\n}\n\n/**\n * Activity history filters for API query parameters\n */\nexport interface ActivityHistoryFilters {\n page?: number;\n limit?: number;\n status?: GenericApiStatus;\n search?: string;\n startDate?: string;\n finalDate?: string;\n subjectId?: string;\n schoolId?: string;\n sortBy?: 'finalDate' | 'title' | 'completionPercentage';\n sortOrder?: 'asc' | 'desc';\n}\n\n/**\n * Activity draft filters object from backend\n */\nexport interface ActivityDraftFilters {\n questionTypes?: string[];\n questionBanks?: string[];\n subjects?: string[];\n topics?: string[];\n subtopics?: string[];\n contents?: string[];\n}\n\n/**\n * Subject object with icon and color information\n */\nexport interface SubjectData {\n id: string;\n subjectName: string;\n subjectIcon: string;\n subjectColor: string;\n}\n\n/**\n * Activity model response from backend API (/activity-drafts)\n */\nexport interface ActivityModelResponse {\n id: string;\n type: ActivityDraftType;\n title: string | null;\n creatorUserInstitutionId: string | null;\n subjectId: string | null;\n subject?: SubjectData | null;\n filters: ActivityDraftFilters | null;\n createdAt: string;\n updatedAt: string;\n}\n\n/**\n * Activity model table item for display\n */\nexport interface ActivityModelTableItem extends Record<string, unknown> {\n id: string;\n title: string;\n savedAt: string;\n subject: SubjectData | null;\n subjectId: string | null;\n}\n\n/**\n * Activity models API response\n */\nexport interface ActivityModelsApiResponse {\n message: string;\n data: {\n activityDrafts: ActivityModelResponse[];\n total: number;\n };\n}\n\n/**\n * Activity model filters for API query\n */\nexport interface ActivityModelFilters {\n page?: number;\n limit?: number;\n search?: string;\n subjectId?: string;\n type?: ActivityDraftType;\n}\n\n/**\n * Filter option for dropdowns\n * Extends with index signature to be compatible with CheckBoxGroup Item type\n */\nexport interface ActivityFilterOption {\n id: string;\n name: string;\n [key: string]: unknown;\n}\n\n/**\n * User data for filter options (schools, classes, subjects)\n */\nexport interface ActivityUserFilterData {\n schools?: Array<{ id: string; name: string }>;\n classes?: Array<{ id: string; name: string; schoolId?: string }>;\n subjects?: Array<{ id: string; name: string }>;\n schoolYears?: Array<{ id: string; name: string }>;\n}\n\n/**\n * Get status badge action based on activity display status\n * @param status - Activity display status\n * @returns Badge action type for styling\n */\nexport const getActivityStatusBadgeAction = (\n status: GenericDisplayStatus\n): BadgeActionType => getStatusBadgeAction(status);\n\n/**\n * Activity status options for filter\n */\nexport const ACTIVITY_FILTER_STATUS_OPTIONS: ActivityFilterOption[] = [\n { id: GenericApiStatus.A_VENCER, name: 'A Vencer' },\n { id: GenericApiStatus.VENCIDA, name: 'Vencida' },\n { id: GenericApiStatus.CONCLUIDA, name: 'Concluída' },\n];\n\n/**\n * Map API status to display status\n * @param apiStatus - Status from backend API\n * @returns Formatted status for UI display\n */\nexport const mapActivityStatusToDisplay = (\n apiStatus: GenericApiStatus\n): GenericDisplayStatus => mapApiStatusToDisplay(apiStatus);\n","import { z } from 'zod';\n\n/**\n * Factory function to create a fetch error handler\n * This reduces code duplication across data fetching hooks\n *\n * @param validationErrorMessage - Message to display for Zod validation errors\n * @param genericErrorMessage - Message to display for other errors\n * @returns Error handler function that returns appropriate error message\n *\n * @example\n * ```typescript\n * const handleFetchError = createFetchErrorHandler(\n * 'Erro ao validar dados',\n * 'Erro ao carregar dados'\n * );\n *\n * try {\n * // fetch data\n * } catch (error) {\n * const errorMessage = handleFetchError(error);\n * }\n * ```\n */\nexport const createFetchErrorHandler =\n (validationErrorMessage: string, genericErrorMessage: string) =>\n (error: unknown): string => {\n if (error instanceof z.ZodError) {\n console.error(validationErrorMessage, error);\n return validationErrorMessage;\n }\n\n console.error(genericErrorMessage, error);\n return genericErrorMessage;\n };\n"],"mappings":"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","names":["z","GenericApiStatus","z"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/hooks/useActivitiesHistory.ts","../../../src/types/common.ts","../../../src/types/activitiesHistory.ts","../../../src/utils/hookErrorHandler.ts"],"sourcesContent":["import { useState, useCallback } from 'react';\nimport { z } from 'zod';\nimport dayjs from 'dayjs';\nimport {\n ActivityApiStatus,\n mapActivityStatusToDisplay,\n} from '../types/activitiesHistory';\nimport type {\n ActivityHistoryResponse,\n ActivityTableItem,\n ActivitiesHistoryApiResponse,\n ActivityHistoryFilters,\n ActivityPagination,\n} from '../types/activitiesHistory';\nimport { createFetchErrorHandler } from '../utils/hookErrorHandler';\n\n/**\n * Zod schema for activity history API response validation\n * Based on /activities/history endpoint\n */\nconst activityHistoryResponseSchema = z.object({\n id: z.string().uuid(),\n title: z.string(),\n startDate: z.string().nullable(),\n finalDate: z.string().nullable(),\n status: z.nativeEnum(ActivityApiStatus),\n completionPercentage: z.number().min(0).max(100).optional().default(0),\n subjectId: z.string().uuid().optional().nullable(),\n schoolId: z.string().optional(),\n schoolName: z.string().optional(),\n year: z.string().optional(),\n className: z.string().optional(),\n subjectName: z.string().optional(),\n});\n\nexport const activitiesHistoryApiResponseSchema = z.object({\n message: z.string(),\n data: z.object({\n activities: z.array(z.unknown()).transform((items) =>\n items\n .map((item) => activityHistoryResponseSchema.safeParse(item))\n .filter(\n (\n result\n ): result is {\n success: true;\n data: z.infer<typeof activityHistoryResponseSchema>;\n } => result.success\n )\n .map((result) => result.data)\n ),\n pagination: z.object({\n total: z.number(),\n page: z.number(),\n limit: z.number(),\n totalPages: z.number(),\n }),\n }),\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}\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 * 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 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 title: activity.title,\n school: activity.schoolName || '-',\n year: activity.year || '-',\n subject: activity.subjectName || '-',\n class: activity.className || '-',\n status: mapActivityStatusToDisplay(activity.status),\n completionPercentage: activity.completionPercentage,\n };\n};\n\n/**\n * Handle errors during activity fetch\n * Uses the generic error handler factory to reduce code duplication\n */\nexport const handleActivityFetchError = createFetchErrorHandler(\n 'Erro ao validar dados de histórico de atividades',\n 'Erro ao carregar histórico de atividades'\n);\n\n/**\n * Factory function to create useActivitiesHistory hook\n *\n * @param fetchActivitiesHistory - Function to fetch activities from API\n * @returns Hook for managing activities history\n *\n * @example\n * ```tsx\n * // In your app setup\n * const fetchActivitiesHistory = async (filters) => {\n * const response = await api.get('/activities/history', { params: filters });\n * return response.data;\n * };\n *\n * const useActivitiesHistory = createUseActivitiesHistory(fetchActivitiesHistory);\n *\n * // In your component\n * const { activities, loading, error, pagination, fetchActivities } = useActivitiesHistory();\n * ```\n */\nexport const createUseActivitiesHistory = (\n fetchActivitiesHistory: (\n filters?: ActivityHistoryFilters\n ) => Promise<ActivitiesHistoryApiResponse>\n) => {\n return (): UseActivitiesHistoryReturn => {\n const [state, setState] = useState<UseActivitiesHistoryState>({\n activities: [],\n loading: false,\n error: null,\n pagination: DEFAULT_ACTIVITIES_PAGINATION,\n });\n\n /**\n * Fetch activities history from API\n * @param filters - Optional filters for pagination, search, sorting, etc.\n */\n const fetchActivities = useCallback(\n async (filters?: ActivityHistoryFilters) => {\n setState((prev) => ({ ...prev, loading: true, error: null }));\n\n try {\n // Fetch data from API\n const responseData = await fetchActivitiesHistory(filters);\n\n // Validate response with Zod\n const validatedData =\n activitiesHistoryApiResponseSchema.parse(responseData);\n\n // Transform activities to table format\n const tableItems = validatedData.data.activities.map(\n transformActivityToTableItem\n );\n\n // Update state with validated and transformed data\n setState({\n activities: tableItems,\n loading: false,\n error: null,\n pagination: validatedData.data.pagination,\n });\n } catch (error) {\n const errorMessage = handleActivityFetchError(error);\n setState((prev) => ({\n ...prev,\n loading: false,\n error: errorMessage,\n }));\n }\n },\n [fetchActivitiesHistory]\n );\n\n return {\n ...state,\n fetchActivities,\n };\n };\n};\n\n/**\n * Alias for createUseActivitiesHistory\n */\nexport const createActivitiesHistoryHook = createUseActivitiesHistory;\n","/**\n * Common Type Definitions\n * Shared types used across multiple features (activities, recommendedClass, etc.)\n */\n\n/**\n * Generic API status for activities and recommendedClass\n * Used by backend endpoints for status filtering\n */\nexport enum GenericApiStatus {\n A_VENCER = 'A_VENCER',\n VENCIDA = 'VENCIDA',\n CONCLUIDA = 'CONCLUIDA',\n}\n\n/**\n * Generic display status for UI components\n * Used for Badge and status display in tables\n */\nexport enum GenericDisplayStatus {\n ATIVA = 'ATIVA',\n VENCIDA = 'VENCIDA',\n CONCLUIDA = 'CONCLUÍDA',\n}\n\n/**\n * Badge action types for status visualization\n * Maps to Badge component action prop\n */\nexport enum BadgeActionType {\n SUCCESS = 'success',\n WARNING = 'warning',\n ERROR = 'error',\n}\n\n/**\n * Get badge action based on display status\n * @param status - Display status value\n * @returns Badge action type for styling\n */\nexport const getStatusBadgeAction = (\n status: GenericDisplayStatus\n): BadgeActionType => {\n const actionMap: Record<GenericDisplayStatus, BadgeActionType> = {\n [GenericDisplayStatus.CONCLUIDA]: BadgeActionType.SUCCESS,\n [GenericDisplayStatus.ATIVA]: BadgeActionType.WARNING,\n [GenericDisplayStatus.VENCIDA]: BadgeActionType.ERROR,\n };\n return actionMap[status] ?? BadgeActionType.WARNING;\n};\n\n/**\n * Map API status to display status\n * @param apiStatus - Status from backend API\n * @returns Formatted status for UI display\n */\nexport const mapApiStatusToDisplay = (\n apiStatus: GenericApiStatus\n): GenericDisplayStatus => {\n const statusMap: Record<GenericApiStatus, GenericDisplayStatus> = {\n [GenericApiStatus.A_VENCER]: GenericDisplayStatus.ATIVA,\n [GenericApiStatus.VENCIDA]: GenericDisplayStatus.VENCIDA,\n [GenericApiStatus.CONCLUIDA]: GenericDisplayStatus.CONCLUIDA,\n };\n return statusMap[apiStatus];\n};\n","/**\n * Activities History Type Definitions\n * Types and interfaces for activities history and models functionality\n * Based on /activities/history and /activity-drafts endpoints\n */\n\nimport {\n GenericApiStatus,\n GenericDisplayStatus,\n BadgeActionType,\n getStatusBadgeAction,\n mapApiStatusToDisplay,\n} from './common';\n\n/**\n * Activity status from backend API /activities/history\n * Re-exported from common for backward compatibility\n */\nexport { GenericApiStatus as ActivityApiStatus } from './common';\n\n/**\n * Activity status for display in UI (Badge component)\n * Re-exported from common for backward compatibility\n */\nexport { GenericDisplayStatus as ActivityDisplayStatus } from './common';\n\n/**\n * Badge action types for activity status visualization\n * Re-exported from common for backward compatibility\n */\nexport { BadgeActionType as ActivityBadgeActionType } from './common';\n\n/**\n * Activity draft type enum (matches backend ACTIVITY_DRAFT_TYPE)\n */\nexport enum ActivityDraftType {\n MODELO = 'MODELO',\n RASCUNHO = 'RASCUNHO',\n}\n\n/**\n * Activity history response from backend API /activities/history\n */\nexport interface ActivityHistoryResponse {\n id: string;\n title: string;\n startDate: string | null;\n finalDate: string | null;\n status: GenericApiStatus;\n completionPercentage: number;\n subjectId?: string | null;\n schoolId?: string;\n schoolName?: string;\n year?: string;\n className?: string;\n subjectName?: string;\n}\n\n/**\n * Activity table item interface for activities list table\n */\nexport interface ActivityTableItem extends Record<string, unknown> {\n id: string;\n startDate: string | null;\n deadline: string | null;\n title: string;\n school: string;\n year: string;\n subject: string;\n class: string;\n status: GenericDisplayStatus;\n completionPercentage: number;\n}\n\n/**\n * Pagination info from API\n */\nexport interface ActivityPagination {\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n}\n\n/**\n * Activities history API complete response\n */\nexport interface ActivitiesHistoryApiResponse {\n message: string;\n data: {\n activities: ActivityHistoryResponse[];\n pagination: ActivityPagination;\n };\n}\n\n/**\n * Activity history filters for API query parameters\n */\nexport interface ActivityHistoryFilters {\n page?: number;\n limit?: number;\n status?: GenericApiStatus;\n search?: string;\n startDate?: string;\n finalDate?: string;\n subjectId?: string;\n schoolId?: string;\n sortBy?: 'finalDate' | 'title' | 'completionPercentage';\n sortOrder?: 'asc' | 'desc';\n}\n\n/**\n * Activity draft filters object from backend\n */\nexport interface ActivityDraftFilters {\n questionTypes?: string[];\n questionBanks?: string[];\n subjects?: string[];\n topics?: string[];\n subtopics?: string[];\n contents?: string[];\n}\n\n/**\n * Subject object with icon and color information\n */\nexport interface SubjectData {\n id: string;\n subjectName: string;\n subjectIcon: string;\n subjectColor: string;\n}\n\n/**\n * Activity model response from backend API (/activity-drafts)\n */\nexport interface ActivityModelResponse {\n id: string;\n type: ActivityDraftType;\n title: string | null;\n creatorUserInstitutionId: string | null;\n subjectId: string | null;\n subject?: SubjectData | null;\n filters: ActivityDraftFilters | null;\n createdAt: string;\n updatedAt: string;\n}\n\n/**\n * Activity model table item for display\n */\nexport interface ActivityModelTableItem extends Record<string, unknown> {\n id: string;\n title: string;\n savedAt: string;\n subject: SubjectData | null;\n subjectId: string | null;\n}\n\n/**\n * Activity models API response\n */\nexport interface ActivityModelsApiResponse {\n message: string;\n data: {\n activityDrafts: ActivityModelResponse[];\n total: number;\n };\n}\n\n/**\n * Activity model filters for API query\n */\nexport interface ActivityModelFilters {\n page?: number;\n limit?: number;\n search?: string;\n subjectId?: string;\n type?: ActivityDraftType;\n}\n\n/**\n * Filter option for dropdowns\n * Extends with index signature to be compatible with CheckBoxGroup Item type\n */\nexport interface ActivityFilterOption {\n id: string;\n name: string;\n [key: string]: unknown;\n}\n\n/**\n * User data for filter options (schools, classes, subjects)\n */\nexport interface ActivityUserFilterData {\n schools?: Array<{ id: string; name: string }>;\n classes?: Array<{ id: string; name: string; schoolId?: string }>;\n subjects?: Array<{ id: string; name: string }>;\n schoolYears?: Array<{ id: string; name: string }>;\n}\n\n/**\n * Get status badge action based on activity display status\n * @param status - Activity display status\n * @returns Badge action type for styling\n */\nexport const getActivityStatusBadgeAction = (\n status: GenericDisplayStatus\n): BadgeActionType => getStatusBadgeAction(status);\n\n/**\n * Activity status options for filter\n */\nexport const ACTIVITY_FILTER_STATUS_OPTIONS: ActivityFilterOption[] = [\n { id: GenericApiStatus.A_VENCER, name: 'A Vencer' },\n { id: GenericApiStatus.VENCIDA, name: 'Vencida' },\n { id: GenericApiStatus.CONCLUIDA, name: 'Concluída' },\n];\n\n/**\n * Map API status to display status\n * @param apiStatus - Status from backend API\n * @returns Formatted status for UI display\n */\nexport const mapActivityStatusToDisplay = (\n apiStatus: GenericApiStatus\n): GenericDisplayStatus => mapApiStatusToDisplay(apiStatus);\n","import { z } from 'zod';\n\n/**\n * Factory function to create a fetch error handler\n * This reduces code duplication across data fetching hooks\n *\n * @param validationErrorMessage - Message to display for Zod validation errors\n * @param genericErrorMessage - Message to display for other errors\n * @returns Error handler function that returns appropriate error message\n *\n * @example\n * ```typescript\n * const handleFetchError = createFetchErrorHandler(\n * 'Erro ao validar dados',\n * 'Erro ao carregar dados'\n * );\n *\n * try {\n * // fetch data\n * } catch (error) {\n * const errorMessage = handleFetchError(error);\n * }\n * ```\n */\nexport const createFetchErrorHandler =\n (validationErrorMessage: string, genericErrorMessage: string) =>\n (error: unknown): string => {\n if (error instanceof z.ZodError) {\n console.error(validationErrorMessage, error);\n return validationErrorMessage;\n }\n\n console.error(genericErrorMessage, error);\n return genericErrorMessage;\n };\n"],"mappings":"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","names":["z","GenericApiStatus","z"]}
|
|
@@ -50,7 +50,7 @@ export declare const createUseNotifications: (apiClient: NotificationApiClient)
|
|
|
50
50
|
title: string;
|
|
51
51
|
type: string;
|
|
52
52
|
} | null;
|
|
53
|
-
|
|
53
|
+
recommendedClass?: {
|
|
54
54
|
id: string;
|
|
55
55
|
title: string;
|
|
56
56
|
} | null;
|
|
@@ -118,7 +118,7 @@ export declare const createNotificationsHook: (apiClient: NotificationApiClient)
|
|
|
118
118
|
title: string;
|
|
119
119
|
type: string;
|
|
120
120
|
} | null;
|
|
121
|
-
|
|
121
|
+
recommendedClass?: {
|
|
122
122
|
id: string;
|
|
123
123
|
title: string;
|
|
124
124
|
} | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useNotifications.d.ts","sourceRoot":"","sources":["../../src/hooks/useNotifications.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAG9E;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,GAAI,WAAW,qBAAqB;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"useNotifications.d.ts","sourceRoot":"","sources":["../../src/hooks/useNotifications.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAG9E;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,GAAI,WAAW,qBAAqB;;;;;;;;;;;;;gCAsF3D,MAAM,eACG,MAAM,aACR,MAAM,oBACC,MAAM,IAAI;;kCA3Df,MAAM,aACR,MAAM,oBACC,MAAM,IAAI;kCA4BhB,MAAM,KAAG,MAAM,GAAG,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyG9C,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,uBAAuB,GAAI,WAAW,qBAAqB;;;;;;;;;;;;;gCAlG5D,MAAM,eACG,MAAM,aACR,MAAM,oBACC,MAAM,IAAI;;kCA3Df,MAAM,aACR,MAAM,oBACC,MAAM,IAAI;kCA4BhB,MAAM,KAAG,MAAM,GAAG,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8H9C,CAAC"}
|