diff --git a/frontend/src/features/triage/TasksView.tsx b/frontend/src/features/triage/TasksView.tsx index 950e950..30c9567 100644 --- a/frontend/src/features/triage/TasksView.tsx +++ b/frontend/src/features/triage/TasksView.tsx @@ -173,7 +173,7 @@ export const TasksView: React.FC = ({ const [filter, setFilter] = useState<'open' | 'done' | 'discarded'>('open'); const [tasks, setTasks] = useState([]); const [taskLists, setTaskLists] = useState([]); - const [selectedListId, setSelectedListId] = useState( + const [selectedListId, setSelectedListIdState] = useState( () => remembered.listId || 'all' ); const viewMode: ViewMode = viewModes[selectedListId] || 'list'; @@ -304,6 +304,10 @@ export const TasksView: React.FC = ({ ]); if (seq !== loadSeqRef.current) return; // a newer reload is under way loadedListRef.current = listId; + listCacheRef.current.set(listId, { + tasks: Array.isArray(allTasks) ? allTasks : [], + trash: Array.isArray(trash) ? trash : [], + }); setTasks(Array.isArray(allTasks) ? allTasks : []); setTaskLists(Array.isArray(allLists) ? allLists : []); // The remembered list was deleted or unshared meanwhile @@ -327,6 +331,33 @@ export const TasksView: React.FC = ({ const selectedListIdRef = useRef(selectedListId); selectedListIdRef.current = selectedListId; + // Last known tasks of every list opened in this session. Switching lists shows them in the same render + // as the new list's view (list or Kanban), so the board never flashes the previous list's tasks; the + // reload then brings them up to date. A list not opened yet takes its share of "Alle Aufgaben". + const listCacheRef = useRef(new Map()); + useEffect(() => { + if (!loading && loadedListRef.current === selectedListId) { + listCacheRef.current.set(selectedListId, { tasks, trash: taskTrash }); + } + }, [tasks, taskTrash, loading, selectedListId]); + const setSelectedListId = useCallback((id: string) => { + if (id === selectedListIdRef.current) return; + const cache = listCacheRef.current; + let known = cache.get(id); + const all = cache.get('all'); + if (!known && id !== 'all' && all) { + known = { + tasks: all.tasks.filter((t) => t.taskListId === id), + trash: all.trash.filter((t) => t.taskListId === id), + }; + } + setTasks(known ? known.tasks : []); + setTaskTrash(known ? known.trash : []); + setLoading(!known); + loadedListRef.current = known ? id : null; + setSelectedListIdState(id); + }, []); + const onRefreshStatsRef = useRef(onRefreshStats); onRefreshStatsRef.current = onRefreshStats; // The realtime handler is registered once; it must reload with the current list, not the first one @@ -1371,7 +1402,9 @@ export const TasksView: React.FC = ({ try { await api.deleteTaskList(listId); setTaskLists((prev) => prev.filter((l) => l.id !== listId)); - setSelectedListId('all'); + // Plain switch: the deleted list's tasks belong to "Alle Aufgaben" anyway (and the menu effect keeps + // this handler out of its dependencies) + setSelectedListIdState('all'); } catch (err: any) { alert(err.message); } @@ -1568,6 +1601,7 @@ export const TasksView: React.FC = ({ groupBy, defaultGroupBy, setViewMode, + setSelectedListId, sortBy, openTasks.length, doneTasks.length,