Skip to content

Commit e05a915

Browse files
Merge pull request #27 from QuentinHourdeaux/feat/draft-list-and-quick-create-ui
Add draft list and quick-create UI
2 parents 97acffb + 44d313f commit e05a915

23 files changed

Lines changed: 2787 additions & 206 deletions

docs/planned-prs/16-draft-list-and-quick-create-ui.md

Lines changed: 0 additions & 80 deletions
This file was deleted.

frontend/src/api/drafts.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { readJson } from "../lib/api/read-json.ts";
2+
3+
export interface Draft {
4+
readonly id: string;
5+
readonly stackId: string | null;
6+
readonly title: string;
7+
readonly description: string;
8+
readonly stateId: string;
9+
readonly createdAt: string;
10+
readonly updatedAt: string;
11+
}
12+
13+
export interface CreateDraftInput {
14+
readonly title: string;
15+
readonly stackId?: string;
16+
}
17+
18+
export interface ListDraftsFilter {
19+
readonly stateId?: string;
20+
readonly stackId?: string;
21+
}
22+
23+
/** GET /api/drafts — list Drafts, optionally filtered by stateId and/or stackId. */
24+
export const listDrafts = async (
25+
filter?: ListDraftsFilter,
26+
signal?: AbortSignal,
27+
): Promise<Draft[]> => {
28+
const searchParams = new URLSearchParams();
29+
30+
if (filter?.stateId !== undefined) {
31+
searchParams.set("stateId", filter.stateId);
32+
}
33+
34+
if (filter?.stackId !== undefined) {
35+
searchParams.set("stackId", filter.stackId);
36+
}
37+
38+
const query = searchParams.toString();
39+
const path = query.length > 0 ? `/api/drafts?${query}` : "/api/drafts";
40+
const response = await fetch(path, { signal });
41+
const body = await readJson<{ drafts: Draft[] }>(response);
42+
return body.drafts;
43+
};
44+
45+
/** GET /api/drafts/:draftId — load one Draft by id. */
46+
export const getDraft = async (
47+
draftId: string,
48+
signal?: AbortSignal,
49+
): Promise<Draft> => {
50+
const response = await fetch(`/api/drafts/${draftId}`, { signal });
51+
return await readJson<Draft>(response);
52+
};
53+
54+
/** POST /api/drafts — create a Draft. Omit stackId for a standalone Draft. */
55+
export const createDraft = async (
56+
input: CreateDraftInput,
57+
signal?: AbortSignal,
58+
): Promise<Draft> => {
59+
const response = await fetch("/api/drafts", {
60+
method: "POST",
61+
headers: {
62+
"Content-Type": "application/json",
63+
},
64+
body: JSON.stringify(input),
65+
signal,
66+
});
67+
68+
return await readJson<Draft>(response);
69+
};

frontend/src/app/app-shell.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ export function AppShell() {
1818

1919
<nav className="app-nav" aria-label="Main">
2020
<NavLink className="app-nav__link" to="/" end>
21+
Drafts
22+
</NavLink>
23+
<NavLink className="app-nav__link" to="/stacks">
2124
Stacks
2225
</NavLink>
2326
<NavLink className="app-nav__link" to="/settings/states">

frontend/src/app/app.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { Route, Routes } from "react-router";
22
import { AppShell } from "./app-shell.tsx";
3+
import { DraftDetailPage } from "./routes/draft-detail-page.tsx";
4+
import { DraftListPage } from "./routes/draft-list-page.tsx";
35
import { NotFoundPage } from "./routes/not-found-page.tsx";
46
import { StackDetailPage } from "./routes/stack-detail-page.tsx";
57
import { StackListPage } from "./routes/stack-list-page.tsx";
@@ -9,8 +11,10 @@ export function App() {
911
return (
1012
<Routes>
1113
<Route element={<AppShell />}>
12-
<Route index element={<StackListPage />} />
14+
<Route index element={<DraftListPage />} />
15+
<Route path="stacks" element={<StackListPage />} />
1316
<Route path="stacks/:stackId" element={<StackDetailPage />} />
17+
<Route path="drafts/:draftId" element={<DraftDetailPage />} />
1418
<Route path="settings/states" element={<StateSettingsPage />} />
1519
<Route path="*" element={<NotFoundPage />} />
1620
</Route>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { DraftDetailScreen } from "../../features/draft/draft-detail-screen.tsx";
2+
3+
export function DraftDetailPage() {
4+
return <DraftDetailScreen />;
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { DraftListScreen } from "../../features/draft/draft-list-screen.tsx";
2+
3+
export function DraftListPage() {
4+
return <DraftListScreen />;
5+
}

frontend/src/app/routes/not-found-page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export function NotFoundPage() {
1414
</p>
1515
<p>
1616
<Link className="page__action-link" to="/">
17-
Back to Stacks
17+
Back to Drafts
1818
</Link>
1919
</p>
2020
</section>

0 commit comments

Comments
 (0)