Prototype of making the new threads via generic interfaces

This commit is contained in:
2025-09-17 16:39:50 -07:00
parent 1c26daa828
commit 43afdc8684
3 changed files with 130 additions and 38 deletions

View File

@@ -1,33 +1,30 @@
import { AutoSaveTextarea } from "@/components/AutoSaveTextarea";
import { pb } from "@/lib/pocketbase";
import type { AnyDocument, Location } from "@/lib/types";
import { getDocumentType, type AnyDocument } from "@/lib/types";
import { useDocumentCache } from "@/context/document/hooks";
import {
getFieldsForType,
type DocumentField,
type FieldType,
} from "@/lib/fields";
export type GenericFieldType = "multiline" | "singleline" | "checkbox";
export type Props<T extends AnyDocument> = {
doc: T;
fields: { [K in keyof T["data"]]: GenericFieldType };
};
export const GenericEditForm = <T extends AnyDocument>({
doc,
fields,
}: Props<T>) => {
export const GenericEditForm = <T extends AnyDocument>({ doc }: Props<T>) => {
const docType = getDocumentType(doc) as T["type"];
const fields = getFieldsForType(docType);
return (
<div className="">
{
// The type checker seems to lose the types when using Object.entries here.
Object.entries(fields).map(
([fieldName, fieldType]: [string, unknown]) => (
<GenericEditFormField
key={fieldName}
doc={doc}
fieldName={fieldName as keyof T["data"]}
fieldType={fieldType as GenericFieldType}
/>
),
)
fields.map((documentField) => (
<GenericEditFormField doc={doc} field={documentField} />
))
}
</div>
);
@@ -35,51 +32,46 @@ export const GenericEditForm = <T extends AnyDocument>({
const GenericEditFormField = <T extends AnyDocument>({
doc,
fieldName,
fieldType,
field,
}: {
doc: T;
fieldName: keyof T["data"];
fieldType: GenericFieldType;
field: DocumentField<T["type"], FieldType>;
}) => {
const { dispatch } = useDocumentCache();
// The type checker really doesn't like indexing into this type implicitly, so we'll store it in a temporary to give it the right hints.
const data = doc.data as T["data"];
async function saveField(value: string) {
async function saveField(value: string | boolean) {
const updated: T = await pb.collection("documents").update(doc.id, {
data: {
...doc.data,
[fieldName]: value,
},
data: field.setter(value, doc.data),
});
dispatch({ type: "setDocument", doc: updated });
}
switch (fieldType) {
case "multiline":
switch (field.fieldType) {
case "longText":
return (
<AutoSaveTextarea
multiline={true}
value={data[fieldName] as string}
value={field.getter(data) as string}
onSave={saveField}
/>
);
case "singleline":
case "shortText":
return (
<AutoSaveTextarea
multiline={false}
value={data[fieldName] as string}
value={field.getter(data) as string}
onSave={saveField}
/>
);
case "checkbox":
case "toggle":
return (
<input
type="checkbox"
checked={data[fieldName] as boolean}
onChange={(e) => saveField(e.target.value)}
checked={!!field.getter(data)}
onChange={(e) => saveField(!!e.target.value)}
className="accent-emerald-500 w-5 h-5"
/>
);