92 lines
2.6 KiB
TypeScript
92 lines
2.6 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="rounded-full bg-ink px-6 py-3 text-sm font-semibold text-haze shadow-glow"
|
|
>
|
|
Start a private ledger
|
|
</button>
|
|
<button
|
|
type="button"
|
|
onClick={onViewExport}
|
|
className="rounded-full border border-ink/20 bg-white/70 px-6 py-3 text-sm font-semibold text-ink"
|
|
>
|
|
View export sample
|
|
</button>
|
|
</div>
|
|
{status ? <p className="text-xs text-muted">{status}</p> : null}
|
|
</div>
|
|
);
|
|
}
|