Adds new campaign form. Adds fronts and thread types
This commit is contained in:
54
pb_migrations/1754253375_updated_documents.js
Normal file
54
pb_migrations/1754253375_updated_documents.js
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/// <reference path="../pb_data/types.d.ts" />
|
||||||
|
migrate((app) => {
|
||||||
|
const collection = app.findCollectionByNameOrId("pbc_3332084752")
|
||||||
|
|
||||||
|
// 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": [
|
||||||
|
"location",
|
||||||
|
"monster",
|
||||||
|
"npc",
|
||||||
|
"scene",
|
||||||
|
"secret",
|
||||||
|
"session",
|
||||||
|
"treasure",
|
||||||
|
"thread",
|
||||||
|
"front"
|
||||||
|
]
|
||||||
|
}))
|
||||||
|
|
||||||
|
return app.save(collection)
|
||||||
|
}, (app) => {
|
||||||
|
const collection = app.findCollectionByNameOrId("pbc_3332084752")
|
||||||
|
|
||||||
|
// 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": [
|
||||||
|
"location",
|
||||||
|
"monster",
|
||||||
|
"npc",
|
||||||
|
"scene",
|
||||||
|
"secret",
|
||||||
|
"session",
|
||||||
|
"treasure"
|
||||||
|
]
|
||||||
|
}))
|
||||||
|
|
||||||
|
return app.save(collection)
|
||||||
|
})
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
type AnyDocument,
|
type AnyDocument,
|
||||||
type CampaignId,
|
type CampaignId,
|
||||||
|
type DocumentId,
|
||||||
type DocumentType,
|
type DocumentType,
|
||||||
} from "@/lib/types";
|
} from "@/lib/types";
|
||||||
import { useDocumentCache } from "@/context/document/hooks";
|
import { useDocumentCache } from "@/context/document/hooks";
|
||||||
@@ -9,6 +10,7 @@ import { getAllDocumentsOfType } from "@/context/document/state";
|
|||||||
import { DocumentRow } from "../documents/DocumentRow";
|
import { DocumentRow } from "../documents/DocumentRow";
|
||||||
import { pb } from "@/lib/pocketbase";
|
import { pb } from "@/lib/pocketbase";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
|
import { NewCampaignDocumentForm } from "../documents/NewCampaignDocumentForm";
|
||||||
|
|
||||||
export type Props = {
|
export type Props = {
|
||||||
campaignId: CampaignId;
|
campaignId: CampaignId;
|
||||||
@@ -40,12 +42,28 @@ export const CampaignDocuments = ({ campaignId, docType }: Props) => {
|
|||||||
fetchDocuments();
|
fetchDocuments();
|
||||||
}, [campaignId, docType]);
|
}, [campaignId, docType]);
|
||||||
|
|
||||||
|
const handleRemove = (id: DocumentId) => {
|
||||||
|
pb.collection("documents").delete(id);
|
||||||
|
dispatch({
|
||||||
|
type: "removeDocument",
|
||||||
|
docId: id,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DocumentList
|
<DocumentList
|
||||||
items={items}
|
items={items}
|
||||||
renderRow={(doc) => <DocumentRow document={doc} />}
|
renderRow={(doc) => <DocumentRow document={doc} />}
|
||||||
newItemForm={() => <div>New Item Form</div>}
|
newItemForm={(onSubmit) => (
|
||||||
removeItem={() => console.error("TODO")}
|
<NewCampaignDocumentForm
|
||||||
|
campaignId={campaignId}
|
||||||
|
docType={docType}
|
||||||
|
onCreate={async () => {
|
||||||
|
onSubmit();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
removeItem={handleRemove}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ const ShowDocument = ({ doc }: { doc: AnyDocument }) => {
|
|||||||
return (
|
return (
|
||||||
<BasicPreview
|
<BasicPreview
|
||||||
id={doc.id}
|
id={doc.id}
|
||||||
title={doc.created}
|
title={doc.data.name ?? doc.created}
|
||||||
description={doc.data.strongStart}
|
description={doc.data.strongStart}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// DocumentRow.tsx
|
// DocumentRow.tsx
|
||||||
// Generic row component for displaying any document type.
|
// Generic row component for displaying any document type.
|
||||||
import { SecretToggleRow } from "@/components/documents/secret/SecretToggleRow";
|
import { SecretToggleRow } from "@/components/documents/secret/SecretToggleRow";
|
||||||
import { type AnyDocument, type Session } from "@/lib/types";
|
import { type AnyDocument } from "@/lib/types";
|
||||||
import { BasicRow } from "./BasicRow";
|
import { BasicRow } from "./BasicRow";
|
||||||
import { TreasureToggleRow } from "./treasure/TreasureToggleRow";
|
import { TreasureToggleRow } from "./treasure/TreasureToggleRow";
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ export const DocumentRow = ({
|
|||||||
return (
|
return (
|
||||||
<BasicRow
|
<BasicRow
|
||||||
doc={document}
|
doc={document}
|
||||||
title={document.created}
|
title={document.data.name || document.created}
|
||||||
description={document.data.strongStart}
|
description={document.data.strongStart}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,24 +1,28 @@
|
|||||||
import { type AnyDocument, type Session } from "@/lib/types";
|
import { type AnyDocument } from "@/lib/types";
|
||||||
import { FormattedDate } from "../FormattedDate";
|
import { FormattedDate } from "../FormattedDate";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders the document title to go at the top a document page.
|
* Renders the document title to go at the top a document page.
|
||||||
*/
|
*/
|
||||||
export const DocumentTitle = ({
|
export const DocumentTitle = ({ doc }: { doc: AnyDocument }) => {
|
||||||
document,
|
return (
|
||||||
}: {
|
<h1 className="text-2xl font-bold">
|
||||||
document: AnyDocument;
|
<TitleText doc={doc} />
|
||||||
session?: Session;
|
</h1>
|
||||||
}) => {
|
);
|
||||||
switch (document.type) {
|
};
|
||||||
|
|
||||||
|
const TitleText = ({ doc }: { doc: AnyDocument }) => {
|
||||||
|
switch (doc.type) {
|
||||||
case "session":
|
case "session":
|
||||||
return (
|
if (doc.data.name) {
|
||||||
<h1>
|
return doc.data.name;
|
||||||
<FormattedDate date={document.created} />
|
}
|
||||||
</h1>
|
|
||||||
);
|
return <FormattedDate date={doc.created} />;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return <h1>document.type</h1>;
|
// TODO: Put in proper names for other document types
|
||||||
|
return doc.type;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -48,16 +48,17 @@ export function DocumentView({
|
|||||||
>
|
>
|
||||||
← Back to campaign
|
← Back to campaign
|
||||||
</Link>
|
</Link>
|
||||||
<Link
|
{/* Print link isn't currently working */}
|
||||||
to="/document/$documentId/print"
|
{/* <Link */}
|
||||||
params={{ documentId: doc.id }}
|
{/* to="/document/$documentId/print" */}
|
||||||
className="text-slate-400 hover:text-violet-400 text-sm underline underline-offset-2 transition-colors"
|
{/* params={{ documentId: doc.id }} */}
|
||||||
>
|
{/* className="text-slate-400 hover:text-violet-400 text-sm underline underline-offset-2 transition-colors" */}
|
||||||
Print
|
{/* > */}
|
||||||
</Link>
|
{/* Print */}
|
||||||
|
{/* </Link> */}
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
title={<DocumentTitle document={doc} />}
|
title={<DocumentTitle doc={doc} />}
|
||||||
tabs={[
|
tabs={[
|
||||||
<Tab
|
<Tab
|
||||||
to="/document/$documentId"
|
to="/document/$documentId"
|
||||||
|
|||||||
28
src/components/documents/NewCampaignDocumentForm.tsx
Normal file
28
src/components/documents/NewCampaignDocumentForm.tsx
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import {
|
||||||
|
type AnyDocument,
|
||||||
|
type CampaignId,
|
||||||
|
type DocumentType,
|
||||||
|
} from "@/lib/types";
|
||||||
|
import { NewSessionForm } from "./session/NewSessionForm";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a form for any document type depending on the relationship.
|
||||||
|
*/
|
||||||
|
export const NewCampaignDocumentForm = ({
|
||||||
|
campaignId,
|
||||||
|
docType,
|
||||||
|
onCreate,
|
||||||
|
}: {
|
||||||
|
campaignId: CampaignId;
|
||||||
|
docType: DocumentType;
|
||||||
|
onCreate: (doc: AnyDocument) => Promise<void>;
|
||||||
|
}) => {
|
||||||
|
switch (docType) {
|
||||||
|
case "session":
|
||||||
|
return <NewSessionForm campaignId={campaignId} onCreate={onCreate} />;
|
||||||
|
default:
|
||||||
|
throw new Error(
|
||||||
|
`Rendered NewCampaignDocumentForm with unsupported docType: ${docType}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
96
src/components/documents/session/NewSessionForm.tsx
Normal file
96
src/components/documents/session/NewSessionForm.tsx
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
import { BaseForm } from "@/components/form/BaseForm";
|
||||||
|
import { SingleLineInput } from "@/components/form/SingleLineInput";
|
||||||
|
import { useDocumentCache } from "@/context/document/hooks";
|
||||||
|
import { pb } from "@/lib/pocketbase";
|
||||||
|
import type {
|
||||||
|
AnyDocument,
|
||||||
|
CampaignId,
|
||||||
|
Relationship,
|
||||||
|
Session,
|
||||||
|
} from "@/lib/types";
|
||||||
|
import { useCallback, useState } from "react";
|
||||||
|
|
||||||
|
export type Props = {
|
||||||
|
campaignId: CampaignId;
|
||||||
|
onCreate: (doc: AnyDocument) => Promise<void>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const NewSessionForm = ({ campaignId, onCreate }: Props) => {
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
const [name, setName] = useState<string>("");
|
||||||
|
const { dispatch } = useDocumentCache();
|
||||||
|
|
||||||
|
console.log("Rendering with name: ", name);
|
||||||
|
|
||||||
|
const createNewSession = useCallback(async () => {
|
||||||
|
setIsLoading(true);
|
||||||
|
console.log("Creating session: ", name);
|
||||||
|
try {
|
||||||
|
// Check for a previous session
|
||||||
|
const prevSession = await pb
|
||||||
|
.collection("documents")
|
||||||
|
.getFirstListItem(`campaign = "${campaignId}" && type = 'session'`, {
|
||||||
|
sort: "-created",
|
||||||
|
});
|
||||||
|
|
||||||
|
const newSession: Session = await pb.collection("documents").create({
|
||||||
|
campaign: campaignId,
|
||||||
|
type: "session",
|
||||||
|
data: {
|
||||||
|
name,
|
||||||
|
strongStart: "",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// If any relations, then copy things over
|
||||||
|
if (prevSession) {
|
||||||
|
const prevRelations = await pb
|
||||||
|
.collection<Relationship>("relationships")
|
||||||
|
.getFullList({
|
||||||
|
filter: `primary = "${prevSession.id}"`,
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const relation of prevRelations) {
|
||||||
|
await pb.collection("relationships").create({
|
||||||
|
primary: newSession.id,
|
||||||
|
type: relation.type,
|
||||||
|
secondary: relation.secondary,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dispatch({
|
||||||
|
type: "setDocument",
|
||||||
|
doc: newSession,
|
||||||
|
});
|
||||||
|
await onCreate?.(newSession);
|
||||||
|
} catch (e: unknown) {
|
||||||
|
if (e instanceof Error) {
|
||||||
|
setError(e.message);
|
||||||
|
} else {
|
||||||
|
setError("An unknown error occurred while creating the session.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setIsLoading(false);
|
||||||
|
}, [campaignId, name, dispatch, setIsLoading, setError]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BaseForm
|
||||||
|
title="Create new session"
|
||||||
|
onSubmit={createNewSession}
|
||||||
|
isLoading={isLoading}
|
||||||
|
error={error}
|
||||||
|
content={
|
||||||
|
<>
|
||||||
|
<SingleLineInput
|
||||||
|
label="Name"
|
||||||
|
value={name}
|
||||||
|
onChange={setName}
|
||||||
|
disabled={isLoading}
|
||||||
|
placeholder="Enter session name"
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -11,7 +11,7 @@ export const SessionRow = ({ session }: { session: Session }) => {
|
|||||||
search={{ tab: "sessions", docId: session.id }}
|
search={{ tab: "sessions", docId: session.id }}
|
||||||
className="block font-semibold text-lg text-slate-300"
|
className="block font-semibold text-lg text-slate-300"
|
||||||
>
|
>
|
||||||
<FormattedDate date={session.created} />
|
{session.name ? session.name : <FormattedDate date={session.created} />}
|
||||||
</Link>
|
</Link>
|
||||||
<div className="">{session.data.strongStart}</div>
|
<div className="">{session.data.strongStart}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -16,7 +16,13 @@ export const BaseForm = ({
|
|||||||
onSubmit,
|
onSubmit,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
return (
|
return (
|
||||||
<form className="flex flex-col items-left gap-2" onSubmit={onSubmit}>
|
<form
|
||||||
|
className="flex flex-col items-left gap-2"
|
||||||
|
onSubmit={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
onSubmit(e);
|
||||||
|
}}
|
||||||
|
>
|
||||||
<h3 className="text-lg font-semibold text-slate-100">{title}</h3>
|
<h3 className="text-lg font-semibold text-slate-100">{title}</h3>
|
||||||
<div className="flex flex-col gap-2 w-full items-stretch">{content}</div>
|
<div className="flex flex-col gap-2 w-full items-stretch">{content}</div>
|
||||||
{error && <div className="text-red-400 mt-2 text-sm">{error}</div>}
|
{error && <div className="text-red-400 mt-2 text-sm">{error}</div>}
|
||||||
|
|||||||
@@ -19,4 +19,8 @@ export type DocumentAction =
|
|||||||
doc: AnyDocument;
|
doc: AnyDocument;
|
||||||
relationships: Relationship[];
|
relationships: Relationship[];
|
||||||
relatedDocuments: AnyDocument[];
|
relatedDocuments: AnyDocument[];
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: "removeDocument";
|
||||||
|
docId: DocumentId;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
|
import _ from "lodash";
|
||||||
import type { AnyDocument, DocumentId, Relationship } from "@/lib/types";
|
import type { AnyDocument, DocumentId, Relationship } from "@/lib/types";
|
||||||
import type { DocumentAction } from "./actions";
|
import type { DocumentAction } from "./actions";
|
||||||
import { ready, loading, unloaded, type DocumentState } from "./state";
|
import {
|
||||||
|
ready,
|
||||||
|
loading,
|
||||||
|
unloaded,
|
||||||
|
type DocumentState,
|
||||||
|
mapResult,
|
||||||
|
} from "./state";
|
||||||
import { relationshipsForDocument } from "@/lib/relationships";
|
import { relationshipsForDocument } from "@/lib/relationships";
|
||||||
|
|
||||||
function setLoadingDocument(
|
function setLoadingDocument(
|
||||||
@@ -65,6 +72,36 @@ function setRelationship(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function removeDocument(
|
||||||
|
docId: DocumentId,
|
||||||
|
state: DocumentState,
|
||||||
|
): DocumentState {
|
||||||
|
const remainingDocs: DocumentState["documents"] = _.omit(state.documents, [
|
||||||
|
docId,
|
||||||
|
]);
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
documents: _.mapValues(remainingDocs, (result) => {
|
||||||
|
if (result.type !== "ready") {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return ready({
|
||||||
|
doc: result.value.doc,
|
||||||
|
relationships: _.mapValues(
|
||||||
|
result.value.relationships,
|
||||||
|
(relationshipResult) =>
|
||||||
|
mapResult(relationshipResult, (relationship) => ({
|
||||||
|
...relationship,
|
||||||
|
secondary: relationship.secondary.filter(
|
||||||
|
(relatedId) => relatedId !== docId,
|
||||||
|
),
|
||||||
|
})),
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function reducer(
|
export function reducer(
|
||||||
state: DocumentState,
|
state: DocumentState,
|
||||||
action: DocumentAction,
|
action: DocumentAction,
|
||||||
@@ -84,5 +121,7 @@ export function reducer(
|
|||||||
setDocument(state, action.doc),
|
setDocument(state, action.doc),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
case "removeDocument":
|
||||||
|
return removeDocument(action.docId, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,16 @@ export const error = (err: unknown): Result<any> => ({ type: "error", err });
|
|||||||
export const loading = (): Result<any> => ({ type: "loading" });
|
export const loading = (): Result<any> => ({ type: "loading" });
|
||||||
export const ready = <V>(value: V): Result<V> => ({ type: "ready", value });
|
export const ready = <V>(value: V): Result<V> => ({ type: "ready", value });
|
||||||
|
|
||||||
|
export const mapResult = <A, B>(
|
||||||
|
result: Result<A>,
|
||||||
|
f: (a: A) => B,
|
||||||
|
): Result<B> => {
|
||||||
|
if (result.type === "ready") {
|
||||||
|
return ready(f(result.value));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
export type DocumentState = {
|
export type DocumentState = {
|
||||||
documents: Record<
|
documents: Record<
|
||||||
DocumentId,
|
DocumentId,
|
||||||
|
|||||||
@@ -65,12 +65,14 @@ export type Relationship = RecordModel & {
|
|||||||
******************************************/
|
******************************************/
|
||||||
|
|
||||||
export type DocumentType =
|
export type DocumentType =
|
||||||
|
| "front"
|
||||||
| "location"
|
| "location"
|
||||||
| "monster"
|
| "monster"
|
||||||
| "npc"
|
| "npc"
|
||||||
| "scene"
|
| "scene"
|
||||||
| "secret"
|
| "secret"
|
||||||
| "session"
|
| "session"
|
||||||
|
| "thread"
|
||||||
| "treasure";
|
| "treasure";
|
||||||
|
|
||||||
export type DocumentData<Type extends DocumentType, Data> = {
|
export type DocumentData<Type extends DocumentType, Data> = {
|
||||||
@@ -90,12 +92,14 @@ export type Document<Type extends DocumentType, Data> = RecordModel & {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type AnyDocument =
|
export type AnyDocument =
|
||||||
|
| Front
|
||||||
| Location
|
| Location
|
||||||
| Monster
|
| Monster
|
||||||
| Npc
|
| Npc
|
||||||
| Scene
|
| Scene
|
||||||
| Secret
|
| Secret
|
||||||
| Session
|
| Session
|
||||||
|
| Thread
|
||||||
| Treasure;
|
| Treasure;
|
||||||
|
|
||||||
export function getDocumentType(doc: AnyDocument): DocumentType {
|
export function getDocumentType(doc: AnyDocument): DocumentType {
|
||||||
@@ -135,6 +139,7 @@ export type Npc = Document<
|
|||||||
export type Session = Document<
|
export type Session = Document<
|
||||||
"session",
|
"session",
|
||||||
{
|
{
|
||||||
|
name?: string;
|
||||||
strongStart: string;
|
strongStart: string;
|
||||||
}
|
}
|
||||||
>;
|
>;
|
||||||
@@ -167,3 +172,24 @@ export type Treasure = Document<
|
|||||||
discovered: boolean;
|
discovered: boolean;
|
||||||
}
|
}
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
/** Thread **/
|
||||||
|
|
||||||
|
export type Thread = Document<
|
||||||
|
"thread",
|
||||||
|
{
|
||||||
|
text: string;
|
||||||
|
resolved: boolean;
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
|
||||||
|
/** Front **/
|
||||||
|
|
||||||
|
export type Front = Document<
|
||||||
|
"front",
|
||||||
|
{
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
resolved: boolean;
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ const CampaignTabs = {
|
|||||||
secrets: { label: "Secrets", docType: "secret" },
|
secrets: { label: "Secrets", docType: "secret" },
|
||||||
npcs: { label: "NPCs", docType: "npc" },
|
npcs: { label: "NPCs", docType: "npc" },
|
||||||
locations: { label: "Locations", docType: "location" },
|
locations: { label: "Locations", docType: "location" },
|
||||||
|
threads: { label: "Threads", docType: "thread" },
|
||||||
|
fronts: { label: "Fronts", docType: "front" },
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
const campaignSearchSchema = z.object({
|
const campaignSearchSchema = z.object({
|
||||||
@@ -38,7 +40,6 @@ function RouteComponent() {
|
|||||||
|
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [campaign, setCampaign] = useState<Campaign | null>(null);
|
const [campaign, setCampaign] = useState<Campaign | null>(null);
|
||||||
const [sessions, setSessions] = useState<Session[]>([]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function fetchData() {
|
async function fetchData() {
|
||||||
@@ -46,54 +47,11 @@ function RouteComponent() {
|
|||||||
const campaign = await pb
|
const campaign = await pb
|
||||||
.collection("campaigns")
|
.collection("campaigns")
|
||||||
.getOne(params.campaignId);
|
.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[]);
|
|
||||||
setCampaign(campaign as Campaign);
|
setCampaign(campaign as Campaign);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
fetchData();
|
fetchData();
|
||||||
}, [setCampaign, setSessions, setLoading]);
|
}, [setCampaign, setLoading]);
|
||||||
|
|
||||||
const createNewSession = useCallback(async () => {
|
|
||||||
if (campaign === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Check for a previous session
|
|
||||||
const prevSession = await pb
|
|
||||||
.collection("documents")
|
|
||||||
.getFirstListItem(`campaign = "${campaign.id}" && type = 'session'`, {
|
|
||||||
sort: "-created",
|
|
||||||
});
|
|
||||||
|
|
||||||
const newSession = await pb.collection("documents").create({
|
|
||||||
campaign: campaign.id,
|
|
||||||
type: "session",
|
|
||||||
data: {
|
|
||||||
strongStart: "",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// If any relations, then copy things over
|
|
||||||
if (prevSession) {
|
|
||||||
const prevRelations = await pb
|
|
||||||
.collection<Relationship>("relationships")
|
|
||||||
.getFullList({
|
|
||||||
filter: `primary = "${prevSession.id}"`,
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const relation of prevRelations) {
|
|
||||||
await pb.collection("relationships").create({
|
|
||||||
primary: newSession.id,
|
|
||||||
type: relation.type,
|
|
||||||
secondary: relation.secondary,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [campaign]);
|
|
||||||
|
|
||||||
if (loading || campaign === null) {
|
if (loading || campaign === null) {
|
||||||
return <Loader />;
|
return <Loader />;
|
||||||
|
|||||||
Reference in New Issue
Block a user