@@ -120,14 +120,14 @@ export default function ProjectManagement({
120120 useStoreWorkspace ( ) ;
121121
122122 const [ activeProjectId , setActiveProjectId ] = useState < string > (
123- initialProjectId ? initialProjectId : ( projects [ 0 ] ?. id ?? "" ) ,
123+ initialProjectId ? initialProjectId : projects [ 0 ] ?. id ?? "" ,
124124 ) ;
125125
126126 const [ activeWorkspaceId , setActiveWorkspaceId ] = useState < string > (
127- initialWorkspaceId ? initialWorkspaceId : ( workspaces [ 0 ] ?. id ?? "" ) ,
127+ initialWorkspaceId ? initialWorkspaceId : workspaces [ 0 ] ?. id ?? "" ,
128128 ) ;
129129 const [ lastActiveWorkspaceId , setLastActiveWorkspaceId ] = useState < string > (
130- initialWorkspaceId ? initialWorkspaceId : ( workspaces [ 0 ] ?. id ?? "" ) ,
130+ initialWorkspaceId ? initialWorkspaceId : workspaces [ 0 ] ?. id ?? "" ,
131131 ) ;
132132
133133 const rafRef = useRef < number | null > ( null ) ;
@@ -1412,12 +1412,21 @@ export default function ProjectManagement({
14121412
14131413 // 🧠 NORMAL MERGE (REALTIME / OPTIMISTIC SAFE)
14141414 setTasks ( ( localTasks ) => {
1415- const tmp = localTasks . filter ( ( t ) => nid ( t . id ) . startsWith ( "tmp_" ) ) ;
1416-
1415+ // 1) Group local tasks by ID (real and tmp) and clientId (if available)
14171416 const localById = new Map ( localTasks . map ( ( t ) => [ nid ( t . id ) , t ] ) ) ;
1417+ const localByClientId = new Map ( ) ;
1418+ localTasks . forEach ( ( t ) => {
1419+ const cid = ( t as any ) . clientId ;
1420+ if ( cid ) localByClientId . set ( nid ( cid ) , t ) ;
1421+ } ) ;
14181422
1423+ // 2) Merge server tasks with local versions (preserving local changes like comments)
14191424 const mergedServerTasks : Task [ ] = serverTasks . map ( ( st ) => {
1420- const lt = localById . get ( nid ( st . id ) ) ;
1425+ // Try to find local version by id or by clientId (useful if server returned real id but cache still has tmp id)
1426+ const lt =
1427+ localById . get ( nid ( st . id ) ) ||
1428+ localByClientId . get ( nid ( st . id ) ) ||
1429+ localByClientId . get ( nid ( ( st as any ) . clientId ) ) ;
14211430
14221431 // merge comments safely
14231432 const serverComments = Array . isArray ( ( st as any ) . comments )
@@ -1461,16 +1470,35 @@ export default function ProjectManagement({
14611470 return { ...st , comments : chosenComments } ;
14621471 } ) ;
14631472
1464- const merged = [ ...mergedServerTasks , ...tmp ] ;
1473+ // 3) Keep tasks that are in local state but not yet in server tasks
1474+ // (This covers the gap between mutateAsync return and refetch completion)
1475+ const serverIds = new Set ( serverTasks . map ( ( st ) => nid ( st . id ) ) ) ;
1476+ const serverClientIds = new Set (
1477+ serverTasks . map ( ( st ) => nid ( ( st as any ) . clientId ) ) . filter ( ( id ) => id ) ,
1478+ ) ;
1479+
1480+ const localOnly = localTasks . filter ( ( lt ) => {
1481+ const id = nid ( lt . id ) ;
1482+ const cid = nid ( ( lt as any ) . clientId ) ;
1483+ return ! serverIds . has ( id ) && ( ! cid || ! serverClientIds . has ( cid ) ) ;
1484+ } ) ;
1485+
1486+ const merged = [ ...mergedServerTasks , ...localOnly ] ;
14651487
14661488 // sync selectedTask ref
14671489 const mergedMap = new Map ( merged . map ( ( t ) => [ nid ( t . id ) , t ] ) ) ;
14681490 setSelectedTask ( ( cur ) => {
14691491 if ( ! cur ) return null ;
14701492 const found = mergedMap . get ( nid ( cur . id ) ) ;
14711493 if ( found ) return found ;
1472- // keep optimistic task if it's currently selected (prevents auto-close during creation)
1494+
1495+ // keep optimistic task if it's currently selected
14731496 if ( nid ( cur . id ) . startsWith ( "tmp_" ) ) return cur ;
1497+
1498+ // also keep if it's in localTasks (prevents auto-close during creation)
1499+ const inLocal = localTasks . find ( ( t ) => nid ( t . id ) === nid ( cur . id ) ) ;
1500+ if ( inLocal ) return inLocal ;
1501+
14741502 return null ;
14751503 } ) ;
14761504
@@ -1512,15 +1540,19 @@ export default function ProjectManagement({
15121540
15131541 setTasks ( ( s ) => {
15141542 const replaced = s . map ( ( t ) =>
1515- nid ( t . id ) === nid ( optimistic . id ) ? created : t ,
1543+ nid ( t . id ) === nid ( optimistic . id )
1544+ ? { ...created , clientId : optimistic . id }
1545+ : t ,
15161546 ) ;
15171547 const map = new Map < string , Task > ( ) ;
15181548 for ( const t of replaced ) map . set ( nid ( t . id ) , t ) ;
15191549 return Array . from ( map . values ( ) ) ;
15201550 } ) ;
15211551
15221552 setSelectedTask ( ( cur ) =>
1523- cur && nid ( cur . id ) === nid ( optimistic . id ) ? created : cur ,
1553+ cur && nid ( cur . id ) === nid ( optimistic . id )
1554+ ? { ...created , clientId : optimistic . id }
1555+ : cur ,
15241556 ) ;
15251557
15261558 qcRef . current . invalidateQueries ( [ "tasks" , activeProjectId ] ) ;
@@ -1623,17 +1655,17 @@ export default function ProjectManagement({
16231655 ( updated as any ) . startDate === null
16241656 ? null
16251657 : ( updated as any ) . startDate instanceof Date
1626- ? ( updated as any ) . startDate . toISOString ( )
1627- : String ( ( updated as any ) . startDate ) ;
1658+ ? ( updated as any ) . startDate . toISOString ( )
1659+ : String ( ( updated as any ) . startDate ) ;
16281660 }
16291661
16301662 if ( typeof ( updated as any ) . dueDate !== "undefined" ) {
16311663 patch . dueDate =
16321664 ( updated as any ) . dueDate === null
16331665 ? null
16341666 : ( updated as any ) . dueDate instanceof Date
1635- ? ( updated as any ) . dueDate . toISOString ( )
1636- : String ( ( updated as any ) . dueDate ) ;
1667+ ? ( updated as any ) . dueDate . toISOString ( )
1668+ : String ( ( updated as any ) . dueDate ) ;
16371669 }
16381670
16391671 // include comments when provided (array|null)
@@ -2543,8 +2575,8 @@ export default function ProjectManagement({
25432575 ? projects . find ( ( x ) => x . id === activeProjectId ) ?. name ||
25442576 "—"
25452577 : viewMode === "MY_TASKS"
2546- ? "My Tasks"
2547- : "Report" }
2578+ ? "My Tasks"
2579+ : "Report" }
25482580 </ h2 >
25492581 ) }
25502582 { viewMode === "PROJECT" && (
0 commit comments