Dev #2

Merged
sandrodach merged 37 commits from dev into main 2026-10-25 12:14:23 +01:00
2 changed files with 40 additions and 14 deletions
Showing only changes of commit 6e09888a44 - Show all commits

No files matched your search

+5 -2
View File
@@ -208,7 +208,7 @@ export const App: React.FC = () => {
} else { } else {
disconnectWebSocket(); disconnectWebSocket();
} }
}, [user]); }, [user?.id]);
// Refresh stats on task/doc real-time events // Refresh stats on task/doc real-time events
useEffect(() => { useEffect(() => {
@@ -253,7 +253,10 @@ export const App: React.FC = () => {
target: 'inbox' | 'task' | 'list_item' | 'document' = 'inbox' target: 'inbox' | 'task' | 'list_item' | 'document' = 'inbox'
) => { ) => {
if (target === 'inbox' && thought.status === 'inbox') { if (target === 'inbox' && thought.status === 'inbox') {
setDeck((prev) => [thought, ...prev]); setDeck((prev) => {
if (prev.some((t) => t.id === thought.id)) return prev;
return [thought, ...prev];
});
setStats((prev) => ({ ...prev, inboxCount: prev.inboxCount + 1 })); setStats((prev) => ({ ...prev, inboxCount: prev.inboxCount + 1 }));
} else if (target === 'document' && thought.convertedRefId) { } else if (target === 'document' && thought.convertedRefId) {
setSelectedDocId(thought.convertedRefId); setSelectedDocId(thought.convertedRefId);
+35 -12
View File
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState, useRef, useMemo } from 'react';
import { import {
Check, Check,
Plus, Plus,
@@ -96,7 +96,16 @@ export const TasksView: React.FC<TasksViewProps> = ({
loadData(); loadData();
}, [refreshTrigger, selectedListId]); }, [refreshTrigger, selectedListId]);
// Live-Sync WebSocket listener for tasks const selectedListIdRef = useRef(selectedListId);
selectedListIdRef.current = selectedListId;
const activeNotesTaskIdRef = useRef(activeNotesTaskId);
activeNotesTaskIdRef.current = activeNotesTaskId;
const onRefreshStatsRef = useRef(onRefreshStats);
onRefreshStatsRef.current = onRefreshStats;
// Live-Sync WebSocket listener for tasks (registered once on mount)
useEffect(() => { useEffect(() => {
const handleWs = (e: any) => { const handleWs = (e: any) => {
const msg = e.detail; const msg = e.detail;
@@ -113,10 +122,10 @@ export const TasksView: React.FC<TasksViewProps> = ({
) { ) {
setTasks((prev) => { setTasks((prev) => {
if (prev.some((t) => t.id === created.id)) return prev; if (prev.some((t) => t.id === created.id)) return prev;
if (selectedListId !== 'all' && created.taskListId !== selectedListId) return prev; if (selectedListIdRef.current !== 'all' && created.taskListId !== selectedListIdRef.current) return prev;
return [created, ...prev]; return [created, ...prev];
}); });
onRefreshStats(); onRefreshStatsRef.current();
} }
} else if (msg.event === 'TASK_UPDATED') { } else if (msg.event === 'TASK_UPDATED') {
const updated = msg.payload as Thought; const updated = msg.payload as Thought;
@@ -129,37 +138,37 @@ export const TasksView: React.FC<TasksViewProps> = ({
updated.kanbanStatus || updated.kanbanStatus ||
updated.taskListId || updated.taskListId ||
updated.isCompleted !== undefined) && updated.isCompleted !== undefined) &&
(selectedListId === 'all' || updated.taskListId === selectedListId) (selectedListIdRef.current === 'all' || updated.taskListId === selectedListIdRef.current)
) { ) {
return [updated, ...prev]; return [updated, ...prev];
} }
return prev; return prev;
} }
if (selectedListId !== 'all' && updated.taskListId !== selectedListId) { if (selectedListIdRef.current !== 'all' && updated.taskListId !== selectedListIdRef.current) {
return prev.filter((t) => t.id !== updated.id); return prev.filter((t) => t.id !== updated.id);
} }
return prev.map((t) => { return prev.map((t) => {
if (t.id !== updated.id) return t; if (t.id !== updated.id) return t;
return { return {
...updated, ...updated,
notes: activeNotesTaskId === updated.id ? t.notes : updated.notes, notes: activeNotesTaskIdRef.current === updated.id ? t.notes : updated.notes,
}; };
}); });
}); });
onRefreshStats(); onRefreshStatsRef.current();
} }
} else if (msg.event === 'TASK_DELETED') { } else if (msg.event === 'TASK_DELETED') {
const deletedId = typeof msg.payload === 'string' ? msg.payload : msg.payload?.id; const deletedId = typeof msg.payload === 'string' ? msg.payload : msg.payload?.id;
if (deletedId) { if (deletedId) {
setTasks((prev) => prev.filter((t) => t.id !== deletedId)); setTasks((prev) => prev.filter((t) => t.id !== deletedId));
onRefreshStats(); onRefreshStatsRef.current();
} }
} }
}; };
window.addEventListener('mindsift:ws', handleWs); window.addEventListener('mindsift:ws', handleWs);
return () => window.removeEventListener('mindsift:ws', handleWs); return () => window.removeEventListener('mindsift:ws', handleWs);
}, [selectedListId, activeNotesTaskId, onRefreshStats]); }, []);
const handleToggleDone = async (task: Thought) => { const handleToggleDone = async (task: Thought) => {
triggerHaptic(15); triggerHaptic(15);
@@ -400,7 +409,10 @@ export const TasksView: React.FC<TasksViewProps> = ({
target: 'task', target: 'task',
taskListId: selectedListId === 'all' ? '' : selectedListId, taskListId: selectedListId === 'all' ? '' : selectedListId,
}); });
setTasks((prev) => [created, ...prev]); setTasks((prev) => {
if (prev.some((t) => t.id === created.id)) return prev;
return [created, ...prev];
});
onRefreshStats(); onRefreshStats();
} catch { } catch {
loadData(); loadData();
@@ -466,7 +478,18 @@ export const TasksView: React.FC<TasksViewProps> = ({
} }
}; };
const safeTasks = Array.isArray(tasks) ? tasks : []; const safeTasks = useMemo(() => {
if (!Array.isArray(tasks)) return [];
const seen = new Set<string>();
const unique: Thought[] = [];
for (const t of tasks) {
if (t && t.id && !seen.has(t.id)) {
seen.add(t.id);
unique.push(t);
}
}
return unique;
}, [tasks]);
const safeTaskLists = Array.isArray(taskLists) ? taskLists : []; const safeTaskLists = Array.isArray(taskLists) ? taskLists : [];
const safeSpaces = Array.isArray(spaces) ? spaces : []; const safeSpaces = Array.isArray(spaces) ? spaces : [];
const safeDiscarded = Array.isArray(discarded) ? discarded : []; const safeDiscarded = Array.isArray(discarded) ? discarded : [];