11import { DotsCircleSpinner } from "@components/DotsCircleSpinner" ;
2- import { RenameTaskDialog } from "@components/RenameTaskDialog" ;
3- import { useDeleteTask , useTasks } from "@features/tasks/hooks/useTasks" ;
2+ import {
3+ useDeleteTask ,
4+ useTasks ,
5+ useUpdateTask ,
6+ } from "@features/tasks/hooks/useTasks" ;
47import { useTaskContextMenu } from "@hooks/useTaskContextMenu" ;
58import { Box , Flex } from "@radix-ui/themes" ;
9+ import { logger } from "@renderer/lib/logger" ;
610import type { Task } from "@shared/types" ;
711import { useNavigationStore } from "@stores/navigationStore" ;
8- import { memo , useEffect , useRef } from "react" ;
12+ import { useQueryClient } from "@tanstack/react-query" ;
13+ import { memo , useCallback , useEffect , useRef } from "react" ;
914import { useWorkspaceStore } from "@/renderer/features/workspace/stores/workspaceStore" ;
1015import { useSidebarData } from "../hooks/useSidebarData" ;
1116import { usePinnedTasksStore } from "../stores/pinnedTasksStore" ;
@@ -22,7 +27,7 @@ function SidebarMenuComponent() {
2227 const workspaces = useWorkspaceStore . use . workspaces ( ) ;
2328 const markAsViewed = useTaskViewedStore ( ( state ) => state . markAsViewed ) ;
2429
25- const { showContextMenu, renameTask , renameDialogOpen , setRenameDialogOpen } =
30+ const { showContextMenu, editingTaskId , setEditingTaskId } =
2631 useTaskContextMenu ( ) ;
2732 const { deleteWithConfirm } = useDeleteTask ( ) ;
2833 const togglePin = usePinnedTasksStore ( ( state ) => state . togglePin ) ;
@@ -94,52 +99,90 @@ function SidebarMenuComponent() {
9499 } ) ;
95100 } ;
96101
102+ const updateTask = useUpdateTask ( ) ;
103+ const queryClient = useQueryClient ( ) ;
104+ const log = logger . scope ( "sidebar-menu" ) ;
105+
106+ const handleTaskDoubleClick = useCallback (
107+ ( taskId : string ) => {
108+ setEditingTaskId ( taskId ) ;
109+ } ,
110+ [ setEditingTaskId ] ,
111+ ) ;
112+
113+ const handleTaskEditSubmit = useCallback (
114+ async ( taskId : string , newTitle : string ) => {
115+ setEditingTaskId ( null ) ;
116+
117+ // Optimistically update task title in all cached task lists
118+ queryClient . setQueriesData < Task [ ] > (
119+ { queryKey : [ "tasks" , "list" ] } ,
120+ ( old ) =>
121+ old ?. map ( ( task ) =>
122+ task . id === taskId ? { ...task , title : newTitle } : task ,
123+ ) ,
124+ ) ;
125+
126+ try {
127+ await updateTask . mutateAsync ( {
128+ taskId,
129+ updates : { title : newTitle } ,
130+ } ) ;
131+ } catch ( error ) {
132+ log . error ( "Failed to rename task" , error ) ;
133+ // Refetch to revert optimistic update on failure
134+ queryClient . invalidateQueries ( { queryKey : [ "tasks" , "list" ] } ) ;
135+ }
136+ } ,
137+ [ setEditingTaskId , updateTask , queryClient , log ] ,
138+ ) ;
139+
140+ const handleTaskEditCancel = useCallback ( ( ) => {
141+ setEditingTaskId ( null ) ;
142+ } , [ setEditingTaskId ] ) ;
143+
97144 return (
98- < >
99- < RenameTaskDialog
100- task = { renameTask }
101- open = { renameDialogOpen }
102- onOpenChange = { setRenameDialogOpen }
103- />
104-
105- < Box height = "100%" position = "relative" >
106- < Box
107- style = { {
108- height : "100%" ,
109- overflowY : "auto" ,
110- overflowX : "hidden" ,
111- } }
112- >
113- < Flex direction = "column" py = "2" >
114- < Box mb = "2" >
115- < NewTaskItem
116- isActive = { sidebarData . isHomeActive }
117- onClick = { handleNewTaskClick }
118- />
119- </ Box >
120-
121- { sidebarData . isLoading ? (
122- < SidebarItem
123- depth = { 0 }
124- icon = { < DotsCircleSpinner size = { 12 } className = "text-gray-10" /> }
125- label = "Loading tasks..."
126- />
127- ) : (
128- < TaskListView
129- pinnedTasks = { sidebarData . pinnedTasks }
130- flatTasks = { sidebarData . flatTasks }
131- groupedTasks = { sidebarData . groupedTasks }
132- activeTaskId = { sidebarData . activeTaskId }
133- onTaskClick = { handleTaskClick }
134- onTaskContextMenu = { handleTaskContextMenu }
135- onTaskDelete = { handleTaskDelete }
136- hasMore = { sidebarData . hasMore }
137- />
138- ) }
139- </ Flex >
140- </ Box >
145+ < Box height = "100%" position = "relative" >
146+ < Box
147+ style = { {
148+ height : "100%" ,
149+ overflowY : "auto" ,
150+ overflowX : "hidden" ,
151+ } }
152+ >
153+ < Flex direction = "column" py = "2" >
154+ < Box mb = "2" >
155+ < NewTaskItem
156+ isActive = { sidebarData . isHomeActive }
157+ onClick = { handleNewTaskClick }
158+ />
159+ </ Box >
160+
161+ { sidebarData . isLoading ? (
162+ < SidebarItem
163+ depth = { 0 }
164+ icon = { < DotsCircleSpinner size = { 12 } className = "text-gray-10" /> }
165+ label = "Loading tasks..."
166+ />
167+ ) : (
168+ < TaskListView
169+ pinnedTasks = { sidebarData . pinnedTasks }
170+ flatTasks = { sidebarData . flatTasks }
171+ groupedTasks = { sidebarData . groupedTasks }
172+ activeTaskId = { sidebarData . activeTaskId }
173+ editingTaskId = { editingTaskId }
174+ onTaskClick = { handleTaskClick }
175+ onTaskDoubleClick = { handleTaskDoubleClick }
176+ onTaskContextMenu = { handleTaskContextMenu }
177+ onTaskDelete = { handleTaskDelete }
178+ onTaskEditSubmit = { handleTaskEditSubmit }
179+ onTaskEditCancel = { handleTaskEditCancel }
180+ hasMore = { sidebarData . hasMore }
181+ />
182+ ) }
183+ </ Flex >
141184 </ Box >
142- </ >
185+ </ Box >
143186 ) ;
144187}
145188
0 commit comments