diff --git a/VERSION b/VERSION index fd8ccaa..34d6b60 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.8.8 +4.8.9 diff --git a/play-life-backend/main.go b/play-life-backend/main.go index c862bc8..eb116b8 100644 --- a/play-life-backend/main.go +++ b/play-life-backend/main.go @@ -6644,8 +6644,16 @@ func (a *App) getTasksHandler(w http.ResponseWriter, r *http.Request) { LEFT JOIN task_drafts td ON td.task_id = t.id AND td.user_id = $1 WHERE t.user_id = $1 AND t.parent_task_id IS NULL AND t.deleted = FALSE ORDER BY + -- Сначала разделяем на невыполненные (0) и выполненные (1) CASE WHEN t.last_completed_at IS NULL OR t.last_completed_at::date < CURRENT_DATE THEN 0 ELSE 1 END, - t.name + -- Для невыполненных: сортируем по completed DESC (больше завершений выше), затем по id ASC (раньше добавленные выше) + CASE WHEN t.last_completed_at IS NULL OR t.last_completed_at::date < CURRENT_DATE THEN -t.completed ELSE 0 END, + CASE WHEN t.last_completed_at IS NULL OR t.last_completed_at::date < CURRENT_DATE THEN t.id ELSE 0 END, + -- Для выполненных: сортируем по next_show_at ASC (ранние в начале), NULL значения в начале через COALESCE + CASE WHEN t.last_completed_at IS NOT NULL AND t.last_completed_at::date >= CURRENT_DATE + THEN COALESCE(t.next_show_at, '1970-01-01'::timestamp with time zone) + ELSE '1970-01-01'::timestamp with time zone + END ` rows, err := a.DB.Query(query, userID) diff --git a/play-life-web/package.json b/play-life-web/package.json index c3e7c39..43b9708 100644 --- a/play-life-web/package.json +++ b/play-life-web/package.json @@ -1,6 +1,6 @@ { "name": "play-life-web", - "version": "4.8.8", + "version": "4.8.9", "type": "module", "scripts": { "dev": "vite", diff --git a/play-life-web/src/components/TaskList.jsx b/play-life-web/src/components/TaskList.jsx index ec339fa..ed14d1d 100644 --- a/play-life-web/src/components/TaskList.jsx +++ b/play-life-web/src/components/TaskList.jsx @@ -493,6 +493,46 @@ function TaskList({ onNavigate, data, loading, backgroundLoading, error, onRetry }) }) + // Сортируем задачи внутри каждой группы проекта + Object.keys(groups).forEach(projectName => { + const group = groups[projectName] + + // Сортируем невыполненные задачи: по completed DESC (больше завершений выше), затем по id ASC (раньше добавленные выше) + group.notCompleted.sort((a, b) => { + if (b.completed !== a.completed) { + return b.completed - a.completed // DESC + } + return a.id - b.id // ASC + }) + + // Сортируем выполненные задачи: бесконечные первыми, затем по next_show_at ASC (ранние в начале), NULL в начале + group.completed.sort((a, b) => { + // Проверяем, является ли задача бесконечной + const hasZeroPeriodA = a.repetition_period && isZeroPeriod(a.repetition_period) + const hasZeroDateA = a.repetition_date && isZeroDate(a.repetition_date) + const isInfiniteA = (hasZeroPeriodA && hasZeroDateA) || (hasZeroPeriodA && !a.repetition_date) + + const hasZeroPeriodB = b.repetition_period && isZeroPeriod(b.repetition_period) + const hasZeroDateB = b.repetition_date && isZeroDate(b.repetition_date) + const isInfiniteB = (hasZeroPeriodB && hasZeroDateB) || (hasZeroPeriodB && !b.repetition_date) + + // Бесконечные задачи идут первыми + if (isInfiniteA && !isInfiniteB) return -1 + if (!isInfiniteA && isInfiniteB) return 1 + if (isInfiniteA && isInfiniteB) return 0 + + // Для остальных: NULL значения идут первыми + if (!a.next_show_at && !b.next_show_at) return 0 + if (!a.next_show_at) return -1 + if (!b.next_show_at) return 1 + + // Сравниваем даты + const dateA = new Date(a.next_show_at).getTime() + const dateB = new Date(b.next_show_at).getTime() + return dateA - dateB // ASC + }) + }) + return groups }, [tasks])