import { useEffect, useState } from 'react' import { RefreshCw, KeyRound, Ban, Trash2, Copy, Download } from 'lucide-react' import { fetchTerminals, createTerminal, revokeTerminal, deleteTerminal, extensionDownloadUrl } from '../api' import type { Terminal } from '../types' export default function Terminals() { const [terminals, setTerminals] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState('') const [newName, setNewName] = useState('') const [creating, setCreating] = useState(false) const [revealedKey, setRevealedKey] = useState<{ name: string; key: string } | null>(null) function load() { setLoading(true) fetchTerminals() .then(setTerminals) .catch(e => setError(e instanceof Error ? e.message : 'Failed to load terminals')) .finally(() => setLoading(false)) } useEffect(load, []) async function handleCreate(e: React.FormEvent) { e.preventDefault() if (!newName.trim()) return setCreating(true); setError('') try { const t = await createTerminal(newName.trim()) setRevealedKey({ name: t.name, key: t.api_key }) setNewName('') load() } catch (e) { setError(e instanceof Error ? e.message : 'Create failed') } finally { setCreating(false) } } async function handleRevoke(id: string) { if (!confirm('Revoke this terminal key? The Chrome extension using it will stop working immediately.')) return try { await revokeTerminal(id) load() } catch (e) { setError(e instanceof Error ? e.message : 'Revoke failed') } } async function handleDelete(id: string) { if (!confirm('Delete this terminal permanently?')) return try { await deleteTerminal(id) load() } catch (e) { setError(e instanceof Error ? e.message : 'Delete failed') } } return (

Terminals

API keys for the standalone "Send to Check-in Tablet" Chrome extension — one per reception PC. The extension calls this app's push endpoint using a terminal key instead of a staff login (hotel-owned hardware gets a device credential, same trust tier as the tablets themselves).

Chrome Extension

Not published anywhere yet, so it needs installing manually on each reception PC: download, unzip, then chrome://extensions → enable Developer mode → Load unpacked → select the unzipped folder. It'll need a terminal key from below to actually authorize pushes — create one first if you haven't already.

Download Extension (.zip)
{error &&
{error}
} {revealedKey && (
Key for "{revealedKey.name}"

Copy this now and paste it into the extension's settings popup — it will never be shown again.

{revealedKey.key}
)}
setNewName(e.target.value)} style={{ flex: 1, border: '1px solid var(--card-border)', borderRadius: 8, padding: '8px 10px' }} />
{loading ?

Loading…

: terminals.length === 0 ? (
No terminals yet.
) : (
{terminals.map(t => ( ))}
NameCreatedLast UsedStatus
{t.name} {new Date(t.created_at).toLocaleDateString('en-GB')} {t.last_used_at ? new Date(t.last_used_at).toLocaleString('en-GB') : 'never'} {t.revoked_at ? Revoked : Active} {!t.revoked_at && ( )}
)}
) }