React-admin向けにリッチなUIを実現できる削除確認画面を作ってみた

# 背景

Reactのフロントエンドフレームワークである[React-admin](https://marmelab.com/react-admin/)を使って、アプリケーションを開発中。

削除ボタンをクリックしたときに`本当に削除してもよろしいですか？`と確認画面を出すことは多い。
React-adminの標準コンポーネント`<DeleteButton>`を使用すると、下の図のように

* タイトル文字列
* 本文（確認メッセージ文字列）
* [実行]ボタン
* [キャンセル]ボタン

を表示することができる。
また、`<DeleteButton>`を使用して削除確認画面を表示するには`undoable={false}`のオプションを付与が必要という制限もある。

本来はこの削除確認画面に、削除対象の詳細情報などを表示した上で、実行確認するのがより親切。
ということで、**本文の部分に文字列ではなく、任意のReactのコンポーネント（エレメント）を表示できる`削除確認画面`を実装してみた**。

![10xpyypk5l.csb.app_(Laptop with MDPI screen).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562193/03c690f8-130e-2e53-c553-98cb75489df0.png)

なお、今回は[前回の投稿](https://qiita.com/itTkm/items/74a7edd666ddaf748b35)で紹介した[ra-custom-confirm](https://www.npmjs.com/package/ra-custom-confirm)を活用している。
`ra-custom-confirm`は、削除を問わず任意のアクションに対する実行確認画面に、任意のReactコンポーネント（エレメント）を表示できる。

# つくったもの

名前が長いですがご容赦を、、

* ra-delete-with-custom-confirm-button
    * npm: https://www.npmjs.com/package/ra-delete-with-custom-confirm-button
    * GitHub: https://github.com/itTkm/ra-delete-with-custom-confirm-button

![ra-delete-with-custom-confirm-button.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562193/d85d2c6e-64c8-12f2-afac-bd830c445907.gif)

表示できるのは、

* 任意のタイトル文字列
* 任意のReactコンポーネント（エレメント）
* [実行]ボタン
* [キャンセル]ボタン

[実行]ボタンや[キャンセル]ボタンの、アイコンやラベルも自由に設定可能にしてある。
また、`undoable={false}`のオプションがない場合でも、削除確認画面を表示できる。

# 使い方

## インストール

```bash
# npmの場合
npm install --save ra-delete-with-custom-confirm-button

# yarnの場合
yarn add ra-delete-with-custom-confirm-button
```

## デモ

下記のコマンドを実行することで、デモを確認できる。
コマンド実行後、ブラウザで [http://localhost:8080/](http://localhost:8080/) にアクセス。
ログインを求められた場合は *login/password* を使う。

```bash
git clone https://github.com/itTkm/ra-delete-with-custom-confirm-button.git
cd ra-delete-with-custom-confirm-button/example/
yarn install
yarn start
```

## 実装例

```js
import DeleteWithCustomConfirmButton from 'ra-delete-with-custom-confirm-button';
import Delete from '@material-ui/icons/Delete';
import ErrorOutline from '@material-ui/icons/ErrorOutline';

// Define your custom title of confirm dialog
const DeleteConfirmTitle = 'Are you sure you want to delete this post?';

// Define your custom contents of confirm dialog
const DeleteConfirmContent = props => {
  return (
    <SimpleShowLayout {...props} >
      <TextField source='title' label='title' />
      <TextField source='user' label='user' />
      <TextField source='date' label='date' />
      <RichTextField source='description' label='description' />
    </SimpleShowLayout>
  );
};

const InformationList = props => {
  const translate = useTranslate();
  return (
    <List {...props} >
      <Datagrid>
        <TextField source='title' label='title' />
        <TextField source='date' label='date' />
        <TextField source='user' label='user' />
        <DeleteWithCustomConfirmButton
          title={DeleteConfirmTitle}      // your custom title of delete confirm dialog
          content={DeleteConfirmContent}  // your custom contents of delete confirm dialog
          label='Delete'                  // label of delete button (default: 'Delete')
          confirmColor='warning'          // color of delete button ('warning' or 'primary', default: 'warning')
          ConfirmIcon={Delete}            // icon of delete button (default: 'Delete')
          cancel='Cancel'                 // label of cancel button (default: 'Cancel')
          CancelIcon={ErrorOutline}       // icon of cancel button (default: 'ErrorOutline')
          undoable={true}                 // undoable (default: true)
        />
      </Datagrid>
    </List>
  );
};

export default InformationList;
```

## props

Name|Type|Description|Default
---|---|---|---
title|string|your custom title of delete confirm dialog|
content|element|your custom contents of delete confirm dialog|
label|string|label of delete button|'ra.action.delete' (`Delete` in English)
confirmColor|string|color of delete button ('warning' or 'primary')|'warning'
DeleteIcon|element|icon of delete button from [@material-ui/icons](https://www.npmjs.com/package/@material-ui/icons)|![Delete](https://github.com/google/material-design-icons/blob/master/action/drawable-hdpi/ic_delete_black_18dp.png?raw=true "import Delete from '@material-ui/icons/Delete';")
cancel|string|label of cancel button|'ra.action.cancel' (`Cancel` in English)
CancelIcon|element|icon of cancel button from [@material-ui/icons](https://www.npmjs.com/package/@material-ui/icons)|![ErrorOutline](https://github.com/google/material-design-icons/blob/master/alert/drawable-hdpi/ic_error_outline_black_18dp.png?raw=true "import ErrorOutline from '@material-ui/icons/ErrorOutline';")
undoable|bool|undoable or not|true
redirect|string|redirect to|'list'