Files
classroomio/apps/dashboard/src/lib/features/course/api/people.svelte.ts
T

296 lines
8.4 KiB
TypeScript
Raw Normal View History

2026-03-09 11:18:22 +01:00
import type {
AddPeopleRequest,
CreateStudentInviteRequest,
DeletePeopleRequest,
GetStudentInviteAuditRequest,
GetUserCourseAnalyticsRequest,
ListStudentInvitesRequest,
ListPeopleRequest,
RevokeStudentInviteRequest,
UpdatePeopleRequest
} from '../utils/types';
import { BaseApiWithErrors, classroomio } from '$lib/utils/services/api';
import type { TAddCourseMembers } from '@cio/utils/validation/course/people';
import { snackbar } from '$features/ui/snackbar/store';
/**
* API class for course members operations
*/
export class PeopleApi extends BaseApiWithErrors {
/**
* Lists all course members for a course
* @param courseId Course ID
* @returns Array of course members with profile data
*/
async list(courseId: string) {
return this.execute<ListPeopleRequest>({
requestFn: () =>
classroomio.course[':courseId']['members'].$get({
param: { courseId }
}),
logContext: 'listing course members',
onSuccess: (response) => {
if (response.data) {
this.success = true;
this.errors = {};
}
},
onError: (result) => {
if (typeof result === 'string') {
snackbar.error('Failed to list course members');
}
}
});
}
/**
* Adds course members to a course
* @param courseId Course ID
* @param members Array of members to add
* @returns Array of created members or null on error
*/
async add(courseId: string, members: TAddCourseMembers) {
await this.execute<AddPeopleRequest>({
requestFn: () =>
classroomio.course[':courseId']['members'].$post({
param: { courseId },
json: members
}),
logContext: 'adding course members',
onSuccess: (response) => {
if (response.data) {
const count = Array.isArray(response.data) ? response.data.length : 1;
snackbar.success(`${count} member${count > 1 ? 's' : ''} added successfully`);
this.success = true;
this.errors = {};
}
},
onError: (result) => {
if (typeof result === 'string') {
snackbar.error('Failed to add course members');
}
}
});
}
/**
* Creates a secure student invite link for a course
* @param courseId Course ID
* @param payload Invite settings
* @returns Invite data including inviteLink
*/
async createStudentInvite(
courseId: string,
payload: {
preset?: 'ONE_TIME_24H' | 'MULTI_USE_7D' | 'MULTI_USE_30D' | 'CUSTOM';
expiresAt?: string;
maxUses?: number;
allowedEmails?: string[];
allowedDomains?: string[];
recipientEmails?: string[];
recipientCsv?: string;
sendEmail?: boolean;
metadata?: Record<string, unknown>;
}
) {
const result = await this.execute<CreateStudentInviteRequest>({
requestFn: () =>
classroomio.course[':courseId']['invites'].$post({
param: { courseId },
json: payload
}),
logContext: 'creating student invite',
onSuccess: () => {
this.success = true;
this.errors = {};
},
onError: (result) => {
if (typeof result === 'string') {
snackbar.error('Failed to create student invite');
return;
}
if ('error' in result && 'field' in result && result.field) {
this.errors[result.field] = result.error;
} else if ('error' in result) {
this.errors.general = result.error;
}
}
});
return result?.data;
}
/**
* Lists secure student invites for a course
* @param courseId Course ID
*/
async listStudentInvites(courseId: string) {
const result = await this.execute<ListStudentInvitesRequest>({
requestFn: () =>
classroomio.course[':courseId']['invites'].$get({
param: { courseId }
}),
logContext: 'listing student invites',
onSuccess: () => {
this.success = true;
this.errors = {};
},
onError: (result) => {
if (typeof result === 'string') {
snackbar.error('Failed to list invites');
}
}
});
return result?.data;
}
/**
* Revokes a secure student invite
* @param courseId Course ID
* @param inviteId Invite ID
*/
async revokeStudentInvite(courseId: string, inviteId: string) {
const result = await this.execute<RevokeStudentInviteRequest>({
requestFn: () =>
classroomio.course[':courseId']['invites'][':inviteId']['revoke'].$post({
param: { courseId, inviteId }
}),
logContext: 'revoking student invite',
onSuccess: () => {
this.success = true;
this.errors = {};
},
onError: (result) => {
if (typeof result === 'string') {
snackbar.error('Failed to revoke invite');
}
}
});
return result?.data;
}
/**
* Loads invite audit events for one invite
* @param courseId Course ID
* @param inviteId Invite ID
*/
async getStudentInviteAudit(courseId: string, inviteId: string) {
const result = await this.execute<GetStudentInviteAuditRequest>({
requestFn: () =>
classroomio.course[':courseId']['invites'][':inviteId']['audit'].$get({
param: { courseId, inviteId }
}),
logContext: 'loading invite audit',
onSuccess: () => {
this.success = true;
this.errors = {};
},
onError: (result) => {
if (typeof result === 'string') {
snackbar.error('Failed to load invite audit');
}
}
});
return result?.data;
}
/**
* Updates a course member
* @param courseId Course ID
* @param memberId Member ID
* @param data Partial member data to update
* @returns The updated member data or null on error
*/
async update(courseId: string, memberId: string, data: Partial<{ roleId: number; email: string }>) {
await this.execute<UpdatePeopleRequest>({
requestFn: () =>
classroomio.course[':courseId']['members'][':memberId'].$put({
param: { courseId, memberId },
json: data
}),
logContext: 'updating course member',
onSuccess: (response) => {
if (response.data) {
snackbar.success('Member updated successfully');
this.success = true;
this.errors = {};
}
},
onError: (result) => {
if (typeof result === 'string') {
snackbar.error('Failed to update course member');
return;
}
if ('error' in result && 'field' in result && result.field) {
this.errors[result.field] = result.error;
snackbar.error(result.error);
} else if ('error' in result) {
this.errors.general = result.error;
snackbar.error(result.error);
}
}
});
}
/**
* Deletes a course member
* @param courseId Course ID
* @param memberId Member ID
* @returns The deleted member data or null on error
*/
async delete(courseId: string, memberId: string) {
await this.execute<DeletePeopleRequest>({
requestFn: () =>
classroomio.course[':courseId']['members'][':memberId'].$delete({
param: { courseId, memberId }
}),
logContext: 'deleting course member',
onSuccess: (response) => {
if (response.data) {
snackbar.success('Member removed successfully');
this.success = true;
this.errors = {};
}
},
onError: (result) => {
if (typeof result === 'string') {
snackbar.error('Failed to delete course member');
}
}
});
}
/**
* Gets user course analytics for a specific course
* @param courseId Course ID
* @param userId User ID (profile ID)
* @returns User course analytics data or null on error
*/
async getUserCourseAnalytics(courseId: string, userId: string) {
return this.execute<GetUserCourseAnalyticsRequest>({
requestFn: () =>
classroomio.course[':courseId']['members'][':userId']['analytics'].$get({
param: { courseId, userId }
}),
logContext: 'fetching user course analytics',
onSuccess: (response) => {
if (response.data) {
this.success = true;
this.errors = {};
}
},
onError: (result) => {
if (typeof result === 'string') {
snackbar.error('Failed to fetch user course analytics');
}
}
});
}
}
export const peopleApi = /* @__PURE__ */ new PeopleApi();