Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 34 additions & 12 deletions frontend/src/pages/CourseDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -183,19 +183,41 @@ export default function CourseDetails() {
setErrorMessage('');
setIsAddingTask(true);

const { data, error } = await supabase
.from('tasks')
.insert([
{
title: newTaskTitle.trim(),
course_id: id,
is_completed: false,
deadline: newTaskDeadline || null,
const normalizedTitle = newTaskTitle.trim();
const normalizedDeadline = newTaskDeadline || null;

},
])
.select()
.single();
const { data: existingTask, error: duplicateCheckError } = await supabase
.from('tasks')
.select('id')
.eq('course_id', id)
.eq('title', normalizedTitle)
.eq('deadline', normalizedDeadline)
.maybeSingle();

if (duplicateCheckError) {
setErrorMessage('Ошибка проверки дубликата задачи: ' + duplicateCheckError.message);
setIsAddingTask(false);
return;
}

if (existingTask) {
setErrorMessage('Задача с таким названием и дедлайном уже существует.');
setIsAddingTask(false);
return;
}

const { data, error } = await supabase
.from('tasks')
.insert([
{
title: normalizedTitle,
course_id: id,
is_completed: false,
deadline: normalizedDeadline,
},
])
.select()
.single();

if (error) {
setErrorMessage('Ошибка создания задачи: ' + error.message);
Expand Down
95 changes: 57 additions & 38 deletions frontend/src/pages/CoursesPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,17 +106,38 @@ export default function CoursesPage() {
return;
}

const normalizedCourseName = newCourseName.trim();

const { data: existingCourse, error: duplicateCheckError } = await supabase
.from('courses')
.select('id')
.eq('user_id', user.id)
.eq('name', normalizedCourseName)
.maybeSingle();

if (duplicateCheckError) {
setErrorMessage('Ошибка проверки дубликата курса: ' + duplicateCheckError.message);
setIsCreatingCourse(false);
return;
}

if (existingCourse) {
setErrorMessage('Курс с таким названием уже существует.');
setIsCreatingCourse(false);
return;
}

const { data: createdCourse, error: courseError } = await supabase
.from('courses')
.insert([
{
name: newCourseName.trim(),
description: newCourseDescription.trim() || null,
user_id: user.id,
},
])
.select()
.single();
.from('courses')
.insert([
{
name: normalizedCourseName,
description: newCourseDescription.trim() || null,
user_id: user.id,
},
])
.select()
.single();

if (courseError) {
setErrorMessage('Ошибка создания курса: ' + courseError.message);
Expand All @@ -133,14 +154,14 @@ export default function CoursesPage() {
if (selectedFile) {
const originalFileName = selectedFile.name;
const safeFileName = originalFileName
.replace(/\s+/g, '_')
.replace(/[^a-zA-Z0-9._-]/g, '_');
.replace(/\s+/g, '_')
.replace(/[^a-zA-Z0-9._-]/g, '_');

const filePath = `courses/${createdCourse.id}/${Date.now()}_${safeFileName}`;

const { error: uploadError } = await supabase.storage
.from('file_attachments')
.upload(filePath, selectedFile);
.from('file_attachments')
.upload(filePath, selectedFile);

if (uploadError) {
setCourses((prevCourses) => [createdCourse, ...prevCourses]);
Expand All @@ -160,21 +181,21 @@ export default function CoursesPage() {
}

const { error: attachmentError } = await supabase
.from('course_attachments')
.insert([
{
id: crypto.randomUUID(),
course_id: createdCourse.id,
name: selectedFile.name,
url: filePath,
is_external: false,
},
]);
.from('course_attachments')
.insert([
{
id: crypto.randomUUID(),
course_id: createdCourse.id,
name: selectedFile.name,
url: filePath,
is_external: false,
},
]);

if (attachmentError) {
setCourses((prevCourses) => [createdCourse, ...prevCourses]);
setErrorMessage(
'Курс создан, файл загружен, но запись о вложении не сохранилась: ' +
'Курс создан, файл загружен, но запись о вложении не сохранилась: ' +
attachmentError.message
);
setNewCourseName('');
Expand All @@ -196,22 +217,20 @@ export default function CoursesPage() {
const cleanLink = newCourseLink.trim();

const { error: linkError } = await supabase
.from('course_attachments')
.insert([
{
id: crypto.randomUUID(),
course_id: createdCourse.id,
name: cleanLink,
url: cleanLink,
is_external: true,
},
]);
.from('course_attachments')
.insert([
{
id: crypto.randomUUID(),
course_id: createdCourse.id,
name: cleanLink,
url: cleanLink,
is_external: true,
},
]);

if (linkError) {
setCourses((prevCourses) => [createdCourse, ...prevCourses]);
setErrorMessage(
'Курс создан, но ссылка не сохранилась: ' + linkError.message
);
setErrorMessage('Курс создан, но ссылка не сохранилась: ' + linkError.message);
setNewCourseName('');
setNewCourseDescription('');
setNewCourseLink('');
Expand Down
28 changes: 26 additions & 2 deletions frontend/src/pages/TaskDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -224,15 +224,39 @@ export default function TaskDetails() {
return;
}

const normalizedTitle = editTitle.trim();
const normalizedDeadline = editDeadline || null;

setErrorMessage('');
setIsSavingTask(true);

const { data: existingTask, error: duplicateCheckError } = await supabase
.from('tasks')
.select('id')
.eq('course_id', task.course_id)
.eq('title', normalizedTitle)
.eq('deadline', normalizedDeadline)
.neq('id', task.id)
.maybeSingle();

if (duplicateCheckError) {
setErrorMessage('Ошибка проверки дубликата задачи: ' + duplicateCheckError.message);
setIsSavingTask(false);
return;
}

if (existingTask) {
setErrorMessage('Задача с таким названием и дедлайном уже существует.');
setIsSavingTask(false);
return;
}

const { data, error } = await supabase
.from('tasks')
.update({
title: editTitle.trim(),
title: normalizedTitle,
description: editDescription.trim() || null,
deadline: editDeadline || null,
deadline: normalizedDeadline,
})
.eq('id', task.id)
.select()
Expand Down
Loading