diff --git a/packages/payload/src/admin/providers/DocumentInfo.ts b/packages/payload/src/admin/providers/DocumentInfo.ts index b4fa99aeebf..adae3c356cc 100644 --- a/packages/payload/src/admin/providers/DocumentInfo.ts +++ b/packages/payload/src/admin/providers/DocumentInfo.ts @@ -26,7 +26,9 @@ export type DocumentInfoContext = { versionsConfig: SanitizedCollectionConfig['versions'] | SanitizedGlobalConfig['versions'] }>, ) => void + setDocumentTitle: (title: string) => void slug?: string + title?: string unpublishedVersions?: PaginatedDocs> versions?: PaginatedDocs> versionsConfig?: SanitizedCollectionConfig['versions'] | SanitizedGlobalConfig['versions'] diff --git a/packages/ui/src/elements/DeleteDocument/index.tsx b/packages/ui/src/elements/DeleteDocument/index.tsx index 87cb0a3b0e4..1c159edf0d4 100644 --- a/packages/ui/src/elements/DeleteDocument/index.tsx +++ b/packages/ui/src/elements/DeleteDocument/index.tsx @@ -7,16 +7,17 @@ import type { Props } from './types' import { getTranslation } from '@payloadcms/translations' // import { requests } from '../../../api' -import useTitle from '../../hooks/useTitle' import { useForm } from '../../forms/Form/context' import { MinimalTemplate } from '../../templates/Minimal' import { useTranslation } from '../../providers/Translation' import { useConfig } from '../../providers/Config' import { Button } from '../Button' import * as PopupList from '../Popup/PopupButtonList' -import './index.scss' import { useRouter } from 'next/navigation' import { Translation } from '../Translation' +import { useDocumentInfo } from '../../providers/DocumentInfo' + +import './index.scss' const baseClass = 'delete-document' @@ -33,9 +34,7 @@ const DeleteDocument: React.FC = (props) => { const { toggleModal } = useModal() const history = useRouter() const { i18n, t } = useTranslation() - const title = useTitle({ - useAsTitle, - }) + const { title } = useDocumentInfo() const titleToRender = titleFromProps || title || id diff --git a/packages/ui/src/elements/DocumentHeader/index.tsx b/packages/ui/src/elements/DocumentHeader/index.tsx index ea0c48f1f7c..71998460828 100644 --- a/packages/ui/src/elements/DocumentHeader/index.tsx +++ b/packages/ui/src/elements/DocumentHeader/index.tsx @@ -35,9 +35,6 @@ export const DocumentHeader: React.FC<{ = (props) => { - const { - className, - useAsTitle, - globalLabel, - globalSlug, - element = 'h1', - fallback = '[untitled]', - title: titleFromProps, - } = props - - const { id } = useDocumentInfo() - - const titleFromForm = useTitle({ - useAsTitle: useAsTitle, - globalLabel: globalLabel, - globalSlug: globalSlug, - }) - - let title = titleFromForm - if (!title) title = id?.toString() - if (!title) title = fallback - title = titleFromProps || title + const { className, element = 'h1', title: titleFromProps } = props + + const { title: titleFromContext, id } = useDocumentInfo() + + const title = titleFromProps || titleFromContext const idAsTitle = title === id diff --git a/packages/ui/src/elements/RenderTitle/types.ts b/packages/ui/src/elements/RenderTitle/types.ts index a65fb93caa9..9a4032c6b13 100644 --- a/packages/ui/src/elements/RenderTitle/types.ts +++ b/packages/ui/src/elements/RenderTitle/types.ts @@ -2,9 +2,6 @@ import type { SanitizedCollectionConfig, SanitizedGlobalConfig } from 'payload/t export type Props = { className?: string - useAsTitle?: SanitizedCollectionConfig['admin']['useAsTitle'] - globalLabel?: SanitizedGlobalConfig['label'] - globalSlug?: SanitizedGlobalConfig['slug'] element?: React.ElementType fallback?: string title?: string diff --git a/packages/ui/src/hooks/useTitle.tsx b/packages/ui/src/hooks/useTitle.tsx deleted file mode 100644 index 8656f491fdb..00000000000 --- a/packages/ui/src/hooks/useTitle.tsx +++ /dev/null @@ -1,41 +0,0 @@ -'use client' -import type { SanitizedCollectionConfig, SanitizedGlobalConfig } from 'payload/types' - -import { useFormFields } from '../forms/Form/context' -import { formatDocTitle } from '../utilities/formatDocTitle' -import { useTranslation } from '../providers/Translation' -import { getTranslation } from '@payloadcms/translations' - -const useTitle = (args: { - useAsTitle?: SanitizedCollectionConfig['admin']['useAsTitle'] - globalLabel?: SanitizedGlobalConfig['label'] - globalSlug?: SanitizedGlobalConfig['slug'] -}): string => { - const { useAsTitle, globalLabel, globalSlug } = args - const { i18n } = useTranslation() - - let title: string = '' - - const field = useFormFields(([fields]) => (fields && fields?.[useAsTitle]) || null) - - if (useAsTitle) { - title = formatDocTitle({ - useAsTitle, - field, - // TODO: Fix this - // @ts-ignore-next-line - i18n, - }) - } - - if (globalLabel) { - title = typeof globalLabel === 'string' ? globalLabel : globalSlug - // TODO: Fix this - // @ts-ignore-next-line - title = getTranslation(globalLabel, i18n) || globalSlug - } - - return title -} - -export default useTitle diff --git a/packages/ui/src/providers/DocumentInfo/SetDocumentInfo/index.tsx b/packages/ui/src/providers/DocumentInfo/SetDocumentInfo/index.tsx index 6b74d37ae27..a4160a97c05 100644 --- a/packages/ui/src/providers/DocumentInfo/SetDocumentInfo/index.tsx +++ b/packages/ui/src/providers/DocumentInfo/SetDocumentInfo/index.tsx @@ -13,11 +13,6 @@ export const SetDocumentInfo: React.FC<{ useEffect(() => { setDocumentInfo({ collectionSlug, globalSlug, id, versionsConfig }) - - return () => { - // reset on navigation away - setDocumentInfo({}) - } }, [collectionSlug, globalSlug, id, setDocumentInfo, versionsConfig]) return null diff --git a/packages/ui/src/providers/DocumentInfo/index.tsx b/packages/ui/src/providers/DocumentInfo/index.tsx index f6b56d6b273..b116303f846 100644 --- a/packages/ui/src/providers/DocumentInfo/index.tsx +++ b/packages/ui/src/providers/DocumentInfo/index.tsx @@ -28,6 +28,7 @@ export const DocumentInfoProvider: React.FC = ({ children, ...rest }) => routes: { api }, serverURL, } = useConfig() + const { getPreference, setPreference } = usePreferences() const { i18n } = useTranslation() const { permissions } = useAuth() @@ -42,6 +43,8 @@ export const DocumentInfoProvider: React.FC = ({ children, ...rest }) => ...rest, }) + const [title, setTitle] = useState('') + const { globalSlug, collectionSlug, id, versionsConfig } = propsToUse const baseURL = `${serverURL}${api}` @@ -257,6 +260,13 @@ export const DocumentInfoProvider: React.FC = ({ children, ...rest }) => getDocPermissions() }, [getDocPermissions]) + const setDocumentTitle = useCallback( + (title) => { + setTitle(title || id?.toString() || '[untitled]') + }, + [setPropsToUse, id], + ) + const value: DocumentInfoContext = { id, collectionSlug, @@ -272,6 +282,8 @@ export const DocumentInfoProvider: React.FC = ({ children, ...rest }) => versionsConfig, versions, setDocumentInfo: setPropsToUse, + setDocumentTitle, + title, } return {children} diff --git a/packages/ui/src/views/Edit/SetDocumentTitle/index.tsx b/packages/ui/src/views/Edit/SetDocumentTitle/index.tsx new file mode 100644 index 00000000000..74f05eb5b9e --- /dev/null +++ b/packages/ui/src/views/Edit/SetDocumentTitle/index.tsx @@ -0,0 +1,56 @@ +'use client' +import { useEffect } from 'react' +import { useDocumentInfo } from '../../../providers/DocumentInfo' +import { useTranslation } from '../../../providers/Translation' +import { ClientConfig } from 'payload/types' +import { useFormFields } from '../../../forms/Form/context' +import { formatDate } from '../../..' +import { getTranslation } from '@payloadcms/translations' + +export const SetDocumentTitle: React.FC<{ + config?: ClientConfig + globalConfig?: ClientConfig['globals'][0] + collectionConfig?: ClientConfig['collections'][0] +}> = (props) => { + const { config, globalConfig, collectionConfig } = props + + const dateFormatFromConfig = config?.admin?.dateFormat + + const useAsTitle = collectionConfig?.admin?.useAsTitle + + const field = useFormFields(([fields]) => (useAsTitle && fields && fields?.[useAsTitle]) || null) + + const { i18n } = useTranslation() + + const { setDocumentTitle } = useDocumentInfo() + + let title: string + + if (typeof field === 'string') { + title = field + } else if (typeof field === 'number') { + title = String(field) + } else { + title = field?.value as string + } + + if (collectionConfig && useAsTitle) { + const fieldConfig = collectionConfig.fields.find((f) => 'name' in f && f.name === useAsTitle) + const isDate = fieldConfig?.type === 'date' + + if (title && isDate) { + const dateFormat = fieldConfig?.admin?.date?.displayFormat || dateFormatFromConfig + title = formatDate(title, dateFormat, i18n.language) + } + } + + if (globalConfig) { + title = getTranslation(globalConfig?.label, i18n) || globalConfig?.slug + } + + useEffect(() => { + setDocumentTitle(title) + }, [setDocumentTitle, title]) + + return null +} diff --git a/packages/ui/src/views/Edit/SetStepNav.tsx b/packages/ui/src/views/Edit/SetStepNav/index.tsx similarity index 76% rename from packages/ui/src/views/Edit/SetStepNav.tsx rename to packages/ui/src/views/Edit/SetStepNav/index.tsx index a0297d9b34c..a5d41adfbc1 100644 --- a/packages/ui/src/views/Edit/SetStepNav.tsx +++ b/packages/ui/src/views/Edit/SetStepNav/index.tsx @@ -1,15 +1,15 @@ 'use client' import { useEffect } from 'react' -import { useTranslation } from '../../providers/Translation' +import { useTranslation } from '../../../providers/Translation' import type { SanitizedCollectionConfig, SanitizedGlobalConfig } from 'payload/types' -import type { StepNavItem } from '../../elements/StepNav/types' +import type { StepNavItem } from '../../../elements/StepNav/types' import { getTranslation } from '@payloadcms/translations' -import { useStepNav } from '../../elements/StepNav' -import { useConfig } from '../../providers/Config' -import { useEditDepth } from '../../providers/EditDepth' -import useTitle from '../../hooks/useTitle' +import { useStepNav } from '../../../elements/StepNav' +import { useConfig } from '../../../providers/Config' +import { useEditDepth } from '../../../providers/EditDepth' +import { useDocumentInfo } from '../../../providers/DocumentInfo' export const SetStepNav: React.FC<{ collectionSlug?: SanitizedCollectionConfig['slug'] @@ -21,23 +21,11 @@ export const SetStepNav: React.FC<{ isEditing?: boolean view?: string }> = (props) => { - const { - collectionSlug, - globalSlug, - pluralLabel, - useAsTitle, - id, - isEditing = true, - globalLabel, - } = props + const { collectionSlug, globalSlug, pluralLabel, useAsTitle, id, isEditing = true } = props const view: string | undefined = props?.view || undefined - const title = useTitle({ - useAsTitle, - globalLabel, - globalSlug, - }) + const { title } = useDocumentInfo() const { setStepNav } = useStepNav() diff --git a/packages/ui/src/views/Edit/index.tsx b/packages/ui/src/views/Edit/index.tsx index 427f9c65e3a..bbfe854a81a 100644 --- a/packages/ui/src/views/Edit/index.tsx +++ b/packages/ui/src/views/Edit/index.tsx @@ -18,6 +18,7 @@ import { Upload } from './Upload' import { useConfig } from '../../providers/Config' import { useTranslation } from '../../providers/Translation' import { useComponentMap } from '../../providers/ComponentMapProvider' +import { SetDocumentTitle } from './SetDocumentTitle' import './index.scss' @@ -41,7 +42,9 @@ export const DefaultEditView: React.FC = (props) => { locale, } = props - const { collections, globals } = useConfig() + const config = useConfig() + const { collections, globals } = config + const { i18n } = useTranslation() const { getFieldMap } = useComponentMap() @@ -189,6 +192,11 @@ export const DefaultEditView: React.FC = (props) => { isEditing={isEditing || false} pluralLabel={collectionConfig?.labels?.plural} /> +