@crimson-education/sdk 0.2.5 → 0.3.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.
- package/README.md +155 -2
- package/dist/core/account.d.ts +16 -1
- package/dist/core/account.js +19 -0
- package/dist/core/client.d.ts +4 -0
- package/dist/core/client.js +5 -1
- package/dist/core/gradeTemplates.d.ts +117 -0
- package/dist/core/gradeTemplates.js +98 -0
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.js +4 -1
- package/dist/core/indigo.d.ts +103 -0
- package/dist/core/indigo.js +127 -0
- package/dist/core/types.d.ts +100 -0
- package/dist/react/hooks/index.d.ts +3 -1
- package/dist/react/hooks/index.js +21 -1
- package/dist/react/hooks/useGradeTemplates.d.ts +24 -0
- package/dist/react/hooks/useGradeTemplates.js +97 -0
- package/dist/react/hooks/useIndigo.d.ts +112 -0
- package/dist/react/hooks/useIndigo.js +160 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -231,6 +231,100 @@ SDK 会将后端返回的 action item 做归一化,保证至少返回以下核
|
|
|
231
231
|
- `getMissionById(missionId: string): Promise<MissionDetail | null>`
|
|
232
232
|
- 注意:当后端返回非 2xx(例如 404)时,SDK 会抛异常;建议使用 `try/catch` 处理。
|
|
233
233
|
|
|
234
|
+
### 7) AccountApi(`client.account`)
|
|
235
|
+
|
|
236
|
+
涉及接口:
|
|
237
|
+
|
|
238
|
+
- `GET /api/v1/account/me/roles`
|
|
239
|
+
- `GET /api/v1/account/me/students`
|
|
240
|
+
- `GET /api/v1/account/me/profile`
|
|
241
|
+
|
|
242
|
+
主要方法:
|
|
243
|
+
|
|
244
|
+
- `getCurrentUserRoles(): Promise<CurrentUserRoles>`
|
|
245
|
+
- 获取当前用户的角色列表
|
|
246
|
+
- 返回 `{ userId, roles: [{ roleId, isPrimary }] }`
|
|
247
|
+
- `getMyStudents(): Promise<StudentSummary[]>`
|
|
248
|
+
- 获取当前用户关联的学生列表(主要用于 Staff 用户)
|
|
249
|
+
- 返回学生基本信息:`userId`, `firstName`, `lastName`, `email`, `profileImageUrl`
|
|
250
|
+
- `getMyProfile(): Promise<UserProfile>`
|
|
251
|
+
- 获取当前用户的完整 Profile 信息
|
|
252
|
+
- 返回字段:
|
|
253
|
+
- `userId`, `email`, `firstName`, `lastName`
|
|
254
|
+
- `nickname` - 首选名称
|
|
255
|
+
- `name` - 完整显示名
|
|
256
|
+
- `picture` - 头像 URL
|
|
257
|
+
- `status` - 用户状态
|
|
258
|
+
- `isMultiTenant` - 是否多租户用户
|
|
259
|
+
- `roles[]` - 角色数组(支持多角色),每个包含 `roleId`, `roleName`, `isPrimary`
|
|
260
|
+
- `tenant` - 租户信息 `{ id, name }`
|
|
261
|
+
|
|
262
|
+
### 8) IndigoApi(`client.indigo`)
|
|
263
|
+
|
|
264
|
+
Indigo 专用 API,提供用户身份识别和学生-Tutor 关系查询功能。
|
|
265
|
+
|
|
266
|
+
涉及接口:
|
|
267
|
+
|
|
268
|
+
- `GET /api/v1/indigo/me`
|
|
269
|
+
- `GET /api/v1/indigo/student/tutors`
|
|
270
|
+
- `GET /api/v1/indigo/tutor/students`
|
|
271
|
+
|
|
272
|
+
> **注意**:所有 Indigo API 需要用户拥有 INDIGO 产品订阅才能访问。
|
|
273
|
+
|
|
274
|
+
主要方法:
|
|
275
|
+
|
|
276
|
+
- `getMe(): Promise<IndigoMe>`
|
|
277
|
+
- 获取当前用户的 Indigo 身份信息
|
|
278
|
+
- 返回字段:
|
|
279
|
+
- `userId`, `email`, `firstName`, `lastName`
|
|
280
|
+
- `role` - 用户角色:`"student"` 或 `"tutor"`
|
|
281
|
+
- `tenantId`, `tenantName` - 主租户信息
|
|
282
|
+
- `isMultiTenant` - 是否跨租户用户
|
|
283
|
+
- `relatedAccounts[]` - 关联账户列表(多租户场景)
|
|
284
|
+
- `getStudentTutors(): Promise<IndigoTutor[]>`
|
|
285
|
+
- 获取当前学生的 Tutor 列表
|
|
286
|
+
- 支持跨租户聚合(多租户学生可看到所有租户的 Tutor)
|
|
287
|
+
- 返回字段:`userId`, `email`, `firstName`, `lastName`, `profileImageUrl`, `contractId`, `contractStatus`, `source`
|
|
288
|
+
- `getTutorStudents(): Promise<IndigoStudent[]>`
|
|
289
|
+
- 获取当前 Tutor 的学生列表
|
|
290
|
+
- 支持跨租户聚合(多租户 Tutor 可看到所有租户的学生)
|
|
291
|
+
- 返回字段:`userId`, `email`, `firstName`, `lastName`, `profileImageUrl`, `contractId`, `contractStatus`, `source`
|
|
292
|
+
|
|
293
|
+
示例:
|
|
294
|
+
|
|
295
|
+
```ts
|
|
296
|
+
const client = createCrimsonClient({
|
|
297
|
+
apiUrl: "https://api.crimson.io",
|
|
298
|
+
clientId: "indigo-website",
|
|
299
|
+
getToken: () => localStorage.getItem("token") || "",
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
// 获取用户身份
|
|
303
|
+
const me = await client.indigo.getMe();
|
|
304
|
+
console.log(`Role: ${me.role}, Multi-tenant: ${me.isMultiTenant}`);
|
|
305
|
+
|
|
306
|
+
// 学生获取 Tutor 列表
|
|
307
|
+
if (me.role === "student") {
|
|
308
|
+
const tutors = await client.indigo.getStudentTutors();
|
|
309
|
+
tutors.forEach((t) =>
|
|
310
|
+
console.log(`${t.firstName} ${t.lastName} (${t.source})`),
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Tutor 获取学生列表(按来源分组)
|
|
315
|
+
if (me.role === "tutor") {
|
|
316
|
+
const students = await client.indigo.getTutorStudents();
|
|
317
|
+
const bySource = students.reduce(
|
|
318
|
+
(acc, s) => {
|
|
319
|
+
(acc[s.source] ||= []).push(s);
|
|
320
|
+
return acc;
|
|
321
|
+
},
|
|
322
|
+
{} as Record<string, typeof students>,
|
|
323
|
+
);
|
|
324
|
+
console.log(`Crimson App: ${bySource.crimsonapp?.length || 0} students`);
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
234
328
|
---
|
|
235
329
|
|
|
236
330
|
## iframe 层(嵌入/跨域场景)
|
|
@@ -334,6 +428,65 @@ Props:
|
|
|
334
428
|
- `useTemplateMissions/useTemplateMissionsInfinite`
|
|
335
429
|
- `useTemplateTasks/useTemplateTasksInfinite`
|
|
336
430
|
- `useTemplateMissionDetail(missionId)`
|
|
431
|
+
- Indigo 身份相关:
|
|
432
|
+
- `useIndigoMe(enabled?)` - 获取当前用户的 Indigo 身份
|
|
433
|
+
- `useStudentTutors(enabled?)` - 获取学生的 Tutor 列表
|
|
434
|
+
- `useTutorStudents(enabled?)` - 获取 Tutor 的学生列表
|
|
435
|
+
|
|
436
|
+
### Indigo Hooks 示例
|
|
437
|
+
|
|
438
|
+
```tsx
|
|
439
|
+
import {
|
|
440
|
+
useIndigoMe,
|
|
441
|
+
useStudentTutors,
|
|
442
|
+
useTutorStudents,
|
|
443
|
+
} from "@crimson-education/sdk/react";
|
|
444
|
+
|
|
445
|
+
function IndigoProfile() {
|
|
446
|
+
const { data: me, isLoading: isMeLoading } = useIndigoMe();
|
|
447
|
+
// 仅当用户是 student 时才请求 tutors
|
|
448
|
+
const { data: tutors } = useStudentTutors(me?.role === "student");
|
|
449
|
+
// 仅当用户是 tutor 时才请求 students
|
|
450
|
+
const { data: students } = useTutorStudents(me?.role === "tutor");
|
|
451
|
+
|
|
452
|
+
if (isMeLoading) return <Spinner />;
|
|
453
|
+
|
|
454
|
+
return (
|
|
455
|
+
<div>
|
|
456
|
+
<h1>
|
|
457
|
+
{me?.firstName} {me?.lastName}
|
|
458
|
+
</h1>
|
|
459
|
+
<p>Role: {me?.role}</p>
|
|
460
|
+
|
|
461
|
+
{me?.role === "student" && tutors && (
|
|
462
|
+
<section>
|
|
463
|
+
<h2>My Tutors ({tutors.length})</h2>
|
|
464
|
+
<ul>
|
|
465
|
+
{tutors.map((t) => (
|
|
466
|
+
<li key={t.contractId}>
|
|
467
|
+
{t.firstName} {t.lastName}
|
|
468
|
+
</li>
|
|
469
|
+
))}
|
|
470
|
+
</ul>
|
|
471
|
+
</section>
|
|
472
|
+
)}
|
|
473
|
+
|
|
474
|
+
{me?.role === "tutor" && students && (
|
|
475
|
+
<section>
|
|
476
|
+
<h2>My Students ({students.length})</h2>
|
|
477
|
+
<ul>
|
|
478
|
+
{students.map((s) => (
|
|
479
|
+
<li key={s.contractId}>
|
|
480
|
+
{s.firstName} {s.lastName} ({s.source})
|
|
481
|
+
</li>
|
|
482
|
+
))}
|
|
483
|
+
</ul>
|
|
484
|
+
</section>
|
|
485
|
+
)}
|
|
486
|
+
</div>
|
|
487
|
+
);
|
|
488
|
+
}
|
|
489
|
+
```
|
|
337
490
|
|
|
338
491
|
---
|
|
339
492
|
|
|
@@ -362,7 +515,7 @@ SDK 支持向后端发送客户端标识信息,用于追踪 API 调用来源
|
|
|
362
515
|
| Header | 说明 | 示例值 |
|
|
363
516
|
| ------------------- | -------------- | ------------------------- |
|
|
364
517
|
| `X-Client-ID` | 客户端应用标识 | `new-roadmap`, `capstone` |
|
|
365
|
-
| `X-Client-Version` | SDK 版本 | `0.
|
|
518
|
+
| `X-Client-Version` | SDK 版本 | `0.3.0` |
|
|
366
519
|
| `X-Client-Platform` | 运行环境 | `browser`, `node` |
|
|
367
520
|
|
|
368
521
|
### 后端日志
|
|
@@ -374,7 +527,7 @@ SDK 支持向后端发送客户端标识信息,用于追踪 API 调用来源
|
|
|
374
527
|
"type": "api_request",
|
|
375
528
|
"request_id": "uuid",
|
|
376
529
|
"client_id": "new-roadmap",
|
|
377
|
-
"client_version": "0.
|
|
530
|
+
"client_version": "0.3.0",
|
|
378
531
|
"client_platform": "browser",
|
|
379
532
|
"auth_mode": "bearer",
|
|
380
533
|
"user_id": "auth0-xxx",
|
package/dist/core/account.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CrimsonClient } from "./client";
|
|
2
|
-
import type { CurrentUserRoles, StudentSummary } from "./types";
|
|
2
|
+
import type { CurrentUserRoles, StudentSummary, UserProfile } from "./types";
|
|
3
3
|
export declare class AccountApi {
|
|
4
4
|
private client;
|
|
5
5
|
constructor(client: CrimsonClient);
|
|
@@ -22,4 +22,19 @@ export declare class AccountApi {
|
|
|
22
22
|
* @returns Array of student summaries with basic info for display
|
|
23
23
|
*/
|
|
24
24
|
getMyStudents(): Promise<StudentSummary[]>;
|
|
25
|
+
/**
|
|
26
|
+
* Get the current logged-in user's profile information.
|
|
27
|
+
*
|
|
28
|
+
* This is a unified endpoint that returns comprehensive user profile data including:
|
|
29
|
+
* - Basic info (userId, email, name)
|
|
30
|
+
* - Nickname/preferred name
|
|
31
|
+
* - Profile picture URL
|
|
32
|
+
* - User status
|
|
33
|
+
* - Multi-tenant status
|
|
34
|
+
* - All user roles (with names)
|
|
35
|
+
* - Tenant information
|
|
36
|
+
*
|
|
37
|
+
* @returns User profile information
|
|
38
|
+
*/
|
|
39
|
+
getMyProfile(): Promise<UserProfile>;
|
|
25
40
|
}
|
package/dist/core/account.js
CHANGED
|
@@ -43,5 +43,24 @@ class AccountApi {
|
|
|
43
43
|
return this.client.fetch("/api/v1/account/me/students");
|
|
44
44
|
});
|
|
45
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Get the current logged-in user's profile information.
|
|
48
|
+
*
|
|
49
|
+
* This is a unified endpoint that returns comprehensive user profile data including:
|
|
50
|
+
* - Basic info (userId, email, name)
|
|
51
|
+
* - Nickname/preferred name
|
|
52
|
+
* - Profile picture URL
|
|
53
|
+
* - User status
|
|
54
|
+
* - Multi-tenant status
|
|
55
|
+
* - All user roles (with names)
|
|
56
|
+
* - Tenant information
|
|
57
|
+
*
|
|
58
|
+
* @returns User profile information
|
|
59
|
+
*/
|
|
60
|
+
getMyProfile() {
|
|
61
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
62
|
+
return this.client.fetch("/api/v1/account/me/profile");
|
|
63
|
+
});
|
|
64
|
+
}
|
|
46
65
|
}
|
|
47
66
|
exports.AccountApi = AccountApi;
|
package/dist/core/client.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ import { MissionLibraryApi } from "./missionLibrary";
|
|
|
6
6
|
import { UsersApi } from "./users";
|
|
7
7
|
import { AccountApi } from "./account";
|
|
8
8
|
import { StudentProfileApi } from "./studentProfile";
|
|
9
|
+
import { IndigoApi } from "./indigo";
|
|
10
|
+
import { GradeTemplatesApi } from "./gradeTemplates";
|
|
9
11
|
import { OAuthAdapter } from "./auth/oauth-adapter";
|
|
10
12
|
import type { OAuthAuthState, OAuthAuthStateListener } from "./auth/types";
|
|
11
13
|
export declare class CrimsonClient {
|
|
@@ -80,5 +82,7 @@ export declare class CrimsonClient {
|
|
|
80
82
|
users: UsersApi;
|
|
81
83
|
account: AccountApi;
|
|
82
84
|
studentProfile: StudentProfileApi;
|
|
85
|
+
indigo: IndigoApi;
|
|
86
|
+
gradeTemplates: GradeTemplatesApi;
|
|
83
87
|
}
|
|
84
88
|
export declare function createCrimsonClient(config: CrimsonClientConfig): CrimsonClient;
|
package/dist/core/client.js
CHANGED
|
@@ -18,9 +18,11 @@ const missionLibrary_1 = require("./missionLibrary");
|
|
|
18
18
|
const users_1 = require("./users");
|
|
19
19
|
const account_1 = require("./account");
|
|
20
20
|
const studentProfile_1 = require("./studentProfile");
|
|
21
|
+
const indigo_1 = require("./indigo");
|
|
22
|
+
const gradeTemplates_1 = require("./gradeTemplates");
|
|
21
23
|
const oauth_adapter_1 = require("./auth/oauth-adapter");
|
|
22
24
|
/** SDK version from package.json */
|
|
23
|
-
const SDK_VERSION = "0.
|
|
25
|
+
const SDK_VERSION = "0.3.0";
|
|
24
26
|
const normalizeBase = (url) => url.replace(/\/+$/, "");
|
|
25
27
|
const normalizeToken = (token) => token.replace(/^Bearer\s+/i, "");
|
|
26
28
|
/**
|
|
@@ -50,6 +52,8 @@ class CrimsonClient {
|
|
|
50
52
|
this.users = new users_1.UsersApi(this);
|
|
51
53
|
this.account = new account_1.AccountApi(this);
|
|
52
54
|
this.studentProfile = new studentProfile_1.StudentProfileApi(this);
|
|
55
|
+
this.indigo = new indigo_1.IndigoApi(this);
|
|
56
|
+
this.gradeTemplates = new gradeTemplates_1.GradeTemplatesApi(this);
|
|
53
57
|
this.baseUrl = normalizeBase(config.apiUrl);
|
|
54
58
|
this.clientId = config.clientId || "unknown";
|
|
55
59
|
this.clientVersion = config.clientVersion || SDK_VERSION;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import type { CrimsonClient } from "./client";
|
|
2
|
+
export interface GradeTemplateMission {
|
|
3
|
+
id: string;
|
|
4
|
+
gradeTemplateId: string;
|
|
5
|
+
templateMissionId: string;
|
|
6
|
+
startYearOffset?: number;
|
|
7
|
+
startMonth: number;
|
|
8
|
+
startDay?: number;
|
|
9
|
+
endYearOffset?: number;
|
|
10
|
+
endMonth: number;
|
|
11
|
+
endDay?: number;
|
|
12
|
+
createdAt: string;
|
|
13
|
+
updatedAt: string;
|
|
14
|
+
title?: string;
|
|
15
|
+
category?: string;
|
|
16
|
+
description?: string;
|
|
17
|
+
subcategory?: string;
|
|
18
|
+
tasks?: GradeTemplateTask[];
|
|
19
|
+
}
|
|
20
|
+
export interface GradeTemplateTaskResource {
|
|
21
|
+
id: string;
|
|
22
|
+
title: string;
|
|
23
|
+
type: string;
|
|
24
|
+
url: string;
|
|
25
|
+
mediaType?: string;
|
|
26
|
+
orderIndex?: number;
|
|
27
|
+
}
|
|
28
|
+
export interface GradeTemplateTask {
|
|
29
|
+
id: string;
|
|
30
|
+
description: string;
|
|
31
|
+
content?: string;
|
|
32
|
+
resources?: GradeTemplateTaskResource[];
|
|
33
|
+
}
|
|
34
|
+
export interface CreateGradeTemplateMissionInput {
|
|
35
|
+
templateMissionId: string;
|
|
36
|
+
startYearOffset?: number;
|
|
37
|
+
startMonth: number;
|
|
38
|
+
startDay?: number;
|
|
39
|
+
endYearOffset?: number;
|
|
40
|
+
endMonth: number;
|
|
41
|
+
endDay?: number;
|
|
42
|
+
}
|
|
43
|
+
export interface GradeTemplateBrief {
|
|
44
|
+
id: string;
|
|
45
|
+
title: string;
|
|
46
|
+
gradeLevel: number;
|
|
47
|
+
startYearOffset?: number;
|
|
48
|
+
startMonth: number;
|
|
49
|
+
startDay?: number;
|
|
50
|
+
endYearOffset?: number;
|
|
51
|
+
endMonth: number;
|
|
52
|
+
endDay?: number;
|
|
53
|
+
}
|
|
54
|
+
export interface GradeTemplate extends GradeTemplateBrief {
|
|
55
|
+
missions: GradeTemplateMission[];
|
|
56
|
+
createdAt: string;
|
|
57
|
+
updatedAt: string;
|
|
58
|
+
}
|
|
59
|
+
export interface CreateGradeTemplateInput {
|
|
60
|
+
title: string;
|
|
61
|
+
gradeLevel: number;
|
|
62
|
+
startYearOffset?: number;
|
|
63
|
+
startMonth: number;
|
|
64
|
+
startDay?: number;
|
|
65
|
+
endYearOffset?: number;
|
|
66
|
+
endMonth: number;
|
|
67
|
+
endDay?: number;
|
|
68
|
+
}
|
|
69
|
+
export interface GradeTemplateFilters {
|
|
70
|
+
ids?: string[];
|
|
71
|
+
startGrade?: number;
|
|
72
|
+
endGrade?: number;
|
|
73
|
+
}
|
|
74
|
+
export interface AddGradeTemplateToRoadmapInput {
|
|
75
|
+
studentId: string;
|
|
76
|
+
startYear: number;
|
|
77
|
+
missions?: {
|
|
78
|
+
gradeTemplateMissionId: string;
|
|
79
|
+
taskIds?: string[];
|
|
80
|
+
startDate?: string;
|
|
81
|
+
endDate?: string;
|
|
82
|
+
}[];
|
|
83
|
+
}
|
|
84
|
+
export declare class GradeTemplatesApi {
|
|
85
|
+
private client;
|
|
86
|
+
constructor(client: CrimsonClient);
|
|
87
|
+
/**
|
|
88
|
+
* List grade templates
|
|
89
|
+
*/
|
|
90
|
+
listGradeTemplates(filters?: GradeTemplateFilters): Promise<GradeTemplate[]>;
|
|
91
|
+
/**
|
|
92
|
+
* Get grade template by ID
|
|
93
|
+
*/
|
|
94
|
+
getGradeTemplateById(id: string): Promise<GradeTemplate>;
|
|
95
|
+
/**
|
|
96
|
+
* Create a new grade template
|
|
97
|
+
*/
|
|
98
|
+
createGradeTemplate(input: CreateGradeTemplateInput): Promise<GradeTemplate>;
|
|
99
|
+
/**
|
|
100
|
+
* Delete a grade template
|
|
101
|
+
*/
|
|
102
|
+
deleteGradeTemplate(id: string): Promise<void>;
|
|
103
|
+
/**
|
|
104
|
+
* Add mission to grade template
|
|
105
|
+
*/
|
|
106
|
+
addMissionToGradeTemplate(id: string, input: CreateGradeTemplateMissionInput): Promise<GradeTemplateMission>;
|
|
107
|
+
/**
|
|
108
|
+
* Remove mission from grade template
|
|
109
|
+
*/
|
|
110
|
+
removeMissionFromGradeTemplate(missionId: string): Promise<void>;
|
|
111
|
+
/**
|
|
112
|
+
* Add grade template to roadmap
|
|
113
|
+
*/
|
|
114
|
+
addGradeTemplateToRoadmap(id: string, input: AddGradeTemplateToRoadmapInput): Promise<{
|
|
115
|
+
success: boolean;
|
|
116
|
+
}>;
|
|
117
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.GradeTemplatesApi = void 0;
|
|
13
|
+
class GradeTemplatesApi {
|
|
14
|
+
constructor(client) {
|
|
15
|
+
this.client = client;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* List grade templates
|
|
19
|
+
*/
|
|
20
|
+
listGradeTemplates(filters) {
|
|
21
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
22
|
+
const params = new URLSearchParams();
|
|
23
|
+
if ((filters === null || filters === void 0 ? void 0 : filters.startGrade) !== undefined) {
|
|
24
|
+
params.append("startgrade", String(filters.startGrade));
|
|
25
|
+
}
|
|
26
|
+
if ((filters === null || filters === void 0 ? void 0 : filters.endGrade) !== undefined) {
|
|
27
|
+
params.append("endgrade", String(filters.endGrade));
|
|
28
|
+
}
|
|
29
|
+
const query = params.toString();
|
|
30
|
+
const path = query
|
|
31
|
+
? `/roadmap/grade-templates?${query}`
|
|
32
|
+
: "/roadmap/grade-templates";
|
|
33
|
+
return this.client.fetch(path);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get grade template by ID
|
|
38
|
+
*/
|
|
39
|
+
getGradeTemplateById(id) {
|
|
40
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
41
|
+
return this.client.fetch(`/roadmap/grade-templates/${id}`);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Create a new grade template
|
|
46
|
+
*/
|
|
47
|
+
createGradeTemplate(input) {
|
|
48
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
49
|
+
return this.client.fetch("/roadmap/grade-templates", {
|
|
50
|
+
method: "POST",
|
|
51
|
+
body: JSON.stringify(input),
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Delete a grade template
|
|
57
|
+
*/
|
|
58
|
+
deleteGradeTemplate(id) {
|
|
59
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
60
|
+
return this.client.fetch(`/roadmap/grade-templates/${id}`, {
|
|
61
|
+
method: "DELETE",
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Add mission to grade template
|
|
67
|
+
*/
|
|
68
|
+
addMissionToGradeTemplate(id, input) {
|
|
69
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
70
|
+
return this.client.fetch(`/roadmap/grade-templates/${id}/missions`, {
|
|
71
|
+
method: "POST",
|
|
72
|
+
body: JSON.stringify(input),
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Remove mission from grade template
|
|
78
|
+
*/
|
|
79
|
+
removeMissionFromGradeTemplate(missionId) {
|
|
80
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
81
|
+
return this.client.fetch(`/roadmap/grade-templates/missions/${missionId}`, {
|
|
82
|
+
method: "DELETE",
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Add grade template to roadmap
|
|
88
|
+
*/
|
|
89
|
+
addGradeTemplateToRoadmap(id, input) {
|
|
90
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
91
|
+
return this.client.fetch(`/roadmap/grade-templates/${id}/add-to-roadmap`, {
|
|
92
|
+
method: "POST",
|
|
93
|
+
body: JSON.stringify(input),
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
exports.GradeTemplatesApi = GradeTemplatesApi;
|
package/dist/core/index.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ export { MissionLibraryApi } from "./missionLibrary";
|
|
|
6
6
|
export { UsersApi } from "./users";
|
|
7
7
|
export { AccountApi } from "./account";
|
|
8
8
|
export { StudentProfileApi } from "./studentProfile";
|
|
9
|
+
export { IndigoApi } from "./indigo";
|
|
10
|
+
export * from "./gradeTemplates";
|
|
9
11
|
export * from "./types";
|
|
10
12
|
export { OAuthAdapter, createCrimsonOAuthAdapter, TokenManager, LocalStorageTokenStorage, SessionStorageTokenStorage, MemoryTokenStorage, createDefaultTokenStorage, generateCodeVerifier, generateCodeChallenge, generateState, } from "./auth";
|
|
11
13
|
export type { OAuthConfig, OAuthTokens, TokenStorage, OAuthAuthState, OAuthAuthStateListener, AuthorizeOptions, CallbackParams, OAuthError, OAuthAdapterConfig, TokenManagerConfig, } from "./auth";
|
package/dist/core/index.js
CHANGED
|
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.generateState = exports.generateCodeChallenge = exports.generateCodeVerifier = exports.createDefaultTokenStorage = exports.MemoryTokenStorage = exports.SessionStorageTokenStorage = exports.LocalStorageTokenStorage = exports.TokenManager = exports.createCrimsonOAuthAdapter = exports.OAuthAdapter = exports.StudentProfileApi = exports.AccountApi = exports.UsersApi = exports.MissionLibraryApi = exports.RoadmapApi = exports.TasksApi = exports.MissionsApi = exports.createCrimsonClient = exports.CrimsonClient = void 0;
|
|
17
|
+
exports.generateState = exports.generateCodeChallenge = exports.generateCodeVerifier = exports.createDefaultTokenStorage = exports.MemoryTokenStorage = exports.SessionStorageTokenStorage = exports.LocalStorageTokenStorage = exports.TokenManager = exports.createCrimsonOAuthAdapter = exports.OAuthAdapter = exports.IndigoApi = exports.StudentProfileApi = exports.AccountApi = exports.UsersApi = exports.MissionLibraryApi = exports.RoadmapApi = exports.TasksApi = exports.MissionsApi = exports.createCrimsonClient = exports.CrimsonClient = void 0;
|
|
18
18
|
var client_1 = require("./client");
|
|
19
19
|
Object.defineProperty(exports, "CrimsonClient", { enumerable: true, get: function () { return client_1.CrimsonClient; } });
|
|
20
20
|
Object.defineProperty(exports, "createCrimsonClient", { enumerable: true, get: function () { return client_1.createCrimsonClient; } });
|
|
@@ -32,6 +32,9 @@ var account_1 = require("./account");
|
|
|
32
32
|
Object.defineProperty(exports, "AccountApi", { enumerable: true, get: function () { return account_1.AccountApi; } });
|
|
33
33
|
var studentProfile_1 = require("./studentProfile");
|
|
34
34
|
Object.defineProperty(exports, "StudentProfileApi", { enumerable: true, get: function () { return studentProfile_1.StudentProfileApi; } });
|
|
35
|
+
var indigo_1 = require("./indigo");
|
|
36
|
+
Object.defineProperty(exports, "IndigoApi", { enumerable: true, get: function () { return indigo_1.IndigoApi; } });
|
|
37
|
+
__exportStar(require("./gradeTemplates"), exports);
|
|
35
38
|
__exportStar(require("./types"), exports);
|
|
36
39
|
// OAuth authentication
|
|
37
40
|
var auth_1 = require("./auth");
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { CrimsonClient } from "./client";
|
|
2
|
+
import type { IndigoMe, IndigoTutor, IndigoStudent } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* Indigo API Module
|
|
5
|
+
*
|
|
6
|
+
* Provides methods for Indigo-specific functionality including:
|
|
7
|
+
* - User identity retrieval
|
|
8
|
+
* - Student-tutor relationships
|
|
9
|
+
* - Cross-tenant aggregation for multi-tenant users
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const client = createCrimsonClient({
|
|
14
|
+
* apiUrl: 'https://api.crimson.io',
|
|
15
|
+
* clientId: 'indigo-website',
|
|
16
|
+
* getToken: () => localStorage.getItem('token') || '',
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* // Get current user's Indigo identity
|
|
20
|
+
* const me = await client.indigo.getMe();
|
|
21
|
+
* console.log(`Role: ${me.role}, Multi-tenant: ${me.isMultiTenant}`);
|
|
22
|
+
*
|
|
23
|
+
* // For students: get tutors
|
|
24
|
+
* if (me.role === 'student') {
|
|
25
|
+
* const tutors = await client.indigo.getStudentTutors();
|
|
26
|
+
* }
|
|
27
|
+
*
|
|
28
|
+
* // For tutors: get students (aggregated across tenants)
|
|
29
|
+
* if (me.role === 'tutor') {
|
|
30
|
+
* const students = await client.indigo.getTutorStudents();
|
|
31
|
+
* }
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare class IndigoApi {
|
|
35
|
+
private client;
|
|
36
|
+
constructor(client: CrimsonClient);
|
|
37
|
+
/**
|
|
38
|
+
* Get the current user's Indigo identity information
|
|
39
|
+
*
|
|
40
|
+
* Returns the authenticated user's identity including:
|
|
41
|
+
* - Basic profile (userId, email, name)
|
|
42
|
+
* - Role (student or tutor)
|
|
43
|
+
* - Tenant information
|
|
44
|
+
* - Multi-tenant status and related accounts
|
|
45
|
+
*
|
|
46
|
+
* @returns Current user's Indigo identity
|
|
47
|
+
* @throws Error if user is not authenticated or doesn't have Indigo subscription
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* const me = await client.indigo.getMe();
|
|
52
|
+
* if (me.isMultiTenant) {
|
|
53
|
+
* console.log(`User has ${me.relatedAccounts.length} related accounts`);
|
|
54
|
+
* }
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
getMe(): Promise<IndigoMe>;
|
|
58
|
+
/**
|
|
59
|
+
* Get the list of tutors for the current student
|
|
60
|
+
*
|
|
61
|
+
* Returns tutors associated with the authenticated student user.
|
|
62
|
+
* For multi-tenant students, this aggregates tutors across all
|
|
63
|
+
* related accounts.
|
|
64
|
+
*
|
|
65
|
+
* @returns Array of tutors with contract information
|
|
66
|
+
* @throws Error if user is not a student or not authenticated
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* const tutors = await client.indigo.getStudentTutors();
|
|
71
|
+
* tutors.forEach(tutor => {
|
|
72
|
+
* console.log(`${tutor.firstName} ${tutor.lastName} (${tutor.source})`);
|
|
73
|
+
* });
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
getStudentTutors(): Promise<IndigoTutor[]>;
|
|
77
|
+
/**
|
|
78
|
+
* Get the list of students for the current tutor
|
|
79
|
+
*
|
|
80
|
+
* Returns students associated with the authenticated tutor user.
|
|
81
|
+
* For multi-tenant tutors (e.g., tutors working with both Crimson App
|
|
82
|
+
* and Collegewise students), this aggregates students across all
|
|
83
|
+
* related accounts, with source tracking.
|
|
84
|
+
*
|
|
85
|
+
* @returns Array of students with contract and source information
|
|
86
|
+
* @throws Error if user is not a tutor or not authenticated
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```typescript
|
|
90
|
+
* const students = await client.indigo.getTutorStudents();
|
|
91
|
+
*
|
|
92
|
+
* // Group by source tenant
|
|
93
|
+
* const bySource = students.reduce((acc, s) => {
|
|
94
|
+
* (acc[s.source] ||= []).push(s);
|
|
95
|
+
* return acc;
|
|
96
|
+
* }, {} as Record<string, IndigoStudent[]>);
|
|
97
|
+
*
|
|
98
|
+
* console.log(`Crimson App: ${bySource.crimsonapp?.length || 0} students`);
|
|
99
|
+
* console.log(`Collegewise: ${bySource.collegewise?.length || 0} students`);
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
getTutorStudents(): Promise<IndigoStudent[]>;
|
|
103
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.IndigoApi = void 0;
|
|
13
|
+
/**
|
|
14
|
+
* Indigo API Module
|
|
15
|
+
*
|
|
16
|
+
* Provides methods for Indigo-specific functionality including:
|
|
17
|
+
* - User identity retrieval
|
|
18
|
+
* - Student-tutor relationships
|
|
19
|
+
* - Cross-tenant aggregation for multi-tenant users
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const client = createCrimsonClient({
|
|
24
|
+
* apiUrl: 'https://api.crimson.io',
|
|
25
|
+
* clientId: 'indigo-website',
|
|
26
|
+
* getToken: () => localStorage.getItem('token') || '',
|
|
27
|
+
* });
|
|
28
|
+
*
|
|
29
|
+
* // Get current user's Indigo identity
|
|
30
|
+
* const me = await client.indigo.getMe();
|
|
31
|
+
* console.log(`Role: ${me.role}, Multi-tenant: ${me.isMultiTenant}`);
|
|
32
|
+
*
|
|
33
|
+
* // For students: get tutors
|
|
34
|
+
* if (me.role === 'student') {
|
|
35
|
+
* const tutors = await client.indigo.getStudentTutors();
|
|
36
|
+
* }
|
|
37
|
+
*
|
|
38
|
+
* // For tutors: get students (aggregated across tenants)
|
|
39
|
+
* if (me.role === 'tutor') {
|
|
40
|
+
* const students = await client.indigo.getTutorStudents();
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
class IndigoApi {
|
|
45
|
+
constructor(client) {
|
|
46
|
+
this.client = client;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Get the current user's Indigo identity information
|
|
50
|
+
*
|
|
51
|
+
* Returns the authenticated user's identity including:
|
|
52
|
+
* - Basic profile (userId, email, name)
|
|
53
|
+
* - Role (student or tutor)
|
|
54
|
+
* - Tenant information
|
|
55
|
+
* - Multi-tenant status and related accounts
|
|
56
|
+
*
|
|
57
|
+
* @returns Current user's Indigo identity
|
|
58
|
+
* @throws Error if user is not authenticated or doesn't have Indigo subscription
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```typescript
|
|
62
|
+
* const me = await client.indigo.getMe();
|
|
63
|
+
* if (me.isMultiTenant) {
|
|
64
|
+
* console.log(`User has ${me.relatedAccounts.length} related accounts`);
|
|
65
|
+
* }
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
getMe() {
|
|
69
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
70
|
+
return this.client.fetch("/api/v1/indigo/me");
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Get the list of tutors for the current student
|
|
75
|
+
*
|
|
76
|
+
* Returns tutors associated with the authenticated student user.
|
|
77
|
+
* For multi-tenant students, this aggregates tutors across all
|
|
78
|
+
* related accounts.
|
|
79
|
+
*
|
|
80
|
+
* @returns Array of tutors with contract information
|
|
81
|
+
* @throws Error if user is not a student or not authenticated
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```typescript
|
|
85
|
+
* const tutors = await client.indigo.getStudentTutors();
|
|
86
|
+
* tutors.forEach(tutor => {
|
|
87
|
+
* console.log(`${tutor.firstName} ${tutor.lastName} (${tutor.source})`);
|
|
88
|
+
* });
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
getStudentTutors() {
|
|
92
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
93
|
+
return this.client.fetch("/api/v1/indigo/student/tutors");
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Get the list of students for the current tutor
|
|
98
|
+
*
|
|
99
|
+
* Returns students associated with the authenticated tutor user.
|
|
100
|
+
* For multi-tenant tutors (e.g., tutors working with both Crimson App
|
|
101
|
+
* and Collegewise students), this aggregates students across all
|
|
102
|
+
* related accounts, with source tracking.
|
|
103
|
+
*
|
|
104
|
+
* @returns Array of students with contract and source information
|
|
105
|
+
* @throws Error if user is not a tutor or not authenticated
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```typescript
|
|
109
|
+
* const students = await client.indigo.getTutorStudents();
|
|
110
|
+
*
|
|
111
|
+
* // Group by source tenant
|
|
112
|
+
* const bySource = students.reduce((acc, s) => {
|
|
113
|
+
* (acc[s.source] ||= []).push(s);
|
|
114
|
+
* return acc;
|
|
115
|
+
* }, {} as Record<string, IndigoStudent[]>);
|
|
116
|
+
*
|
|
117
|
+
* console.log(`Crimson App: ${bySource.crimsonapp?.length || 0} students`);
|
|
118
|
+
* console.log(`Collegewise: ${bySource.collegewise?.length || 0} students`);
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
getTutorStudents() {
|
|
122
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
123
|
+
return this.client.fetch("/api/v1/indigo/tutor/students");
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
exports.IndigoApi = IndigoApi;
|
package/dist/core/types.d.ts
CHANGED
|
@@ -383,6 +383,106 @@ export interface StudentSummary {
|
|
|
383
383
|
export interface MyStudentsResponse {
|
|
384
384
|
data: StudentSummary[];
|
|
385
385
|
}
|
|
386
|
+
/**
|
|
387
|
+
* Subscription source - matches production tenant names
|
|
388
|
+
*/
|
|
389
|
+
export type SubscriptionSource = "crimsonapp" | "collegewise" | "crimsonmoe" | "delta" | "indigo" | "kfs" | "mawhiba";
|
|
390
|
+
/**
|
|
391
|
+
* Related account for multi-tenant users
|
|
392
|
+
*/
|
|
393
|
+
export interface IndigoRelatedAccount {
|
|
394
|
+
userId: string;
|
|
395
|
+
email: string;
|
|
396
|
+
tenantName: string;
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Response from GET /api/v1/indigo/me
|
|
400
|
+
* Contains current user's Indigo identity information
|
|
401
|
+
*/
|
|
402
|
+
export interface IndigoMe {
|
|
403
|
+
userId: string;
|
|
404
|
+
email: string;
|
|
405
|
+
firstName: string;
|
|
406
|
+
lastName: string;
|
|
407
|
+
/** User role: student or tutor */
|
|
408
|
+
role: "student" | "tutor";
|
|
409
|
+
/** Primary tenant ID */
|
|
410
|
+
tenantId: string;
|
|
411
|
+
/** Primary tenant name */
|
|
412
|
+
tenantName: string;
|
|
413
|
+
/** Whether user has accounts across multiple tenants */
|
|
414
|
+
isMultiTenant: boolean;
|
|
415
|
+
/** Related accounts in other tenants (for multi-tenant users) */
|
|
416
|
+
relatedAccounts: IndigoRelatedAccount[];
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Tutor information for students
|
|
420
|
+
* Response item from GET /api/v1/indigo/student/tutors
|
|
421
|
+
*/
|
|
422
|
+
export interface IndigoTutor {
|
|
423
|
+
userId: string;
|
|
424
|
+
email: string;
|
|
425
|
+
firstName: string;
|
|
426
|
+
lastName: string;
|
|
427
|
+
profileImageUrl?: string;
|
|
428
|
+
/** Contract ID linking student and tutor */
|
|
429
|
+
contractId: string;
|
|
430
|
+
/** Contract status (e.g., 'active', 'accepted') */
|
|
431
|
+
contractStatus: string;
|
|
432
|
+
/** Source tenant where this relationship exists */
|
|
433
|
+
source: string;
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Student information for tutors
|
|
437
|
+
* Response item from GET /api/v1/indigo/tutor/students
|
|
438
|
+
*/
|
|
439
|
+
export interface IndigoStudent {
|
|
440
|
+
userId: string;
|
|
441
|
+
email: string;
|
|
442
|
+
firstName: string;
|
|
443
|
+
lastName: string;
|
|
444
|
+
profileImageUrl?: string;
|
|
445
|
+
/** Contract ID linking student and tutor */
|
|
446
|
+
contractId: string;
|
|
447
|
+
/** Contract status (e.g., 'active', 'accepted') */
|
|
448
|
+
contractStatus: string;
|
|
449
|
+
/** Source tenant where this relationship exists (e.g., 'crimsonapp', 'collegewise') */
|
|
450
|
+
source: string;
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Role information in user profile
|
|
454
|
+
*/
|
|
455
|
+
export interface UserProfileRole {
|
|
456
|
+
roleId: string;
|
|
457
|
+
roleName: string;
|
|
458
|
+
isPrimary: boolean;
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* User profile response from GET /api/v1/account/me/profile
|
|
462
|
+
*/
|
|
463
|
+
export interface UserProfile {
|
|
464
|
+
userId: string;
|
|
465
|
+
email: string;
|
|
466
|
+
firstName: string;
|
|
467
|
+
lastName: string;
|
|
468
|
+
/** Preferred name / nickname */
|
|
469
|
+
nickname: string | null;
|
|
470
|
+
/** Full display name (firstName + lastName) */
|
|
471
|
+
name: string;
|
|
472
|
+
/** Profile picture URL */
|
|
473
|
+
picture: string | null;
|
|
474
|
+
/** User status */
|
|
475
|
+
status: string;
|
|
476
|
+
/** Whether user has accounts in multiple tenants */
|
|
477
|
+
isMultiTenant: boolean;
|
|
478
|
+
/** User roles (can have multiple) */
|
|
479
|
+
roles: UserProfileRole[];
|
|
480
|
+
/** Tenant information */
|
|
481
|
+
tenant: {
|
|
482
|
+
id: string;
|
|
483
|
+
name: string;
|
|
484
|
+
};
|
|
485
|
+
}
|
|
386
486
|
/**
|
|
387
487
|
* Prefilled field with value and source information
|
|
388
488
|
*/
|
|
@@ -2,9 +2,11 @@ export { useAuthState } from "./useAuthState";
|
|
|
2
2
|
export { useOAuth, useOAuthCallback } from "./useOAuth";
|
|
3
3
|
export type { UseOAuthResult } from "./useOAuth";
|
|
4
4
|
export { useMissions, useMissionsInfinite, useCreateMission, useUpdateMission, useDeleteMission, missionKeys, } from "./useMissions";
|
|
5
|
-
export { useTasks, useAllUserTasks, useTasksByRoadmapId, useTasksInfinite, useCreateTask, useUpdateTask, useDeleteTask, useBulkDeleteTasks, useBulkUpdateTasks, taskKeys, useGetDownloadUrl, useTaskCreators } from "./useTasks";
|
|
5
|
+
export { useTasks, useAllUserTasks, useTasksByRoadmapId, useTasksInfinite, useCreateTask, useUpdateTask, useDeleteTask, useBulkDeleteTasks, useBulkUpdateTasks, taskKeys, useGetDownloadUrl, useTaskCreators, } from "./useTasks";
|
|
6
6
|
export { useUsers, useUser, userKeys } from "./useUsers";
|
|
7
7
|
export { useCurrentUserRoles, useMyStudents, accountKeys } from "./useAccount";
|
|
8
8
|
export { useRoadmapContext } from "./useRoadmapContext";
|
|
9
9
|
export { useTemplateMissions, useTemplateMissionsInfinite, useTemplateTasks, useTemplateTasksInfinite, useTemplateMissionDetail, useUpdateTemplateMission, useCopyTemplateMission, useAssignBulkMission, useAssignBulkTask, useCreateFromPredefinedTasks, missionLibraryKeys, useCreateTemplateMission, useDeleteTemplateMission, } from "./useMissionLibrary";
|
|
10
10
|
export { useStudentProfile, useStudentPrefilledInfo, studentProfileKeys, } from "./useStudentProfile";
|
|
11
|
+
export { useIndigoMe, useStudentTutors, useTutorStudents, indigoKeys, } from "./useIndigo";
|
|
12
|
+
export * from "./useGradeTemplates";
|
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
2
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.studentProfileKeys = exports.useStudentPrefilledInfo = exports.useStudentProfile = exports.useDeleteTemplateMission = exports.useCreateTemplateMission = exports.missionLibraryKeys = exports.useCreateFromPredefinedTasks = exports.useAssignBulkTask = exports.useAssignBulkMission = exports.useCopyTemplateMission = exports.useUpdateTemplateMission = exports.useTemplateMissionDetail = exports.useTemplateTasksInfinite = exports.useTemplateTasks = exports.useTemplateMissionsInfinite = exports.useTemplateMissions = exports.useRoadmapContext = exports.accountKeys = exports.useMyStudents = exports.useCurrentUserRoles = exports.userKeys = exports.useUser = exports.useUsers = exports.useTaskCreators = exports.useGetDownloadUrl = exports.taskKeys = exports.useBulkUpdateTasks = exports.useBulkDeleteTasks = exports.useDeleteTask = exports.useUpdateTask = exports.useCreateTask = exports.useTasksInfinite = exports.useTasksByRoadmapId = exports.useAllUserTasks = exports.useTasks = exports.missionKeys = exports.useDeleteMission = exports.useUpdateMission = exports.useCreateMission = exports.useMissionsInfinite = exports.useMissions = exports.useOAuthCallback = exports.useOAuth = exports.useAuthState = void 0;
|
|
17
|
+
exports.indigoKeys = exports.useTutorStudents = exports.useStudentTutors = exports.useIndigoMe = exports.studentProfileKeys = exports.useStudentPrefilledInfo = exports.useStudentProfile = exports.useDeleteTemplateMission = exports.useCreateTemplateMission = exports.missionLibraryKeys = exports.useCreateFromPredefinedTasks = exports.useAssignBulkTask = exports.useAssignBulkMission = exports.useCopyTemplateMission = exports.useUpdateTemplateMission = exports.useTemplateMissionDetail = exports.useTemplateTasksInfinite = exports.useTemplateTasks = exports.useTemplateMissionsInfinite = exports.useTemplateMissions = exports.useRoadmapContext = exports.accountKeys = exports.useMyStudents = exports.useCurrentUserRoles = exports.userKeys = exports.useUser = exports.useUsers = exports.useTaskCreators = exports.useGetDownloadUrl = exports.taskKeys = exports.useBulkUpdateTasks = exports.useBulkDeleteTasks = exports.useDeleteTask = exports.useUpdateTask = exports.useCreateTask = exports.useTasksInfinite = exports.useTasksByRoadmapId = exports.useAllUserTasks = exports.useTasks = exports.missionKeys = exports.useDeleteMission = exports.useUpdateMission = exports.useCreateMission = exports.useMissionsInfinite = exports.useMissions = exports.useOAuthCallback = exports.useOAuth = exports.useAuthState = void 0;
|
|
4
18
|
var useAuthState_1 = require("./useAuthState");
|
|
5
19
|
Object.defineProperty(exports, "useAuthState", { enumerable: true, get: function () { return useAuthState_1.useAuthState; } });
|
|
6
20
|
var useOAuth_1 = require("./useOAuth");
|
|
@@ -54,3 +68,9 @@ var useStudentProfile_1 = require("./useStudentProfile");
|
|
|
54
68
|
Object.defineProperty(exports, "useStudentProfile", { enumerable: true, get: function () { return useStudentProfile_1.useStudentProfile; } });
|
|
55
69
|
Object.defineProperty(exports, "useStudentPrefilledInfo", { enumerable: true, get: function () { return useStudentProfile_1.useStudentPrefilledInfo; } });
|
|
56
70
|
Object.defineProperty(exports, "studentProfileKeys", { enumerable: true, get: function () { return useStudentProfile_1.studentProfileKeys; } });
|
|
71
|
+
var useIndigo_1 = require("./useIndigo");
|
|
72
|
+
Object.defineProperty(exports, "useIndigoMe", { enumerable: true, get: function () { return useIndigo_1.useIndigoMe; } });
|
|
73
|
+
Object.defineProperty(exports, "useStudentTutors", { enumerable: true, get: function () { return useIndigo_1.useStudentTutors; } });
|
|
74
|
+
Object.defineProperty(exports, "useTutorStudents", { enumerable: true, get: function () { return useIndigo_1.useTutorStudents; } });
|
|
75
|
+
Object.defineProperty(exports, "indigoKeys", { enumerable: true, get: function () { return useIndigo_1.indigoKeys; } });
|
|
76
|
+
__exportStar(require("./useGradeTemplates"), exports);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { GradeTemplateFilters, CreateGradeTemplateInput, CreateGradeTemplateMissionInput, AddGradeTemplateToRoadmapInput } from "../../core/gradeTemplates";
|
|
2
|
+
export declare const gradeTemplateKeys: {
|
|
3
|
+
all: readonly ["gradeTemplates"];
|
|
4
|
+
list: (filters?: GradeTemplateFilters) => readonly ["gradeTemplates", "list", GradeTemplateFilters | undefined];
|
|
5
|
+
detail: (id: string) => readonly ["gradeTemplates", "detail", string];
|
|
6
|
+
};
|
|
7
|
+
export declare function useGradeTemplates(filters?: GradeTemplateFilters, enabled?: boolean): import("@tanstack/react-query").UseQueryResult<import("../../core/gradeTemplates").GradeTemplate[], Error>;
|
|
8
|
+
export declare function useGradeTemplate(id: string, enabled?: boolean): import("@tanstack/react-query").UseQueryResult<import("../../core/gradeTemplates").GradeTemplate, Error>;
|
|
9
|
+
export declare function useCreateGradeTemplate(): import("@tanstack/react-query").UseMutationResult<import("../../core/gradeTemplates").GradeTemplate, Error, CreateGradeTemplateInput, unknown>;
|
|
10
|
+
export declare function useDeleteGradeTemplate(): import("@tanstack/react-query").UseMutationResult<void, Error, string, unknown>;
|
|
11
|
+
export declare function useAddMissionToGradeTemplate(): import("@tanstack/react-query").UseMutationResult<import("../../core/gradeTemplates").GradeTemplateMission, Error, {
|
|
12
|
+
id: string;
|
|
13
|
+
input: CreateGradeTemplateMissionInput;
|
|
14
|
+
}, unknown>;
|
|
15
|
+
export declare function useRemoveMissionFromGradeTemplate(): import("@tanstack/react-query").UseMutationResult<void, Error, {
|
|
16
|
+
gradeTemplateId: string;
|
|
17
|
+
missionId: string;
|
|
18
|
+
}, unknown>;
|
|
19
|
+
export declare function useAddGradeTemplateToRoadmap(): import("@tanstack/react-query").UseMutationResult<{
|
|
20
|
+
success: boolean;
|
|
21
|
+
}, Error, {
|
|
22
|
+
id: string;
|
|
23
|
+
input: AddGradeTemplateToRoadmapInput;
|
|
24
|
+
}, unknown>;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
"use client";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.gradeTemplateKeys = void 0;
|
|
5
|
+
exports.useGradeTemplates = useGradeTemplates;
|
|
6
|
+
exports.useGradeTemplate = useGradeTemplate;
|
|
7
|
+
exports.useCreateGradeTemplate = useCreateGradeTemplate;
|
|
8
|
+
exports.useDeleteGradeTemplate = useDeleteGradeTemplate;
|
|
9
|
+
exports.useAddMissionToGradeTemplate = useAddMissionToGradeTemplate;
|
|
10
|
+
exports.useRemoveMissionFromGradeTemplate = useRemoveMissionFromGradeTemplate;
|
|
11
|
+
exports.useAddGradeTemplateToRoadmap = useAddGradeTemplateToRoadmap;
|
|
12
|
+
const react_query_1 = require("@tanstack/react-query");
|
|
13
|
+
const provider_1 = require("../provider");
|
|
14
|
+
const useMissions_1 = require("./useMissions");
|
|
15
|
+
const useTasks_1 = require("./useTasks");
|
|
16
|
+
exports.gradeTemplateKeys = {
|
|
17
|
+
all: ["gradeTemplates"],
|
|
18
|
+
list: (filters) => [...exports.gradeTemplateKeys.all, "list", filters],
|
|
19
|
+
detail: (id) => [...exports.gradeTemplateKeys.all, "detail", id],
|
|
20
|
+
};
|
|
21
|
+
// --- Queries ---
|
|
22
|
+
function useGradeTemplates(filters, enabled = true) {
|
|
23
|
+
const client = (0, provider_1.useCrimsonClient)();
|
|
24
|
+
return (0, react_query_1.useQuery)({
|
|
25
|
+
queryKey: exports.gradeTemplateKeys.list(filters),
|
|
26
|
+
queryFn: () => client.gradeTemplates.listGradeTemplates(filters),
|
|
27
|
+
enabled,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
function useGradeTemplate(id, enabled = true) {
|
|
31
|
+
const client = (0, provider_1.useCrimsonClient)();
|
|
32
|
+
return (0, react_query_1.useQuery)({
|
|
33
|
+
queryKey: exports.gradeTemplateKeys.detail(id),
|
|
34
|
+
queryFn: () => client.gradeTemplates.getGradeTemplateById(id),
|
|
35
|
+
enabled: !!id && enabled,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
// --- Mutations ---
|
|
39
|
+
function useCreateGradeTemplate() {
|
|
40
|
+
const client = (0, provider_1.useCrimsonClient)();
|
|
41
|
+
const queryClient = (0, react_query_1.useQueryClient)();
|
|
42
|
+
return (0, react_query_1.useMutation)({
|
|
43
|
+
mutationFn: (input) => client.gradeTemplates.createGradeTemplate(input),
|
|
44
|
+
onSuccess: () => {
|
|
45
|
+
queryClient.invalidateQueries({
|
|
46
|
+
queryKey: exports.gradeTemplateKeys.list(),
|
|
47
|
+
});
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
function useDeleteGradeTemplate() {
|
|
52
|
+
const client = (0, provider_1.useCrimsonClient)();
|
|
53
|
+
const queryClient = (0, react_query_1.useQueryClient)();
|
|
54
|
+
return (0, react_query_1.useMutation)({
|
|
55
|
+
mutationFn: (id) => client.gradeTemplates.deleteGradeTemplate(id),
|
|
56
|
+
onSuccess: () => {
|
|
57
|
+
queryClient.invalidateQueries({
|
|
58
|
+
queryKey: exports.gradeTemplateKeys.list(),
|
|
59
|
+
});
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
function useAddMissionToGradeTemplate() {
|
|
64
|
+
const client = (0, provider_1.useCrimsonClient)();
|
|
65
|
+
const queryClient = (0, react_query_1.useQueryClient)();
|
|
66
|
+
return (0, react_query_1.useMutation)({
|
|
67
|
+
mutationFn: ({ id, input, }) => client.gradeTemplates.addMissionToGradeTemplate(id, input),
|
|
68
|
+
onSuccess: (_, variables) => {
|
|
69
|
+
queryClient.invalidateQueries({
|
|
70
|
+
queryKey: exports.gradeTemplateKeys.detail(variables.id),
|
|
71
|
+
});
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
function useRemoveMissionFromGradeTemplate() {
|
|
76
|
+
const client = (0, provider_1.useCrimsonClient)();
|
|
77
|
+
const queryClient = (0, react_query_1.useQueryClient)();
|
|
78
|
+
return (0, react_query_1.useMutation)({
|
|
79
|
+
mutationFn: ({ gradeTemplateId, missionId }) => client.gradeTemplates.removeMissionFromGradeTemplate(missionId),
|
|
80
|
+
onSuccess: (_, variables) => {
|
|
81
|
+
queryClient.invalidateQueries({
|
|
82
|
+
queryKey: exports.gradeTemplateKeys.detail(variables.gradeTemplateId),
|
|
83
|
+
});
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
function useAddGradeTemplateToRoadmap() {
|
|
88
|
+
const client = (0, provider_1.useCrimsonClient)();
|
|
89
|
+
const queryClient = (0, react_query_1.useQueryClient)();
|
|
90
|
+
return (0, react_query_1.useMutation)({
|
|
91
|
+
mutationFn: ({ id, input, }) => client.gradeTemplates.addGradeTemplateToRoadmap(id, input),
|
|
92
|
+
onSuccess: () => {
|
|
93
|
+
queryClient.invalidateQueries({ queryKey: useMissions_1.missionKeys.all });
|
|
94
|
+
queryClient.invalidateQueries({ queryKey: useTasks_1.taskKeys.all });
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import type { IndigoMe, IndigoTutor, IndigoStudent } from "../../core/types";
|
|
2
|
+
export declare const indigoKeys: {
|
|
3
|
+
all: readonly ["indigo"];
|
|
4
|
+
me: () => readonly ["indigo", "me"];
|
|
5
|
+
studentTutors: () => readonly ["indigo", "studentTutors"];
|
|
6
|
+
tutorStudents: () => readonly ["indigo", "tutorStudents"];
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Hook to get current user's Indigo identity
|
|
10
|
+
*
|
|
11
|
+
* Returns the authenticated user's identity including:
|
|
12
|
+
* - Basic profile (userId, email, name)
|
|
13
|
+
* - Role (student or tutor)
|
|
14
|
+
* - Tenant information
|
|
15
|
+
* - Multi-tenant status and related accounts
|
|
16
|
+
*
|
|
17
|
+
* @param enabled - Whether to enable the query (default: true)
|
|
18
|
+
* @returns Query result containing IndigoMe data
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```tsx
|
|
22
|
+
* function IndigoProfile() {
|
|
23
|
+
* const { data: me, isLoading } = useIndigoMe();
|
|
24
|
+
*
|
|
25
|
+
* if (isLoading) return <Spinner />;
|
|
26
|
+
*
|
|
27
|
+
* return (
|
|
28
|
+
* <div>
|
|
29
|
+
* <h1>{me.firstName} {me.lastName}</h1>
|
|
30
|
+
* <p>Role: {me.role}</p>
|
|
31
|
+
* {me.isMultiTenant && (
|
|
32
|
+
* <p>Has {me.relatedAccounts.length} related accounts</p>
|
|
33
|
+
* )}
|
|
34
|
+
* </div>
|
|
35
|
+
* );
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare function useIndigoMe(enabled?: boolean): import("@tanstack/react-query").UseQueryResult<IndigoMe, Error>;
|
|
40
|
+
/**
|
|
41
|
+
* Hook to get tutors for the current student
|
|
42
|
+
*
|
|
43
|
+
* Returns tutors associated with the authenticated student user.
|
|
44
|
+
* For multi-tenant students, this aggregates tutors across all
|
|
45
|
+
* related accounts.
|
|
46
|
+
*
|
|
47
|
+
* @param enabled - Whether to enable the query (default: true)
|
|
48
|
+
* @returns Query result containing array of IndigoTutor
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```tsx
|
|
52
|
+
* function StudentTutorList() {
|
|
53
|
+
* const { data: me } = useIndigoMe();
|
|
54
|
+
* const { data: tutors, isLoading } = useStudentTutors(me?.role === 'student');
|
|
55
|
+
*
|
|
56
|
+
* if (isLoading) return <Spinner />;
|
|
57
|
+
*
|
|
58
|
+
* return (
|
|
59
|
+
* <ul>
|
|
60
|
+
* {tutors?.map(tutor => (
|
|
61
|
+
* <li key={tutor.contractId}>
|
|
62
|
+
* {tutor.firstName} {tutor.lastName}
|
|
63
|
+
* </li>
|
|
64
|
+
* ))}
|
|
65
|
+
* </ul>
|
|
66
|
+
* );
|
|
67
|
+
* }
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export declare function useStudentTutors(enabled?: boolean): import("@tanstack/react-query").UseQueryResult<IndigoTutor[], Error>;
|
|
71
|
+
/**
|
|
72
|
+
* Hook to get students for the current tutor
|
|
73
|
+
*
|
|
74
|
+
* Returns students associated with the authenticated tutor user.
|
|
75
|
+
* For multi-tenant tutors, this aggregates students across all
|
|
76
|
+
* related accounts with source tracking.
|
|
77
|
+
*
|
|
78
|
+
* @param enabled - Whether to enable the query (default: true)
|
|
79
|
+
* @returns Query result containing array of IndigoStudent
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```tsx
|
|
83
|
+
* function TutorStudentList() {
|
|
84
|
+
* const { data: me } = useIndigoMe();
|
|
85
|
+
* const { data: students, isLoading } = useTutorStudents(me?.role === 'tutor');
|
|
86
|
+
*
|
|
87
|
+
* if (isLoading) return <Spinner />;
|
|
88
|
+
*
|
|
89
|
+
* // Group by source tenant
|
|
90
|
+
* const bySource = students?.reduce((acc, s) => {
|
|
91
|
+
* (acc[s.source] ||= []).push(s);
|
|
92
|
+
* return acc;
|
|
93
|
+
* }, {} as Record<string, IndigoStudent[]>);
|
|
94
|
+
*
|
|
95
|
+
* return (
|
|
96
|
+
* <div>
|
|
97
|
+
* {Object.entries(bySource || {}).map(([source, list]) => (
|
|
98
|
+
* <section key={source}>
|
|
99
|
+
* <h2>{source} ({list.length})</h2>
|
|
100
|
+
* <ul>
|
|
101
|
+
* {list.map(s => (
|
|
102
|
+
* <li key={s.contractId}>{s.firstName} {s.lastName}</li>
|
|
103
|
+
* ))}
|
|
104
|
+
* </ul>
|
|
105
|
+
* </section>
|
|
106
|
+
* ))}
|
|
107
|
+
* </div>
|
|
108
|
+
* );
|
|
109
|
+
* }
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
export declare function useTutorStudents(enabled?: boolean): import("@tanstack/react-query").UseQueryResult<IndigoStudent[], Error>;
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
"use client";
|
|
3
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
4
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
5
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
6
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
7
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
8
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
9
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.indigoKeys = void 0;
|
|
14
|
+
exports.useIndigoMe = useIndigoMe;
|
|
15
|
+
exports.useStudentTutors = useStudentTutors;
|
|
16
|
+
exports.useTutorStudents = useTutorStudents;
|
|
17
|
+
const react_query_1 = require("@tanstack/react-query");
|
|
18
|
+
const provider_1 = require("../provider");
|
|
19
|
+
// Query keys for Indigo module
|
|
20
|
+
exports.indigoKeys = {
|
|
21
|
+
all: ["indigo"],
|
|
22
|
+
me: () => [...exports.indigoKeys.all, "me"],
|
|
23
|
+
studentTutors: () => [...exports.indigoKeys.all, "studentTutors"],
|
|
24
|
+
tutorStudents: () => [...exports.indigoKeys.all, "tutorStudents"],
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Hook to get current user's Indigo identity
|
|
28
|
+
*
|
|
29
|
+
* Returns the authenticated user's identity including:
|
|
30
|
+
* - Basic profile (userId, email, name)
|
|
31
|
+
* - Role (student or tutor)
|
|
32
|
+
* - Tenant information
|
|
33
|
+
* - Multi-tenant status and related accounts
|
|
34
|
+
*
|
|
35
|
+
* @param enabled - Whether to enable the query (default: true)
|
|
36
|
+
* @returns Query result containing IndigoMe data
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```tsx
|
|
40
|
+
* function IndigoProfile() {
|
|
41
|
+
* const { data: me, isLoading } = useIndigoMe();
|
|
42
|
+
*
|
|
43
|
+
* if (isLoading) return <Spinner />;
|
|
44
|
+
*
|
|
45
|
+
* return (
|
|
46
|
+
* <div>
|
|
47
|
+
* <h1>{me.firstName} {me.lastName}</h1>
|
|
48
|
+
* <p>Role: {me.role}</p>
|
|
49
|
+
* {me.isMultiTenant && (
|
|
50
|
+
* <p>Has {me.relatedAccounts.length} related accounts</p>
|
|
51
|
+
* )}
|
|
52
|
+
* </div>
|
|
53
|
+
* );
|
|
54
|
+
* }
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
function useIndigoMe(enabled = true) {
|
|
58
|
+
const client = (0, provider_1.useCrimsonClient)();
|
|
59
|
+
return (0, react_query_1.useQuery)({
|
|
60
|
+
queryKey: exports.indigoKeys.me(),
|
|
61
|
+
queryFn: () => __awaiter(this, void 0, void 0, function* () {
|
|
62
|
+
return client.indigo.getMe();
|
|
63
|
+
}),
|
|
64
|
+
enabled,
|
|
65
|
+
staleTime: 1000 * 60 * 5, // 5 minutes - identity doesn't change often
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Hook to get tutors for the current student
|
|
70
|
+
*
|
|
71
|
+
* Returns tutors associated with the authenticated student user.
|
|
72
|
+
* For multi-tenant students, this aggregates tutors across all
|
|
73
|
+
* related accounts.
|
|
74
|
+
*
|
|
75
|
+
* @param enabled - Whether to enable the query (default: true)
|
|
76
|
+
* @returns Query result containing array of IndigoTutor
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```tsx
|
|
80
|
+
* function StudentTutorList() {
|
|
81
|
+
* const { data: me } = useIndigoMe();
|
|
82
|
+
* const { data: tutors, isLoading } = useStudentTutors(me?.role === 'student');
|
|
83
|
+
*
|
|
84
|
+
* if (isLoading) return <Spinner />;
|
|
85
|
+
*
|
|
86
|
+
* return (
|
|
87
|
+
* <ul>
|
|
88
|
+
* {tutors?.map(tutor => (
|
|
89
|
+
* <li key={tutor.contractId}>
|
|
90
|
+
* {tutor.firstName} {tutor.lastName}
|
|
91
|
+
* </li>
|
|
92
|
+
* ))}
|
|
93
|
+
* </ul>
|
|
94
|
+
* );
|
|
95
|
+
* }
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
function useStudentTutors(enabled = true) {
|
|
99
|
+
const client = (0, provider_1.useCrimsonClient)();
|
|
100
|
+
return (0, react_query_1.useQuery)({
|
|
101
|
+
queryKey: exports.indigoKeys.studentTutors(),
|
|
102
|
+
queryFn: () => __awaiter(this, void 0, void 0, function* () {
|
|
103
|
+
return client.indigo.getStudentTutors();
|
|
104
|
+
}),
|
|
105
|
+
enabled,
|
|
106
|
+
staleTime: 1000 * 60 * 5, // 5 minutes
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Hook to get students for the current tutor
|
|
111
|
+
*
|
|
112
|
+
* Returns students associated with the authenticated tutor user.
|
|
113
|
+
* For multi-tenant tutors, this aggregates students across all
|
|
114
|
+
* related accounts with source tracking.
|
|
115
|
+
*
|
|
116
|
+
* @param enabled - Whether to enable the query (default: true)
|
|
117
|
+
* @returns Query result containing array of IndigoStudent
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```tsx
|
|
121
|
+
* function TutorStudentList() {
|
|
122
|
+
* const { data: me } = useIndigoMe();
|
|
123
|
+
* const { data: students, isLoading } = useTutorStudents(me?.role === 'tutor');
|
|
124
|
+
*
|
|
125
|
+
* if (isLoading) return <Spinner />;
|
|
126
|
+
*
|
|
127
|
+
* // Group by source tenant
|
|
128
|
+
* const bySource = students?.reduce((acc, s) => {
|
|
129
|
+
* (acc[s.source] ||= []).push(s);
|
|
130
|
+
* return acc;
|
|
131
|
+
* }, {} as Record<string, IndigoStudent[]>);
|
|
132
|
+
*
|
|
133
|
+
* return (
|
|
134
|
+
* <div>
|
|
135
|
+
* {Object.entries(bySource || {}).map(([source, list]) => (
|
|
136
|
+
* <section key={source}>
|
|
137
|
+
* <h2>{source} ({list.length})</h2>
|
|
138
|
+
* <ul>
|
|
139
|
+
* {list.map(s => (
|
|
140
|
+
* <li key={s.contractId}>{s.firstName} {s.lastName}</li>
|
|
141
|
+
* ))}
|
|
142
|
+
* </ul>
|
|
143
|
+
* </section>
|
|
144
|
+
* ))}
|
|
145
|
+
* </div>
|
|
146
|
+
* );
|
|
147
|
+
* }
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
150
|
+
function useTutorStudents(enabled = true) {
|
|
151
|
+
const client = (0, provider_1.useCrimsonClient)();
|
|
152
|
+
return (0, react_query_1.useQuery)({
|
|
153
|
+
queryKey: exports.indigoKeys.tutorStudents(),
|
|
154
|
+
queryFn: () => __awaiter(this, void 0, void 0, function* () {
|
|
155
|
+
return client.indigo.getTutorStudents();
|
|
156
|
+
}),
|
|
157
|
+
enabled,
|
|
158
|
+
staleTime: 1000 * 60 * 5, // 5 minutes
|
|
159
|
+
});
|
|
160
|
+
}
|