@@ -129,6 +129,12 @@ const Activity: FC<Props> = ({
129129 const [ adjustReason , setAdjustReason ] = useState ( "" ) ;
130130 const [ adjustType , setAdjustType ] = useState < "award" | "remove" > ( "award" ) ;
131131 const [ submittingAdjust , setSubmittingAdjust ] = useState ( false ) ;
132+ const [ localSessions , setLocalSessions ] = useState ( sessions ) ;
133+
134+ // keep in sync if prop changes (e.g. week switch)
135+ useEffect ( ( ) => {
136+ setLocalSessions ( sessions ) ;
137+ } , [ sessions ] ) ;
132138
133139 // Update displayMinutes when timeSpent prop changes (e.g., when switching between weeks)
134140 useEffect ( ( ) => {
@@ -139,7 +145,9 @@ const Activity: FC<Props> = ({
139145 const fetchConfig = async ( ) => {
140146 if ( id ) {
141147 try {
142- const res = await axios . get ( `/api/workspace/${ id } /settings/activity/getConfig` ) ;
148+ const res = await axios . get (
149+ `/api/workspace/${ id } /settings/activity/getConfig` ,
150+ ) ;
143151 setIdleTimeEnabled ( res . data . idleTimeEnabled ?? true ) ;
144152 } catch ( error ) {
145153 console . error ( "Failed to fetch activity config:" , error ) ;
@@ -183,11 +191,11 @@ const Activity: FC<Props> = ({
183191 minutes : val ,
184192 action : adjustType ,
185193 reason : adjustReason ,
186- }
194+ } ,
187195 ) ;
188196 if ( ! data . success ) throw new Error ( "Failed" ) ;
189197 setDisplayMinutes (
190- ( prev ) => prev + ( adjustType === "remove" ? - val : val )
198+ ( prev ) => prev + ( adjustType === "remove" ? - val : val ) ,
191199 ) ;
192200 toast . success ( "Adjustment saved!" ) ;
193201 setAdjustModal ( false ) ;
@@ -209,7 +217,10 @@ const Activity: FC<Props> = ({
209217 Activity
210218 </ Tab >
211219 < Tab className = { ( { selected } ) => profileTabClass ( selected ) } >
212- < IconCalendarEvent className = "w-3.5 h-3.5 sm:w-4 sm:h-4" stroke = { 1.75 } />
220+ < IconCalendarEvent
221+ className = "w-3.5 h-3.5 sm:w-4 sm:h-4"
222+ stroke = { 1.75 }
223+ />
213224 Sessions
214225 </ Tab >
215226 < Tab className = { ( { selected } ) => profileTabClass ( selected ) } >
@@ -233,11 +244,11 @@ const Activity: FC<Props> = ({
233244 { selectedWeek > 0 && availableHistory [ selectedWeek - 1 ] ? (
234245 < >
235246 { moment (
236- availableHistory [ selectedWeek - 1 ] . period . start
247+ availableHistory [ selectedWeek - 1 ] . period . start ,
237248 ) . format ( "MMM DD" ) } { " " }
238249 -{ " " }
239250 { moment (
240- availableHistory [ selectedWeek - 1 ] . period . end
251+ availableHistory [ selectedWeek - 1 ] . period . end ,
241252 ) . format ( "MMM DD, YYYY" ) }
242253 </ >
243254 ) : (
@@ -273,39 +284,69 @@ const Activity: FC<Props> = ({
273284 ) : (
274285 < div >
275286 { isHistorical && historicalPeriod && (
276- < div className = "mb-6 rounded-xl bg-amber-500/10 p-4" >
277- < div className = "flex items-center gap-3" >
278- < div className = "rounded-lg bg-amber-500/15 p-2" >
279- < IconCalendarTime className = "h-5 w-5 text-amber-600 dark:text-amber-400" stroke = { 1.75 } />
280- </ div >
281- < div >
282- < h3 className = "text-sm font-medium text-amber-900 dark:text-amber-200" >
283- Historical Activity Data
284- </ h3 >
285- < p className = "text-xs text-amber-700 dark:text-amber-300" >
286- Showing activity from{ " " }
287- { moment ( historicalPeriod . start ) . format ( "MMM DD" ) } -{ " " }
288- { moment ( historicalPeriod . end ) . format ( "MMM DD, YYYY" ) }
289- </ p >
287+ < div className = "mb-6 rounded-xl bg-amber-500/10 p-4" >
288+ < div className = "flex items-center gap-3" >
289+ < div className = "rounded-lg bg-amber-500/15 p-2" >
290+ < IconCalendarTime
291+ className = "h-5 w-5 text-amber-600 dark:text-amber-400"
292+ stroke = { 1.75 }
293+ />
294+ </ div >
295+ < div >
296+ < h3 className = "text-sm font-medium text-amber-900 dark:text-amber-200" >
297+ Historical Activity Data
298+ </ h3 >
299+ < p className = "text-xs text-amber-700 dark:text-amber-300" >
300+ Showing activity from{ " " }
301+ { moment ( historicalPeriod . start ) . format ( "MMM DD" ) } -{ " " }
302+ { moment ( historicalPeriod . end ) . format ( "MMM DD, YYYY" ) }
303+ </ p >
304+ </ div >
290305 </ div >
291306 </ div >
292- </ div >
293307 ) }
294308
295309 < Tab . Panels className = "min-h-[400px]" >
296310 < Tab . Panel >
297311 { ! isHistorical && canAdjustActivity && (
298- < div className = "mb-4 flex justify-end" >
299- < button
300- onClick = { ( ) => setAdjustModal ( true ) }
301- className = { profilePrimaryButtonClass }
302- >
303- < IconAdjustments className = "h-4 w-4" stroke = { 1.75 } />
304- Manual Adjustment
305- </ button >
306- </ div >
307- ) }
312+ < div className = "mb-4 flex justify-end" >
313+ < button
314+ onClick = { ( ) => setAdjustModal ( true ) }
315+ className = { profilePrimaryButtonClass }
316+ >
317+ < IconAdjustments className = "h-4 w-4" stroke = { 1.75 } />
318+ Manual Adjustment
319+ </ button >
320+ </ div >
321+ ) }
308322 < ActivityOverview
323+ onEndSession = { ( sid , wid ) => {
324+ toast . loading ( "Ending session..." , {
325+ id : `session-${ sid } ` ,
326+ } ) ;
327+ axios
328+ . post ( "/api/activity/force-end" , {
329+ sessionId : sid ,
330+ workspaceId : wid ,
331+ } )
332+ . then ( ( ) => {
333+ toast . success ( "Session ended" , {
334+ id : `session-${ sid } ` ,
335+ } ) ;
336+ setLocalSessions ( ( prev ) =>
337+ prev . map ( ( s ) =>
338+ s . id === sid
339+ ? { ...s , active : false , endTime : new Date ( ) }
340+ : s ,
341+ ) ,
342+ ) ;
343+ } )
344+ . catch ( ( ) => {
345+ toast . error ( "Failed to end session" , {
346+ id : `session-${ sid } ` ,
347+ } ) ;
348+ } ) ;
349+ } }
309350 data = { data }
310351 displayMinutes = { displayMinutes }
311352 messages = { messages }
@@ -315,13 +356,13 @@ const Activity: FC<Props> = ({
315356 idleTimeEnabled = { idleTimeEnabled }
316357 notices = { notices }
317358 adjustments = { adjustments }
318- sessions = { sessions }
359+ sessions = { localSessions }
319360 avatar = { avatar }
320361 />
321362 </ Tab . Panel >
322363 < Tab . Panel >
323364 < SessionsHistory
324- sessions = { sessions }
365+ sessions = { localSessions }
325366 notices = { notices }
326367 adjustments = { adjustments }
327368 avatar = { avatar }
@@ -374,7 +415,9 @@ const Activity: FC<Props> = ({
374415 leaveFrom = "opacity-100 scale-100"
375416 leaveTo = "opacity-0 scale-95"
376417 >
377- < Dialog . Panel className = { `w-full max-w-md transform overflow-hidden rounded-2xl bg-white p-6 text-left align-middle transition-all dark:bg-zinc-900 ${ profilePanelShadow } ` } >
418+ < Dialog . Panel
419+ className = { `w-full max-w-md transform overflow-hidden rounded-2xl bg-white p-6 text-left align-middle transition-all dark:bg-zinc-900 ${ profilePanelShadow } ` }
420+ >
378421 < Dialog . Title
379422 as = "h3"
380423 className = "mb-4 text-lg font-semibold text-zinc-900 dark:text-white"
@@ -394,7 +437,9 @@ const Activity: FC<Props> = ({
394437 type = "button"
395438 onClick = { ( ) => setAdjustType ( "remove" ) }
396439 className = { `flex-1 ${ profileTabClass ( adjustType === "remove" ) } ${
397- adjustType === "remove" ? "!bg-red-600 !text-white dark:!bg-red-600" : ""
440+ adjustType === "remove"
441+ ? "!bg-red-600 !text-white dark:!bg-red-600"
442+ : ""
398443 } `}
399444 >
400445 Remove
@@ -413,8 +458,8 @@ const Activity: FC<Props> = ({
413458 setAdjustMinutes (
414459 Math . min (
415460 1000 ,
416- Math . max ( 0 , parseInt ( e . target . value , 10 ) || 0 )
417- )
461+ Math . max ( 0 , parseInt ( e . target . value , 10 ) || 0 ) ,
462+ ) ,
418463 )
419464 }
420465 className = { profileInputClass }
@@ -453,8 +498,8 @@ const Activity: FC<Props> = ({
453498 { submittingAdjust
454499 ? "Saving..."
455500 : adjustType === "award"
456- ? "Award Minutes"
457- : "Remove Minutes" }
501+ ? "Award Minutes"
502+ : "Remove Minutes" }
458503 </ button >
459504 </ div >
460505 </ Dialog . Panel >
0 commit comments