From 63b6240c22f82a89fb71adcbfb0ae12be954c2fe Mon Sep 17 00:00:00 2001 From: jtricerolph Date: Mon, 13 Jul 2026 12:48:06 +0000 Subject: [PATCH] Add This Device tab to portal admin settings --- src/pages/AdminSettings.tsx | 78 +++++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 3 deletions(-) diff --git a/src/pages/AdminSettings.tsx b/src/pages/AdminSettings.tsx index 34695d3..b73056f 100644 --- a/src/pages/AdminSettings.tsx +++ b/src/pages/AdminSettings.tsx @@ -47,7 +47,7 @@ interface AppRow { } export function AdminSettings({ user }: { user: User }) { - const [tab, setTab] = useState<'integrations' | 'rooms' | 'apps'>('integrations') + const [tab, setTab] = useState<'integrations' | 'rooms' | 'apps' | 'device'>('integrations') const [integrations, setIntegrations] = useState([]) const [loading, setLoading] = useState(true) @@ -68,7 +68,7 @@ export function AdminSettings({ user }: { user: User }) {

- {(['integrations', 'rooms', 'apps'] as const).map(t => ( + {(['integrations', 'rooms', 'apps', 'device'] as const).map(t => ( ))}
@@ -95,6 +95,7 @@ export function AdminSettings({ user }: { user: User }) { {tab === 'rooms' && } {tab === 'apps' && } + {tab === 'device' && } ) @@ -554,6 +555,77 @@ function AppsTab() { ) } +const TIMEOUT_OPTIONS = [ + { label: 'Off', value: 0 }, + { label: '5 min', value: 5 }, + { label: '10 min', value: 10 }, + { label: '15 min', value: 15 }, + { label: '30 min', value: 30 }, +] + +function getInactivityMins(): number { + const c = document.cookie.split(';').map(s => s.trim()).find(s => s.startsWith('hnf_inactivity_mins=')) + return c ? parseInt(c.split('=')[1]) || 0 : 0 +} + +function setInactivityMins(mins: number) { + document.cookie = mins > 0 + ? `hnf_inactivity_mins=${mins}; max-age=31536000; path=/; SameSite=Strict` + : 'hnf_inactivity_mins=; max-age=0; path=/; SameSite=Strict' +} + +function DeviceTab() { + const [inactivityMins, setInactivityMinsState] = useState(getInactivityMins) + const [saved, setSaved] = useState(false) + const isPwa = window.matchMedia('(display-mode: standalone)').matches + + return ( +
+

+ {isPwa + ? 'This device is running as an installed PWA — inactivity timeout is automatically disabled. Sessions last until the 30-day sign-in limit.' + : 'Set an inactivity timeout for this device. Users will be signed out automatically after the chosen period of no activity. Use on shared or front-desk computers. Ignored when running as an installed PWA.'} +

+ +

+ Inactivity timeout +

+ +
+ {TIMEOUT_OPTIONS.map(opt => ( + + ))} +
+ + {saved && ( +

+ ✓ Saved — takes effect immediately +

+ )} +
+ ) +} + const inputStyle: React.CSSProperties = { background: 'var(--body-bg)', border: '1px solid var(--card-border)', borderRadius: '6px', padding: '0.45rem 0.75rem', fontSize: '0.85rem',