/* ============================================================ approval.jsx — tokenised email-link approval landing The target of the one-click Approve/Reject links in the notification email. Standalone full-page (no persona shell). ============================================================ */ function ApprovalLanding({ token }) { const [doc, setDoc] = React.useState(null); const [biz, setBiz] = React.useState(null); const [state, setState] = React.useState("loading"); // loading|ready|invalid|done const [result, setResult] = React.useState(null); const [rejecting, setRejecting] = React.useState(false); const [reason, setReason] = React.useState(""); React.useEffect(() => { (async () => { try { const d = await api.get(`/api/approvals/${token}`); setDoc(d); setBiz(d.business || { name: d.biz, short: "?", color: "#888" }); setState("ready"); } catch (e) { setState("invalid"); } })(); }, [token]); const approve = async () => { try { const r = await api.post(`/api/approvals/${token}/approve`); setResult(r.status); setState("done"); } catch (e) { setState("invalid"); } }; const reject = async () => { try { const r = await api.post(`/api/approvals/${token}/reject`, { reason }); setResult(r.status); setState("done"); } catch (e) { setState("invalid"); } }; return (
Lekha AI Credit Note Approval
{state === "loading" &&
Loading…
} {state === "invalid" && (
Link no longer valid
This approval link has already been used or has expired. Open the portal to check the latest status.
Go to portal
)} {state === "done" && (
{result === "cancelled" ? : }
{result === "cancelled" ? "Credit note rejected" : "Approved — posting to Tally"}
{result === "cancelled" ? "Nakad has been notified." : "The entry is on its way to Tally. No manual entry needed."}
Go to portal
)} {state === "ready" && doc && biz && (
{doc.cnNo}
{biz.name} · against {doc.invoice}
Total credit
{fmtINR(doc.amount)}
You're approving as the authorised finance email for {biz.name}. Approving posts this entry to Tally automatically.
{rejecting ? (
Reason for rejection