analytica-frontend-lib 1.3.15 → 1.3.16

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.
@@ -1,14 +1,15 @@
1
- import { HTMLAttributes } from 'react';
1
+ import { type HTMLAttributes } from 'react';
2
2
  import type { StudentHighlightItem } from '../../hooks/useStudentsHighlight';
3
+ import { type RankingVariant } from '../shared/RankingShared';
4
+ /**
5
+ * Re-export RankingVariant as StudentRankingVariant for backwards compatibility
6
+ */
7
+ export type StudentRankingVariant = RankingVariant;
3
8
  /**
4
9
  * Re-export StudentHighlightItem as StudentRankingItem for backwards compatibility
5
10
  * and direct usage with the component
6
11
  */
7
12
  export type StudentRankingItem = Pick<StudentHighlightItem, 'position' | 'name' | 'percentage'>;
8
- /**
9
- * Card variant type
10
- */
11
- export type StudentRankingVariant = 'highlight' | 'attention';
12
13
  /**
13
14
  * Props for a single ranking card
14
15
  */
@@ -16,7 +17,7 @@ export interface RankingCardProps extends HTMLAttributes<HTMLDivElement> {
16
17
  /** Card title */
17
18
  title: string;
18
19
  /** Card variant: highlight (best students) or attention (needs attention) */
19
- variant: StudentRankingVariant;
20
+ variant: RankingVariant;
20
21
  /** List of students to display */
21
22
  students: StudentRankingItem[];
22
23
  }
