82 lines
2.5 KiB
TypeScript
82 lines
2.5 KiB
TypeScript
import { DocumentList } from "@/components/DocumentList";
|
|
import { pb } from "@/lib/pocketbase";
|
|
import { displayName } from "@/lib/relationships";
|
|
import type { AnyDocument, Document, RelationshipType } from "@/lib/types";
|
|
import { useState } from "react";
|
|
import { Loader } from "./Loader";
|
|
import { DocumentRow } from "./documents/DocumentRow";
|
|
import { NewRelatedDocumentForm } from "./documents/NewRelatedDocumentForm";
|
|
|
|
interface RelationshipListProps {
|
|
root: AnyDocument;
|
|
items: AnyDocument[];
|
|
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({
|
|
root,
|
|
items: initialItems,
|
|
relationshipType,
|
|
}: RelationshipListProps) {
|
|
const [items, setItems] = useState<Document[]>(initialItems);
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
// Handles creation of a new document and adds it to the relationship
|
|
const handleCreate = async (doc: Document) => {
|
|
setLoading(true);
|
|
setError(null);
|
|
try {
|
|
// Check for existing relationship
|
|
const existing = await pb.collection("relationships").getFullList({
|
|
filter: `primary = "${root.id}" && type = "${relationshipType}"`,
|
|
});
|
|
if (existing.length > 0) {
|
|
console.debug("Adding to existing relationship");
|
|
await pb.collection("relationships").update(existing[0].id, {
|
|
"+secondary": doc.id,
|
|
});
|
|
} else {
|
|
console.debug("Creating new relationship");
|
|
await pb.collection("relationships").create({
|
|
primary: root.id,
|
|
secondary: [doc.id],
|
|
type: relationshipType,
|
|
});
|
|
}
|
|
setItems((prev) => [...prev, doc]);
|
|
} catch (e: any) {
|
|
setError(e?.message || "Failed to add document to relationship.");
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
if (loading) {
|
|
<Loader />;
|
|
}
|
|
|
|
return (
|
|
<DocumentList
|
|
title={displayName(relationshipType)}
|
|
items={items}
|
|
error={error}
|
|
renderRow={(document) => <DocumentRow document={document} />}
|
|
newItemForm={(onSubmit) => (
|
|
<NewRelatedDocumentForm
|
|
campaignId={root.campaign}
|
|
relationshipType={relationshipType}
|
|
onCreate={async (doc: Document) => {
|
|
await handleCreate(doc);
|
|
onSubmit();
|
|
}}
|
|
/>
|
|
)}
|
|
/>
|
|
);
|
|
}
|