From 86444bc850c05ae4cf13e4157c8088a20fb8ff6b Mon Sep 17 00:00:00 2001 From: ginnoir Date: Fri, 10 Jul 2026 02:57:45 -0500 Subject: [PATCH] feat(pets): register module navigation --- src/app/pets/page.tsx | 34 ++++++++++++++++++++++ src/components/nav-icon.tsx | 2 ++ src/modules/index.ts | 2 ++ src/modules/pets/manifest.tsx | 49 ++++++++++++++++++++++++++++++++ tests/unit/pets-manifest.test.ts | 8 ++++++ 5 files changed, 95 insertions(+) create mode 100644 src/app/pets/page.tsx create mode 100644 src/modules/pets/manifest.tsx create mode 100644 tests/unit/pets-manifest.test.ts diff --git a/src/app/pets/page.tsx b/src/app/pets/page.tsx new file mode 100644 index 0000000..087cdc5 --- /dev/null +++ b/src/app/pets/page.tsx @@ -0,0 +1,34 @@ +import Link from "next/link"; +import { listPets } from "@/modules/pets/server/queries"; + +export default async function PetsPage() { + const pets = await listPets(); + return ( +
+
+

Pets

+ + Add pet + +
+ {pets.length === 0 ? ( +

No pets yet.

+ ) : ( +
+ {pets.map((pet) => ( + +

{pet.name}

+

+ {[pet.species, pet.breed].filter(Boolean).join(" ยท ")} +

+ + ))} +
+ )} +
+ ); +} diff --git a/src/components/nav-icon.tsx b/src/components/nav-icon.tsx index b332ed9..780454e 100644 --- a/src/components/nav-icon.tsx +++ b/src/components/nav-icon.tsx @@ -3,6 +3,7 @@ import { BookHeart, Calendar, Sprout, + PawPrint, CalendarDays, CheckSquare, ChevronDown, @@ -73,6 +74,7 @@ const ICONS: Record> = { filter: Filter, sun: Sun, sprout: Sprout, + "paw-print": PawPrint, mail: Mail, menu: Menu, "message-circle": MessageCircle, diff --git a/src/modules/index.ts b/src/modules/index.ts index 50b7486..93d25ab 100644 --- a/src/modules/index.ts +++ b/src/modules/index.ts @@ -4,6 +4,7 @@ import calendarManifest from "./calendar/manifest"; import listsManifest from "./lists/manifest"; import notesManifest from "./notes/manifest"; import gardenManifest from "./garden/manifest"; +import petsManifest from "./pets/manifest"; import bangsManifest from "./bangs/manifest"; import journalManifest from "./journal/manifest"; import agentManifest from "./agent/manifest"; @@ -13,6 +14,7 @@ registerModule(calendarManifest); registerModule(listsManifest); registerModule(notesManifest); registerModule(gardenManifest); +registerModule(petsManifest); registerModule(bangsManifest); registerModule(journalManifest); registerModule(agentManifest); diff --git a/src/modules/pets/manifest.tsx b/src/modules/pets/manifest.tsx new file mode 100644 index 0000000..2ca7b20 --- /dev/null +++ b/src/modules/pets/manifest.tsx @@ -0,0 +1,49 @@ +import { z } from "zod"; +import type { ModuleManifest } from "../_core/module"; +import { searchPets } from "./server/queries"; + +const petsManifest: ModuleManifest = { + id: "pets", + name: "Pets", + nav: { href: "/pets", label: "Pets", icon: "paw-print" }, + entities: [ + { + type: "pets.pet", + label: { singular: "Pet", plural: "Pets" }, + search: { search: searchPets }, + reminder: { canRemind: true }, + resolveUrl: (id) => `/pets/${id}`, + renderActivity: (entry) => { + const name = entry.payload?.name as string | undefined; + if (entry.action === "create") return `Added pet${name ? ` "${name}"` : ""}`; + if (entry.action === "delete") return `Removed pet${name ? ` "${name}"` : ""}`; + return `Updated pet${name ? ` "${name}"` : ""}`; + }, + }, + ], + dashboardWidgets: [ + { + id: "pets.overview", + title: "Pets overview", + description: "Pet count and medical items due within 30 days.", + category: "Pets", + defaultSize: { w: 3, h: 2 }, + minSize: { w: 2, h: 2 }, + defaultPriority: 60, + configSchema: z.object({}), + defaultConfig: {}, + render: () => null, + }, + ], + quickAdds: [ + { + id: "pets.add", + label: "Add pet", + icon: "paw-print", + url: "/pets/new", + createKey: "pets.pet", + }, + ], +}; + +export default petsManifest; diff --git a/tests/unit/pets-manifest.test.ts b/tests/unit/pets-manifest.test.ts new file mode 100644 index 0000000..e690c78 --- /dev/null +++ b/tests/unit/pets-manifest.test.ts @@ -0,0 +1,8 @@ +import assert from "node:assert/strict"; +import test from "node:test"; +import petsManifest from "../../src/modules/pets/manifest"; + +test("pets manifest contributes visible navigation and a quick add action", () => { + assert.deepEqual(petsManifest.nav, { href: "/pets", label: "Pets", icon: "paw-print" }); + assert.equal(petsManifest.quickAdds?.[0]?.createKey, "pets.pet"); +});