Files
payload/packages/ui/src/elements/GenerateConfirmation/index.tsx
Jacob Fletcher bd8ced1b60 feat(ui): confirmation modal (#11271)
There are nearly a dozen independent implementations of the same modal
spread throughout the admin panel and various plugins. These modals are
used to confirm or cancel an action, such as deleting a document, bulk
publishing, etc. Each of these instances is nearly identical, leading to
unnecessary development efforts when creating them, inconsistent UI, and
duplicative stylesheets.

Everything is now standardized behind a new `ConfirmationModal`
component. This modal comes with a standard API that is flexible enough
to replace nearly every instance. This component has also been exported
for reuse.

Here is a basic example of how to use it:

```tsx
'use client'
import { ConfirmationModal, useModal } from '@payloadcms/ui'
import React, { Fragment } from 'react'

const modalSlug = 'my-confirmation-modal'

export function MyComponent() {
  const { openModal } = useModal()

  return (
    <Fragment>
      <button
        onClick={() => {
          openModal(modalSlug)
        }}
        type="button"
      >
        Do something
      </button>
      <ConfirmationModal
        heading="Are you sure?"
        body="Confirm or cancel before proceeding."
        modalSlug={modalSlug}
        onConfirm={({ closeConfirmationModal, setConfirming }) => {
          // do something
          setConfirming(false)
          closeConfirmationModal()
        }}
      />
    </Fragment>
  )
}
```
2025-02-19 02:27:03 -05:00

68 lines
1.9 KiB
TypeScript

'use client'
import { useModal } from '@faceless-ui/modal'
import React, { useCallback } from 'react'
import { toast } from 'sonner'
import type { OnConfirm } from '../ConfirmationModal/index.js'
import { useDocumentInfo } from '../../providers/DocumentInfo/index.js'
import { useTranslation } from '../../providers/Translation/index.js'
import { Button } from '../Button/index.js'
import { ConfirmationModal } from '../ConfirmationModal/index.js'
import { Translation } from '../Translation/index.js'
export type GenerateConfirmationProps = {
highlightField: (Boolean) => void
setKey: () => void
}
export function GenerateConfirmation(props: GenerateConfirmationProps) {
const { highlightField, setKey } = props
const { id } = useDocumentInfo()
const { toggleModal } = useModal()
const { t } = useTranslation()
const modalSlug = `generate-confirmation-${id}`
const handleGenerate: OnConfirm = useCallback(
({ closeConfirmationModal, setConfirming }) => {
setKey()
toast.success(t('authentication:newAPIKeyGenerated'))
highlightField(true)
setConfirming(false)
closeConfirmationModal()
},
[highlightField, setKey, t],
)
return (
<React.Fragment>
<Button
buttonStyle="secondary"
onClick={() => {
toggleModal(modalSlug)
}}
size="small"
>
{t('authentication:generateNewAPIKey')}
</Button>
<ConfirmationModal
body={
<Translation
elements={{
1: ({ children }) => <strong>{children}</strong>,
}}
i18nKey="authentication:generatingNewAPIKeyWillInvalidate"
t={t}
/>
}
confirmLabel={t('authentication:generate')}
heading={t('authentication:confirmGeneration')}
modalSlug={modalSlug}
onConfirm={handleGenerate}
/>
</React.Fragment>
)
}