@@ -43,7 +44,6 @@ export interface StudentRankingProps extends HTMLAttributes<HTMLDivElement> {
43
44
  *
44
45
  * @example
45
46
  * ```tsx
46
- * // Basic usage with static data
47
47
  * <StudentRanking
48
48
  * highlightTitle="Estudantes em destaque"
49
49
  * attentionTitle="Estudantes precisando de atenção"
@@ -59,34 +59,6 @@ export interface StudentRankingProps extends HTMLAttributes<HTMLDivElement> {
59
59
  * ]}
60
60
  * />
61
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: '1_MONTH' });
78
- * }, [fetchStudentsHighlight]);
79
- *
80
- * if (loading) return <Skeleton />;
81
- *
82
- * return (
83
- * <StudentRanking
84
- * highlightStudents={topStudents}
85
- * attentionStudents={bottomStudents}
86
- * />
87
- * );
88
- * }
89
- * ```
90
62
  */
91
63
  export declare const StudentRanking: ({ highlightTitle, attentionTitle, highlightStudents, attentionStudents, className, ...props }: StudentRankingProps) => import("react/jsx-runtime").JSX.Element;
92
64
  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;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
+ {"version":3,"file":"StudentRanking.d.ts","sourceRoot":"","sources":["../../../src/components/StudentRanking/StudentRanking.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,OAAO,CAAC;AAI5C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AAC7E,OAAO,EACL,KAAK,cAAc,EAMpB,MAAM,yBAAyB,CAAC;AAEjC;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG,cAAc,CAAC;AAEnD;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG,IAAI,CACnC,oBAAoB,EACpB,UAAU,GAAG,MAAM,GAAG,YAAY,CACnC,CAAC;AA6DF;;GAEG;AACH,MAAM,WAAW,gBAAiB,SAAQ,cAAc,CAAC,cAAc,CAAC;IACtE,iBAAiB;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,6EAA6E;IAC7E,OAAO,EAAE,cAAc,CAAC;IACxB,kCAAkC;IAClC,QAAQ,EAAE,kBAAkB,EAAE,CAAC;CAChC;AAED;;GAEG;AACH,eAAO,MAAM,WAAW,GAAI,mDAMzB,gBAAgB,4CAelB,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;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,cAAc,GAAI,+FAO5B,mBAAmB,4CAerB,CAAC;AAEF,eAAe,cAAc,CAAC"}
@@ -25,7 +25,7 @@ __export(StudentRanking_exports, {
25
25
  default: () => StudentRanking_default
26
26
  });
27
27
  module.exports = __toCommonJS(StudentRanking_exports);
28
- var import_phosphor_react = require("phosphor-react");
28
+ var import_phosphor_react2 = require("phosphor-react");
29
29
 
30
30
  // src/utils/utils.ts
31
31
  var import_clsx = require("clsx");
@@ -85,7 +85,8 @@ var Text = ({
85
85
  };
86
86
  var Text_default = Text;
87
87
 
88
- // src/components/StudentRanking/StudentRanking.tsx
88
+ // src/components/shared/RankingShared.tsx
89
+ var import_phosphor_react = require("phosphor-react");
89
90
  var import_jsx_runtime2 = require("react/jsx-runtime");
90
91
  var CARD_BACKGROUND_CLASSES = {
91
92
  highlight: {
@@ -107,18 +108,88 @@ var PERCENTAGE_BADGE_CLASSES = {
107
108
  highlight: "bg-success-700",
108
109
  attention: "bg-indicator-negative"
109
110
  };
110
- var HEADER_BADGE_CLASSES = {
111
- highlight: "bg-indicator-positive",
112
- attention: "bg-indicator-negative"
113
- };
111
+ var HEADER_BADGE_CLASSES = BADGE_BACKGROUND_CLASSES;
114
112
  var getPositionBackgroundClass = (variant, position) => {
115
113
  const positionKey = Math.max(1, Math.min(position, 3));
116
114
  return CARD_BACKGROUND_CLASSES[variant][positionKey];
117
115
  };
118
- var StudentCard = ({ student, variant }) => {
119
- const TrendIcon = variant === "highlight" ? import_phosphor_react.TrendUp : import_phosphor_react.TrendDown;
120
- const backgroundClass = getPositionBackgroundClass(variant, student.position);
116
+ function BaseRankingCard({
117
+ title,
118
+ variant,
119
+ items,
120
+ renderItem,
121
+ headerIcon,
122
+ className,
123
+ ...props
124
+ }) {
125
+ const DefaultIcon = variant === "highlight" ? import_phosphor_react.Trophy : import_phosphor_react.Warning;
121
126
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
127
+ "div",
128
+ {
129
+ className: cn(
130
+ "flex flex-col flex-1 min-h-[254px] p-5 gap-4 bg-background border border-border-50 rounded-xl",
131
+ className
132
+ ),
133
+ ...props,
134
+ children: [
135
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-row justify-between items-center h-6 gap-4", children: [
136
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
137
+ Text_default,
138
+ {
139
+ as: "h3",
140
+ size: "lg",
141
+ weight: "bold",
142
+ className: "text-text-950 tracking-[0.2px]",
143
+ children: title
144
+ }
145
+ ),
146
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
147
+ "span",
148
+ {
149
+ className: cn(
150
+ "w-6 h-6 rounded-full flex items-center justify-center",
151
+ HEADER_BADGE_CLASSES[variant]
152
+ ),
153
+ children: headerIcon ?? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
154
+ DefaultIcon,
155
+ {
156
+ size: 14,
157
+ weight: "fill",
158
+ className: variant === "highlight" ? "text-text-950" : "text-text"
159
+ }
160
+ )
161
+ }
162
+ )
163
+ ] }),
164
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex flex-col gap-2", children: items.map((item, index) => renderItem(item, variant, index)) })
165
+ ]
166
+ }
167
+ );
168
+ }
169
+ function RankingLayout({
170
+ children,
171
+ className,
172
+ ...props
173
+ }) {
174
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
175
+ "div",
176
+ {
177
+ className: cn("flex flex-col md:flex-row w-full gap-4", className),
178
+ ...props,
179
+ children
180
+ }
181
+ );
182
+ }
183
+
184
+ // src/components/StudentRanking/StudentRanking.tsx
185
+ var import_jsx_runtime3 = require("react/jsx-runtime");
186
+ var StudentCard = ({
187
+ student,
188
+ variant
189
+ }) => {
190
+ const TrendIcon = variant === "highlight" ? import_phosphor_react2.TrendUp : import_phosphor_react2.TrendDown;
191
+ const backgroundClass = getPositionBackgroundClass(variant, student.position);
192
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
122
193
  "div",
123
194
  {
124
195
  className: cn(
@@ -126,7 +197,7 @@ var StudentCard = ({ student, variant }) => {
126
197
  backgroundClass
127
198
  ),
128
199
  children: [
129
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
200
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
130
201
  Text_default,
131
202
  {
132
203
  size: "xs",
@@ -139,7 +210,7 @@ var StudentCard = ({ student, variant }) => {
139
210
  children: student.position
140
211
  }
141
212
  ),
142
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
213
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
143
214
  Text_default,
144
215
  {
145
216
  size: "sm",
@@ -148,7 +219,7 @@ var StudentCard = ({ student, variant }) => {
148
219
  children: student.name
149
220
  }
150
221
  ),
151
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
222
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
152
223
  Text_default,
153
224
  {
154
225
  size: "xs",
@@ -159,7 +230,7 @@ var StudentCard = ({ student, variant }) => {
159
230
  PERCENTAGE_BADGE_CLASSES[variant]
160
231
  ),
161
232
  children: [
162
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(TrendIcon, { size: 16, weight: "bold", "aria-hidden": "true" }),
233
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TrendIcon, { size: 16, weight: "bold", "aria-hidden": "true" }),
163
234
  student.percentage,
164
235
  "%"
165
236
  ]
@@ -175,58 +246,24 @@ var RankingCard = ({
175
246
  students,
176
247
  className,
177
248
  ...props
178
- }) => {
179
- const HeaderIcon = variant === "highlight" ? import_phosphor_react.Trophy : import_phosphor_react.Warning;
180
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
181
- "div",
182
- {
183
- className: cn(
184
- "flex flex-col flex-1 min-h-[254px] p-5 gap-4 bg-background border border-border-50 rounded-xl",
185
- className
186
- ),
187
- ...props,
188
- children: [
189
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-row justify-between items-center h-6 gap-4", children: [
190
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
191
- Text_default,
192
- {
193
- as: "h3",
194
- size: "lg",
195
- weight: "bold",
196
- className: "text-text-950 tracking-[0.2px]",
197
- children: title
198
- }
199
- ),
200
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
201
- "span",
202
- {
203
- className: cn(
204
- "w-6 h-6 rounded-full flex items-center justify-center",
205
- HEADER_BADGE_CLASSES[variant]
206
- ),
207
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
208
- HeaderIcon,
209
- {
210
- size: 14,
211
- weight: "fill",
212
- className: variant === "highlight" ? "text-text-950" : "text-text"
213
- }
214
- )
215
- }
216
- )
217
- ] }),
218
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex flex-col gap-2", children: students.map((student, index) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
219
- StudentCard,
220
- {
221
- student,
222
- variant
223
- },
224
- `${variant}-${index}-${student.position}`
225
- )) })
226
- ]
227
- }
228
- );
229
- };
249
+ }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
250
+ BaseRankingCard,
251
+ {
252
+ title,
253
+ variant,
254
+ items: students,
255
+ renderItem: (student, v, index) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
256
+ StudentCard,
257
+ {
258
+ student,
259
+ variant: v
260
+ },
261
+ `${v}-${index}-${student.position}`
262
+ ),
263
+ className,
264
+ ...props
265
+ }
266
+ );
230
267
  var StudentRanking = ({
231
268
  highlightTitle = "Estudantes em destaque",
232
269
  attentionTitle = "Estudantes precisando de aten\xE7\xE3o",
@@ -235,31 +272,24 @@ var StudentRanking = ({
235
272
  className,
236
273
  ...props
237
274
  }) => {
238
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
239
- "div",
240
- {
241
- className: cn("flex flex-col md:flex-row w-full gap-4", className),
242
- ...props,
243
- children: [
244
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
245
- RankingCard,
246
- {
247
- title: highlightTitle,
248
- variant: "highlight",
249
- students: highlightStudents
250
- }
251
- ),
252
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
253
- RankingCard,
254
- {
255
- title: attentionTitle,
256
- variant: "attention",
257
- students: attentionStudents
258
- }
259
- )
260
- ]
261
- }
262
- );
275
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(RankingLayout, { className, ...props, children: [
276
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
277
+ RankingCard,
278
+ {
279
+ title: highlightTitle,
280
+ variant: "highlight",
281
+ students: highlightStudents
282
+ }
283
+ ),
284
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
285
+ RankingCard,
286
+ {
287
+ title: attentionTitle,
288
+ variant: "attention",
289
+ students: attentionStudents
290
+ }
291
+ )
292
+ ] });
263
293
  };
