I'm working on an application that has a session timeout after 30 mins of inactivity. I have a new requirement to pop up a message asking users if they'd like to keep their session active, a couple mins before they're automatically logged out.
Right now the session is managed in what I think is a pretty unorthodox manner, and I need to try to work with what's already there. There's a service used by the App Module called context.service
(injected as a provider) that uses a setTimeout to determine when 30 mins of inactivity has expired.
Given that I need access to that countdown, I wanted to create a mirrored timeout that executes 2 mins earlier and fires the modal, asking the user if they want to keep their session open. After injecting NgbModal
into the ContextService
I receive a circular reference error which seems quite reasonable. It seems a little crazy to try to populate a modal on the DOM using a provider, but I'm not sure what a viable alternative is.
Here's the current state as it exists (with the circular reference error):
// ...
import { SessionExpirationWarning } from '../components/session-expiration-warning/session-expiration-warning.component';
// ....
constructor(
private _http: HttpClient,
private _injector: Injector,
private modalSvc: NgbModal
) {
// ...
}
// ...
setSessionTimeout() {
if (this.appConfig === null) { return; }
clearTimeout(this._timeoutId);
clearTimeout(this.timeoutWarning);
const sessionTimeOutConfig = this.appConfig.SessionTimeoutMinutes;
const SessionTimeoutMinutes = sessionTimeOutConfig === undefined ? 5 : sessionTimeOutConfig;
const sessionWarningMinutes = 2;
this._timeoutId = setTimeout(() => {
this.sessionExpired();
}, SessionTimeoutMinutes * (60 * 1000));
this.timeoutWarning = setTimeout(() => {
if (!this.warningIsActive) {
const timeOutWarningModal = this.modalSvc.open(SessionExpirationWarning);
timeOutWarningModal.result.then((modalResponse) => {
if (modalResponse === true) {
this.keepAlive(null);
}
});
}
}, sessionWarningMinutes * (60 * 1000));
}
The this.timeoutWarning
was my attempt at hacking together a solution.
What you could do is to have an Observable
that emits when the warning popup should be displayed:
import { timer } from 'rxjs/observable/timer';
// ...
public sessionWarningTimer$ = new Subject();
// ...
setSessionTimeout() {
// ...
timer(sessionWarningMinutes * 60 * 1000).subscribe(this.sessionWarningTimer$);
}
In a component (e.g. your AppComponent
) you could then subscribe to sessionWarningTimer$
:
private destroyed$ = new Subject();
ngOnInit() {
this
.contextService
.sessionWarningTimer$
.takeUntil(this.destroyed$)
.subscribe(() => this.displaySessionWarning());
}
ngOnDestroy() {
this.destroyed$.next();
}
displaySessionWarning() {
// your display code here
}
Like this, you can avoid any UI code in your service and rather focus on the warning logics.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With