0.2.75
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useQuery } from '../lib/hooks';
|
||||
import { initials, num, presence, recent, when } from '../lib/format';
|
||||
import { initials, num, presence, recent, watchTime, when } from '../lib/format';
|
||||
import { Banner, Empty, Loading, Note, PageHead, Tag, Tiles } from '../components/ui';
|
||||
import type { KnownClient } from '../api/types';
|
||||
|
||||
@@ -9,6 +9,21 @@ import type { KnownClient } from '../api/types';
|
||||
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. */
|
||||
|
||||
/* Watch time comes from Tracearr, and `matched` is the field that matters: a household
|
||||
running no Tracearr, and a person Tracearr has never seen, both arrive as zeroes. Drawing
|
||||
those as "0 min this week" would have an operator asking why somebody stopped watching
|
||||
when the real answer is that nothing was asked. */
|
||||
interface WatchTime {
|
||||
matched: boolean;
|
||||
tracearrUsername?: string;
|
||||
weekMs: number;
|
||||
monthMs: number;
|
||||
totalMs: number;
|
||||
weekSessions: number;
|
||||
monthSessions: number;
|
||||
lastWatchedAt?: string;
|
||||
}
|
||||
|
||||
interface Account {
|
||||
id: string;
|
||||
username: string;
|
||||
@@ -16,6 +31,7 @@ interface Account {
|
||||
lastSeen: string;
|
||||
devices: KnownClient[] | null;
|
||||
recommendations?: { prompted?: boolean; completed?: boolean };
|
||||
watchTime?: WatchTime;
|
||||
}
|
||||
|
||||
interface AccountsResponse {
|
||||
@@ -32,6 +48,10 @@ export function AccountsPage() {
|
||||
const queued = accounts.filter(
|
||||
(account) => account.recommendations?.prompted && !account.recommendations?.completed,
|
||||
).length;
|
||||
/* Summed from the same rows the list draws, so the tile and the column underneath it can
|
||||
never disagree — a separate total query is how those two come apart. */
|
||||
const tracked = accounts.filter((account) => account.watchTime?.matched);
|
||||
const weekMs = tracked.reduce((total, account) => total + (account.watchTime?.weekMs ?? 0), 0);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -60,6 +80,16 @@ export function AccountsPage() {
|
||||
},
|
||||
{ label: 'recommendation setups completed', value: num(completed), icon: 'check', tone: 'ok' },
|
||||
{ label: 'setup prompts queued', value: num(queued), icon: 'sparkle', tone: 'note' },
|
||||
...(tracked.length
|
||||
? [
|
||||
{
|
||||
label: 'watched by the household this week',
|
||||
value: watchTime(weekMs),
|
||||
icon: 'pulse' as const,
|
||||
tone: 'data' as const,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
]}
|
||||
/>
|
||||
|
||||
@@ -78,6 +108,7 @@ export function AccountsPage() {
|
||||
? { label: 'prompt queued', tone: 'warn' as const }
|
||||
: { label: 'not invited', tone: undefined };
|
||||
const seen = presence(account.lastSeen);
|
||||
const watched = account.watchTime;
|
||||
return (
|
||||
<Link className="list-row" key={account.id} to={`/admin/accounts/${encodeURIComponent(account.id)}`}>
|
||||
<span className="list-main">
|
||||
@@ -90,10 +121,17 @@ export function AccountsPage() {
|
||||
<span className="list-meta">
|
||||
{num(list.length)} device{list.length === 1 ? '' : 's'}
|
||||
{active ? ` · ${active} active now` : ''} · last seen {when(account.lastSeen)}
|
||||
{/* The month sits beside the week because a quiet week only means
|
||||
something next to the month around it. Both are omitted rather
|
||||
than zeroed for somebody Tracearr has never seen. */}
|
||||
{watched?.matched
|
||||
? ` · watched ${watchTime(watched.weekMs)} this week, ${watchTime(watched.monthMs)} this month`
|
||||
: ''}
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<span className="list-actions">
|
||||
{watched?.matched ? <Tag tone="data">{watchTime(watched.weekMs)}</Tag> : null}
|
||||
<Tag tone={state.tone}>{state.label}</Tag>
|
||||
<span className="crumb">Manage</span>
|
||||
</span>
|
||||
|
||||
Reference in New Issue
Block a user