264
294
  var StudentRanking_default = StudentRanking;
265
295
  // Annotate the CommonJS export names for ESM import in node:
@@ -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';\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: '1_MONTH' });\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
+ {"version":3,"sources":["../../src/components/StudentRanking/StudentRanking.tsx","../../src/utils/utils.ts","../../src/components/Text/Text.tsx","../../src/components/shared/RankingShared.tsx"],"sourcesContent":["import { type HTMLAttributes } from 'react';\nimport { TrendUp, TrendDown } from 'phosphor-react';\nimport Text from '../Text/Text';\nimport { cn } from '../../utils/utils';\nimport type { StudentHighlightItem } from '../../hooks/useStudentsHighlight';\nimport {\n type RankingVariant,\n BADGE_BACKGROUND_CLASSES,\n PERCENTAGE_BADGE_CLASSES,\n getPositionBackgroundClass,\n BaseRankingCard,\n RankingLayout,\n} from '../shared/RankingShared';\n\n/**\n * Re-export RankingVariant as StudentRankingVariant for backwards compatibility\n */\nexport type StudentRankingVariant = RankingVariant;\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 * Individual student card component\n */\nconst StudentCard = ({\n student,\n variant,\n}: {\n student: StudentRankingItem;\n variant: RankingVariant;\n}) => {\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: RankingVariant;\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 <BaseRankingCard\n title={title}\n variant={variant}\n items={students}\n renderItem={(student, v, index) => (\n <StudentCard\n key={`${v}-${index}-${student.position}`}\n student={student}\n variant={v}\n />\n )}\n className={className}\n {...props}\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 <RankingLayout className={className} {...props}>\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 </RankingLayout>\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","import { type HTMLAttributes, type ReactNode } from 'react';\nimport { Trophy, Warning } from 'phosphor-react';\nimport Text from '../Text/Text';\nimport { cn } from '../../utils/utils';\n\n/**\n * Shared ranking variant type\n */\nexport type RankingVariant = 'highlight' | 'attention';\n\n/**\n * Card background colors by position (1 = most intense, 3+ = lightest)\n */\nexport const 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 * Position badge background colors\n */\nexport const BADGE_BACKGROUND_CLASSES = {\n highlight: 'bg-indicator-positive',\n attention: 'bg-indicator-negative',\n} as const;\n\n/**\n * Percentage badge background colors\n */\nexport const PERCENTAGE_BADGE_CLASSES = {\n highlight: 'bg-success-700',\n attention: 'bg-indicator-negative',\n} as const;\n\n/** Header icon badge uses the same palette as position badges */\nexport const HEADER_BADGE_CLASSES = BADGE_BACKGROUND_CLASSES;\n\n/**\n * Get background class based on position (1, 2, or 3+)\n */\nexport const getPositionBackgroundClass = (\n variant: RankingVariant,\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 * Generic ranking card wrapper — renders a header (title + icon badge)\n * followed by a list of items using the provided render function.\n */\nexport interface BaseRankingCardProps<T>\n extends HTMLAttributes<HTMLDivElement> {\n title: string;\n variant: RankingVariant;\n items: T[];\n renderItem: (item: T, variant: RankingVariant, index: number) => ReactNode;\n /** Override the default header icon (Trophy/Warning) */\n headerIcon?: ReactNode;\n}\n\nexport function BaseRankingCard<T>({\n title,\n variant,\n items,\n renderItem,\n headerIcon,\n className,\n ...props\n}: Readonly<BaseRankingCardProps<T>>) {\n const DefaultIcon = 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 <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 <DefaultIcon\n size={14}\n weight=\"fill\"\n className={\n variant === 'highlight' ? 'text-text-950' : 'text-text'\n }\n />\n )}\n </span>\n </div>\n\n {/* Items list */}\n <div className=\"flex flex-col gap-2\">\n {items.map((item, index) => renderItem(item, variant, index))}\n </div>\n </div>\n );\n}\n\n/**\n * Two-card side-by-side responsive layout for ranking components\n */\nexport interface RankingLayoutProps extends HTMLAttributes<HTMLDivElement> {\n children: ReactNode;\n}\n\nexport function RankingLayout({\n children,\n className,\n ...props\n}: Readonly<RankingLayoutProps>) {\n return (\n <div\n className={cn('flex flex-col md:flex-row w-full gap-4', className)}\n {...props}\n >\n {children}\n </div>\n );\n}\n"],"mappings":"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","names":["import_phosphor_react","import_jsx_runtime","import_jsx_runtime"]}