Lock Screen
After a configurable period of inactivity the application overlays a full-screen lock screen. The user must re-enter their password to continue. The session (JWT) remains valid — the lock is enforced client-side and backed by a server-side password check.
How it works
User inactive for N minutes
│
▼
lockScreen() dispatched
isLocked = true in Redux
│
▼
<LockScreen /> overlay renders (z-index 9999, backdrop blur)
│
user enters password
│
▼
POST /api/auth/password/verify
│
┌────┴────┐
204 401
│ │
unlock show error,
screen clear field
Configuration
The inactivity timeout is driven by the ui.lock.timeout_minutes config key.
| Property | Value |
|---|---|
| Config key | ui.lock.timeout_minutes |
| Type | int |
| Default | 15 minutes |
| Range | 1 – 480 minutes |
| Allowed levels | Global + Tenant (bitmask 3) |
A TenantAdmin can override the timeout for their organisation:
POST /api/config/tenant/set
{ "code": "ui.lock.timeout_minutes", "value": "30" }
The resolved value arrives in the login config map and is persisted in localStorage under the key hr_lock_timeout_minutes so it survives a page refresh.
Redux state — lockSlice
File: src/reduxToolkit/reducers/layout/lockSlice.ts
| State field | Type | Description |
|---|---|---|
isLocked | boolean | true while the lock screen is shown |
timeoutMinutes | number | Inactivity threshold; initialised from localStorage |
Actions
| Action | Description |
|---|---|
lockScreen() | Activates the lock screen |
unlockScreen() | Dismisses the lock screen after a successful password check |
setLockTimeout(n) | Updates the timeout and persists it to localStorage |
Inactivity hook — useLockScreen
File: src/hooks/useLockScreen.ts
Registers window-level event listeners and resets a setTimeout on every interaction. When the timer fires, it dispatches lockScreen().
Monitored events: mousemove, mousedown, keydown, touchstart, scroll, click.
The hook is a no-op when isAuthenticated === false or isLocked === true, so it never runs before login or while already locked.
Usage — called once at the top of Layout:
// src/layout/index.tsx
useLockScreen();
Lock screen component — <LockScreen />
File: src/auth/LockScreen.tsx
Rendered inside Layout whenever isLocked === true:
{isLocked && <LockScreen />}
Features
- Fixed full-screen overlay with backdrop blur (
blur(6px)) and a semi-transparent dark background. - Shows the logged-in user's avatar, full name, and email address.
- Password field with show/hide toggle.
- Submit calls
authService.verifyPassword(password)→POST /api/auth/password/verify.- On
204: dispatchesunlockScreen(). - On
401: shows thelockScreen.errorWrongPasswordi18n message and clears the field.
- On
- "Not you?" button dispatches
logout()and redirects to/login.
i18n keys
All visible strings use the lockScreen.* namespace. Add translations for every supported locale.
| Key | English value |
|---|---|
lockScreen.title | Session locked. Enter your password to continue. |
lockScreen.password | Password |
lockScreen.unlock | Unlock |
lockScreen.unlocking | Verifying... |
lockScreen.errorWrongPassword | Incorrect password. Please try again. |
lockScreen.notYou | Not you? Sign in with a different account |
Changing the timeout at runtime
Call setLockTimeout from any component or settings page:
import { setLockTimeout } from "../reduxToolkit/reducers/layout/lockSlice";
dispatch(setLockTimeout(30)); // 30 minutes
This updates both the Redux state and localStorage. The change takes effect on the next timer reset (i.e., after the next user interaction).