Keep completed todos at the end (#1430)
Co-authored-by: Konstantin Zolin <zolin_ka@vk.com>
This commit is contained in:
committed by
GitHub
co-authored by
Konstantin Zolin
parent
db2464d94d
commit
4c34031f8d
@@ -101,6 +101,19 @@ const createTodoId = (): string => {
|
||||
return `todo_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
||||
};
|
||||
|
||||
const sortTodosWithCompletedLast = (items: OpenChamberProjectTodoItem[]): OpenChamberProjectTodoItem[] => [
|
||||
...items.filter((todo) => !todo.completed),
|
||||
...items.filter((todo) => todo.completed),
|
||||
];
|
||||
|
||||
const insertTodoBeforeCompleted = (items: OpenChamberProjectTodoItem[], item: OpenChamberProjectTodoItem): OpenChamberProjectTodoItem[] => {
|
||||
const firstCompletedIndex = items.findIndex((todo) => todo.completed);
|
||||
if (firstCompletedIndex === -1) {
|
||||
return [...items, item];
|
||||
}
|
||||
return [...items.slice(0, firstCompletedIndex), item, ...items.slice(firstCompletedIndex)];
|
||||
};
|
||||
|
||||
type SortableTodoHandleProps = {
|
||||
attributes: ReturnType<typeof useSortable>['attributes'];
|
||||
listeners: ReturnType<typeof useSortable>['listeners'];
|
||||
@@ -216,7 +229,7 @@ export const ProjectNotesTodoPanel: React.FC<ProjectNotesTodoPanelProps> = ({
|
||||
return;
|
||||
}
|
||||
setNotes(data.notes);
|
||||
setTodos(data.todos);
|
||||
setTodos(sortTodosWithCompletedLast(data.todos));
|
||||
setPlans(nextPlans);
|
||||
lastSavedNotesRef.current = data.notes;
|
||||
notesHydratedRef.current = true;
|
||||
@@ -341,15 +354,12 @@ export const ProjectNotesTodoPanel: React.FC<ProjectNotesTodoPanelProps> = ({
|
||||
return;
|
||||
}
|
||||
|
||||
const nextTodos = [
|
||||
...todos,
|
||||
{
|
||||
id: createTodoId(),
|
||||
text: trimmed.slice(0, OPENCHAMBER_PROJECT_TODO_TEXT_MAX_LENGTH),
|
||||
completed: false,
|
||||
createdAt: Date.now(),
|
||||
},
|
||||
];
|
||||
const nextTodos = insertTodoBeforeCompleted(todos, {
|
||||
id: createTodoId(),
|
||||
text: trimmed.slice(0, OPENCHAMBER_PROJECT_TODO_TEXT_MAX_LENGTH),
|
||||
completed: false,
|
||||
createdAt: Date.now(),
|
||||
});
|
||||
setTodos(nextTodos);
|
||||
setNewTodoText('');
|
||||
void persistProjectData(notes, nextTodos);
|
||||
@@ -369,7 +379,15 @@ export const ProjectNotesTodoPanel: React.FC<ProjectNotesTodoPanelProps> = ({
|
||||
|
||||
const handleToggleTodo = React.useCallback(
|
||||
(id: string, completed: boolean) => {
|
||||
const nextTodos = todos.map((todo) => (todo.id === id ? { ...todo, completed } : todo));
|
||||
const todo = todos.find((item) => item.id === id);
|
||||
if (!todo || todo.completed === completed) {
|
||||
return;
|
||||
}
|
||||
const remainingTodos = todos.filter((item) => item.id !== id);
|
||||
const updatedTodo = { ...todo, completed };
|
||||
const nextTodos = completed
|
||||
? [...remainingTodos, updatedTodo]
|
||||
: insertTodoBeforeCompleted(remainingTodos, updatedTodo);
|
||||
setTodos(nextTodos);
|
||||
void persistProjectData(notes, nextTodos);
|
||||
},
|
||||
@@ -405,7 +423,7 @@ export const ProjectNotesTodoPanel: React.FC<ProjectNotesTodoPanelProps> = ({
|
||||
if (oldIndex === -1 || newIndex === -1) {
|
||||
return;
|
||||
}
|
||||
const nextTodos = arrayMove(todos, oldIndex, newIndex);
|
||||
const nextTodos = sortTodosWithCompletedLast(arrayMove(todos, oldIndex, newIndex));
|
||||
setTodos(nextTodos);
|
||||
void persistProjectData(notes, nextTodos);
|
||||
},
|
||||
@@ -799,7 +817,7 @@ export const ProjectNotesTodoPanel: React.FC<ProjectNotesTodoPanelProps> = ({
|
||||
return (
|
||||
<SortableTodoItem key={todo.id} id={todo.id}>
|
||||
{(dragHandleProps) => (
|
||||
<div className="flex items-start gap-1.5 px-2.5 py-1.5">
|
||||
<div className={cn('flex gap-1.5 px-2.5 py-1.5', isExpandedTodo ? 'items-start' : 'items-center')}>
|
||||
<button
|
||||
type="button"
|
||||
ref={dragHandleProps.setActivatorNodeRef}
|
||||
@@ -826,7 +844,7 @@ export const ProjectNotesTodoPanel: React.FC<ProjectNotesTodoPanelProps> = ({
|
||||
type="button"
|
||||
onClick={() => handleToggleTodoExpanded(todo.id)}
|
||||
className={cn(
|
||||
'block min-h-6 min-w-0 flex-1 bg-transparent p-0 text-left typography-ui-label leading-6 text-foreground',
|
||||
'block min-h-6 min-w-0 flex-1 bg-transparent p-0 text-left typography-ui-label leading-normal text-foreground',
|
||||
isExpandedTodo ? 'whitespace-normal break-words' : 'overflow-hidden text-ellipsis whitespace-nowrap',
|
||||
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50',
|
||||
todo.completed && 'text-muted-foreground line-through'
|
||||
|
||||
Reference in New Issue
Block a user