Projeto bot pontos
This commit is contained in:
137
web/app/(painel)/usuarios/[id]/page.tsx
Normal file
137
web/app/(painel)/usuarios/[id]/page.tsx
Normal file
@@ -0,0 +1,137 @@
|
||||
import Link from "next/link";
|
||||
import { apiGet } from "@/lib/server-api";
|
||||
import { badgeClass, dayStatusLabel, fmtDateTime, pauseReasonLabel, userStatusLabel } from "@/lib/format";
|
||||
import { isRestricted } from "@/lib/access";
|
||||
import type { Me, UserDetail } from "@/lib/types";
|
||||
import { ActionButton } from "@/components/ActionButton";
|
||||
import { CredentialsForm, ScheduleForm, TodayPanel } from "./forms";
|
||||
|
||||
export default async function UserPage({ params }: { params: Promise<{ id: string }> }) {
|
||||
const { id } = await params;
|
||||
const [detail, me] = await Promise.all([apiGet<UserDetail>(`/users/${id}`), apiGet<Me>("/auth/me")]);
|
||||
const { user, credential, today } = detail;
|
||||
const restricted = isRestricted(me.account);
|
||||
const canAdmin = me.account.role !== "viewer";
|
||||
// Conta de leitura ligada a este usuário também altera as próprias configurações.
|
||||
const canEdit = canAdmin || me.account.user_id === user.id;
|
||||
const base = `/users/${user.id}`;
|
||||
|
||||
return (
|
||||
<>
|
||||
{!restricted && (
|
||||
<p>
|
||||
<Link href="/usuarios">← Usuários</Link>
|
||||
</p>
|
||||
)}
|
||||
<h1>
|
||||
{user.display_name} <span className={badgeClass(user.status)}>{userStatusLabel[user.status]}</span>
|
||||
</h1>
|
||||
<p className="muted">
|
||||
ID {user.id} · chat {user.telegram_chat_id} · cadastrado em {fmtDateTime(user.created_at)}
|
||||
</p>
|
||||
|
||||
<section className="card">
|
||||
<h2>Cadastro e lembretes</h2>
|
||||
<dl className="kv">
|
||||
<dt>Lembretes</dt>
|
||||
<dd>
|
||||
{user.notifications_enabled
|
||||
? "ligados"
|
||||
: user.paused_reason
|
||||
? pauseReasonLabel[user.paused_reason]
|
||||
: "desligados"}
|
||||
</dd>
|
||||
<dt>Admin do bot</dt>
|
||||
<dd>{user.is_bot_admin ? "sim" : "não"}</dd>
|
||||
<dt>Hoje ({today.day})</dt>
|
||||
<dd>
|
||||
<span className={badgeClass(today.status)}>{dayStatusLabel[today.status]}</span>{" "}
|
||||
<span className="muted">
|
||||
{today.last_point_count} ponto(s) na última consulta · próxima consulta: {fmtDateTime(today.next_check_at)}
|
||||
</span>
|
||||
</dd>
|
||||
</dl>
|
||||
{canEdit && (
|
||||
<div className="actions">
|
||||
{canAdmin && user.status !== "active" && <ActionButton path={`${base}/activate`} label="Ativar" variant="primary" />}
|
||||
{canAdmin && user.status !== "disabled" && (
|
||||
<ActionButton
|
||||
path={`${base}/disable`}
|
||||
label="Desativar"
|
||||
variant="danger"
|
||||
confirm="Desativar este usuário? Os lembretes agendados serão cancelados."
|
||||
/>
|
||||
)}
|
||||
{user.status === "active" &&
|
||||
(user.notifications_enabled ? (
|
||||
<ActionButton path={`${base}/notifications/disable`} label="Pausar lembretes" />
|
||||
) : (
|
||||
<ActionButton path={`${base}/notifications/enable`} label="Ligar lembretes" variant="primary" />
|
||||
))}
|
||||
{canAdmin && (
|
||||
<ActionButton
|
||||
path={`${base}/bot-admin`}
|
||||
method="PUT"
|
||||
body={{ enabled: !user.is_bot_admin }}
|
||||
label={user.is_bot_admin ? "Remover admin do bot" : "Tornar admin do bot"}
|
||||
/>
|
||||
)}
|
||||
{canAdmin && (today.status === "no_points" || today.status === "not_working") && (
|
||||
<ActionButton path={`${base}/today/resume`} label="Retomar consultas de hoje" />
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
|
||||
<section className="card">
|
||||
<h2>Credencial PontoMais</h2>
|
||||
{credential ? (
|
||||
<dl className="kv">
|
||||
<dt>E-mail</dt>
|
||||
<dd>{credential.api_email}</dd>
|
||||
<dt>Situação</dt>
|
||||
<dd>
|
||||
{credential.validated ? (
|
||||
<span className="badge ok">validada em {fmtDateTime(credential.last_validated_at)}</span>
|
||||
) : (
|
||||
<span className="badge warn">não validada</span>
|
||||
)}
|
||||
</dd>
|
||||
<dt>Falhas seguidas</dt>
|
||||
<dd>{credential.consecutive_failures}</dd>
|
||||
{credential.last_error && (
|
||||
<>
|
||||
<dt>Último erro</dt>
|
||||
<dd className="error-text">{credential.last_error}</dd>
|
||||
</>
|
||||
)}
|
||||
</dl>
|
||||
) : (
|
||||
<p className="muted">Nenhuma credencial configurada. Sem ela o usuário não pode ser ativado.</p>
|
||||
)}
|
||||
{canEdit && <CredentialsForm userId={user.id} />}
|
||||
</section>
|
||||
|
||||
<section className="card">
|
||||
<h2>Jornada e janela de consulta</h2>
|
||||
<ScheduleForm
|
||||
userId={user.id}
|
||||
schedule={detail.schedule}
|
||||
timezone={user.timezone}
|
||||
effectiveWindow={detail.effective_window}
|
||||
disabled={!canEdit}
|
||||
/>
|
||||
</section>
|
||||
|
||||
<section className="card">
|
||||
<h2>Pontos de hoje</h2>
|
||||
<TodayPanel userId={user.id} canTest={canEdit} />
|
||||
</section>
|
||||
|
||||
<p>
|
||||
<Link href={`/notificacoes?user_id=${user.id}`}>Lembretes deste usuário</Link> ·{" "}
|
||||
{!restricted && <Link href={`/auditoria?target_user_id=${user.id}`}>Auditoria deste usuário</Link>}
|
||||
</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user