Add This Device tab to portal admin settings
This commit is contained in:
parent
af810f14c7
commit
63b6240c22
1 changed files with 75 additions and 3 deletions
|
|
@ -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<Integration[]>([])
|
||||
const [loading, setLoading] = useState(true)
|
||||
|
||||
|
|
@ -68,7 +68,7 @@ export function AdminSettings({ user }: { user: User }) {
|
|||
</p>
|
||||
|
||||
<div style={{ display: 'flex', gap: '0.25rem', marginBottom: '1.75rem', borderBottom: '1px solid var(--card-border)', paddingBottom: '0' }}>
|
||||
{(['integrations', 'rooms', 'apps'] as const).map(t => (
|
||||
{(['integrations', 'rooms', 'apps', 'device'] as const).map(t => (
|
||||
<button key={t} onClick={() => setTab(t)} style={{
|
||||
background: 'none', border: 'none', padding: '0.5rem 1rem',
|
||||
fontSize: '0.85rem', fontWeight: 600, cursor: 'pointer',
|
||||
|
|
@ -76,7 +76,7 @@ export function AdminSettings({ user }: { user: User }) {
|
|||
borderBottom: tab === t ? '2px solid var(--navy)' : '2px solid transparent',
|
||||
marginBottom: '-1px',
|
||||
}}>
|
||||
{t === 'integrations' ? 'Integrations' : t === 'rooms' ? 'Rooms & Sites' : 'App Settings'}
|
||||
{t === 'integrations' ? 'Integrations' : t === 'rooms' ? 'Rooms & Sites' : t === 'apps' ? 'App Settings' : 'This Device'}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
|
@ -95,6 +95,7 @@ export function AdminSettings({ user }: { user: User }) {
|
|||
|
||||
{tab === 'rooms' && <RoomsTab />}
|
||||
{tab === 'apps' && <AppsTab />}
|
||||
{tab === 'device' && <DeviceTab />}
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
|
|
@ -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 (
|
||||
<div style={{ maxWidth: '480px' }}>
|
||||
<p style={{ fontSize: '0.83rem', color: 'var(--text-mid)', marginBottom: '1.5rem' }}>
|
||||
{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.'}
|
||||
</p>
|
||||
|
||||
<p style={{ fontSize: '0.72rem', fontWeight: 700, color: 'var(--text-mid)',
|
||||
textTransform: 'uppercase', letterSpacing: '0.08em', marginBottom: '0.75rem' }}>
|
||||
Inactivity timeout
|
||||
</p>
|
||||
|
||||
<div style={{ display: 'flex', gap: '0.5rem', flexWrap: 'wrap', marginBottom: '1.25rem' }}>
|
||||
{TIMEOUT_OPTIONS.map(opt => (
|
||||
<button
|
||||
key={opt.value}
|
||||
disabled={isPwa}
|
||||
onClick={() => {
|
||||
setInactivityMins(opt.value)
|
||||
setInactivityMinsState(opt.value)
|
||||
setSaved(true)
|
||||
setTimeout(() => setSaved(false), 2000)
|
||||
}}
|
||||
style={{
|
||||
padding: '0.4rem 1rem', borderRadius: '6px', fontSize: '0.85rem', fontWeight: 600,
|
||||
cursor: isPwa ? 'not-allowed' : 'pointer', opacity: isPwa ? 0.4 : 1,
|
||||
border: `1px solid ${inactivityMins === opt.value ? 'var(--navy)' : 'var(--card-border)'}`,
|
||||
background: inactivityMins === opt.value ? 'var(--navy)' : 'var(--body-bg)',
|
||||
color: inactivityMins === opt.value ? '#fff' : 'var(--text-dark)',
|
||||
transition: 'all 0.15s',
|
||||
}}
|
||||
>
|
||||
{opt.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{saved && (
|
||||
<p style={{ fontSize: '0.82rem', color: '#16a34a' }}>
|
||||
✓ Saved — takes effect immediately
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const inputStyle: React.CSSProperties = {
|
||||
background: 'var(--body-bg)', border: '1px solid var(--card-border)',
|
||||
borderRadius: '6px', padding: '0.45rem 0.75rem', fontSize: '0.85rem',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue