diff --git a/core/app/components/forms/elements/RelatedPubsElement.tsx b/core/app/components/forms/elements/RelatedPubsElement.tsx index 42256e9a2..fe05f4014 100644 --- a/core/app/components/forms/elements/RelatedPubsElement.tsx +++ b/core/app/components/forms/elements/RelatedPubsElement.tsx @@ -2,7 +2,7 @@ import type { ReactNode } from "react"; -import { useState } from "react"; +import { useMemo, useState } from "react"; import { Value } from "@sinclair/typebox/value"; import { useFormContext } from "react-hook-form"; import { relationBlockConfigSchema } from "schemas"; @@ -33,9 +33,15 @@ export const RelatedPubsElement = ({ return null; } - const linkablePubs = pubs - // do not allow linking to itself. TODO: do not show already linked pubs - .filter((p) => p.id !== pubId); + const pubTitlesById = useMemo(() => { + return pubs.reduce( + (acc, { id, title }) => { + acc[id] = title; + return acc; + }, + {} as Record + ); + }, [pubs]); return ( <> @@ -43,10 +49,21 @@ export const RelatedPubsElement = ({ control={control} name={slug} render={({ field }) => { + const linkedPubs = Array.isArray(field.value) + ? field.value.map((v) => v.relatedPubId) + : []; + const linkablePubs = pubs + // do not allow linking to itself or any pubs it is already linked to + .filter((p) => p.id !== pubId && !linkedPubs.includes(p.id)); + const handleAddPubs = (newPubs: GetPubsResult) => { // todo: make value an actual thing const value = newPubs.map((p) => ({ relatedPubId: p.id, value: "" })); - field.onChange(value); + if (Array.isArray(field.value)) { + field.onChange([...field.value, ...value]); + } else { + field.onChange(value); + } }; return ( @@ -70,8 +87,7 @@ export const RelatedPubsElement = ({ ? field.value.map((pub: any) => { return (
- {/* TODO: use pub title */} - {pub.relatedPubId} + {pubTitlesById[pub.relatedPubId]}
); }) diff --git a/core/app/components/pubs/PubEditor/PubEditorClient.tsx b/core/app/components/pubs/PubEditor/PubEditorClient.tsx index 37f4ba417..4b26a71cc 100644 --- a/core/app/components/pubs/PubEditor/PubEditorClient.tsx +++ b/core/app/components/pubs/PubEditor/PubEditorClient.tsx @@ -11,7 +11,6 @@ import { Type } from "@sinclair/typebox"; import partition from "lodash.partition"; import { useForm } from "react-hook-form"; import { getDefaultValueByCoreSchemaType, getJsonSchemaByCoreSchemaType } from "schemas"; -import { RelatedPub } from "schemas/schemas"; import type { JsonValue, ProcessedPub } from "contracts"; import type { PubsId, PubTypesId, StagesId } from "db/public"; @@ -74,14 +73,22 @@ const buildDefaultValues = (elements: BasicFormElements[], pubValues: ProcessedP for (const element of elements) { if (element.slug && element.schemaName) { const pubValue = pubValues.find((v) => v.fieldSlug === element.slug)?.value; + defaultValues[element.slug] = pubValue ?? getDefaultValueByCoreSchemaType(element.schemaName); if (element.schemaName === CoreSchemaType.DateTime && pubValue) { defaultValues[element.slug] = new Date(pubValue as string); } + // There can be multiple relations for a single slug + if (element.isRelation) { + const relatedPubValues = pubValues.filter((v) => v.fieldSlug === element.slug); + defaultValues[element.slug] = relatedPubValues.map((pv) => ({ + value: pv.value, + relatedPubId: pv.relatedPubId, + })); + } } } - return defaultValues; }; @@ -248,53 +255,49 @@ export const PubEditorClient = ({ formState: formInstance.formState, toggleContext, }); - // TODO: for related fields, we need to make something like - // {fieldSlug, relatedPubId, value} - // and unnest it for each array, but the update funcs will need to take an array - // since the slugs will be duplicated so a dict won't work - console.log({ pubValues }); - // const { stageId: stageIdFromButtonConfig, submitButtonId } = getButtonConfig({ - // evt, - // withButtonElements, - // buttonElements, - // }); - - // const stageId = stageIdFromForm ?? stageIdFromButtonConfig; - // let result; - // if (isUpdating) { - // result = await runUpdatePub({ - // pubId: pubId, - // pubValues, - // stageId, - // formSlug, - // continueOnValidationError: autoSave, - // }); - // } else { - // result = await runCreatePub({ - // formSlug, - // body: { - // id: pubId, - // pubTypeId: pub.pubTypeId as PubTypesId, - // values: pubValues as Record, - // stageId: stageId, - // }, - // communityId: community.id, - // parent: parentId ? { id: parentId } : undefined, - // addUserToForm: isExternalForm, - // }); - // } - // if (didSucceed(result)) { - // // Reset dirty state to prevent the unsaved changes warning from - // // blocking navigation. - // // See https://stackoverflow.com/questions/63953501/react-hook-form-resetting-isdirty-without-clearing-form - // formInstance.reset( - // {}, - // { - // keepValues: true, - // } - // ); - // onSuccess({ isAutoSave: autoSave, submitButtonId, values: pubValues }); - // } + + const { stageId: stageIdFromButtonConfig, submitButtonId } = getButtonConfig({ + evt, + withButtonElements, + buttonElements, + }); + + const stageId = stageIdFromForm ?? stageIdFromButtonConfig; + let result; + if (isUpdating) { + result = await runUpdatePub({ + pubId: pubId, + pubValues, + stageId, + formSlug, + continueOnValidationError: autoSave, + }); + } else { + result = await runCreatePub({ + formSlug, + body: { + id: pubId, + pubTypeId: pub.pubTypeId as PubTypesId, + values: pubValues as Record, + stageId: stageId, + }, + communityId: community.id, + parent: parentId ? { id: parentId } : undefined, + addUserToForm: isExternalForm, + }); + } + if (didSucceed(result)) { + // Reset dirty state to prevent the unsaved changes warning from + // blocking navigation. + // See https://stackoverflow.com/questions/63953501/react-hook-form-resetting-isdirty-without-clearing-form + formInstance.reset( + {}, + { + keepValues: true, + } + ); + onSuccess({ isAutoSave: autoSave, submitButtonId, values: pubValues }); + } }, [ formElements,