academe-kit 0.9.8 → 0.10.0

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.
@@ -16,6 +16,7 @@ export { useProtectedAppColors } from "./components/ProtectedApp";
16
16
  export type { AcademeKeycloakContextProps, SecurityProviderProps, KeycloakUser, SecurityContextType, AcademeUser, } from "./context/SecurityProvider/types";
17
17
  export { createAcademeApiClient } from "./services";
18
18
  export type { AcademeApiClient, AcademeServices } from "./services";
19
+ export type { ChallengeUserQuizAttempt, ChallengeUserQuizAttemptsResponse, } from "./services/ChallengeService";
19
20
  export { cn } from "./lib/utils";
20
21
  import "./index.css";
21
22
  import "./styles/globals.css";
@@ -28,6 +28,35 @@ export interface UpdateEvaluationCriterionBody {
28
28
  description?: string;
29
29
  index?: number;
30
30
  }
31
+ export interface ChallengeUserQuizAttempt {
32
+ challengeStepId: string;
33
+ challengeStepName: string;
34
+ challengeStepIndex: number;
35
+ courseModuleId: string;
36
+ courseModuleTitle: string;
37
+ quizId: string;
38
+ quizTitle: string;
39
+ attempt: {
40
+ id: string;
41
+ score: number;
42
+ passed: boolean;
43
+ startedAt: string;
44
+ completedAt: string | null;
45
+ } | null;
46
+ certificate: {
47
+ id: string;
48
+ certificateNumber: string;
49
+ url: string | null;
50
+ } | null;
51
+ }
52
+ export interface ChallengeUserQuizAttemptsResponse {
53
+ data?: {
54
+ status?: string;
55
+ data?: ChallengeUserQuizAttempt[];
56
+ };
57
+ error?: unknown;
58
+ response: Response;
59
+ }
31
60
  export declare function createChallengeService(apiClient: AcademeApiClient): {
32
61
  /**
33
62
  * List challenges with filters and pagination
@@ -339,6 +368,12 @@ export declare function createChallengeService(apiClient: AcademeApiClient): {
339
368
  title?: string;
340
369
  };
341
370
  }, `${string}/${string}`>>;
371
+ /**
372
+ * Get a user's quiz attempts for the quizzes attached to this challenge's
373
+ * course modules (one entry per step with course_module.quiz_id).
374
+ * Defaults to the authenticated user when userId is omitted.
375
+ */
376
+ getUserQuizAttempts(challengeId: string, userId?: string): Promise<ChallengeUserQuizAttemptsResponse>;
342
377
  /**
343
378
  * Add a step to the challenge
344
379
  */
@@ -570,6 +570,81 @@ export declare function createReportService(apiClient: AcademeApiClient): {
570
570
  query: GetTopStudentsParams;
571
571
  };
572
572
  }, `${string}/${string}`>>;
573
+ /**
574
+ * Get encourage dashboard for an institution
575
+ * Retorna o payload agregado da tela /new-dashboard:
576
+ * overview (com lista de períodos do ano letivo + flag isAllPeriods),
577
+ * KPIs, licenças (alunos), jornada (cursos do bimestre selecionado ou do
578
+ * ano letivo quando allPeriods), submissões do bimestre corrente,
579
+ * desempenho por turma, top alunos e top professores do bimestre.
580
+ *
581
+ * @param id UUID da instituição.
582
+ * @param params.periodId UUID do educational_model_period. Quando omitido,
583
+ * o backend resolve para o período corrente (NOW).
584
+ * Ignorado quando allPeriods=true.
585
+ * @param params.allPeriods Quando true, desliga o recorte por período em
586
+ * Jornada/Classes/TopTeachers — passa a refletir
587
+ * o ano letivo inteiro. SubmissionsCard continua
588
+ * sempre no bimestre corrente.
589
+ */
590
+ getEncourageDashboardByInstitution(id: string, params?: {
591
+ periodId?: string;
592
+ allPeriods?: boolean;
593
+ }): Promise<import("openapi-fetch").FetchResponse<{
594
+ parameters: {
595
+ query?: {
596
+ periodId?: string;
597
+ allPeriods?: "true";
598
+ };
599
+ header?: never;
600
+ path: {
601
+ id: string;
602
+ };
603
+ cookie?: never;
604
+ };
605
+ requestBody?: never;
606
+ responses: {
607
+ 200: {
608
+ headers: {
609
+ [name: string]: unknown;
610
+ };
611
+ content: {
612
+ "application/json": {
613
+ status?: string;
614
+ data?: import("../types/academe-api").components["schemas"]["EncourageDashboardResponse"];
615
+ };
616
+ };
617
+ };
618
+ 400: {
619
+ headers: {
620
+ [name: string]: unknown;
621
+ };
622
+ content?: never;
623
+ };
624
+ 401: {
625
+ headers: {
626
+ [name: string]: unknown;
627
+ };
628
+ content?: never;
629
+ };
630
+ 500: {
631
+ headers: {
632
+ [name: string]: unknown;
633
+ };
634
+ content?: never;
635
+ };
636
+ };
637
+ }, {
638
+ params: {
639
+ path: {
640
+ id: string;
641
+ };
642
+ query: {
643
+ periodId?: string;
644
+ allPeriods?: "true";
645
+ } | undefined;
646
+ };
647
+ }, `${string}/${string}`>>;
573
648
  };
