@@ -16,7 +16,6 @@ import {
1616 type ComponentProps ,
1717} from 'react' ;
1818import { useOptimisticThreadState } from '@/components/mail/optimistic-thread-state' ;
19- import { useIsFetching , useMutation , useQueryClient } from '@tanstack/react-query' ;
2019import { focusedIndexAtom , useMailNavigation } from '@/hooks/use-mail-navigation' ;
2120import { Tooltip , TooltipContent , TooltipTrigger } from '@/components/ui/tooltip' ;
2221import type { MailSelectMode , ParsedMessage , ThreadProps } from '@/types' ;
@@ -25,22 +24,21 @@ import { useOptimisticActions } from '@/hooks/use-optimistic-actions';
2524import { Archive2 , GroupPeople , Star2 , Trash } from '../icons/icons' ;
2625import { Avatar , AvatarFallback , AvatarImage } from '../ui/avatar' ;
2726import { useMail , type Config } from '@/components/mail/use-mail' ;
28- import { Briefcase , Check , Star , StickyNote } from 'lucide-react' ;
29- import { backgroundQueueAtom } from '@/store/backgroundQueue' ;
3027import { type ThreadDestination } from '@/lib/thread-actions' ;
3128import { useThread , useThreads } from '@/hooks/use-threads' ;
3229import { useSearchValue } from '@/hooks/use-search-value' ;
3330import { highlightText } from '@/lib/email-utils.client' ;
3431import { useHotkeysContext } from 'react-hotkeys-hook' ;
3532import { AnimatePresence , motion } from 'motion/react' ;
33+ import { useIsFetching } from '@tanstack/react-query' ;
3634import { useTRPC } from '@/providers/query-provider' ;
3735import { useThreadLabels } from '@/hooks/use-labels' ;
3836import { useKeyState } from '@/hooks/use-hot-key' ;
3937import { VList , type VListHandle } from 'virtua' ;
4038import { RenderLabels } from './render-labels' ;
4139import { Badge } from '@/components/ui/badge' ;
4240import { useDraft } from '@/hooks/use-drafts' ;
43- import { useStats } from '@/hooks/use-stats ' ;
41+ import { Check , Star } from 'lucide-react ' ;
4442import { useTranslations } from 'use-intl' ;
4543import { useParams } from 'react-router' ;
4644import { useTheme } from 'next-themes' ;
@@ -73,19 +71,56 @@ const Thread = memo(
7371 }
7472 } , [ getThreadData ?. latest ?. tags ] ) ;
7573
76- // Import the optimistic actions hook
74+ const optimisticState = message . id
75+ ? useOptimisticThreadState ( message . id )
76+ : useMemo (
77+ ( ) => ( {
78+ isMoving : false ,
79+ isStarring : false ,
80+ isMarkingAsRead : false ,
81+ isAddingLabel : false ,
82+ isRemoving : false ,
83+ shouldHide : false ,
84+ optimisticStarred : null ,
85+ optimisticRead : null ,
86+ optimisticDestination : null ,
87+ hasOptimisticState : false ,
88+ } ) ,
89+ [ ] ,
90+ ) ;
91+
92+ const displayStarred =
93+ optimisticState . optimisticStarred !== null ? optimisticState . optimisticStarred : isStarred ;
94+
95+ const optimisticLabels = useMemo ( ( ) => {
96+ if ( ! getThreadData ?. labels ) return [ ] ;
97+
98+ const labels = [ ...getThreadData . labels ] ;
99+ const hasStarredLabel = labels . some ( ( label ) => label . name === 'STARRED' ) ;
100+
101+ if ( optimisticState . optimisticStarred !== null ) {
102+ if ( optimisticState . optimisticStarred && ! hasStarredLabel ) {
103+ labels . push ( { id : 'starred-optimistic' , name : 'STARRED' } ) ;
104+ } else if ( ! optimisticState . optimisticStarred && hasStarredLabel ) {
105+ return labels . filter ( ( label ) => label . name !== 'STARRED' ) ;
106+ }
107+ }
108+
109+ return labels ;
110+ } , [ getThreadData ?. labels , optimisticState . optimisticStarred ] ) ;
111+
77112 const { optimisticToggleStar } = useOptimisticActions ( ) ;
78113
79114 const handleToggleStar = useCallback (
80115 async ( e : React . MouseEvent ) => {
81116 e . stopPropagation ( ) ;
82117 if ( ! getThreadData || ! message . id ) return ;
83118
84- const newStarredState = ! isStarred ;
119+ const newStarredState = ! displayStarred ;
85120 setIsStarred ( newStarredState ) ;
86121 await optimisticToggleStar ( [ message . id ] , newStarredState ) ;
87122 } ,
88- [ getThreadData , message . id , isStarred , optimisticToggleStar ] ,
123+ [ getThreadData , message . id , displayStarred , optimisticToggleStar ] ,
89124 ) ;
90125
91126 const handleNext = useCallback (
@@ -103,7 +138,6 @@ const Thread = memo(
103138 [ threads , id , focusedIndex ] ,
104139 ) ;
105140
106- // Use the optimistic move function
107141 const { optimisticMoveThreadsTo } = useOptimisticActions ( ) ;
108142
109143 const moveThreadTo = useCallback (
@@ -118,25 +152,6 @@ const Thread = memo(
118152 const latestMessage = getThreadData ?. latest ;
119153 const emailContent = getThreadData ?. latest ?. body ;
120154
121- // Get optimistic state for this thread - only if we have a valid message ID
122- const optimisticState = message . id
123- ? useOptimisticThreadState ( message . id )
124- : useMemo (
125- ( ) => ( {
126- isMoving : false ,
127- isStarring : false ,
128- isMarkingAsRead : false ,
129- isAddingLabel : false ,
130- isRemoving : false ,
131- shouldHide : false ,
132- optimisticStarred : null ,
133- optimisticRead : null ,
134- optimisticDestination : null ,
135- hasOptimisticState : false ,
136- } ) ,
137- [ ] ,
138- ) ;
139-
140155 const { labels : threadLabels } = useThreadLabels (
141156 getThreadData ?. labels ? getThreadData . labels . map ( ( l ) => l . id ) : [ ] ,
142157 ) ;
@@ -228,15 +243,17 @@ const Thread = memo(
228243 < Star2
229244 className = { cn (
230245 'h-4 w-4' ,
231- isStarred
246+ displayStarred
232247 ? 'fill-yellow-400 stroke-yellow-400'
233248 : 'fill-transparent stroke-[#9D9D9D] dark:stroke-[#9D9D9D]' ,
234249 ) }
235250 />
236251 </ Button >
237252 </ TooltipTrigger >
238- < TooltipContent className = "dark:bg-panelDark mb-1 bg-white" >
239- { isStarred ? t ( 'common.threadDisplay.unstar' ) : t ( 'common.threadDisplay.star' ) }
253+ < TooltipContent className = "mb-1 bg-white dark:bg-[#1A1A1A]" >
254+ { displayStarred
255+ ? t ( 'common.threadDisplay.unstar' )
256+ : t ( 'common.threadDisplay.star' ) }
240257 </ TooltipContent >
241258 </ Tooltip >
242259 { /* <Tooltip>
@@ -382,7 +399,7 @@ const Thread = memo(
382399 </ TooltipContent >
383400 </ Tooltip >
384401 ) : null }
385- < MailLabels labels = { getThreadData . labels } />
402+ < MailLabels labels = { optimisticLabels } />
386403 </ div >
387404 { latestMessage . receivedOn ? (
388405 < p
0 commit comments