Files
lms-adm-fe/src/lib/curriculum.ts
T

276 lines
7.8 KiB
TypeScript

export type CurriculumWeek = {
week: number;
title: string;
tags: string[];
progress: number;
state: string;
topics: string[];
duration: string;
github: string;
detail: {
overview: string;
learningSteps?: Array<{
title: string;
description: string;
videoEnabled?: boolean;
videoUrl?: string;
concepts?: string[];
}>;
topicDetails: string[];
topicVideoUrls?: string[];
practiceContents?: Array<{
title: string;
description: string;
}>;
references?: CurriculumReference[];
exampleCodes?: CurriculumReference[];
deliverable: string;
requiresSourceSubmission: boolean;
};
modules?: CurriculumModule[];
visualizationPlatforms?: CurriculumVisualizationPlatform[];
};
export type CurriculumModule = {
id: string;
sortOrder: number;
category: string;
name: string;
folderName: string;
templateRepositoryUrl?: string | null;
dockerImage?: string | null;
enabled?: boolean;
};
export type CurriculumReference = {
id: string;
kind?: string;
title: string;
description?: string | null;
fileName: string;
contentType?: string | null;
fileSizeBytes?: number | string | null;
week?: number | string | null;
weekNumber?: number | string | null;
downloadUrl: string;
createdAt?: string;
};
export type CurriculumVisualizationPlatform = {
key: string;
type: string;
displayName: string;
description?: string | null;
config?: unknown;
};
export type CurriculumTagOption = {
key: string;
label: string;
};
export type InstructorCurriculumResponse = {
course: {
id: string;
title: string;
subtitle?: string | null;
description?: string | null;
organizationName: string;
} | null;
weeks: CurriculumWeek[];
setting: {
groupId?: string | null;
activeWeek: number;
activeLearningStep?: string | null;
} | null;
tagOptions?: CurriculumTagOption[];
visualizationPlatforms?: CurriculumVisualizationPlatform[];
};
const LMS_API_BASE_URL = (import.meta.env.VITE_API_BASE_URL ?? 'http://localhost:4400/api').replace(/\/+$/, '');
export async function getInstructorCurriculum(accessToken: string, groupId?: string | null, courseId?: string | null): Promise<InstructorCurriculumResponse> {
const params = new URLSearchParams();
if (groupId) params.set('groupId', groupId);
if (courseId) params.set('courseId', courseId);
const query = params.toString() ? `?${params.toString()}` : '';
const response = await fetch(`${LMS_API_BASE_URL}/instructor/curriculum${query}`, {
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
if (!response.ok) throw new Error(`커리큘럼을 불러오지 못했습니다. (${response.status})`);
return response.json() as Promise<InstructorCurriculumResponse>;
}
export async function updateInstructorCurriculum(
accessToken: string,
input: {
courseId?: string | null;
groupId?: string | null;
activeWeek: number;
activeLearningStep?: string | null;
applyToStudents?: boolean;
completed?: boolean;
tagLabel?: string;
title?: string;
duration?: string;
overview?: string;
deliverable?: string;
requiresSourceSubmission?: boolean;
topics?: string[];
learningSteps?: Array<{
title?: string;
description?: string;
videoEnabled?: boolean;
videoUrl?: string;
concepts?: string[];
}>;
topicDetails?: string[];
topicVideoUrls?: string[];
practiceContents?: Array<{
title?: string;
description?: string;
}>;
disabledModuleIds?: string[];
visualizationPlatformKeys?: string[];
},
): Promise<InstructorCurriculumResponse> {
const response = await fetch(`${LMS_API_BASE_URL}/instructor/curriculum`, {
method: 'PUT',
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<InstructorCurriculumResponse>;
}
export async function deleteInstructorCurriculumWeek(
accessToken: string,
week: number,
): Promise<InstructorCurriculumResponse> {
const response = await fetch(`${LMS_API_BASE_URL}/instructor/curriculum/weeks/${week}`, {
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<InstructorCurriculumResponse>;
}
export async function uploadCurriculumReference(
accessToken: string,
input: {
courseId?: string | null;
week: number;
title?: string;
file: File;
},
): Promise<InstructorCurriculumResponse> {
const formData = new FormData();
formData.set('file', input.file);
formData.set('courseId', input.courseId ?? '');
formData.set('title', input.title?.trim() || input.file.name);
const response = await fetch(`${LMS_API_BASE_URL}/instructor/curriculum/weeks/${input.week}/references`, {
method: 'POST',
headers: {
Authorization: `Bearer ${accessToken}`,
},
body: formData,
});
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<InstructorCurriculumResponse>;
}
export async function uploadCurriculumExampleCode(
accessToken: string,
input: {
courseId?: string | null;
week: number;
title?: string;
file: File;
},
): Promise<InstructorCurriculumResponse> {
const formData = new FormData();
formData.set('file', input.file);
formData.set('courseId', input.courseId ?? '');
formData.set('title', input.title?.trim() || input.file.name);
const response = await fetch(`${LMS_API_BASE_URL}/instructor/curriculum/weeks/${input.week}/example-codes`, {
method: 'POST',
headers: {
Authorization: `Bearer ${accessToken}`,
},
body: formData,
});
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<InstructorCurriculumResponse>;
}
export async function deleteCurriculumReference(
accessToken: string,
referenceId: string,
courseId?: string | null,
): Promise<InstructorCurriculumResponse> {
const query = courseId ? `?courseId=${encodeURIComponent(courseId)}` : '';
const response = await fetch(`${LMS_API_BASE_URL}/instructor/curriculum/references/${referenceId}${query}`, {
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<InstructorCurriculumResponse>;
}