feat: phase1 platform upgrade with moderation, dev payments, admin panel and landing updates
This commit is contained in:
@ -183,6 +183,13 @@ class ApiClient {
|
||||
return this.request<any>(`/courses/${courseId}/lessons/${lessonId}/quiz`);
|
||||
}
|
||||
|
||||
async generateLessonHomework(courseId: string, lessonId: string, type?: 'TEXT' | 'FILE' | 'PROJECT' | 'QUIZ' | 'GITHUB') {
|
||||
return this.request<any>(`/courses/${courseId}/lessons/${lessonId}/homework/generate`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ type }),
|
||||
});
|
||||
}
|
||||
|
||||
// Generation
|
||||
async startGeneration(prompt: string) {
|
||||
return this.request<{ id: string; status: string; progress: number }>('/generation/start', {
|
||||
@ -290,10 +297,15 @@ class ApiClient {
|
||||
return this.request<any>(`/enrollment/${courseId}/lessons/${lessonId}/homework`);
|
||||
}
|
||||
|
||||
async submitLessonHomework(courseId: string, lessonId: string, content: string) {
|
||||
async submitLessonHomework(
|
||||
courseId: string,
|
||||
lessonId: string,
|
||||
data: { content?: string; type?: string; attachmentUrl?: string; githubUrl?: string } | string
|
||||
) {
|
||||
const payload = typeof data === 'string' ? { content: data } : data;
|
||||
return this.request<any>(`/enrollment/${courseId}/lessons/${lessonId}/homework`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ content }),
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
}
|
||||
|
||||
@ -340,18 +352,19 @@ class ApiClient {
|
||||
return this.request<any>(`/groups/course/${courseId}/default`);
|
||||
}
|
||||
|
||||
async getGroupMessages(groupId: string) {
|
||||
return this.request<any[]>(`/groups/${groupId}/messages`);
|
||||
async getGroupMessages(groupId: string, lessonId?: string) {
|
||||
const query = lessonId ? `?lessonId=${encodeURIComponent(lessonId)}` : '';
|
||||
return this.request<any[]>(`/groups/${groupId}/messages${query}`);
|
||||
}
|
||||
|
||||
async getGroupMembers(groupId: string) {
|
||||
return this.request<any[]>(`/groups/${groupId}/members`);
|
||||
}
|
||||
|
||||
async sendGroupMessage(groupId: string, content: string) {
|
||||
async sendGroupMessage(groupId: string, content: string, lessonId?: string) {
|
||||
return this.request<any>(`/groups/${groupId}/messages`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ content }),
|
||||
body: JSON.stringify({ content, lessonId }),
|
||||
});
|
||||
}
|
||||
|
||||
@ -431,6 +444,17 @@ class ApiClient {
|
||||
return this.request<any[]>('/moderation/pending');
|
||||
}
|
||||
|
||||
async getModerationCoursePreview(courseId: string) {
|
||||
return this.request<any>(`/moderation/${courseId}/preview`);
|
||||
}
|
||||
|
||||
async previewModerationQuiz(courseId: string, lessonId: string, answers?: number[]) {
|
||||
return this.request<any>(`/moderation/${courseId}/quiz-preview`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ lessonId, answers }),
|
||||
});
|
||||
}
|
||||
|
||||
async approveModerationCourse(courseId: string, note?: string) {
|
||||
return this.request<any>(`/moderation/${courseId}/approve`, {
|
||||
method: 'POST',
|
||||
@ -451,6 +475,80 @@ class ApiClient {
|
||||
});
|
||||
}
|
||||
|
||||
async getAdminUsers(params?: { search?: string; role?: string; limit?: number }) {
|
||||
const searchParams = new URLSearchParams();
|
||||
if (params?.search) searchParams.set('search', params.search);
|
||||
if (params?.role) searchParams.set('role', params.role);
|
||||
if (params?.limit) searchParams.set('limit', String(params.limit));
|
||||
const query = searchParams.toString();
|
||||
return this.request<any[]>(`/admin/users${query ? `?${query}` : ''}`);
|
||||
}
|
||||
|
||||
async updateAdminUserRole(userId: string, role: 'USER' | 'MODERATOR' | 'ADMIN') {
|
||||
return this.request<any>(`/admin/users/${userId}/role`, {
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify({ role }),
|
||||
});
|
||||
}
|
||||
|
||||
async getAdminPayments(params?: {
|
||||
mode?: 'DEV' | 'PROD';
|
||||
provider?: 'STRIPE' | 'YOOMONEY';
|
||||
status?: string;
|
||||
search?: string;
|
||||
limit?: number;
|
||||
}) {
|
||||
const searchParams = new URLSearchParams();
|
||||
if (params?.mode) searchParams.set('mode', params.mode);
|
||||
if (params?.provider) searchParams.set('provider', params.provider);
|
||||
if (params?.status) searchParams.set('status', params.status);
|
||||
if (params?.search) searchParams.set('search', params.search);
|
||||
if (params?.limit) searchParams.set('limit', String(params.limit));
|
||||
const query = searchParams.toString();
|
||||
return this.request<any[]>(`/admin/payments${query ? `?${query}` : ''}`);
|
||||
}
|
||||
|
||||
async submitCooperationRequest(data: {
|
||||
organization: string;
|
||||
contactName: string;
|
||||
email: string;
|
||||
phone?: string;
|
||||
role?: string;
|
||||
organizationType?: string;
|
||||
message: string;
|
||||
}) {
|
||||
return this.request<any>('/cooperation/requests', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
}
|
||||
|
||||
async uploadCourseSource(courseId: string, file: File) {
|
||||
const token = getApiToken();
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
||||
const response = await fetch(`${API_URL}/courses/${courseId}/sources/upload`, {
|
||||
method: 'POST',
|
||||
headers: token ? { Authorization: `Bearer ${token}` } : undefined,
|
||||
body: formData,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({ message: 'Upload failed' }));
|
||||
throw new Error(error.message || `HTTP ${response.status}`);
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async getCourseSources(courseId: string) {
|
||||
return this.request<any[]>(`/courses/${courseId}/sources`);
|
||||
}
|
||||
|
||||
async getCourseSourceOutlineHints(courseId: string) {
|
||||
return this.request<any>(`/courses/${courseId}/sources/outline-hints`);
|
||||
}
|
||||
|
||||
// Search
|
||||
async searchCourses(query: string, filters?: { category?: string; difficulty?: string }) {
|
||||
const searchParams = new URLSearchParams({ q: query });
|
||||
|
||||
Reference in New Issue
Block a user