From 2fbc2c853f2bd00ae022750eff080702ec312ac5 Mon Sep 17 00:00:00 2001 From: Drew Haven Date: Sun, 3 Aug 2025 12:50:52 -0700 Subject: [PATCH] Makes campaigns load all types of docs and then link to the docs --- src/components/DocumentList.tsx | 4 +- src/components/campaign/CampaignDocuments.tsx | 51 ++++++++++++++++ src/components/documents/BasicPreview.tsx | 14 ++++- src/components/documents/DocumentLink.tsx | 38 +++++++++--- src/components/documents/DocumentPreview.tsx | 16 +++-- src/components/documents/DocumentView.tsx | 3 +- src/components/layout/TabbedLayout.tsx | 2 +- src/context/auth/AuthContext.tsx | 4 +- src/context/document/state.ts | 11 ++++ src/lib/documentPath.ts | 30 ++++++---- src/lib/relationships.ts | 7 ++- .../_authenticated/campaigns.$campaignId.tsx | 60 +++++-------------- .../_authenticated/document.$documentId.$.tsx | 5 +- 13 files changed, 170 insertions(+), 75 deletions(-) create mode 100644 src/components/campaign/CampaignDocuments.tsx diff --git a/src/components/DocumentList.tsx b/src/components/DocumentList.tsx index bba9bf6..1ad65b2 100644 --- a/src/components/DocumentList.tsx +++ b/src/components/DocumentList.tsx @@ -9,7 +9,7 @@ import { import { Fragment, useCallback, useState } from "react"; type Props = { - title: React.ReactNode; + title?: React.ReactNode; error?: React.ReactNode; items: T[]; renderRow: (item: T) => React.ReactNode; @@ -49,7 +49,7 @@ export function DocumentList({ return (
-

{title}

+ {title &&

{title}

}
{isEditing && (
{content}
diff --git a/src/context/auth/AuthContext.tsx b/src/context/auth/AuthContext.tsx index 811fcb4..0957206 100644 --- a/src/context/auth/AuthContext.tsx +++ b/src/context/auth/AuthContext.tsx @@ -29,7 +29,9 @@ const AuthContext = createContext(undefined); */ export function AuthProvider({ children }: { children: ReactNode }) { const [isLoading, setIsLoading] = useState(false); - const [user, setUser] = useState(pb.authStore.record); + const [user, setUser] = useState( + pb.authStore.isValid ? pb.authStore.record : null, + ); const navigate = useNavigate(); diff --git a/src/context/document/state.ts b/src/context/document/state.ts index 91c3695..f460a48 100644 --- a/src/context/document/state.ts +++ b/src/context/document/state.ts @@ -1,6 +1,7 @@ import type { AnyDocument, DocumentId, + DocumentType, Relationship, RelationshipType, } from "@/lib/types"; @@ -30,3 +31,13 @@ export const initialState = (): DocumentState => ({ documents: {}, }) as DocumentState; + +export const getAllDocumentsOfType = ( + docType: T, + state: DocumentState, +): (AnyDocument & { type: T })[] => + Object.values(state.documents).flatMap((docRecord) => + docRecord.type === "ready" && docRecord.value.doc.type === docType + ? [docRecord.value.doc as AnyDocument & { type: T }] + : [], + ); diff --git a/src/lib/documentPath.ts b/src/lib/documentPath.ts index a61e985..1ade3c1 100644 --- a/src/lib/documentPath.ts +++ b/src/lib/documentPath.ts @@ -24,22 +24,30 @@ const documentParams = z }), ); -export function useDocumentPath(): { - documentId: DocumentId; - relationshipType: RelationshipType | null; - childDocId: DocumentId | null; -} { +export function useDocumentPath(): + | { + documentId: DocumentId; + relationshipType: RelationshipType | null; + childDocId: DocumentId | null; + } + | undefined { const params = useParams({ from: "/_app/_authenticated/document/$documentId/$", + shouldThrow: false, }); - const { relationshipType, childDocId } = documentParams.parse(params._splat); + if (params) { + const { relationshipType, childDocId } = documentParams.parse( + params._splat, + ); + return { + documentId: params.documentId as DocumentId, + relationshipType, + childDocId, + }; + } - return { - documentId: params.documentId as DocumentId, - relationshipType, - childDocId, - }; + return undefined; } export function makeDocumentPath( diff --git a/src/lib/relationships.ts b/src/lib/relationships.ts index f864081..8fa3bc9 100644 --- a/src/lib/relationships.ts +++ b/src/lib/relationships.ts @@ -1,4 +1,9 @@ -import { getDocumentType, RelationshipType, type AnyDocument } from "./types"; +import { + getDocumentType, + type DocumentType, + RelationshipType, + type AnyDocument, +} from "./types"; export function displayName(relationshipType: RelationshipType) { return relationshipType.charAt(0).toUpperCase() + relationshipType.slice(1); diff --git a/src/routes/_app/_authenticated/campaigns.$campaignId.tsx b/src/routes/_app/_authenticated/campaigns.$campaignId.tsx index ad0eae0..b08a778 100644 --- a/src/routes/_app/_authenticated/campaigns.$campaignId.tsx +++ b/src/routes/_app/_authenticated/campaigns.$campaignId.tsx @@ -1,23 +1,20 @@ +import { CampaignDocuments } from "@/components/campaign/CampaignDocuments"; import { DocumentPreview } from "@/components/documents/DocumentPreview"; -import { DocumentRow } from "@/components/documents/DocumentRow"; -import { SessionRow } from "@/components/documents/session/SessionRow"; import { Tab, TabbedLayout } from "@/components/layout/TabbedLayout"; import { Loader } from "@/components/Loader"; import { DocumentLoader } from "@/context/document/DocumentLoader"; import { useDocument } from "@/context/document/hooks"; import { pb } from "@/lib/pocketbase"; import type { Campaign, DocumentId, Relationship, Session } from "@/lib/types"; -import { Button } from "@headlessui/react"; import { createFileRoute, Link } from "@tanstack/react-router"; import { useCallback, useEffect, useState } from "react"; import { z } from "zod"; const CampaignTabs = { - sessions: "Sessions", - npcs: "NPCs", - locations: "Locations", - factions: "Factions", - threads: "Threads", + sessions: { label: "Sessions", docType: "session" }, + secrets: { label: "Secrets", docType: "secret" }, + npcs: { label: "NPCs", docType: "npc" }, + locations: { label: "Locations", docType: "location" }, } as const; const campaignSearchSchema = z.object({ @@ -50,11 +47,11 @@ function RouteComponent() { .collection("campaigns") .getOne(params.campaignId); // Fetch all documents for this campaign - const sessions = await pb.collection("documents").getFullList({ - filter: `campaign = "${params.campaignId}" && type = 'session'`, - sort: "-created", - }); - setSessions(sessions as Session[]); + // const sessions = await pb.collection("documents").getFullList({ + // filter: `campaign = "${params.campaignId}" && type = 'session'`, + // sort: "-created", + // }); + // setSessions(sessions as Session[]); setCampaign(campaign as Campaign); setLoading(false); } @@ -115,8 +112,9 @@ function RouteComponent() { ← Back to campaigns } - tabs={Object.entries(CampaignTabs).map(([key, label]) => ( + tabs={Object.entries(CampaignTabs).map(([key, { label }]) => ( ))} content={ -
-
-

- Sessions -

-
- -
-
- {sessions && sessions.length > 0 ? ( -
-
    - {sessions.map((s: any) => ( -
  • - -
  • - ))} -
-
- ) : ( -
- No sessions found for this campaign. -
- )} -
+ } flyout={docId && } /> diff --git a/src/routes/_app/_authenticated/document.$documentId.$.tsx b/src/routes/_app/_authenticated/document.$documentId.$.tsx index 0b4b637..fbd45a1 100644 --- a/src/routes/_app/_authenticated/document.$documentId.$.tsx +++ b/src/routes/_app/_authenticated/document.$documentId.$.tsx @@ -11,7 +11,10 @@ export const Route = createFileRoute( }); function RouteComponent() { - const { documentId, relationshipType, childDocId } = useDocumentPath(); + const path = useDocumentPath(); + const documentId = path?.documentId; + const relationshipType = path?.relationshipType ?? null; + const childDocId = path?.childDocId ?? null; return (