ledgerone_frontend/components/hero-actions.tsx
2026-03-18 13:02:58 -07:00

98 lines
3.1 KiB
TypeScript

"use client";
import { useState } from "react";
type ApiResponse<T> = {
data: T;
meta: { timestamp: string; version: "v1" };
error: null | { message: string; code?: string };
};
type LinkTokenData = { linkToken?: string };
type ExportData = { status?: string; url?: string; csv?: string };
async function postJson<T>(path: string) {
const res = await fetch(path, {
method: "POST"
});
if (!res.ok) {
throw new Error("Request failed");
}
const payload = (await res.json()) as ApiResponse<T>;
return payload.data;
}
async function getJson<T>(path: string) {
const res = await fetch(path);
if (!res.ok) {
throw new Error("Request failed");
}
const payload = (await res.json()) as ApiResponse<T>;
return payload.data;
}
export function HeroActions() {
const [status, setStatus] = useState<string>("");
const onStart = async () => {
setStatus("Requesting a secure link token...");
try {
const data = await postJson<LinkTokenData>("/api/accounts/link");
if (data.linkToken) {
setStatus(`Link token ready: ${data.linkToken}`);
} else {
setStatus("Link token requested.");
}
} catch {
setStatus("Unable to request link token.");
}
};
const onViewExport = async () => {
setStatus("Preparing export sample...");
try {
const userId = localStorage.getItem("ledgerone_user_id");
const query = userId ? `?user_id=${encodeURIComponent(userId)}` : "";
const data = await getJson<ExportData>(`/api/exports/csv${query}`);
if (data.csv) {
const blob = new Blob([data.csv], { type: "text/csv" });
const url = URL.createObjectURL(blob);
window.open(url, "_blank", "noopener,noreferrer");
setStatus("Export sample opened.");
} else {
setStatus("Export sample ready.");
}
} catch {
setStatus("Unable to fetch export sample.");
}
};
return (
<div className="space-y-3">
<div className="flex flex-wrap gap-4">
<button
type="button"
onClick={onStart}
className="btn-primary inline-flex items-center gap-2 px-6 py-3 transition-all hover:-translate-y-0.5 active:translate-y-0"
>
<svg className="h-4 w-4 text-white/95" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
</svg>
Start a private ledger
</button>
<button
type="button"
onClick={onViewExport}
className="btn-secondary inline-flex items-center gap-2 px-6 py-3"
>
<svg className="h-4 w-4 text-muted-foreground" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
</svg>
View export sample
</button>
</div>
{status ? <p className="text-xs text-muted-foreground">{status}</p> : null}
</div>
);
}