Files
payloadcms/packages/ui/src/elements/DeleteDocument/index.tsx
Jarrod Flesch 56dec13820 fix: format admin url inside forgot pw email (#11509)
### What?
Supersedes https://github.com/payloadcms/payload/pull/11490.

Refactors imports of `formatAdminURL` to import from `payload/shared`
instead of `@payloadcms/ui/shared`. The ui package now imports and
re-exports the function to prevent this from being a breaking change.

### Why?
This makes it easier for other packages/plugins to consume the
`formatAdminURL` function instead of needing to implement their own or
rely on the ui package for the utility.
2025-03-04 11:55:36 -05:00

181 lines
4.8 KiB
TypeScript

'use client'
import type { SanitizedCollectionConfig } from 'payload'
import { useModal } from '@faceless-ui/modal'
import { getTranslation } from '@payloadcms/translations'
import { useRouter } from 'next/navigation.js'
import { formatAdminURL } from 'payload/shared'
import React, { useCallback } from 'react'
import { toast } from 'sonner'
import type { DocumentDrawerContextType } from '../DocumentDrawer/Provider.js'
import { useForm } from '../../forms/Form/context.js'
import { useConfig } from '../../providers/Config/index.js'
import { useDocumentInfo } from '../../providers/DocumentInfo/index.js'
import { useRouteTransition } from '../../providers/RouteTransition/index.js'
import { useTranslation } from '../../providers/Translation/index.js'
import { requests } from '../../utilities/api.js'
import { ConfirmationModal } from '../ConfirmationModal/index.js'
import { PopupList } from '../Popup/index.js'
import { Translation } from '../Translation/index.js'
import './index.scss'
export type Props = {
readonly buttonId?: string
readonly collectionSlug: SanitizedCollectionConfig['slug']
readonly id?: string
readonly onDelete?: DocumentDrawerContextType['onDelete']
readonly redirectAfterDelete?: boolean
readonly singularLabel: SanitizedCollectionConfig['labels']['singular']
readonly title?: string
readonly useAsTitle: SanitizedCollectionConfig['admin']['useAsTitle']
}
export const DeleteDocument: React.FC<Props> = (props) => {
const {
id,
buttonId,
collectionSlug,
onDelete,
redirectAfterDelete = true,
singularLabel,
title: titleFromProps,
} = props
const {
config: {
routes: { admin: adminRoute, api },
serverURL,
},
getEntityConfig,
} = useConfig()
const collectionConfig = getEntityConfig({ collectionSlug })
const { setModified } = useForm()
const router = useRouter()
const { i18n, t } = useTranslation()
const { title } = useDocumentInfo()
const { startRouteTransition } = useRouteTransition()
const { openModal } = useModal()
const titleToRender = titleFromProps || title || id
const modalSlug = `delete-${id}`
const addDefaultError = useCallback(() => {
toast.error(t('error:deletingTitle', { title }))
}, [t, title])
const handleDelete = useCallback(async () => {
setModified(false)
try {
await requests
.delete(`${serverURL}${api}/${collectionSlug}/${id}`, {
headers: {
'Accept-Language': i18n.language,
'Content-Type': 'application/json',
},
})
.then(async (res) => {
try {
const json = await res.json()
if (res.status < 400) {
toast.success(
t('general:titleDeleted', {
label: getTranslation(singularLabel, i18n),
title,
}) || json.message,
)
if (redirectAfterDelete) {
return startRouteTransition(() =>
router.push(
formatAdminURL({
adminRoute,
path: `/collections/${collectionSlug}`,
}),
),
)
}
if (typeof onDelete === 'function') {
await onDelete({ id, collectionConfig })
}
return
}
if (json.errors) {
json.errors.forEach((error) => toast.error(error.message))
} else {
addDefaultError()
}
return false
} catch (_err) {
return addDefaultError()
}
})
} catch (_err) {
return addDefaultError()
}
}, [
setModified,
serverURL,
api,
collectionSlug,
id,
t,
singularLabel,
addDefaultError,
i18n,
title,
router,
adminRoute,
redirectAfterDelete,
onDelete,
collectionConfig,
startRouteTransition,
])
if (id) {
return (
<React.Fragment>
<PopupList.Button
id={buttonId}
onClick={() => {
openModal(modalSlug)
}}
>
{t('general:delete')}
</PopupList.Button>
<ConfirmationModal
body={
<Translation
elements={{
'1': ({ children }) => <strong>{children}</strong>,
}}
i18nKey="general:aboutToDelete"
t={t}
variables={{
label: getTranslation(singularLabel, i18n),
title: titleToRender,
}}
/>
}
confirmingLabel={t('general:deleting')}
heading={t('general:confirmDeletion')}
modalSlug={modalSlug}
onConfirm={handleDelete}
/>
</React.Fragment>
)
}
return null
}