Kentaro Fukunaga 44759b1aac Merged PR 725: タイピストグループ削除 画面実装
## 概要
[Task3536: 画面実装](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/3536)

- タイピストグループ画面に削除ボタン配置
- 削除ボタンクリック時に確認ダイアログ表示→OKで削除API実行&ぐるぐる表示
- API実行結果によってメッセージの出し分け&画面リスト更新
- 翻訳情報追加

## レビューポイント
- エラーコードに認識違いないか?
- 画面実装のお作法にそぐわないところがないか?
- なんか抜けてる実装などあれば

## UIの変更
大した変更ではないので、スクショ置き場に置く手間を省いてここに貼り付けます
![image (2).png](https://dev.azure.com/ODMSCloud/6023ff7b-d41c-4fa7-9c6f-f576ba48c07c/_apis/git/repositories/302da463-a2d7-40f9-b2bb-6e8edf324fa9/pullRequests/725/attachments/image%20%282%29.png)

## 動作確認状況
- 期待される動作を一通りローカルで確認しました。
    - API実行中はぐるぐる表示されること
    - API成功または削除済みの場合は成功メッセージ表示され、画面更新されること
    - API失敗時、理由によってエラーメッセージが表示分けされること
2024-02-05 00:31:47 +00:00

200 lines
7.3 KiB
TypeScript

import React, { useCallback, useEffect, useState } from "react";
import Header from "components/header";
import Footer from "components/footer";
import styles from "styles/app.module.scss";
import { UpdateTokenTimer } from "components/auth/updateTokenTimer";
import progress_activit from "assets/images/progress_activit.svg";
import undo from "assets/images/undo.svg";
import group_add from "assets/images/group_add.svg";
import { useDispatch, useSelector } from "react-redux";
import {
selectTypistGroups,
selectIsLoading,
listTypistGroupsAsync,
deleteTypistGroupAsync,
} from "features/workflow/typistGroup";
import { AppDispatch } from "app/store";
import { useTranslation } from "react-i18next";
import { getTranslationID } from "translation";
import { selectDelegationAccessToken } from "features/auth/selectors";
import { DelegationBar } from "components/delegate";
import { useNavigate } from "react-router-dom";
import { AddTypistGroupPopup } from "./addTypistGroupPopup";
import { EditTypistGroupPopup } from "./editTypistGroupPopup";
const TypistGroupSettingPage: React.FC = (): JSX.Element => {
const dispatch: AppDispatch = useDispatch();
const [t] = useTranslation();
const navigate = useNavigate();
// 代行操作用のトークンを取得する
const delegationAccessToken = useSelector(selectDelegationAccessToken);
const isLoading = useSelector(selectIsLoading);
const typistGroup = useSelector(selectTypistGroups);
const [isAddPopupOpen, setIsAddPopupOpen] = useState(false);
const [isEditPopupOpen, setIsEditPopupOpen] = useState(false);
const [editTypistGroupId, setEditTypistGroupId] = useState<number>(NaN);
const onAddPopupOpen = useCallback(() => {
// typist一覧を取得
setIsAddPopupOpen(true);
}, [setIsAddPopupOpen]);
const onEditPopupOpen = useCallback(
(typistGroupId: number) => {
setEditTypistGroupId(typistGroupId);
setIsEditPopupOpen(true);
},
[setIsEditPopupOpen]
);
const onDeleteTypistGroup = useCallback(
async (typistGroupId: number) => {
if (
/* eslint-disable-next-line no-alert */
!window.confirm(t(getTranslationID("common.message.dialogConfirm")))
) {
return;
}
const { meta } = await dispatch(
deleteTypistGroupAsync({ typistGroupId })
);
if (meta.requestStatus === "fulfilled") {
dispatch(listTypistGroupsAsync());
}
},
[dispatch, t]
);
useEffect(() => {
dispatch(listTypistGroupsAsync());
}, [dispatch]);
return (
<>
<AddTypistGroupPopup
onClose={() => {
setIsAddPopupOpen(false);
}}
isOpen={isAddPopupOpen}
/>
<EditTypistGroupPopup
onClose={() => {
setIsEditPopupOpen(false);
}}
isOpen={isEditPopupOpen}
typistGroupId={editTypistGroupId}
/>
<div
className={`${styles.wrap} ${
delegationAccessToken ? styles.manage : ""
}`}
>
{delegationAccessToken && <DelegationBar />}
<Header />
<UpdateTokenTimer />
<main className={styles.main}>
<div>
<div className={styles.pageHeader}>
<h1 className={styles.pageTitle}>
{t(getTranslationID("workflowPage.label.title"))}
</h1>
<p className={styles.pageTx}>{` ${t(
getTranslationID("typistGroupSetting.label.title")
)}`}</p>
</div>
<section className={styles.workflow}>
<div>
<ul className={styles.menuAction}>
<li>
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}
<a
onClick={() => navigate("/workflow")}
className={`${styles.menuLink} ${styles.isActive}`}
>
<img src={undo} alt="" className={styles.menuIcon} />
{t(getTranslationID("common.label.return"))}
</a>
</li>
<li>
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
<a
className={`${styles.menuLink} ${styles.isActive}`}
onClick={onAddPopupOpen}
>
<img src={group_add} alt="" className={styles.menuIcon} />
{t(getTranslationID("typistGroupSetting.label.addGroup"))}
</a>
</li>
</ul>
<table className={`${styles.table} ${styles.group}`}>
<tr className={styles.tableHeader}>
<th className={styles.noLine}>
{t(
getTranslationID("typistGroupSetting.label.groupName")
)}
</th>
<th>{/** empty th */}</th>
</tr>
{!isLoading && typistGroup.length === 0 ? (
<p style={{ margin: "10px", textAlign: "center" }}>
{t(getTranslationID("common.message.listEmpty"))}
</p>
) : (
typistGroup.map((group) => (
<tr key={group.id}>
<td>{group.name}</td>
<td>
<ul
className={`${styles.menuAction} ${styles.inTable}`}
>
<li>
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
<a
className={`${styles.menuLink} ${styles.isActive}`}
onClick={() => {
onEditPopupOpen(group.id);
}}
>
{t(getTranslationID("common.label.edit"))}
</a>
</li>
<li>
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
<a
className={`${styles.menuLink} ${styles.isActive}`}
onClick={() => {
onDeleteTypistGroup(group.id);
}}
>
{t(getTranslationID("common.label.delete"))}
</a>
</li>
</ul>
</td>
</tr>
))
)}
</table>
{isLoading && (
<img
src={progress_activit}
className={styles.icLoading}
alt="Loading"
/>
)}
</div>
</section>
</div>
</main>
<Footer />
</div>
</>
);
};
export default TypistGroupSettingPage;