43 lines
2.6 KiB
TypeScript
43 lines
2.6 KiB
TypeScript
import { useQuery } from '../lib/hooks';
|
||
import { num } from '../lib/format';
|
||
import { Banner, Card, EmptyRow, Loading, PageHead, TableWrap, Tiles } from '../components/ui';
|
||
import type { ViewsReport } from '../api/types';
|
||
|
||
function change(today: number, previous: number): string {
|
||
if (previous === 0) return today > 0 ? 'new this week' : 'no change';
|
||
const amount = Math.round(((today - previous) / previous) * 100);
|
||
return `${amount > 0 ? '+' : ''}${amount}% vs last week`;
|
||
}
|
||
|
||
export function ViewsPage() {
|
||
const { data, error, loading } = useQuery<ViewsReport>('/admin/api/views', { pollMs: 60_000 });
|
||
const daily = data?.daily ?? [];
|
||
const hourly = data?.hourly ?? [];
|
||
|
||
return (
|
||
<>
|
||
<PageHead title="Views" intro="How often people reach Memby’s home screen. This measures app use, not playback streams." />
|
||
<Banner message={error} />
|
||
{loading ? <Loading /> : (
|
||
<>
|
||
<Tiles tiles={[
|
||
{ label: change(data?.today.visits ?? 0, data?.lastWeek.visits ?? 0), value: num(data?.today.visits), icon: 'overview', tone: 'data' },
|
||
{ label: change(data?.today.viewers ?? 0, data?.lastWeek.viewers ?? 0), value: num(data?.today.viewers), icon: 'people', tone: 'note' },
|
||
{ label: 'busiest time today', value: data?.busiestHour || '—', small: true, icon: 'clock', tone: 'info' },
|
||
]} />
|
||
<Card title="Visits by day" intro="One visit is a signed-in home-screen opening. Viewers are distinct signed-in profiles." icon="chart" tone="data">
|
||
<TableWrap><table><thead><tr><th>Day</th><th className="num">Visits</th><th className="num">Viewers</th></tr></thead><tbody>
|
||
{daily.length === 0 ? <EmptyRow columns={3}>No home-screen visits yet.</EmptyRow> : daily.map((row) => <tr key={row.label}><td>{row.label}</td><td className="num">{num(row.visits)}</td><td className="num">{num(row.viewers)}</td></tr>)}
|
||
</tbody></table></TableWrap>
|
||
</Card>
|
||
<Card title="Today by hour" intro="Local New Zealand time. Use this to see when viewers are opening Memby." icon="clock" tone="info">
|
||
<TableWrap><table><thead><tr><th>Hour</th><th className="num">Visits</th><th className="num">Viewers</th></tr></thead><tbody>
|
||
{hourly.length === 0 ? <EmptyRow columns={3}>No home-screen visits yet today.</EmptyRow> : hourly.map((row) => <tr key={row.label}><td>{row.label}</td><td className="num">{num(row.visits)}</td><td className="num">{num(row.viewers)}</td></tr>)}
|
||
</tbody></table></TableWrap>
|
||
</Card>
|
||
</>
|
||
)}
|
||
</>
|
||
);
|
||
}
|