Adds new campaign form. Adds fronts and thread types
This commit is contained in:
@@ -57,7 +57,7 @@ const ShowDocument = ({ doc }: { doc: AnyDocument }) => {
|
||||
return (
|
||||
<BasicPreview
|
||||
id={doc.id}
|
||||
title={doc.created}
|
||||
title={doc.data.name ?? doc.created}
|
||||
description={doc.data.strongStart}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// DocumentRow.tsx
|
||||
// Generic row component for displaying any document type.
|
||||
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 { TreasureToggleRow } from "./treasure/TreasureToggleRow";
|
||||
|
||||
@@ -42,7 +42,7 @@ export const DocumentRow = ({
|
||||
return (
|
||||
<BasicRow
|
||||
doc={document}
|
||||
title={document.created}
|
||||
title={document.data.name || document.created}
|
||||
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";
|
||||
|
||||
/**
|
||||
* Renders the document title to go at the top a document page.
|
||||
*/
|
||||
export const DocumentTitle = ({
|
||||
document,
|
||||
}: {
|
||||
document: AnyDocument;
|
||||
session?: Session;
|
||||
}) => {
|
||||
switch (document.type) {
|
||||
export const DocumentTitle = ({ doc }: { doc: AnyDocument }) => {
|
||||
return (
|
||||
<h1 className="text-2xl font-bold">
|
||||
<TitleText doc={doc} />
|
||||
</h1>
|
||||
);
|
||||
};
|
||||
|
||||
const TitleText = ({ doc }: { doc: AnyDocument }) => {
|
||||
switch (doc.type) {
|
||||
case "session":
|
||||
return (
|
||||
<h1>
|
||||
<FormattedDate date={document.created} />
|
||||
</h1>
|
||||
);
|
||||
if (doc.data.name) {
|
||||
return doc.data.name;
|
||||
}
|
||||
|
||||
return <FormattedDate date={doc.created} />;
|
||||
|
||||
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
|
||||
</Link>
|
||||
<Link
|
||||
to="/document/$documentId/print"
|
||||
params={{ documentId: doc.id }}
|
||||
className="text-slate-400 hover:text-violet-400 text-sm underline underline-offset-2 transition-colors"
|
||||
>
|
||||
Print
|
||||
</Link>
|
||||
{/* Print link isn't currently working */}
|
||||
{/* <Link */}
|
||||
{/* to="/document/$documentId/print" */}
|
||||
{/* params={{ documentId: doc.id }} */}
|
||||
{/* className="text-slate-400 hover:text-violet-400 text-sm underline underline-offset-2 transition-colors" */}
|
||||
{/* > */}
|
||||
{/* Print */}
|
||||
{/* </Link> */}
|
||||
</>
|
||||
}
|
||||
title={<DocumentTitle document={doc} />}
|
||||
title={<DocumentTitle doc={doc} />}
|
||||
tabs={[
|
||||
<Tab
|
||||
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 }}
|
||||
className="block font-semibold text-lg text-slate-300"
|
||||
>
|
||||
<FormattedDate date={session.created} />
|
||||
{session.name ? session.name : <FormattedDate date={session.created} />}
|
||||
</Link>
|
||||
<div className="">{session.data.strongStart}</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user