574
649
  export type ReportService = ReturnType<typeof createReportService>;
575
650
  export {};
@@ -37,7 +37,14 @@ export declare function createSubmissionService(apiClient: AcademeApiClient): {
37
37
  "application/json": {
38
38
  status?: string;
39
39
  data?: import("../types/academe-api").components["schemas"]["Submission"][];
40
- meta?: import("../types/academe-api").components["schemas"]["PaginationMeta"];
40
+ meta?: import("../types/academe-api").components["schemas"]["PaginationMeta"] & {
41
+ statusCounts?: {
42
+ submitted?: number;
43
+ ai_evaluated?: number;
44
+ approved?: number;
45
+ rejected?: number;
46
+ };
47
+ };
41
48
  };
42
49
  };
43
50
  };
@@ -2790,6 +2790,91 @@ export interface paths {
2790
2790
  };
2791
2791
  trace?: never;
2792
2792
  };
2793
+ "/challenges/{id}/quiz-attempts": {
2794
+ parameters: {
2795
+ query?: never;
2796
+ header?: never;
2797
+ path?: never;
2798
+ cookie?: never;
2799
+ };
2800
+ /**
2801
+ * Get a user's quiz attempts for this challenge's course modules
2802
+ * @description Returns the quiz attempts of `userId` on every quiz attached to a course
2803
+ * module that is referenced by one of this challenge's steps. Optionally
2804
+ * includes the issued certificate per attempt.
2805
+ *
2806
+ * Each entry corresponds to a `challenges_steps` row that has a non-null
2807
+ * `course_module_id` whose `course_module.quiz_id` is also non-null.
2808
+ * `attempt` is `null` when the user has not yet attempted that quiz.
2809
+ */
2810
+ get: {
2811
+ parameters: {
2812
+ query?: {
2813
+ /** @description Defaults to the authenticated user when omitted. */
2814
+ userId?: string;
2815
+ };
2816
+ header?: never;
2817
+ path: {
2818
+ /** @description Resource ID */
2819
+ id: components["parameters"]["id"];
2820
+ };
2821
+ cookie?: never;
2822
+ };
2823
+ requestBody?: never;
2824
+ responses: {
2825
+ /** @description List of quiz attempts (one per quiz-bearing challenge step) */
2826
+ 200: {
2827
+ headers: {
2828
+ [name: string]: unknown;
2829
+ };
2830
+ content: {
2831
+ "application/json": {
2832
+ /** @example success */
2833
+ status?: string;
2834
+ data?: {
2835
+ /** Format: uuid */
2836
+ challengeStepId?: string;
2837
+ challengeStepName?: string;
2838
+ challengeStepIndex?: number;
2839
+ /** Format: uuid */
2840
+ courseModuleId?: string;
2841
+ courseModuleTitle?: string;
2842
+ /** Format: uuid */
2843
+ quizId?: string;
2844
+ quizTitle?: string;
2845
+ attempt?: {
2846
+ /** Format: uuid */
2847
+ id?: string;
2848
+ score?: number;
2849
+ passed?: boolean;
2850
+ /** Format: date-time */
2851
+ startedAt?: string;
2852
+ /** Format: date-time */
2853
+ completedAt?: string | null;
2854
+ } | null;
2855
+ certificate?: {
2856
+ /** Format: uuid */
2857
+ id?: string;
2858
+ certificateNumber?: string;
2859
+ url?: string | null;
2860
+ } | null;
2861
+ }[];
2862
+ };
2863
+ };
2864
+ };
2865
+ 400: components["responses"]["BadRequest"];
2866
+ 401: components["responses"]["Unauthorized"];
2867
+ 404: components["responses"]["NotFound"];
2868
+ };
2869
+ };
2870
+ put?: never;
2871
+ post?: never;
2872
+ delete?: never;
2873
+ options?: never;
2874
+ head?: never;
2875
+ patch?: never;
2876
+ trace?: never;
2877
+ };
2793
2878
  "/classrooms": {
2794
2879
  parameters: {
2795
2880
  query?: never;
@@ -10559,7 +10644,12 @@ export interface paths {
10559
10644
  */
10560
10645
  get: {
10561
10646
  parameters: {
10562
- query?: never;
10647
+ query?: {
10648
+ /** @description UUID do educational_model_period. Quando omitido, o backend resolve para o período corrente (NOW). Ignorado quando allPeriods=true. */
10649
+ periodId?: string;
10650
+ /** @description Quando 'true', desliga o recorte por período em Jornada/Classes/TopTeachers — passa a refletir o ano letivo inteiro. SubmissionsCard continua sempre no bimestre corrente. */
10651
+ allPeriods?: "true";
10652
+ };
10563
10653
  header?: never;
10564
10654
  path: {
10565
10655
  /** @description ID da instituição */
@@ -11619,7 +11709,22 @@ export interface paths {
11619
11709
  /** @example success */
11620
11710
  status?: string;
11621
11711
  data?: components["schemas"]["Submission"][];
11622
- meta?: components["schemas"]["PaginationMeta"];
11712
+ meta?: components["schemas"]["PaginationMeta"] & {
11713
+ /**
11714
+ * @description Contagem por status, ignorando o filtro `status`. Útil para
11715
+ * alimentar abas/pills sem requisições adicionais.
11716
+ */
11717
+ statusCounts?: {
11718
+ /** @example 12 */
11719
+ submitted?: number;
11720
+ /** @example 4 */
11721
+ ai_evaluated?: number;
11722
+ /** @example 30 */
11723
+ approved?: number;
11724
+ /** @example 2 */
11725
+ rejected?: number;
11726
+ };
11727
+ };
11623
11728
  };
11624
11729
  };
11625
11730
  };
@@ -12281,6 +12386,128 @@ export interface paths {
12281
12386
  patch?: never;
12282
12387
  trace?: never;
12283
12388
  };
12389
+ "/user-challenge-progress/journey": {
12390
+ parameters: {
12391
+ query?: never;
12392
+ header?: never;
12393
+ path?: never;
12394
+ cookie?: never;
12395
+ };
12396
+ /**
12397
+ * Jornada completa pré-computada do aluno autenticado
12398
+ * @description Retorna todos os desafios da série com suas etapas e o status de progresso do aluno
12399
+ * já computados pelo backend. Substitui as ~25 chamadas HTTP paralelas que o frontend
12400
+ * fazia anteriormente para montar a tela de jornada.
12401
+ *
12402
+ * **Regra de prioridade:** para cada `index` de desafio dentro da série, o backend
12403
+ * prefere o challenge específico da instituição do aluno sobre o template global
12404
+ * (`institution_id IS NULL`). Isso permite que escolas customizem desafios pontuais
12405
+ * sem recriar toda a jornada.
12406
+ *
12407
+ * **Resolução da série:** se `serieId` não for informado, o backend resolve
12408
+ * automaticamente a partir da turma (`institutionClassroom`) do aluno. Se o aluno
12409
+ * não estiver em nenhuma turma e `serieId` também não for passado, retorna
12410
+ * `challenges: []` com `serieId: null`.
12411
+ *
12412
+ * **Status por etapa:** `done` = completedAt preenchido; `current` = primeira etapa
12413
+ * não concluída (apenas uma por vez); `locked` = todas as demais.
12414
+ *
12415
+ * **Progresso:** para etapas `type=course` no status `current`, o campo `progress`
12416
+ * reflete o percentual de lições concluídas no módulo. Para `done` é sempre 100,
12417
+ * para `locked` é sempre 0.
12418
+ */
12419
+ get: {
12420
+ parameters: {
12421
+ query?: {
12422
+ /**
12423
+ * @description ID da série a filtrar. Opcional — se omitido, o backend resolve pela turma do aluno.
12424
+ * Útil para pré-visualização administrativa ou quando o aluno pertence a múltiplas séries.
12425
+ */
12426
+ serieId?: string;
12427
+ };
12428
+ header?: never;
12429
+ path?: never;
12430
+ cookie?: never;
12431
+ };
12432
+ requestBody?: never;
12433
+ responses: {
12434
+ /** @description Jornada pré-computada com desafios e etapas */
12435
+ 200: {
12436
+ headers: {
12437
+ [name: string]: unknown;
12438
+ };
12439
+ content: {
12440
+ /**
12441
+ * @example {
12442
+ * "status": "success",
12443
+ * "data": {
12444
+ * "serieId": "a1b2c3d4-0000-0000-0000-000000000001",
12445
+ * "serieLabel": "6º ANO",
12446
+ * "challenges": [
12447
+ * {
12448
+ * "id": "a1b2c3d4-0000-0000-0000-000000000002",
12449
+ * "title": "Desafio 1 — Energia Limpa",
12450
+ * "index": 0,
12451
+ * "courseId": "a1b2c3d4-0000-0000-0000-000000000003",
12452
+ * "isUpcoming": false,
12453
+ * "steps": [
12454
+ * {
12455
+ * "id": "a1b2c3d4-0000-0000-0000-000000000010",
12456
+ * "name": "Inicie o desafio",
12457
+ * "index": 0,
12458
+ * "type": "challenge",
12459
+ * "color": "#1AC84A",
12460
+ * "icon": "LuStar",
12461
+ * "status": "done",
12462
+ * "progress": 100,
12463
+ * "courseModuleId": null,
12464
+ * "courseModuleName": null
12465
+ * },
12466
+ * {
12467
+ * "id": "a1b2c3d4-0000-0000-0000-000000000011",
12468
+ * "name": "Módulo de IA",
12469
+ * "index": 1,
12470
+ * "type": "course",
12471
+ * "color": "#8030D8",
12472
+ * "icon": "LuCirclePlay",
12473
+ * "status": "current",
12474
+ * "progress": 67,
12475
+ * "courseModuleId": "a1b2c3d4-0000-0000-0000-000000000020",
12476
+ * "courseModuleName": "Introdução a IA"
12477
+ * }
12478
+ * ]
12479
+ * }
12480
+ * ]
12481
+ * }
12482
+ * }
12483
+ */
12484
+ "application/json": {
12485
+ /** @example success */
12486
+ status?: string;
12487
+ data?: components["schemas"]["JourneyView"];
12488
+ };
12489
+ };
12490
+ };
12491
+ /** @description serieId inválido (não é um UUID) */
12492
+ 400: {
12493
+ headers: {
12494
+ [name: string]: unknown;
12495
+ };
12496
+ content: {
12497
+ "application/json": components["schemas"]["Error"];
12498
+ };
12499
+ };
12500
+ 401: components["responses"]["Unauthorized"];
12501
+ };
12502
+ };
12503
+ put?: never;
12504
+ post?: never;
12505
+ delete?: never;
12506
+ options?: never;
12507
+ head?: never;
12508
+ patch?: never;
12509
+ trace?: never;
12510
+ };
12284
12511
  "/user-challenge-progress/challenges/{id}/advance": {
12285
12512
  parameters: {
12286
12513
  query?: never;
@@ -15145,6 +15372,99 @@ export interface components {
15145
15372
  /** Format: date-time */
15146
15373
  updatedAt?: string;
15147
15374
  };
15375
+ /** @description Etapa de um desafio com status computado pelo backend */
15376
+ JourneyStepView: {
15377
+ /**
15378
+ * Format: uuid
15379
+ * @description ID do challenge_step
15380
+ */
15381
+ id: string;
15382
+ /** @example Módulo de IA */
15383
+ name: string;
15384
+ /**
15385
+ * @description Ordem da etapa dentro do desafio
15386
+ * @example 1
15387
+ */
15388
+ index: number;
15389
+ /**
15390
+ * @description Tipo da etapa (do catálogo de steps)
15391
+ * @example course
15392
+ * @enum {string}
15393
+ */
15394
+ type: "challenge" | "course" | "tutorial" | "publication" | "evaluation" | "certificate";
15395
+ /**
15396
+ * @description Cor hex do step catalog
15397
+ * @example #8030D8
15398
+ */
15399
+ color: string;
15400
+ /**
15401
+ * @description Nome do ícone Lucide do step catalog
15402
+ * @example LuCirclePlay
15403
+ */
15404
+ icon: string;
15405
+ /**
15406
+ * @description Status computado pelo backend: done=concluído, current=etapa ativa, locked=ainda bloqueado
15407
+ * @example current
15408
+ * @enum {string}
15409
+ */
15410
+ status: "done" | "current" | "locked";
15411
+ /**
15412
+ * @description Percentual de progresso (0-100). Para done=100, para locked=0, para current=% do curso ou 0
15413
+ * @example 67
15414
+ */
15415
+ progress: number;
15416
+ /**
15417
+ * Format: uuid
15418
+ * @description ID do módulo do curso referenciado por esta etapa (apenas quando type=course)
15419
+ */
15420
+ courseModuleId?: string | null;
15421
+ /**
15422
+ * @description Título do módulo do curso (apenas quando courseModuleId não é null)
15423
+ * @example Introdução a IA
15424
+ */
15425
+ courseModuleName?: string | null;
15426
+ };
15427
+ /** @description Desafio da jornada com suas etapas e status computados */
15428
+ JourneyChallengeView: {
15429
+ /**
15430
+ * Format: uuid
15431
+ * @description ID do challenge
15432
+ */
15433
+ id: string;
15434
+ /** @example Desafio 1 — Energia Limpa */
15435
+ title: string;
15436
+ /**
15437
+ * @description Ordem do desafio na série
15438
+ * @example 0
15439
+ */
15440
+ index: number;
15441
+ /**
15442
+ * Format: uuid
15443
+ * @description Curso ao qual o desafio está associado
15444
+ */
15445
+ courseId: string;
15446
+ /**
15447
+ * @description True quando o desafio ainda não está disponível para o aluno (challenge seguinte ao ativo com steps pendentes)
15448
+ * @example false
15449
+ */
15450
+ isUpcoming: boolean;
15451
+ steps: components["schemas"]["JourneyStepView"][];
15452
+ };
15453
+ /** @description Resposta completa do endpoint GET /user-challenge-progress/journey — dados pré-computados para renderização direta da tela de jornada */
15454
+ JourneyView: {
15455
+ /** @description Desafios da jornada ordenados por index, com prioridade escola > template aplicada */
15456
+ challenges: components["schemas"]["JourneyChallengeView"][];
15457
+ /**
15458
+ * Format: uuid
15459
+ * @description ID da série resolvida (da turma do aluno, ou do query param serieId)
15460
+ */
15461
+ serieId: string | null;
15462
+ /**
15463
+ * @description Rótulo legível da série para exibição na UI
15464
+ * @example 6º ANO
15465
+ */
15466
+ serieLabel: string | null;
15467
+ };
15148
15468
  /** @description Aggregated progress of a user on a course or module, derived from users_course_log completion events */
15149
15469
  UsersCourseLogProgress: {
15150
15470
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "academe-kit",
3
- "version": "0.9.8",
3
+ "version": "0.10.0",
4
4
  "type": "module",
5
5
  "description": "Official React SDK for Academe ecosystem - Authentication, protected routes, API services, and UI components for educational management applications",
6
6
  "main": "dist/index.cjs",
@@ -99,4 +99,4 @@
99
99
  "tailwind-merge": "^3.3.1",
100
100
  "tailwindcss-animate": "^1.0.7"
101
101
  }
102
- }
102
+ }