import { Link } from 'react-router-dom'; import { useQuery } from '../lib/hooks'; import { initials, num, presence, recent, when } from '../lib/format'; import { Banner, Empty, Loading, Note, PageHead, Tag, Tiles } from '../components/ui'; import type { KnownClient } from '../api/types'; /* A directory, and only a directory. Everything you can *do* to a person lives on their own page: this list used to render a full seventeen-control settings editor for every account at once, which meant the page grew with the household and an operator scrolled past four other people's preferences to reach the one they came for. */ interface Account { id: string; username: string; lastSeen: string; devices: KnownClient[] | null; recommendations?: { prompted?: boolean; completed?: boolean }; } interface AccountsResponse { accounts: Account[] | null; } export function AccountsPage() { const { data, error, loading } = useQuery('/admin/api/accounts', { pollMs: 60_000, }); const accounts = data?.accounts ?? []; const devices = accounts.flatMap((account) => account.devices ?? []); const completed = accounts.filter((account) => account.recommendations?.completed).length; const queued = accounts.filter( (account) => account.recommendations?.prompted && !account.recommendations?.completed, ).length; return ( <> This is the Memby user list, not the Emby user directory. A person appears here only after signing in to the Memby app. Removing access signs their Memby devices out and does not delete or change their Emby account. {loading ? ( ) : ( <> recent(device.lastSeen)).length), icon: 'pulse', tone: 'ok', }, { label: 'recommendation setups completed', value: num(completed), icon: 'check', tone: 'ok' }, { label: 'setup prompts queued', value: num(queued), icon: 'sparkle', tone: 'note' }, ]} />
{accounts.length === 0 ? ( No one has signed in to Memby yet. Emby-only accounts are intentionally not listed here. ) : ( accounts.map((account) => { const list = account.devices ?? []; const active = list.filter((device) => recent(device.lastSeen)).length; const state = account.recommendations?.completed ? { label: 'personalised', tone: 'ok' as const } : account.recommendations?.prompted ? { label: 'prompt queued', tone: 'warn' as const } : { label: 'not invited', tone: undefined }; const seen = presence(account.lastSeen); return ( {initials(account.username)} {account.username || 'Unnamed user'} {num(list.length)} device{list.length === 1 ? '' : 's'} {active ? ` · ${active} active now` : ''} · last seen {when(account.lastSeen)} {state.label} Manage ); }) )}
)} ); } /** The account page reads the same list to find the person it is about. */ export type { Account, AccountsResponse };