@@ -51,6 +51,44 @@ function SettingField({
5151 )
5252}
5353
54+ function ToggleRow ( {
55+ title,
56+ hint,
57+ checked,
58+ disabled,
59+ onChange,
60+ badge,
61+ } : {
62+ title : string
63+ hint : string
64+ checked : boolean
65+ disabled ?: boolean
66+ onChange ?: ( ) => void
67+ badge ?: string
68+ } ) {
69+ return (
70+ < div className = "flex flex-row items-center justify-between gap-4 py-3.5" >
71+ < div className = "min-w-0" >
72+ < p className = "flex items-center gap-1.5 text-sm font-medium text-zinc-800 dark:text-zinc-200" >
73+ { title }
74+ { badge ? (
75+ < span className = "inline-flex items-center whitespace-nowrap rounded-full bg-blue-500/10 px-1.5 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-blue-600 dark:text-blue-400" >
76+ { badge }
77+ </ span >
78+ ) : null }
79+ </ p >
80+ < p className = "text-xs text-zinc-500 dark:text-zinc-400 mt-0.5" > { hint } </ p >
81+ </ div >
82+ < div className = "flex shrink-0 items-center gap-2" >
83+ < span className = "w-8 text-right text-xs tabular-nums text-zinc-500 dark:text-zinc-400" >
84+ { disabled ? "Off" : checked ? "On" : "Off" }
85+ </ span >
86+ < SwitchComponenet checked = { checked } disabled = { disabled } onChange = { onChange } label = "" />
87+ </ div >
88+ </ div >
89+ )
90+ }
91+
5492type props = {
5593 triggerToast : typeof toast ;
5694 hasResetActivityOnly ?: boolean ;
@@ -67,11 +105,10 @@ const Activity: FC<props> = (props) => {
67105 const [ isResetDialogOpen , setIsResetDialogOpen ] = useState ( false ) ;
68106 const [ isResetting , setIsResetting ] = useState ( false ) ;
69107 const [ leaderboardEnabled , setLeaderboardEnabled ] = useState ( false ) ;
70- const [ idleTimeEnabled , setIdleTimeEnabled ] = useState ( true ) ;
71- const [ leaderboardStyle , setLeaderboardStyle ] = useState < "list" | "podium" > (
72- "list"
73- ) ;
108+ const [ leaderboardStyle , setLeaderboardStyle ] = useState < "list" | "podium" > ( "list" ) ;
74109 const [ scheduleEnabled , setScheduleEnabled ] = useState ( false ) ;
110+ const [ privateServerEnabled , setPrivateServerEnabled ] = useState ( false ) ;
111+ const [ studioEnabled , setStudioEnabled ] = useState ( false ) ;
75112 const [ scheduleDay , setScheduleDay ] = useState < string > ( "monday" ) ;
76113 const [ scheduleFrequency , setScheduleFrequency ] = useState < string > ( "weekly" ) ;
77114 const router = useRouter ( ) ;
@@ -85,7 +122,8 @@ const Activity: FC<props> = (props) => {
85122 setRoles ( res . data . roles ) ;
86123 setSelectedRole ( res . data . currentRole ) ;
87124 setSelectedLRole ( res . data . leaderboardRole ) ;
88- setIdleTimeEnabled ( res . data . idleTimeEnabled ?? true ) ;
125+ setPrivateServerEnabled ( res . data . privateServerEnabled ) ;
126+ setStudioEnabled ( res . data . studioEnabled ) ;
89127 }
90128 } ) ( ) ;
91129 } , [ ] ) ;
@@ -204,18 +242,38 @@ const Activity: FC<props> = (props) => {
204242 }
205243 } ;
206244
207- const updateIdleTimeEnabled = async ( enabled : boolean ) => {
245+ const updatePrivateServer = async ( enabled : boolean ) => {
246+ const previous = privateServerEnabled ;
247+ setPrivateServerEnabled ( enabled ) ;
208248 try {
209249 const req = await axios . post (
210- `/api/workspace/${ workspace . groupId } /settings/activity/setIdleTime ` ,
250+ `/api/workspace/${ workspace . groupId } /settings/activity/setprivateserver ` ,
211251 { enabled : enabled }
212252 ) ;
213253 if ( req . status === 200 ) {
214- setIdleTimeEnabled ( enabled ) ;
215- triggerToast . success ( "Updated idle time tracking!" ) ;
254+ setPrivateServerEnabled ( req . data . enabled ) ;
255+ triggerToast . success ( "Updated Private Server tracking!" ) ;
216256 }
217257 } catch ( error : any ) {
218- triggerToast . error ( "Failed to update idle time tracking." ) ;
258+ setPrivateServerEnabled ( previous ) ;
259+ triggerToast . error ( "Failed to update private server tracking." ) ;
260+ }
261+ } ;
262+ const updateStudio = async ( enabled : boolean ) => {
263+ const previous = studioEnabled ;
264+ setStudioEnabled ( enabled ) ;
265+ try {
266+ const req = await axios . post (
267+ `/api/workspace/${ workspace . groupId } /settings/activity/setstudio` ,
268+ { enabled : enabled }
269+ ) ;
270+ if ( req . status === 200 ) {
271+ setStudioEnabled ( req . data . enabled ) ;
272+ triggerToast . success ( "Updated Studio tracking!" ) ;
273+ }
274+ } catch ( error : any ) {
275+ setStudioEnabled ( previous ) ;
276+ triggerToast . error ( "Failed to update studio tracking." ) ;
219277 }
220278 } ;
221279
@@ -295,7 +353,7 @@ const Activity: FC<props> = (props) => {
295353 < div className = "min-w-0" >
296354 < p className = "text-sm font-semibold text-zinc-900 dark:text-zinc-100" > Activity</ p >
297355 < p className = "text-xs text-zinc-400 dark:text-zinc-500 mt-0.5" >
298- Who is tracked, idle detection , and the desktop loader for in-game time.
356+ Who is tracked, settings , and the desktop loader for in-game time.
299357 </ p >
300358 </ div >
301359 </ div >
@@ -308,15 +366,15 @@ const Activity: FC<props> = (props) => {
308366 >
309367 < Listbox value = { selectedRole } onChange = { ( value : number ) => updateRole ( value ) } as = "div" className = "relative" >
310368 < Listbox . Button className = { listboxButtonClass } >
311- < span className = "truncate" > { ( roles . find ( ( r : any ) => r . rank === selectedRole ) as any ) ?. name || " Select a role" } </ span >
369+ < span className = "truncate" > { ( roles . find ( ( r : any ) => r . rank === selectedRole ) as any ) ?. name || ' Select a role' } </ span >
312370 < IconChevronDown className = "w-4 h-4 text-zinc-400 shrink-0" />
313371 </ Listbox . Button >
314372 < Listbox . Options className = { listboxOptionsClass } >
315373 { roles . filter ( ( role : any ) => role . rank > 0 ) . map ( ( role : any , index ) => (
316374 < Listbox . Option key = { index } value = { role . rank } className = { ( { active } ) => listboxOptionClass ( active ) } >
317375 { ( { selected } ) => (
318376 < >
319- < span className = { `${ selected ? "font-semibold" : "" } flex gap-2` } > { role . name } < span className = "text-zinc-400 dark:text-zinc-500" > (Group rank: { role . rank } )</ span > </ span >
377+ < span className = { `${ selected ? "font-semibold" : "" } flex gap-2` } > { role . name } < span className = "text-zinc-400 dark:text-zinc-500" > (Group rank: { role . rank } )</ span > </ span >
320378 { selected && < IconCheck className = "w-4 h-4 text-[color:rgb(var(--group-theme))]" /> }
321379 </ >
322380 ) }
@@ -326,25 +384,37 @@ const Activity: FC<props> = (props) => {
326384 </ Listbox >
327385 </ SettingField >
328386 </ div >
329- < div className = "pt-5 pb-5" >
330- < div className = "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between" >
331- < div className = "min-w-0" >
332- < p className = "text-sm font-medium text-zinc-800 dark:text-zinc-200" > Idle time tracking</ p >
333- < p className = "text-xs text-zinc-500 dark:text-zinc-400 mt-0.5" > Count time when staff are away from keyboard.</ p >
334- </ div >
335- < div className = "flex items-center justify-end gap-2 shrink-0" >
336- < span className = "text-xs text-zinc-500 dark:text-zinc-400 tabular-nums w-12 text-right" > { idleTimeEnabled ? "On" : "Off" } </ span >
337- < SwitchComponenet checked = { idleTimeEnabled } onChange = { ( ) => updateIdleTimeEnabled ( ! idleTimeEnabled ) } label = "" />
338- </ div >
339- </ div >
387+
388+ < div className = "divide-y divide-zinc-100 dark:divide-zinc-800/80" >
389+ < ToggleRow
390+ title = "Private Servers"
391+ hint = "Enable if you want the tracker to track the activity of players in a private server."
392+ checked = { privateServerEnabled }
393+ onChange = { ( ) => updatePrivateServer ( ! privateServerEnabled ) }
394+ />
395+ < ToggleRow
396+ title = "Studio Sessions"
397+ hint = "Enable if you want the tracker to track the activity of players on a studio session."
398+ checked = { studioEnabled }
399+ onChange = { ( ) => updateStudio ( ! studioEnabled ) }
400+ />
401+ < ToggleRow
402+ title = "Workspace Bans"
403+ hint = "Enable it if you don't want the tracker to track staff who are banned from the workspace."
404+ checked = { false }
405+ disabled
406+ badge = "Coming soon"
407+ />
340408 </ div >
409+
341410 < div className = "pt-5" >
342411 < p className = "text-sm font-medium text-zinc-800 dark:text-zinc-200" > Activity loader</ p >
343412 < p className = "text-xs text-zinc-500 dark:text-zinc-400 mt-0.5 mb-3" > Install this on your machine to report session time to the workspace.</ p >
344413 < button
345414 type = "button"
346415 onClick = { downloadLoader }
347- className = "inline-flex w-full sm:w-auto items-center justify-center gap-2 rounded-xl bg-[color:rgb(var(--group-theme))] px-4 py-2.5 text-sm font-medium text-white shadow-sm transition hover:opacity-90"
416+ disabled = { ! selectedRole }
417+ className = "inline-flex w-full sm:w-auto items-center justify-center gap-2 rounded-xl disabled:bg-white/40 disabled:hover:bg-white/40 disabled:cursor-not-allowed bg-[color:rgb(var(--group-theme))] px-4 py-2.5 text-sm font-medium text-white shadow-sm transition-all hover:opacity-90"
348418 >
349419 < IconDownload className = "h-4 w-4" stroke = { 1.5 } />
350420 Download loader
@@ -506,13 +576,13 @@ const Activity: FC<props> = (props) => {
506576 ) }
507577
508578 < div className = "space-y-4 rounded-2xl bg-zinc-50 dark:bg-zinc-800/50 p-4" >
509- < div className = "flex flex-col gap-3 sm:min-h-[2.5rem] sm:flex- row sm: items-center sm: justify-between sm: gap-4" >
510- < div className = "min-w-0 pr-0 sm:pr-2 " >
579+ < div className = "flex flex-row items-center justify-between gap-4" >
580+ < div className = "min-w-0" >
511581 < p className = "text-sm font-medium text-zinc-800 dark:text-zinc-200" > Automatic reset</ p >
512582 < p className = "mt-0.5 text-xs leading-relaxed text-zinc-500 dark:text-zinc-400" > Run a reset on a recurring schedule (saved separately from manual reset).</ p >
513583 </ div >
514- < div className = "flex shrink-0 items-center justify-end gap-2 sm:pt-0 " >
515- < span className = "w-8 text-right text-xs text-zinc-500 tabular-nums " > { scheduleEnabled ? "On" : "Off" } </ span >
584+ < div className = "flex shrink-0 items-center gap-2" >
585+ < span className = "w-8 text-right text-xs tabular-nums text-zinc-500 dark:text-zinc-400 " > { scheduleEnabled ? "On" : "Off" } </ span >
516586 < SwitchComponenet
517587 checked = { scheduleEnabled }
518588 onChange = { ( ) => setScheduleEnabled ( ! scheduleEnabled ) }
@@ -679,4 +749,4 @@ const Activity: FC<props> = (props) => {
679749Activity . title = "Activity" ;
680750Activity . isAboveOthers = true ;
681751
682- export default Activity ;
752+ export default Activity ;
0 commit comments