feat: implement auth, projects, and frontend foundation

This commit is contained in:
2026-05-17 20:21:55 +00:00
parent e7819bfc82
commit 71d9fe6406
88 changed files with 10936 additions and 47 deletions
+79
View File
@@ -0,0 +1,79 @@
import { useCallback, useEffect, useMemo, useState } from "react";
import { getDashboardSummary, type DashboardSummary } from "../api/dashboard";
const CARDS = [
{ label: "Projects", key: "projects" },
{ label: "Repositories", key: "repositories" },
{ label: "SSH Keys", key: "sshKeys" }
] as const;
type DashboardStatus = "loading" | "ready" | "error";
export const DashboardPage = () => {
const [status, setStatus] = useState<DashboardStatus>("loading");
const [summary, setSummary] = useState<DashboardSummary | null>(null);
const loadSummary = useCallback(async () => {
setStatus("loading");
try {
const data = await getDashboardSummary();
setSummary(data);
setStatus("ready");
} catch {
setSummary(null);
setStatus("error");
}
}, []);
useEffect(() => {
void loadSummary();
}, [loadSummary]);
const cards = useMemo(() => CARDS, []);
const isEmpty =
status === "ready" &&
summary !== null &&
summary.projects === 0 &&
summary.repositories === 0 &&
summary.sshKeys === 0 &&
summary.recentActivity.length === 0;
return (
<section className="stack">
<h1>Dashboard</h1>
<p className="muted">Your workspace overview will appear here.</p>
{status === "loading" && <p className="muted">Loading dashboard...</p>}
{status === "error" && (
<div className="card stack">
<p>Dashboard is unavailable</p>
<button className="secondary-button" onClick={() => void loadSummary()} type="button">
Retry
</button>
</div>
)}
<div className="card-grid">
{cards.map((card) => (
<article className="card" key={card.label}>
<p className="card-label">{card.label}</p>
<p className="card-value">{summary ? String(summary[card.key]) : "-"}</p>
</article>
))}
</div>
{isEmpty && <p className="muted">No activity yet</p>}
<div className="quick-actions">
<button className="primary-button" type="button">
New Project
</button>
<button className="secondary-button" type="button">
Add Repository
</button>
</div>
</section>
);
};