Files
headquarter/apps/web/src/pages/DashboardPage.tsx
T
2026-06-03 08:51:02 +00:00

194 lines
5.2 KiB
TypeScript

import { useCallback, useEffect, useMemo, useState } from "react";
import { useNavigate } from "react-router-dom";
import { getDashboardSummary, type DashboardSummary } from "../api/dashboard";
import { getUserSessions } from "../api/sessions";
import { listProjects } from "../api/projects";
import { listToolTypes } from "../api/tool-types";
import type { Session as SessionApi } from "../types/session";
import type { Project } from "../types/project";
import type { ToolType } from "../types/tool-type";
import {
DashboardSummary as DashboardSummaryComponent,
ActiveSessionsList,
ProjectsSection,
QuickCreateForm,
RecentSessionsSection,
} from "../components/features/dashboard";
import { LoadingState, ErrorState } from "../components/ui";
import { useDashboardActions } from "../hooks/use-dashboard-actions";
import { listRepositories } from "../api/git-repositories";
import type { GitRepository } from "../types/git-repository";
type HomeStatus = "loading" | "ready" | "error";
type SessionView = SessionApi;
export const HomePage = () => {
const navigate = useNavigate();
const [status, setStatus] = useState<HomeStatus>("loading");
const [summary, setSummary] = useState<DashboardSummary | null>(null);
const [sessions, setSessions] = useState<SessionView[]>([]);
const [projects, setProjects] = useState<Project[]>([]);
const [repositories, setRepositories] = useState<GitRepository[]>([]);
const [toolTypes, setToolTypes] = useState<ToolType[]>([]);
const safeSessions = Array.isArray(sessions) ? sessions : [];
const loadHome = useCallback(async () => {
setStatus("loading");
try {
const [dashboard, sessionData, projectData, toolTypeData] =
await Promise.all([
getDashboardSummary(),
getUserSessions(),
listProjects(),
listToolTypes(),
]);
setSummary(dashboard);
setSessions(sessionData as SessionView[]);
setProjects(projectData);
setToolTypes(toolTypeData);
setStatus("ready");
} catch {
setStatus("error");
}
}, []);
useEffect(() => {
void loadHome();
}, [loadHome]);
const loadRepos = useCallback(async (projectId: string) => {
try {
setRepositories(await listRepositories(projectId));
} catch {
setRepositories([]);
}
}, []);
const activeSessions = useMemo(
() =>
safeSessions.filter((s) =>
["running", "building", "pending"].includes(s.status),
),
[safeSessions],
);
const recentSessions = useMemo(
() =>
safeSessions
.filter((s) => ["stopped", "error"].includes(s.status))
.slice(0, 5),
[safeSessions],
);
const actions = useDashboardActions(loadHome);
return (
<section className="stack home-page">
<header className="home-hero card">
<div className="stack-sm">
<p className="eyebrow">Workspace overview</p>
<h1>Home</h1>
<p className="muted">
Open sessions, available projects, and the fastest path back into
work.
</p>
</div>
<div className="home-hero-actions">
<button
className="primary-button"
type="button"
onClick={() => navigate("/projects")}
>
New Project
</button>
<button
className="secondary-button"
type="button"
onClick={() => navigate("/settings")}
>
Settings
</button>
</div>
</header>
{status === "loading" && <LoadingState message="Loading overview..." />}
{status === "error" && (
<ErrorState
message="Unable to load your workspace overview."
onRetry={() => void loadHome()}
/>
)}
{status === "ready" && summary && (
<>
<DashboardSummaryComponent
summary={summary}
activeSessionsCount={activeSessions.length}
/>
<section className="card stack home-section">
<div className="page-header">
<div>
<p className="eyebrow">Open sessions</p>
<h2>{activeSessions.length}</h2>
</div>
</div>
<ActiveSessionsList
sessions={activeSessions}
actionBusy={actions.actionBusy}
onOpen={actions.handleOpen}
onStop={actions.handleStop}
onDelete={actions.handleDelete}
onRecreateTunnel={actions.handleRecreateTunnel}
/>
</section>
<section className="card stack home-section">
<div className="page-header">
<div>
<p className="eyebrow">Available projects</p>
<h2>{projects.length}</h2>
</div>
<button
className="secondary-button"
type="button"
onClick={() => navigate("/projects")}
>
View all
</button>
</div>
<ProjectsSection
projects={projects}
onOpenProject={(id) => navigate(`/projects/${id}`)}
/>
</section>
<section className="card stack home-section">
<div className="page-header">
<div>
<p className="eyebrow">Quick create</p>
<h2>Start a session</h2>
</div>
</div>
<QuickCreateForm
projects={projects}
repositories={repositories}
toolTypes={toolTypes}
saveState={actions.saveState}
onSubmit={actions.handleCreate}
onProjectChange={loadRepos}
/>
</section>
<RecentSessionsSection
sessions={recentSessions}
onOpen={actions.handleOpen}
/>
</>
)}
</section>
);
};
export { HomePage as DashboardPage };