Makes a generic document form
This commit is contained in:
@@ -1,26 +1,25 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { pb } from "@/lib/pocketbase";
|
||||
import type { Document } from "@/lib/types";
|
||||
import type { Document, RelationshipType } from "@/lib/types";
|
||||
import { DocumentList } from "@/components/DocumentList";
|
||||
import { Loader } from "./Loader";
|
||||
import { DocumentRow } from "./documents/DocumentRow";
|
||||
import { DocumentForm } from "./documents/DocumentForm";
|
||||
|
||||
interface RelationshipListProps<T extends Document> {
|
||||
interface RelationshipListProps {
|
||||
root: Document;
|
||||
relationshipType: string;
|
||||
newItemForm: (onCreate: (doc: T) => Promise<void>) => React.ReactNode;
|
||||
relationshipType: RelationshipType;
|
||||
}
|
||||
|
||||
/**
|
||||
* RelationshipList manages a list of documents related to a root document via a relationship type.
|
||||
* It handles fetching, creation, and relationship management, and renders a DocumentList.
|
||||
*/
|
||||
export function RelationshipList<T extends Document>({
|
||||
export function RelationshipList({
|
||||
root,
|
||||
relationshipType,
|
||||
newItemForm,
|
||||
}: RelationshipListProps<T>) {
|
||||
const [items, setItems] = useState<T[]>([]);
|
||||
}: RelationshipListProps) {
|
||||
const [items, setItems] = useState<Document[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
@@ -40,13 +39,13 @@ export function RelationshipList<T extends Document>({
|
||||
relationships.items.length > 0
|
||||
? relationships.items[0].secondary
|
||||
: [];
|
||||
let docs: T[] = [];
|
||||
let docs: Document[] = [];
|
||||
if (Array.isArray(secondaryIds) && secondaryIds.length > 0) {
|
||||
docs = (await pb.collection("documents").getFullList({
|
||||
filter: secondaryIds
|
||||
.map((id: string) => `id = "${id}"`)
|
||||
.join(" || "),
|
||||
})) as T[];
|
||||
})) as Document[];
|
||||
}
|
||||
if (!cancelled) setItems(docs);
|
||||
} catch (e: any) {
|
||||
@@ -63,7 +62,7 @@ export function RelationshipList<T extends Document>({
|
||||
}, [root.id, relationshipType]);
|
||||
|
||||
// Handles creation of a new document and adds it to the relationship
|
||||
const handleCreate = async (doc: T) => {
|
||||
const handleCreate = async (doc: Document) => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
@@ -104,12 +103,16 @@ export function RelationshipList<T extends Document>({
|
||||
items={items}
|
||||
error={error}
|
||||
renderRow={(document) => <DocumentRow document={document} />}
|
||||
newItemForm={(onSubmit) =>
|
||||
newItemForm(async (doc: T) => {
|
||||
await handleCreate(doc);
|
||||
onSubmit();
|
||||
})
|
||||
}
|
||||
newItemForm={(onSubmit) => (
|
||||
<DocumentForm
|
||||
campaignId={root.campaign}
|
||||
relationshipType={relationshipType}
|
||||
onCreate={async (doc: Document) => {
|
||||
await handleCreate(doc);
|
||||
onSubmit();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
28
src/components/documents/DocumentForm.tsx
Normal file
28
src/components/documents/DocumentForm.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import { RelationshipType, type CampaignId, type Document } from "@/lib/types";
|
||||
import { SecretForm } from "./secret/SecretForm";
|
||||
|
||||
function assertUnreachable(_x: never): never {
|
||||
throw new Error("DocumentForm switch is not exhaustive");
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a form for any document type depending on the relationship.
|
||||
*/
|
||||
export const DocumentForm = ({
|
||||
campaignId,
|
||||
relationshipType,
|
||||
onCreate,
|
||||
}: {
|
||||
campaignId: CampaignId;
|
||||
relationshipType: RelationshipType;
|
||||
onCreate: (document: Document) => Promise<void>;
|
||||
}) => {
|
||||
switch (relationshipType) {
|
||||
case RelationshipType.Secrets:
|
||||
return <SecretForm campaign={campaignId} onCreate={onCreate} />;
|
||||
case RelationshipType.DiscoveredIn:
|
||||
return "Form not supported here";
|
||||
}
|
||||
|
||||
return assertUnreachable(relationshipType);
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
// SecretForm.tsx
|
||||
// Form for adding a new secret to a session.
|
||||
import { useState } from "react";
|
||||
import type { Secret } from "@/lib/types";
|
||||
import type { CampaignId, Secret } from "@/lib/types";
|
||||
import { pb } from "@/lib/pocketbase";
|
||||
|
||||
/**
|
||||
@@ -11,7 +11,7 @@ export const SecretForm = ({
|
||||
campaign,
|
||||
onCreate,
|
||||
}: {
|
||||
campaign: string;
|
||||
campaign: CampaignId;
|
||||
onCreate: (secret: Secret) => Promise<void>;
|
||||
}) => {
|
||||
const [newSecret, setNewSecret] = useState("");
|
||||
|
||||
@@ -14,7 +14,7 @@ export type Campaign = RecordModel & {
|
||||
|
||||
export type Document = RecordModel & {
|
||||
id: DocumentId;
|
||||
campaign: Campaign;
|
||||
campaign: CampaignId;
|
||||
data: {};
|
||||
// These two are not in Pocketbase's types, but they seem to always be present
|
||||
created: string;
|
||||
@@ -57,8 +57,11 @@ export const RelationshipType = {
|
||||
DiscoveredIn: "discoveredIn",
|
||||
} as const;
|
||||
|
||||
export type RelationshipType =
|
||||
(typeof RelationshipType)[keyof typeof RelationshipType];
|
||||
|
||||
export type Relationship = RecordModel & {
|
||||
primary: DocumentId;
|
||||
secondary: DocumentId[];
|
||||
type: (typeof RelationshipType)[keyof typeof RelationshipType];
|
||||
type: RelationshipType;
|
||||
};
|
||||
|
||||
@@ -3,7 +3,6 @@ import { pb } from "@/lib/pocketbase";
|
||||
import { RelationshipType, type Session } from "@/lib/types";
|
||||
import { RelationshipList } from "@/components/RelationshipList";
|
||||
import { SessionForm } from "@/components/documents/session/SessionForm";
|
||||
import { SecretForm } from "@/components/documents/secret/SecretForm";
|
||||
|
||||
export const Route = createFileRoute("/_authenticated/document/$documentId")({
|
||||
loader: async ({ params }) => {
|
||||
@@ -28,9 +27,6 @@ function RouteComponent() {
|
||||
<RelationshipList
|
||||
root={session}
|
||||
relationshipType={RelationshipType.Secrets}
|
||||
newItemForm={(onCreate) => (
|
||||
<SecretForm campaign={session.campaign.id} onCreate={onCreate} />
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user