diff --git a/pb_migrations/1748757068_updated_relationships.js b/pb_migrations/1748757068_updated_relationships.js new file mode 100644 index 0000000..aa14980 --- /dev/null +++ b/pb_migrations/1748757068_updated_relationships.js @@ -0,0 +1,51 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_617371094") + + // update field + collection.fields.addAt(3, new Field({ + "hidden": false, + "id": "select2363381545", + "maxSelect": 1, + "name": "type", + "presentable": false, + "required": false, + "system": false, + "type": "select", + "values": [ + "discoveredIn", + "secrets", + "treasures", + "scenes", + "npcs", + "locations", + "monsters" + ] + })) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_617371094") + + // update field + collection.fields.addAt(3, new Field({ + "hidden": false, + "id": "select2363381545", + "maxSelect": 1, + "name": "type", + "presentable": false, + "required": false, + "system": false, + "type": "select", + "values": [ + "discoveredIn", + "secrets", + "treasures", + "scenes", + "npcs", + "locations" + ] + })) + + return app.save(collection) +}) diff --git a/src/components/documents/DocumentForm.tsx b/src/components/documents/DocumentForm.tsx index 44f3ddc..d700acb 100644 --- a/src/components/documents/DocumentForm.tsx +++ b/src/components/documents/DocumentForm.tsx @@ -1,8 +1,10 @@ import { RelationshipType, type CampaignId, type Document } from "@/lib/types"; +import { LocationForm } from "./location/LocationForm"; +import { MonsterForm } from "./monsters/MonsterForm"; +import { NpcForm } from "./npc/NpcForm"; +import { SceneForm } from "./scene/SceneForm"; import { SecretForm } from "./secret/SecretForm"; import { TreasureForm } from "./treasure/TreasureForm"; -import { SceneForm } from "./scene/SceneForm"; -import { NpcForm } from "./npc/NpcForm"; function assertUnreachable(_x: never): never { throw new Error("DocumentForm switch is not exhaustive"); @@ -21,6 +23,10 @@ export const DocumentForm = ({ onCreate: (document: Document) => Promise; }) => { switch (relationshipType) { + case RelationshipType.Locations: + return ; + case RelationshipType.Monsters: + return ; case RelationshipType.Npcs: return ; case RelationshipType.Secrets: diff --git a/src/components/documents/DocumentRow.tsx b/src/components/documents/DocumentRow.tsx index fe2fc68..7a2515e 100644 --- a/src/components/documents/DocumentRow.tsx +++ b/src/components/documents/DocumentRow.tsx @@ -1,8 +1,10 @@ // DocumentRow.tsx // Generic row component for displaying any document type. -import { SessionRow } from "@/components/documents/session/SessionRow"; import { SecretRow } from "@/components/documents/secret/SecretRow"; +import { SessionRow } from "@/components/documents/session/SessionRow"; import { + isLocation, + isMonster, isNpc, isScene, isSecret, @@ -11,9 +13,11 @@ import { type Document, type Session, } from "@/lib/types"; -import { TreasureRow } from "./treasure/TreasureRow"; -import { SceneRow } from "./scene/SceneRow"; +import { LocationRow } from "./location/LocationRow"; +import { MonsterRow } from "./monsters/MonsterRow"; import { NpcRow } from "./npc/NpcRow"; +import { SceneRow } from "./scene/SceneRow"; +import { TreasureRow } from "./treasure/TreasureRow"; /** * Renders a row for any document type. Prioritizes Session, then Secret, then falls back to ID and creation time. @@ -26,6 +30,14 @@ export const DocumentRow = ({ document: Document; session?: Session; }) => { + if (isLocation(document)) { + return ; + } + + if (isMonster(document)) { + return ; + } + if (isNpc(document)) { return ; } diff --git a/src/components/documents/location/LocationForm.tsx b/src/components/documents/location/LocationForm.tsx new file mode 100644 index 0000000..7eed94b --- /dev/null +++ b/src/components/documents/location/LocationForm.tsx @@ -0,0 +1,84 @@ +import { useState } from "react"; +import type { CampaignId, Location } from "@/lib/types"; +import { pb } from "@/lib/pocketbase"; + +/** + * Renders a form to add a new location. Calls onCreate with the new location document. + */ +export const LocationForm = ({ + campaign, + onCreate, +}: { + campaign: CampaignId; + onCreate: (location: Location) => Promise; +}) => { + const [name, setName] = useState(""); + const [description, setDescription] = useState(""); + const [adding, setAdding] = useState(false); + const [error, setError] = useState(null); + + async function handleSubmit(e: React.FormEvent) { + e.preventDefault(); + if (!name.trim()) return; + setAdding(true); + setError(null); + try { + const locationDoc: Location = await pb.collection("documents").create({ + campaign, + data: { + location: { + name, + description, + }, + }, + }); + setName(""); + setDescription(""); + await onCreate(locationDoc); + } catch (e: any) { + setError(e?.message || "Failed to add location."); + } finally { + setAdding(false); + } + } + + return ( +
+

Create new location

+
+ + setName(e.target.value)} + disabled={adding} + aria-label="Name" + /> +
+
+ +