feat(01-04): add onboarding wizard with settings API and persisted state
- Settings API: GET/PUT /api/settings/:key with SQLite persistence - useSettings hook with TanStack Query for settings CRUD - OnboardingWizard: 3-step modal overlay (welcome, create category, add item) - Root layout checks onboarding completion flag before rendering wizard - Skip option available at every step, all paths persist completion to DB Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,7 @@ import { itemRoutes } from "./routes/items.ts";
|
||||
import { categoryRoutes } from "./routes/categories.ts";
|
||||
import { totalRoutes } from "./routes/totals.ts";
|
||||
import { imageRoutes } from "./routes/images.ts";
|
||||
import { settingsRoutes } from "./routes/settings.ts";
|
||||
|
||||
// Seed default data on startup
|
||||
seedDefaults();
|
||||
@@ -21,6 +22,7 @@ app.route("/api/items", itemRoutes);
|
||||
app.route("/api/categories", categoryRoutes);
|
||||
app.route("/api/totals", totalRoutes);
|
||||
app.route("/api/images", imageRoutes);
|
||||
app.route("/api/settings", settingsRoutes);
|
||||
|
||||
// Serve uploaded images
|
||||
app.use("/uploads/*", serveStatic({ root: "./" }));
|
||||
|
||||
37
src/server/routes/settings.ts
Normal file
37
src/server/routes/settings.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { Hono } from "hono";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { db as prodDb } from "../../db/index.ts";
|
||||
import { settings } from "../../db/schema.ts";
|
||||
|
||||
type Env = { Variables: { db?: any } };
|
||||
|
||||
const app = new Hono<Env>();
|
||||
|
||||
app.get("/:key", (c) => {
|
||||
const database = c.get("db") ?? prodDb;
|
||||
const key = c.req.param("key");
|
||||
const row = database.select().from(settings).where(eq(settings.key, key)).get();
|
||||
if (!row) return c.json({ error: "Setting not found" }, 404);
|
||||
return c.json(row);
|
||||
});
|
||||
|
||||
app.put("/:key", async (c) => {
|
||||
const database = c.get("db") ?? prodDb;
|
||||
const key = c.req.param("key");
|
||||
const body = await c.req.json<{ value: string }>();
|
||||
|
||||
if (!body.value && body.value !== "") {
|
||||
return c.json({ error: "value is required" }, 400);
|
||||
}
|
||||
|
||||
database
|
||||
.insert(settings)
|
||||
.values({ key, value: body.value })
|
||||
.onConflictDoUpdate({ target: settings.key, set: { value: body.value } })
|
||||
.run();
|
||||
|
||||
const row = database.select().from(settings).where(eq(settings.key, key)).get();
|
||||
return c.json(row);
|
||||
});
|
||||
|
||||
export { app as settingsRoutes };
|
||||
Reference in New Issue
Block a user