110 lines
3.0 KiB
TypeScript
110 lines
3.0 KiB
TypeScript
export type InstructorStudentIssue = {
|
|
type: 'MISSING_SUBMISSION' | 'COMPLETED_WITHOUT_SUBMISSION' | 'LOW_AVERAGE_SCORE';
|
|
title: string;
|
|
detail: string;
|
|
week?: number;
|
|
};
|
|
|
|
export type InstructorStudent = {
|
|
id: string;
|
|
name: string;
|
|
email: string;
|
|
group: string;
|
|
week: string;
|
|
progress: number;
|
|
commits: number;
|
|
issues: number;
|
|
issueItems: InstructorStudentIssue[];
|
|
lastActive: string;
|
|
online: boolean;
|
|
courseTitle?: string;
|
|
};
|
|
|
|
export type InstructorStudentsSummary = {
|
|
totalStudents: number;
|
|
onlineStudents: number;
|
|
averageProgress: number;
|
|
unresolvedIssues: number;
|
|
};
|
|
|
|
export type InstructorStudentsResponse = {
|
|
organization: {
|
|
id?: string;
|
|
name: string;
|
|
} | null;
|
|
summary: InstructorStudentsSummary;
|
|
students: InstructorStudent[];
|
|
};
|
|
|
|
export type CreateInstructorStudentInput = {
|
|
courseId?: string | null;
|
|
email: string;
|
|
name: string;
|
|
groupId?: string | null;
|
|
};
|
|
|
|
const LMS_API_BASE_URL = (import.meta.env.VITE_API_BASE_URL ?? 'https://workspace.autonomystudio.net/lms-api/api').replace(/\/+$/, '');
|
|
|
|
export async function listInstructorStudents(accessToken: string, courseId?: string | null): Promise<InstructorStudentsResponse> {
|
|
const query = courseId ? `?courseId=${encodeURIComponent(courseId)}` : '';
|
|
const response = await fetch(`${LMS_API_BASE_URL}/instructor/students${query}`, {
|
|
headers: {
|
|
Authorization: `Bearer ${accessToken}`,
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`수강생 현황을 불러오지 못했습니다. (${response.status})`);
|
|
}
|
|
|
|
return response.json() as Promise<InstructorStudentsResponse>;
|
|
}
|
|
|
|
export async function createInstructorStudent(
|
|
accessToken: string,
|
|
input: CreateInstructorStudentInput,
|
|
): Promise<InstructorStudentsResponse> {
|
|
const response = await fetch(`${LMS_API_BASE_URL}/instructor/students`, {
|
|
method: 'POST',
|
|
headers: {
|
|
Authorization: `Bearer ${accessToken}`,
|
|
'content-type': 'application/json',
|
|
},
|
|
body: JSON.stringify(input),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const payload = await response.json().catch((): null => null);
|
|
const message =
|
|
payload && typeof payload === 'object' && 'message' in payload
|
|
? String(payload.message)
|
|
: `수강생을 등록하지 못했습니다. (${response.status})`;
|
|
throw new Error(message);
|
|
}
|
|
|
|
return response.json() as Promise<InstructorStudentsResponse>;
|
|
}
|
|
|
|
export async function removeInstructorStudent(
|
|
accessToken: string,
|
|
studentId: string,
|
|
): Promise<InstructorStudentsResponse> {
|
|
const response = await fetch(`${LMS_API_BASE_URL}/instructor/students/${studentId}`, {
|
|
method: 'DELETE',
|
|
headers: {
|
|
Authorization: `Bearer ${accessToken}`,
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const payload = await response.json().catch((): null => null);
|
|
const message =
|
|
payload && typeof payload === 'object' && 'message' in payload
|
|
? String(payload.message)
|
|
: `수강생을 제외하지 못했습니다. (${response.status})`;
|
|
throw new Error(message);
|
|
}
|
|
|
|
return response.json() as Promise<InstructorStudentsResponse>;
|
|
}
|