Idle Detection

Idle detection is the process of monitoring user activity and determining when a user becomes inactive. This is particularly useful for applications that require users to remain logged in, as it allows the system to take appropriate action when a user stops interacting with the application, such as warning them of an impending timeout or automatically logging them out after a period of inactivity.

Key Features of the Idle Detection Service

  1. Configurable Idle and Timeout Durations: The service allows for customization of the idle and timeout durations through the IdleDetectionConfig class.
  2. Automatic Reset on User Activity: The service automatically resets the idle timer whenever user activity is detected, ensuring that the user's session remains active.
  3. Event Emission: The service emits events when the idle period ends and when the countdown to timeout begins, allowing components to take action, such as displaying a warning message to the user.
  4. Reactive Programming: By using RxJS subjects, the service provides observables that emit events when the user becomes idle or when the countdown ends. This allows components to react to these events in real-time.

Usage

1. Configure idle and timeout durations globally

We provide a configuration class that will hold our idle and timeout durations:

export class IdleDetectionConfig {
  idleDurationInSeconds?: number;
  timeoutDurationInSeconds?: number;
}

To use the idle detection service in an Angular application, you would first provide the configuration in your module:

import { provideIdleDetectionConfig, IdleDetectionService } from 'ngx-lift';

@NgModule({
  providers: [
    // After 20 minutes of inactivity, a countdown starts with 300.
    provideIdleDetectionConfig({
      idleDurationInSeconds: 20 * 60, // 20 minutes for idle-detection phase
      timeoutDurationInSeconds: 5 * 60, // 5 minutes for timeout phase
    }),
  ],
})
export class AppModule {}

Use in standalone app:

import { provideIdleDetectionConfig } from 'ngx-lift';

export const appConfig: ApplicationConfig = {
  providers: [
    provideIdleDetectionConfig({ idleDurationInSeconds: 20 * 60, timeoutDurationInSeconds: 5 * 60 }),
  ],
};

bootstrapApplication(AppComponent, appConfig).catch((err) => console.error(err));

2. Use IdleDetectionService in your component

Then, in your AppComponent, you can subscribe to the service's observables to react to idle events:

import { IdleDetectionService } from 'ngx-lift';

export class AppComponent implements OnInit {
  constructor(private idleDetectionService: IdleDetectionService, private authService: AuthService) {}

  ngOnInit() {
    if(this.authService.isLoggedIn) {
      // setConfig is optional if you have idle configuration by provideIdleDetectionConfig
      // This will overwrite the config passed by provideIdleDetectionConfig
      this.idleDetectionService.setConfig({
        idleDurationInSeconds: 5 * 60,
        timeoutDurationInSeconds: 5 * 60,
      });

      // Most important, start to watch for user inactivity!
      this.idleDetectionService.startWatching();

      this.idleDetectionService.onIdleEnd().subscribe(() => {
        // Handle idle end event, e.g., show a warning dialog
        console.log('idle detection phase ends, enter timeout phase');
      });

      this.idleDetectionService.onTimeoutEnd().subscribe(() => {
        // Handle timeout end event, e.g., log out the user
        console.log('timeout phase ends, should logout user');
      });

      this.idleDetectionService.onCountDown().subscribe((countdown) => {
        // Update the UI with the remaining time if needed
        console.log(countdown, 'display countdown in UI');
      });
    }
  }

  ngOnDestroy() {
    this.idleDetectionService.clearTimers();
  }
}

3. (Optional) Use IdleDetectionComponent

Furthermore, we provide a component in clr-lift that displays a Clarity modal dialog when the user is idle. The dialog will appear when the idle-detection phase concludes and start counting down. Once the countdown ends, you can hook into the timeout handler in your component to perform custom logic such as clearing the localStorage token and redirecting the user to the login page.

The parameters idleDurationInSeconds and timeoutDurationInSeconds are optional. When these parameters are passed, they will overwrite the configuration passed by provideIdleDetectionConfig.

import {IdleDetectionComponent} from 'clr-lift';

@Component({
  imports: [IdleDetectionComponent],
  template: `
    if(isLoggedIn) {
      <cll-idle-detection [idleDurationInSeconds]="15 * 60" [timeoutDurationInSeconds]="5 * 60" (timeout)="onTimeout()" />
    }
  `
})
export class AppComponent {
  isLoggedIn = inject(AuthService).isLoggedIn;

  onTimeout() {
    localStorage.removeItem('your-app-jwt');
    location.assign('/login');
  }
}

The dialog looks like below:

Idle Detection Dialog