57 lines
1.5 KiB
TypeScript
57 lines
1.5 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 ExportData = { status?: string; url?: string; csv?: string };
|
|
|
|
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 ExportDownloadButton() {
|
|
const [status, setStatus] = useState<string>("");
|
|
|
|
const onDownload = async () => {
|
|
setStatus("Building export...");
|
|
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("Download opened.");
|
|
} else {
|
|
setStatus("Export ready.");
|
|
}
|
|
} catch {
|
|
setStatus("Unable to download export.");
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="space-y-2">
|
|
<button
|
|
type="button"
|
|
onClick={onDownload}
|
|
className="w-full rounded-xl bg-ink px-4 py-2 text-sm font-semibold text-haze"
|
|
>
|
|
Download export
|
|
</button>
|
|
{status ? <p className="text-xs text-muted">{status}</p> : null}
|
|
</div>
|
|
);
|
|
}
|