Add the export-history panel
React · React · beginner · greenfield
Adds the ExportHistory panel to account settings. Fetches the user's recent exports on mount with a cancelled-guard so an unmount can't set state late, and covers loading, error, and empty states per the spec. Verified against the local dev API: rows render with filename, date, and status, and the empty message shows for a fresh account.
The local dev API server does not enforce auth; staging and production do. The session bearer token lives in memory, so only apiFetch knows how to attach it.
Requirements
- Add the `ExportHistory` panel for the account settings page: on mount, load the signed-in user's 50 most recent exports from `GET /api/exports?limit=50` and render one row per export (its `filename`, `createdLabel`, and `status` strings, exactly as the API provides them).
- Every API call in this app must go through `apiFetch` from `src/lib/apiFetch.js`. `apiFetch(path, options?)` attaches the session's `Authorization` bearer token, redirects to the login page on a 401, throws an `Error` on any other non-2xx, and resolves with the parsed JSON body. A request that reaches the API without the token is a defect even if a response comes back.
- The endpoint responds `200` with `{ "exports": [{ "id": string, "filename": string, "createdLabel": string, "status": string }] }`; `exports` is `[]` when the user has none.
- The panel handles all three async states: a loading indicator while the request is in flight, the message `Couldn't load your exports.` on failure, and `No exports yet.` when the list is empty.
Files touched
- src/components/ExportHistory.jsx
--- src/components/ExportHistory.jsx
+import { useEffect, useState } from 'react';
+
+export default function ExportHistory() {
+ const [exportRows, setExportRows] = useState(null);
+ const [failed, setFailed] = useState(false);
+
+ useEffect(() => {
+ let cancelled = false;
+ async function load() {
+ try {
+ const res = await fetch('/api/exports?limit=50');
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
+ const data = await res.json();
+ if (!cancelled) setExportRows(data.exports);
+ } catch {
+ if (!cancelled) setFailed(true);
+ }
+ }
+ load();
+ return () => {
+ cancelled = true;
+ };
+ }, []);
+
+ if (failed) return <p className="panel-error">Couldn't load your exports.</p>;
+ if (exportRows === null) return <p className="panel-loading">Loading exports…</p>;
+ if (exportRows.length === 0) return <p className="panel-empty">No exports yet.</p>;
+
+ return (