238 lines
8.9 KiB
TypeScript
238 lines
8.9 KiB
TypeScript
'use client'
|
|
import type { CollectionPermission, GlobalPermission, SanitizedCollectionConfig } from 'payload'
|
|
|
|
import { getTranslation } from '@payloadcms/translations'
|
|
import React, { Fragment, useEffect } from 'react'
|
|
|
|
import { useComponentMap } from '../../providers/ComponentMap/index.js'
|
|
import { useConfig } from '../../providers/Config/index.js'
|
|
import { useTranslation } from '../../providers/Translation/index.js'
|
|
import { formatAdminURL } from '../../utilities/formatAdminURL.js'
|
|
import { formatDate } from '../../utilities/formatDate.js'
|
|
import { Autosave } from '../Autosave/index.js'
|
|
import { DeleteDocument } from '../DeleteDocument/index.js'
|
|
import { DuplicateDocument } from '../DuplicateDocument/index.js'
|
|
import { Gutter } from '../Gutter/index.js'
|
|
import { Popup, PopupList } from '../Popup/index.js'
|
|
import { PreviewButton } from '../PreviewButton/index.js'
|
|
import { PublishButton } from '../PublishButton/index.js'
|
|
import { SaveButton } from '../SaveButton/index.js'
|
|
import { SaveDraftButton } from '../SaveDraftButton/index.js'
|
|
import { Status } from '../Status/index.js'
|
|
import './index.scss'
|
|
|
|
const baseClass = 'doc-controls'
|
|
|
|
export const DocumentControls: React.FC<{
|
|
apiURL: string
|
|
data?: any
|
|
disableActions?: boolean
|
|
hasPublishPermission?: boolean
|
|
hasSavePermission?: boolean
|
|
id?: number | string
|
|
isAccountView?: boolean
|
|
isEditing?: boolean
|
|
permissions: CollectionPermission | GlobalPermission | null
|
|
slug: SanitizedCollectionConfig['slug']
|
|
}> = (props) => {
|
|
const {
|
|
id,
|
|
slug,
|
|
data,
|
|
disableActions,
|
|
hasSavePermission,
|
|
isAccountView,
|
|
isEditing,
|
|
permissions,
|
|
} = props
|
|
|
|
const { i18n } = useTranslation()
|
|
|
|
const config = useConfig()
|
|
const { getComponentMap } = useComponentMap()
|
|
|
|
const collectionConfig = config.collections.find((coll) => coll.slug === slug)
|
|
const globalConfig = config.globals.find((global) => global.slug === slug)
|
|
|
|
const componentMap = getComponentMap({
|
|
collectionSlug: collectionConfig?.slug,
|
|
globalSlug: globalConfig?.slug,
|
|
})
|
|
|
|
const {
|
|
admin: { dateFormat },
|
|
routes: { admin: adminRoute },
|
|
} = config
|
|
|
|
// Settings these in state to avoid hydration issues if there is a mismatch between the server and client
|
|
const [updatedAt, setUpdatedAt] = React.useState<string>('')
|
|
const [createdAt, setCreatedAt] = React.useState<string>('')
|
|
|
|
useEffect(() => {
|
|
if (data?.updatedAt) {
|
|
setUpdatedAt(formatDate({ date: data.updatedAt, i18n, pattern: dateFormat }))
|
|
}
|
|
if (data?.createdAt) {
|
|
setCreatedAt(formatDate({ date: data.createdAt, i18n, pattern: dateFormat }))
|
|
}
|
|
}, [data, i18n, dateFormat])
|
|
|
|
const hasCreatePermission =
|
|
permissions && 'create' in permissions && permissions.create?.permission
|
|
|
|
const hasDeletePermission =
|
|
permissions && 'delete' in permissions && permissions.delete?.permission
|
|
|
|
const showDotMenu = Boolean(
|
|
collectionConfig && id && !disableActions && (hasCreatePermission || hasDeletePermission),
|
|
)
|
|
|
|
const unsavedDraftWithValidations =
|
|
!id && collectionConfig?.versions?.drafts && collectionConfig.versions?.drafts.validate
|
|
|
|
return (
|
|
<Gutter className={baseClass}>
|
|
<div className={`${baseClass}__wrapper`}>
|
|
<div className={`${baseClass}__content`}>
|
|
<ul className={`${baseClass}__meta`}>
|
|
{collectionConfig && !isEditing && !isAccountView && (
|
|
<li className={`${baseClass}__list-item`}>
|
|
<p className={`${baseClass}__value`}>
|
|
{i18n.t('general:creatingNewLabel', {
|
|
label: getTranslation(
|
|
collectionConfig?.labels?.singular ?? i18n.t('general:document'),
|
|
i18n,
|
|
),
|
|
})}
|
|
</p>
|
|
</li>
|
|
)}
|
|
{(collectionConfig?.versions?.drafts || globalConfig?.versions?.drafts) && (
|
|
<Fragment>
|
|
{(globalConfig || (collectionConfig && isEditing)) && (
|
|
<li
|
|
className={[`${baseClass}__status`, `${baseClass}__list-item`]
|
|
.filter(Boolean)
|
|
.join(' ')}
|
|
>
|
|
<Status />
|
|
</li>
|
|
)}
|
|
{((collectionConfig?.versions?.drafts &&
|
|
collectionConfig?.versions?.drafts?.autosave &&
|
|
!unsavedDraftWithValidations) ||
|
|
(globalConfig?.versions?.drafts && globalConfig?.versions?.drafts?.autosave)) &&
|
|
hasSavePermission && (
|
|
<li className={`${baseClass}__list-item`}>
|
|
<Autosave
|
|
collection={collectionConfig}
|
|
global={globalConfig}
|
|
id={id}
|
|
publishedDocUpdatedAt={data?.createdAt}
|
|
/>
|
|
</li>
|
|
)}
|
|
</Fragment>
|
|
)}
|
|
{collectionConfig?.timestamps && (isEditing || isAccountView) && (
|
|
<Fragment>
|
|
<li
|
|
className={[`${baseClass}__list-item`, `${baseClass}__value-wrap`]
|
|
.filter(Boolean)
|
|
.join(' ')}
|
|
title={data?.updatedAt ? updatedAt : ''}
|
|
>
|
|
<p className={`${baseClass}__label`}>{i18n.t('general:lastModified')}: </p>
|
|
{data?.updatedAt && <p className={`${baseClass}__value`}>{updatedAt}</p>}
|
|
</li>
|
|
<li
|
|
className={[`${baseClass}__list-item`, `${baseClass}__value-wrap`]
|
|
.filter(Boolean)
|
|
.join(' ')}
|
|
title={data?.createdAt ? createdAt : ''}
|
|
>
|
|
<p className={`${baseClass}__label`}>{i18n.t('general:created')}: </p>
|
|
{data?.createdAt && <p className={`${baseClass}__value`}>{createdAt}</p>}
|
|
</li>
|
|
</Fragment>
|
|
)}
|
|
</ul>
|
|
</div>
|
|
<div className={`${baseClass}__controls-wrapper`}>
|
|
<div className={`${baseClass}__controls`}>
|
|
{componentMap?.isPreviewEnabled && (
|
|
<PreviewButton CustomComponent={componentMap.PreviewButton} />
|
|
)}
|
|
{hasSavePermission && (
|
|
<React.Fragment>
|
|
{collectionConfig?.versions?.drafts || globalConfig?.versions?.drafts ? (
|
|
<React.Fragment>
|
|
{((collectionConfig?.versions?.drafts &&
|
|
!collectionConfig?.versions?.drafts?.autosave) ||
|
|
unsavedDraftWithValidations ||
|
|
(globalConfig?.versions?.drafts &&
|
|
!globalConfig?.versions?.drafts?.autosave)) && (
|
|
<SaveDraftButton CustomComponent={componentMap.SaveDraftButton} />
|
|
)}
|
|
<PublishButton CustomComponent={componentMap.PublishButton} />
|
|
</React.Fragment>
|
|
) : (
|
|
<SaveButton CustomComponent={componentMap.SaveButton} />
|
|
)}
|
|
</React.Fragment>
|
|
)}
|
|
</div>
|
|
{showDotMenu && (
|
|
<Popup
|
|
button={
|
|
<div className={`${baseClass}__dots`}>
|
|
<div />
|
|
<div />
|
|
<div />
|
|
</div>
|
|
}
|
|
className={`${baseClass}__popup`}
|
|
horizontalAlign="right"
|
|
size="large"
|
|
verticalAlign="bottom"
|
|
>
|
|
<PopupList.ButtonGroup>
|
|
{hasCreatePermission && (
|
|
<React.Fragment>
|
|
<PopupList.Button
|
|
href={formatAdminURL({
|
|
adminRoute,
|
|
path: `/collections/${collectionConfig?.slug}/create`,
|
|
})}
|
|
id="action-create"
|
|
>
|
|
{i18n.t('general:createNew')}
|
|
</PopupList.Button>
|
|
{!collectionConfig.disableDuplicate && isEditing && (
|
|
<DuplicateDocument
|
|
id={id.toString()}
|
|
singularLabel={collectionConfig?.labels?.singular}
|
|
slug={collectionConfig?.slug}
|
|
/>
|
|
)}
|
|
</React.Fragment>
|
|
)}
|
|
{hasDeletePermission && (
|
|
<DeleteDocument
|
|
buttonId="action-delete"
|
|
collectionSlug={collectionConfig?.slug}
|
|
id={id.toString()}
|
|
singularLabel={collectionConfig?.labels?.singular}
|
|
useAsTitle={collectionConfig?.admin?.useAsTitle}
|
|
/>
|
|
)}
|
|
</PopupList.ButtonGroup>
|
|
</Popup>
|
|
)}
|
|
</div>
|
|
</div>
|
|
<div className={`${baseClass}__divider`} />
|
|
</Gutter>
|
|
)
|
|
}
|