2020
2121 // Initialize monitoring
2222 window . initActivityMonitor = function ( session , user , type ) {
23- // Only monitor candidates
24- if ( type === 'interviewer' ) {
25- console . log ( 'Activity monitoring skipped for interviewer' ) ;
26- return ;
27- }
28-
29- monitoring = true ;
3023 sessionCode = session ;
3124 userId = user ;
3225 userType = type ;
33- metrics . sessionStart = Date . now ( ) ;
3426
35- console . log ( 'Activity monitoring started for:' , user ) ;
36-
37- // Start monitoring
38- setupVisibilityTracking ( ) ;
39- setupIdleDetection ( ) ;
40- setupActivityTracking ( ) ;
41- reportMetricsPeriodically ( ) ;
27+ // For candidates, track their activity
28+ if ( type === 'candidate' ) {
29+ monitoring = true ;
30+ metrics . sessionStart = Date . now ( ) ;
31+ console . log ( 'Activity monitoring started for candidate:' , user ) ;
32+
33+ // Start monitoring
34+ setupVisibilityTracking ( ) ;
35+ setupIdleDetection ( ) ;
36+ setupActivityTracking ( ) ;
37+ reportMetricsPeriodically ( ) ;
38+ }
39+ // For interviewers, just listen to activity updates from Firebase
40+ else if ( type === 'interviewer' ) {
41+ console . log ( 'Activity monitoring in observer mode for interviewer' ) ;
42+ listenToActivityUpdates ( ) ;
43+ }
4244 } ;
4345
46+ // Listen to activity updates from Firebase (for interviewers)
47+ function listenToActivityUpdates ( ) {
48+ if ( ! window . firebase || ! sessionCode ) return ;
49+
50+ // Listen to activity summary updates
51+ firebase . database ( )
52+ . ref ( `sessions/${ sessionCode } /activity_summary` )
53+ . on ( 'value' , function ( snapshot ) {
54+ const summary = snapshot . val ( ) ;
55+ if ( summary && window . updateActivityDashboard ) {
56+ window . updateActivityDashboard ( summary ) ;
57+ }
58+ } ) ;
59+
60+ // Listen to alerts
61+ firebase . database ( )
62+ . ref ( `sessions/${ sessionCode } /activity_log` )
63+ . orderByChild ( 'timestamp' )
64+ . limitToLast ( 10 )
65+ . on ( 'child_added' , function ( snapshot ) {
66+ const event = snapshot . val ( ) ;
67+ if ( event && event . type === 'alert_triggered' ) {
68+ console . log ( 'Activity alert:' , event . message ) ;
69+ // Could show a toast notification here
70+ }
71+ } ) ;
72+ }
73+
4474 // 1. VISIBILITY API - This actually works!
4575 function setupVisibilityTracking ( ) {
4676 let hiddenTime = null ;
347377
348378 // 10. Update interviewer UI
349379 window . updateActivityDashboard = function ( summary ) {
380+ // Update the dashboard in notes panel
350381 const dashboard = document . getElementById ( 'activity-dashboard' ) ;
351- if ( ! dashboard ) return ;
352-
353- dashboard . style . display = 'block' ;
354- dashboard . innerHTML = `
382+ if ( dashboard ) {
383+ dashboard . style . display = 'block' ;
384+ dashboard . innerHTML = `
355385 <div class="activity-summary">
356386 <h4>Candidate Activity Monitor</h4>
357387 <div class="activity-metrics">
379409 ` : '' }
380410 </div>
381411 ` ;
412+ }
413+
414+ // Also create/update a floating indicator for interviewers
415+ createFloatingIndicator ( summary ) ;
382416 } ;
383417
418+ // Create a floating activity indicator that's always visible
419+ function createFloatingIndicator ( summary ) {
420+ // Only show for interviewers
421+ const user = window . Auth && window . Auth . getCurrentUser ( ) ;
422+ if ( ! user || ! user . isAdmin ) return ;
423+
424+ let indicator = document . getElementById ( 'floating-activity-indicator' ) ;
425+ if ( ! indicator ) {
426+ // Create the floating indicator
427+ indicator = document . createElement ( 'div' ) ;
428+ indicator . id = 'floating-activity-indicator' ;
429+ indicator . style . cssText = `
430+ position: fixed;
431+ bottom: 20px;
432+ left: 20px;
433+ background: rgba(30, 30, 30, 0.95);
434+ border: 1px solid rgba(66, 165, 245, 0.3);
435+ border-radius: 8px;
436+ padding: 12px;
437+ min-width: 200px;
438+ z-index: 1000;
439+ font-family: monospace;
440+ font-size: 12px;
441+ color: #fff;
442+ box-shadow: 0 4px 12px rgba(0,0,0,0.3);
443+ ` ;
444+ document . body . appendChild ( indicator ) ;
445+ }
446+
447+ // Color based on activity score
448+ const scoreColor = summary . activityScore > 80 ? '#4caf50' :
449+ summary . activityScore > 60 ? '#ff9800' : '#ff4444' ;
450+
451+ indicator . innerHTML = `
452+ <div style="font-weight: bold; margin-bottom: 8px; color: #42a5f5;">
453+ 📊 Candidate Activity
454+ </div>
455+ <div style="display: grid; grid-template-columns: auto auto; gap: 4px 12px; font-size: 11px;">
456+ <span style="color: #999;">Score:</span>
457+ <span style="color: ${ scoreColor } ; font-weight: bold;">${ summary . activityScore } %</span>
458+
459+ <span style="color: #999;">Tab Switches:</span>
460+ <span style="color: ${ summary . tabSwitches > 10 ? '#ff9800' : '#fff' } ;">${ summary . tabSwitches } </span>
461+
462+ <span style="color: #999;">Idle:</span>
463+ <span>${ summary . idlePeriods } periods</span>
464+
465+ ${ summary . suspiciousPatterns > 0 ? `
466+ <span style="color: #ff9800;">⚠️ Suspicious:</span>
467+ <span style="color: #ff9800;">${ summary . suspiciousPatterns } </span>
468+ ` : '' }
469+ </div>
470+ <div style="margin-top: 8px; padding-top: 8px; border-top: 1px solid rgba(255,255,255,0.1); font-size: 10px; color: #666;">
471+ Session: ${ summary . sessionDurationMinutes } min
472+ </div>
473+ ` ;
474+ }
475+
384476 console . log ( 'Activity Monitor module loaded - using reliable browser APIs' ) ;
385477} ) ( ) ;
0 commit comments