Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(ui): renders live document title #5115

Merged
merged 3 commits into from
Feb 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/payload/src/admin/providers/DocumentInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ export type DocumentInfoContext = {
versionsConfig: SanitizedCollectionConfig['versions'] | SanitizedGlobalConfig['versions']
}>,
) => void
setDocumentTitle: (title: string) => void
slug?: string
title?: string
unpublishedVersions?: PaginatedDocs<TypeWithVersion<any>>
versions?: PaginatedDocs<TypeWithVersion<any>>
versionsConfig?: SanitizedCollectionConfig['versions'] | SanitizedGlobalConfig['versions']
Expand Down
9 changes: 4 additions & 5 deletions packages/ui/src/elements/DeleteDocument/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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'

Expand All @@ -33,9 +34,7 @@ const DeleteDocument: React.FC<Props> = (props) => {
const { toggleModal } = useModal()
const history = useRouter()
const { i18n, t } = useTranslation()
const title = useTitle({
useAsTitle,
})
const { title } = useDocumentInfo()

const titleToRender = titleFromProps || title || id

Expand Down
3 changes: 0 additions & 3 deletions packages/ui/src/elements/DocumentHeader/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,6 @@ export const DocumentHeader: React.FC<{
<Fragment>
<RenderTitle
className={`${baseClass}__title`}
useAsTitle={collectionConfig?.admin?.useAsTitle}
globalLabel={globalConfig?.label}
globalSlug={globalConfig?.slug}
isDate={titleFieldConfig?.type === 'date'}
dateFormat={
titleFieldConfig && 'date' in titleFieldConfig?.admin
Expand Down
28 changes: 5 additions & 23 deletions packages/ui/src/elements/RenderTitle/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,18 @@ import React from 'react'

import type { Props } from './types'

import useTitle from '../../hooks/useTitle'
import IDLabel from '../IDLabel'
import { useDocumentInfo } from '../../providers/DocumentInfo'
import './index.scss'

const baseClass = 'render-title'

const RenderTitle: React.FC<Props> = (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

Expand Down
3 changes: 0 additions & 3 deletions packages/ui/src/elements/RenderTitle/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
41 changes: 0 additions & 41 deletions packages/ui/src/hooks/useTitle.tsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 12 additions & 0 deletions packages/ui/src/providers/DocumentInfo/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export const DocumentInfoProvider: React.FC<Props> = ({ children, ...rest }) =>
routes: { api },
serverURL,
} = useConfig()

const { getPreference, setPreference } = usePreferences()
const { i18n } = useTranslation()
const { permissions } = useAuth()
Expand All @@ -44,6 +45,8 @@ export const DocumentInfoProvider: React.FC<Props> = ({ children, ...rest }) =>
...rest,
})

const [title, setTitle] = useState<string>('')

const { globalSlug, collectionSlug, id, versionsConfig } = propsToUse

const baseURL = `${serverURL}${api}`
Expand Down Expand Up @@ -257,6 +260,13 @@ export const DocumentInfoProvider: React.FC<Props> = ({ children, ...rest }) =>
getDocPermissions()
}, [getDocPermissions])

const setDocumentTitle = useCallback<DocumentInfoContext['setDocumentTitle']>(
(title) => {
setTitle(title || id?.toString() || '[untitled]')
},
[setPropsToUse, id],
)

const value: DocumentInfoContext = {
id,
collectionSlug,
Expand All @@ -273,6 +283,8 @@ export const DocumentInfoProvider: React.FC<Props> = ({ children, ...rest }) =>
versionsConfig,
versions,
setDocumentInfo: setPropsToUse,
setDocumentTitle,
title,
}

return <Context.Provider value={value}>{children}</Context.Provider>
Expand Down
56 changes: 56 additions & 0 deletions packages/ui/src/views/Edit/SetDocumentTitle/index.tsx
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
@@ -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']
Expand All @@ -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()

Expand Down
10 changes: 9 additions & 1 deletion packages/ui/src/views/Edit/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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'

Expand All @@ -41,7 +42,9 @@ export const DefaultEditView: React.FC<EditViewProps> = (props) => {
locale,
} = props

const { collections, globals } = useConfig()
const config = useConfig()
const { collections, globals } = config

const { i18n } = useTranslation()
const { getFieldMap } = useComponentMap()

Expand Down Expand Up @@ -189,6 +192,11 @@ export const DefaultEditView: React.FC<EditViewProps> = (props) => {
isEditing={isEditing || false}
pluralLabel={collectionConfig?.labels?.plural}
/>
<SetDocumentTitle
config={config}
collectionConfig={collectionConfig}
globalConfig={globalConfig}
/>
<DocumentControls
apiURL={apiURL}
slug={collectionConfig?.slug}
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
"@payloadcms/translations/api": ["./packages/translations/src/all"],
"@payloadcms/next/*": ["./packages/next/src/*"],
"@payloadcms/graphql": ["./packages/graphql/src"],
"payload-config": ["./test/auth/config.ts"]
"payload-config": ["./test/_community/config.ts"]
}
},
"exclude": ["dist", "build", "temp", "node_modules"],
Expand Down
Loading