diff --git a/src/client/routes/admin/tags/index.tsx b/src/client/routes/admin/tags/index.tsx index e70ee1a..ffd3d08 100644 --- a/src/client/routes/admin/tags/index.tsx +++ b/src/client/routes/admin/tags/index.tsx @@ -124,8 +124,10 @@ function AdminTagsPage() { }); setNewName(""); setNewParentId(null); - } catch { - setCreateError("Failed to create tag. Please try again."); + } catch (err: unknown) { + const message = + err instanceof Error ? err.message : "Failed to create tag"; + setCreateError(message); } } @@ -156,39 +158,50 @@ function AdminTagsPage() { {/* Quick-add form */} -
- setNewName(e.target.value)} - placeholder="Tag name..." - className={`flex-1 ${inputClass}`} - /> - - -
- {createError && ( -

{createError}

- )} +
+

+ Add Tag +

+
+
+ + setNewName(e.target.value)} + placeholder="e.g. Bikepacking" + className={inputClass} + /> +
+
+ + +
+ +
+ {createError && ( +

{createError}

+ )} +
{/* Error state */} {isError && ( diff --git a/src/server/routes/admin-tags.ts b/src/server/routes/admin-tags.ts index 4683df4..8c466b3 100644 --- a/src/server/routes/admin-tags.ts +++ b/src/server/routes/admin-tags.ts @@ -45,8 +45,22 @@ app.get("/:id", async (c) => { app.post("/", zValidator("json", createTagSchema), async (c) => { const db = c.get("db"); const data = c.req.valid("json"); - const tag = await createTag(db, data); - return c.json(tag, 201); + try { + const tag = await createTag(db, data); + return c.json(tag, 201); + } catch (err) { + if ( + err instanceof Error && + (err.message.includes("UNIQUE constraint failed") || + err.message.includes("unique constraint")) + ) { + return c.json( + { error: `A tag named "${data.name}" already exists` }, + 409, + ); + } + throw err; + } }); // PUT /api/admin/tags/:id — rename and/or reparent a tag