"use client"; import { useRouter } from "next/navigation"; import { useState, type ChangeEvent, type FormEvent } from "react"; import { WindowFields } from "@/components/WindowFields"; import { apiFetch, errorMessage } from "@/lib/client-api"; import { dayStatusLabel, fmtClock, fmtMinutes } from "@/lib/format"; import type { QueryWindow, Schedule, Today } from "@/lib/types"; /** Grava e valida a credencial na PontoMais; a anterior é mantida se a validação falhar. */ export function CredentialsForm({ userId }: { userId: number }) { const router = useRouter(); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [message, setMessage] = useState<{ ok: boolean; text: string } | null>(null); const [busy, setBusy] = useState(false); async function submit(e: FormEvent) { e.preventDefault(); setBusy(true); setMessage(null); try { await apiFetch(`/users/${userId}/credentials`, { method: "PUT", body: { email, password } }); setPassword(""); setMessage({ ok: true, text: "Credencial validada na PontoMais e gravada." }); router.refresh(); } catch (err) { setMessage({ ok: false, text: errorMessage(err) }); } finally { setBusy(false); } } return (
{message &&

{message.text}

}
); } export function ScheduleForm({ userId, schedule, timezone, effectiveWindow, disabled, }: { userId: number; schedule: Schedule; timezone: string; effectiveWindow: QueryWindow; disabled: boolean; }) { const router = useRouter(); const [form, setForm] = useState({ lunch_minutes: schedule.lunch_minutes, daily_work_minutes: schedule.daily_work_minutes, entrada2_lead_minutes: schedule.entrada2_lead_minutes, saida2_lead_minutes: schedule.saida2_lead_minutes, timezone, }); const [useGlobal, setUseGlobal] = useState(schedule.window === null); const [windowValue, setWindowValue] = useState(schedule.window ?? effectiveWindow); const [message, setMessage] = useState<{ ok: boolean; text: string } | null>(null); const [busy, setBusy] = useState(false); function number(key: keyof typeof form) { return (e: ChangeEvent) => setForm({ ...form, [key]: Number(e.target.value) }); } async function submit(e: FormEvent) { e.preventDefault(); setBusy(true); setMessage(null); try { await apiFetch(`/users/${userId}/schedule`, { method: "PUT", body: { ...form, window: useGlobal ? null : windowValue }, }); setMessage({ ok: true, text: "Jornada salva. Vale a partir da próxima consulta." }); router.refresh(); } catch (err) { setMessage({ ok: false, text: errorMessage(err) }); } finally { setBusy(false); } } return (
Janela de consulta {useGlobal ? (

Janela global: {effectiveWindow.query_window_start} às {effectiveWindow.query_window_end} (confirmação{" "} {effectiveWindow.day_check_deadline}, reverificações até {effectiveWindow.no_points_recheck_until}).

) : ( )}
{!disabled && ( )} {message &&

{message.text}

}
); } /** Consulta ao vivo na PontoMais (não é automática para não gastar consultas à toa). */ export function TodayPanel({ userId, canTest }: { userId: number; canTest: boolean }) { const [today, setToday] = useState(null); const [error, setError] = useState(""); const [busy, setBusy] = useState(false); async function load(test: boolean) { setBusy(true); setError(""); try { const path = test ? `/users/${userId}/credentials/test` : `/users/${userId}/today`; setToday(await apiFetch(path, { method: test ? "POST" : "GET" })); } catch (err) { setError(errorMessage(err)); } finally { setBusy(false); } } return (
{canTest && ( )}
{error &&

{error}

} {today && (
Pontos
{today.points.length ? today.points.map((p) => fmtClock(p, today.timezone)).join(" · ") : "nenhum"}
{today.invalid && ( <>
Atenção
pontos repetidos ou fora de ordem
)} {today.overtime && ( <>
Atenção
mais de quatro pontos (hora extra, fora do escopo)
)}
Retorno previsto
{fmtClock(today.entrada2_at, today.timezone)}
Saída prevista
{today.saida2_error ? {today.saida2_error} : fmtClock(today.saida2_at, today.timezone)}
Situação do dia
{dayStatusLabel[today.day_state.status]}
)}
); }