Switches over to the relationship list

This commit is contained in:
2025-05-31 16:30:18 -07:00
parent 6336b150a7
commit 5eba132bda
4 changed files with 266 additions and 154 deletions

View File

@@ -0,0 +1,116 @@
import { useEffect, useState } from "react";
import { pb } from "@/lib/pocketbase";
import type { Document } from "@/lib/types";
import { DocumentList } from "@/components/DocumentList";
import { Loader } from "./Loader";
interface RelationshipListProps<T extends Document> {
root: Document;
relationshipType: string;
renderRow: (item: T) => React.ReactNode;
newItemForm: (onCreate: (doc: T) => Promise<void>) => React.ReactNode;
}
/**
* 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>({
root,
relationshipType,
renderRow,
newItemForm,
}: RelationshipListProps<T>) {
const [items, setItems] = useState<T[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
// Fetch related documents on mount or when root/relationshipType changes
useEffect(() => {
let cancelled = false;
async function fetchRelated() {
setLoading(true);
setError(null);
try {
const relationships = await pb
.collection("relationships")
.getList(1, 1, {
filter: `primary = "${root.id}" && type = "${relationshipType}"`,
});
const secondaryIds =
relationships.items.length > 0
? relationships.items[0].secondary
: [];
let docs: T[] = [];
if (Array.isArray(secondaryIds) && secondaryIds.length > 0) {
docs = (await pb.collection("documents").getFullList({
filter: secondaryIds
.map((id: string) => `id = "${id}"`)
.join(" || "),
})) as T[];
}
if (!cancelled) setItems(docs);
} catch (e: any) {
if (!cancelled)
setError(e?.message || "Failed to load related documents.");
} finally {
if (!cancelled) setLoading(false);
}
}
fetchRelated();
return () => {
cancelled = true;
};
}, [root.id, relationshipType]);
// Handles creation of a new document and adds it to the relationship
const handleCreate = async (doc: T) => {
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={
relationshipType.charAt(0).toUpperCase() + relationshipType.slice(1)
}
items={items}
error={error}
renderRow={renderRow}
newItemForm={(onSubmit) =>
newItemForm(async (doc: T) => {
await handleCreate(doc);
onSubmit();
})
}
/>
);
}