80 lines
3.1 KiB
TypeScript
80 lines
3.1 KiB
TypeScript
import Link from "next/link";
|
|
import { apiGet } from "@/lib/server-api";
|
|
import { fmtDateTime, fmtDay, notificationStatusLabel } from "@/lib/format";
|
|
import { isRestricted } from "@/lib/access";
|
|
import type { Dashboard, Me } from "@/lib/types";
|
|
|
|
export default async function DashboardPage() {
|
|
const [d, me] = await Promise.all([apiGet<Dashboard>("/dashboard"), apiGet<Me>("/auth/me")]);
|
|
const users = d.users_by_status;
|
|
const restricted = isRestricted(me.account);
|
|
|
|
return (
|
|
<>
|
|
<h1>Início</h1>
|
|
|
|
{d.outage_since && (
|
|
<div className="alert error">
|
|
A PontoMais está fora do ar desde {fmtDateTime(d.outage_since)}. Ninguém foi pausado; os admins foram avisados
|
|
pelo Telegram.
|
|
</div>
|
|
)}
|
|
{d.holiday_fallback_day && (
|
|
<div className="alert warn">
|
|
Não foi possível obter os feriados deste ano: segunda a sexta estão valendo como dias úteis.{" "}
|
|
<Link href="/feriados">Ver feriados</Link>
|
|
</div>
|
|
)}
|
|
|
|
{!restricted && (
|
|
<section className="stats">
|
|
<Stat label="Aguardando aprovação" value={users.pending ?? 0} href="/usuarios?status=pending" />
|
|
<Stat label="Usuários ativos" value={users.active ?? 0} href="/usuarios?status=active" />
|
|
<Stat label="Com lembretes ligados" value={d.notifications_enabled} />
|
|
<Stat label="Pausados por falha na PontoMais" value={d.paused_by_api_failures} tone={d.paused_by_api_failures ? "error" : undefined} />
|
|
<Stat label="Falhas de envio (7 dias)" value={d.failed_last_7_days} href="/notificacoes?status=failed" tone={d.failed_last_7_days ? "error" : undefined} />
|
|
<Stat label="Expirados (7 dias)" value={d.expired_last_7_days} href="/notificacoes?status=expired" />
|
|
<Stat label="Janelas personalizadas" value={d.custom_windows} href="/usuarios?custom_window=true" />
|
|
</section>
|
|
)}
|
|
|
|
<section className="card">
|
|
<h2>Lembretes de hoje ({fmtDay(d.today)})</h2>
|
|
{Object.keys(d.today_by_status).length === 0 ? (
|
|
<p className="muted">Nenhum lembrete gerado hoje.</p>
|
|
) : (
|
|
<ul className="inline-list">
|
|
{Object.entries(d.today_by_status).map(([status, count]) => (
|
|
<li key={status}>
|
|
{restricted ? (
|
|
<span>
|
|
{notificationStatusLabel[status] ?? status}: <strong>{count}</strong>
|
|
</span>
|
|
) : (
|
|
<Link href={`/notificacoes?day=${d.today}&status=${status}`}>
|
|
{notificationStatusLabel[status] ?? status}: <strong>{count}</strong>
|
|
</Link>
|
|
)}
|
|
</li>
|
|
))}
|
|
</ul>
|
|
)}
|
|
</section>
|
|
</>
|
|
);
|
|
}
|
|
|
|
function Stat({ label, value, href, tone }: { label: string; value: number; href?: string; tone?: "error" }) {
|
|
const content = (
|
|
<>
|
|
<span className="stat-value">{value}</span>
|
|
<span className="stat-label">{label}</span>
|
|
</>
|
|
);
|
|
return (
|
|
<div className={`stat ${tone ?? ""}`}>
|
|
{href ? <Link href={href}>{content}</Link> : content}
|
|
</div>
|
|
);
|
|
}
|