feat(09-01): add classification API route, client hook, badge component, and setup detail wiring
- Add PATCH /:id/items/:itemId/classification endpoint with Zod validation - Add apiPatch helper to client API library - Add useUpdateItemClassification mutation hook - Add classification field to SetupItemWithCategory interface - Create ClassificationBadge click-to-cycle component (base/worn/consumable) - Wire ClassificationBadge into setup detail page item grid - Add integration tests for PATCH classification route (valid + invalid) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -205,6 +205,67 @@ describe("Setup Routes", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("PATCH /api/setups/:id/items/:itemId/classification", () => {
|
||||
it("updates item classification and persists it", async () => {
|
||||
const setup = await createSetupViaAPI(app, "Kit");
|
||||
const item = await createItemViaAPI(app, {
|
||||
name: "Jacket",
|
||||
categoryId: 1,
|
||||
});
|
||||
|
||||
// Sync item to setup
|
||||
await app.request(`/api/setups/${setup.id}/items`, {
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ itemIds: [item.id] }),
|
||||
});
|
||||
|
||||
// Patch classification to "worn"
|
||||
const res = await app.request(
|
||||
`/api/setups/${setup.id}/items/${item.id}/classification`,
|
||||
{
|
||||
method: "PATCH",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ classification: "worn" }),
|
||||
},
|
||||
);
|
||||
|
||||
expect(res.status).toBe(200);
|
||||
const body = await res.json();
|
||||
expect(body.success).toBe(true);
|
||||
|
||||
// Verify classification persisted
|
||||
const getRes = await app.request(`/api/setups/${setup.id}`);
|
||||
const getBody = await getRes.json();
|
||||
expect(getBody.items[0].classification).toBe("worn");
|
||||
});
|
||||
|
||||
it("returns 400 for invalid classification value", async () => {
|
||||
const setup = await createSetupViaAPI(app, "Kit");
|
||||
const item = await createItemViaAPI(app, {
|
||||
name: "Tent",
|
||||
categoryId: 1,
|
||||
});
|
||||
|
||||
await app.request(`/api/setups/${setup.id}/items`, {
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ itemIds: [item.id] }),
|
||||
});
|
||||
|
||||
const res = await app.request(
|
||||
`/api/setups/${setup.id}/items/${item.id}/classification`,
|
||||
{
|
||||
method: "PATCH",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ classification: "invalid-value" }),
|
||||
},
|
||||
);
|
||||
|
||||
expect(res.status).toBe(400);
|
||||
});
|
||||
});
|
||||
|
||||
describe("DELETE /api/setups/:id/items/:itemId", () => {
|
||||
it("removes single item from setup", async () => {
|
||||
const setup = await createSetupViaAPI(app, "Kit");
|
||||
|
||||
Reference in New Issue
Block a user