## 概要 [Task2777: ワークフロー更新ポップアップ実装](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2777) - ワークフロー編集ポップアップを実装しました。 ## レビューポイント - 表示内容は適切か - 選択ワークフローの値取得処理は適切か ## UIの変更 - [Task2777](https://ndstokyo.sharepoint.com/:f:/r/sites/Piranha/Shared%20Documents/General/OMDS/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88/Task2777?csf=1&web=1&e=RfM1Dv) ## 動作確認状況 - ローカルで確認
314 lines
11 KiB
TypeScript
314 lines
11 KiB
TypeScript
import React, { useCallback, useEffect, useState } from "react";
|
|
import { AppDispatch } from "app/store";
|
|
import progress_activit from "assets/images/progress_activit.svg";
|
|
import {
|
|
addAssignee,
|
|
removeAssignee,
|
|
changeAuthor,
|
|
changeTemplate,
|
|
changeWorktype,
|
|
clearWorkflow,
|
|
selectIsAddLoading,
|
|
selectWorkflowAssinee,
|
|
selectWorkflowError,
|
|
selectWorkflowRelations,
|
|
selectSelectedWorkflow,
|
|
selectAuthorId,
|
|
selectWorktypeId,
|
|
setAssignees,
|
|
selectTemplateId,
|
|
} from "features/workflow";
|
|
import {
|
|
getworkflowRelationsAsync,
|
|
listWorkflowAsync,
|
|
updateWorkflowAsync,
|
|
} from "features/workflow/operations";
|
|
import { useTranslation } from "react-i18next";
|
|
import { useDispatch, useSelector } from "react-redux";
|
|
import styles from "styles/app.module.scss";
|
|
import { getTranslationID } from "translation";
|
|
import close from "../../assets/images/close.svg";
|
|
|
|
interface EditWorkflowPopupProps {
|
|
onClose: () => void;
|
|
}
|
|
|
|
export const EditWorkflowPopup: React.FC<EditWorkflowPopupProps> = (
|
|
props
|
|
): JSX.Element => {
|
|
const { onClose } = props;
|
|
const dispatch: AppDispatch = useDispatch();
|
|
const [t] = useTranslation();
|
|
// 保存ボタンを押したかどうか
|
|
const [isPushEditButton, setIsPushEditButton] = useState<boolean>(false);
|
|
|
|
const workflow = useSelector(selectSelectedWorkflow);
|
|
const authorId = useSelector(selectAuthorId);
|
|
const worktypeId = useSelector(selectWorktypeId);
|
|
const templateId = useSelector(selectTemplateId);
|
|
|
|
const workflowRelations = useSelector(selectWorkflowRelations);
|
|
const { poolAssignees, selectedAssignees } = useSelector(
|
|
selectWorkflowAssinee
|
|
);
|
|
const isLoading = useSelector(selectIsAddLoading);
|
|
const { hasAuthorIdEmptyError, hasSelectedWorkflowAssineeEmptyError } =
|
|
useSelector(selectWorkflowError);
|
|
useEffect(() => {
|
|
dispatch(getworkflowRelationsAsync());
|
|
// ポップアップのアンマウント時に初期化を行う
|
|
return () => {
|
|
dispatch(clearWorkflow());
|
|
setIsPushEditButton(false);
|
|
};
|
|
}, [dispatch]);
|
|
|
|
useEffect(() => {
|
|
dispatch(changeAuthor({ authorId: workflow?.author?.id }));
|
|
dispatch(changeWorktype({ worktypeId: workflow?.worktype?.id }));
|
|
dispatch(changeTemplate({ templateId: workflow?.template?.id }));
|
|
dispatch(setAssignees({ assignees: workflow?.typists ?? [] }));
|
|
}, [dispatch, workflow]);
|
|
|
|
const changeWorktypeId = useCallback(
|
|
(target: string) => {
|
|
// 空文字の場合はundefinedをdispatchする
|
|
if (target === "") {
|
|
dispatch(changeWorktype({ worktypeId: undefined }));
|
|
} else if (!Number.isNaN(Number(target))) {
|
|
dispatch(changeWorktype({ worktypeId: Number(target) }));
|
|
}
|
|
},
|
|
[dispatch]
|
|
);
|
|
|
|
const changeTemplateId = useCallback(
|
|
(target: string) => {
|
|
// 空文字の場合はundefinedをdispatchする
|
|
if (target === "") {
|
|
dispatch(changeTemplate({ templateId: undefined }));
|
|
} else if (!Number.isNaN(Number(target))) {
|
|
dispatch(changeTemplate({ templateId: Number(target) }));
|
|
}
|
|
},
|
|
[dispatch]
|
|
);
|
|
|
|
const changeAuthorId = useCallback(
|
|
(target: string) => {
|
|
if (!Number.isNaN(target)) {
|
|
dispatch(changeAuthor({ authorId: Number(target) }));
|
|
}
|
|
},
|
|
[dispatch]
|
|
);
|
|
|
|
// 保存ボタン押下時の処理
|
|
const handleSave = useCallback(async () => {
|
|
setIsPushEditButton(true);
|
|
// エラーチェック
|
|
if (hasAuthorIdEmptyError || hasSelectedWorkflowAssineeEmptyError) {
|
|
return;
|
|
}
|
|
const { meta } = await dispatch(updateWorkflowAsync());
|
|
if (meta.requestStatus === "fulfilled") {
|
|
onClose();
|
|
dispatch(listWorkflowAsync());
|
|
}
|
|
}, [
|
|
dispatch,
|
|
hasAuthorIdEmptyError,
|
|
hasSelectedWorkflowAssineeEmptyError,
|
|
onClose,
|
|
]);
|
|
|
|
return (
|
|
<div className={`${styles.modal} ${styles.isShow}`}>
|
|
<div className={styles.modalBox}>
|
|
<p className={styles.modalTitle}>
|
|
{t(getTranslationID("workflowPage.label.editRoutingRule"))}
|
|
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-noninteractive-element-interactions */}
|
|
<img
|
|
src={close}
|
|
className={styles.modalTitleIcon}
|
|
alt="close"
|
|
onClick={onClose}
|
|
/>
|
|
</p>
|
|
<form className={styles.form}>
|
|
<dl className={`${styles.formList} ${styles.hasbg}`}>
|
|
<dt className={styles.formTitle} />
|
|
<dt>{t(getTranslationID("workflowPage.label.authorID"))}</dt>
|
|
<dd>
|
|
<select
|
|
className={styles.formInput}
|
|
value={authorId}
|
|
onChange={(e) => {
|
|
changeAuthorId(e.target.value);
|
|
}}
|
|
>
|
|
<option value="" hidden>
|
|
{`-- ${t(
|
|
getTranslationID("workflowPage.label.selectAuthor")
|
|
)} --`}
|
|
</option>
|
|
{workflowRelations?.authors.map((author) => (
|
|
<option key={author.authorId} value={author.id}>
|
|
{author.authorId}
|
|
</option>
|
|
))}
|
|
</select>
|
|
{isPushEditButton && hasAuthorIdEmptyError && (
|
|
<span className={styles.formError}>
|
|
{t(getTranslationID("workflowPage.message.inputEmptyError"))}
|
|
</span>
|
|
)}
|
|
</dd>
|
|
<dt className={styles.overLine}>
|
|
{t(getTranslationID("workflowPage.label.worktypeOptional"))}
|
|
</dt>
|
|
<dd>
|
|
<select
|
|
className={styles.formInput}
|
|
value={worktypeId}
|
|
onChange={(e) => {
|
|
changeWorktypeId(e.target.value);
|
|
}}
|
|
>
|
|
<option value="" hidden>
|
|
{`-- ${t(
|
|
getTranslationID("workflowPage.label.selectWorktypeId")
|
|
)} --`}
|
|
</option>
|
|
<option value="">
|
|
{`-- ${t(getTranslationID("common.label.notSelected"))} --`}
|
|
</option>
|
|
{workflowRelations?.worktypes.map((worktype) => (
|
|
<option key={worktype.id} value={worktype.id}>
|
|
{worktype.worktypeId}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</dd>
|
|
<dt className={styles.formTitle}>
|
|
{t(getTranslationID("typistGroupSetting.label.transcriptionist"))}
|
|
</dt>
|
|
<dd className={`${styles.formChange} ${styles.last}`}>
|
|
<ul className={styles.chooseMember}>
|
|
<li className={styles.changeTitle}>
|
|
{t(getTranslationID("workflowPage.label.selected"))}
|
|
</li>
|
|
{selectedAssignees?.map((x) => {
|
|
const key = `${x.typistName}_${
|
|
x.typistUserId ?? x.typistGroupId
|
|
}`;
|
|
return (
|
|
<li key={key}>
|
|
<input
|
|
type="checkbox"
|
|
className={styles.formCheck}
|
|
value={x.typistName}
|
|
id={key}
|
|
checked
|
|
onClick={() => {
|
|
dispatch(removeAssignee({ assignee: x }));
|
|
}}
|
|
/>
|
|
<label htmlFor={key} title="Remove">
|
|
{x.typistName}
|
|
</label>
|
|
</li>
|
|
);
|
|
})}
|
|
</ul>
|
|
<p />
|
|
<ul className={styles.holdMember}>
|
|
<li className={styles.changeTitle}>
|
|
{t(getTranslationID("workflowPage.label.pool"))}
|
|
</li>
|
|
{poolAssignees?.map((x) => {
|
|
const key = `${x.typistName}_${
|
|
x.typistUserId ?? x.typistGroupId
|
|
}`;
|
|
return (
|
|
<li key={key}>
|
|
<input
|
|
type="checkbox"
|
|
className={styles.formCheck}
|
|
value={x.typistName}
|
|
id={key}
|
|
onClick={() => dispatch(addAssignee({ assignee: x }))}
|
|
/>
|
|
<label htmlFor={key} title="Add">
|
|
{x.typistName}
|
|
</label>
|
|
</li>
|
|
);
|
|
})}
|
|
</ul>
|
|
{isPushEditButton && hasSelectedWorkflowAssineeEmptyError && (
|
|
<span
|
|
className={styles.formError}
|
|
style={{ margin: "0px 30px 0px 30px" }}
|
|
>
|
|
{t(
|
|
getTranslationID(
|
|
"workflowPage.message.selectedTypistEmptyError"
|
|
)
|
|
)}
|
|
</span>
|
|
)}
|
|
</dd>
|
|
<dt className={styles.overLine}>
|
|
{t(getTranslationID("workflowPage.label.templateOptional"))}
|
|
</dt>
|
|
<dd className={styles.last}>
|
|
<select
|
|
className={styles.formInput}
|
|
value={templateId}
|
|
onChange={(e) => {
|
|
changeTemplateId(e.target.value);
|
|
}}
|
|
>
|
|
<option value="" hidden>
|
|
{`-- ${t(
|
|
getTranslationID("workflowPage.label.selectTemplate")
|
|
)} --`}
|
|
</option>
|
|
<option value="">
|
|
{`-- ${t(getTranslationID("common.label.notSelected"))} --`}
|
|
</option>
|
|
{workflowRelations?.templates.map((template) => (
|
|
<option
|
|
key={`${template.name}_${template.id}`}
|
|
value={template.id}
|
|
>
|
|
{template.name}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</dd>
|
|
<dd className={`${styles.full} ${styles.alignCenter}`}>
|
|
<input
|
|
type="button"
|
|
value={t(getTranslationID("common.label.save"))}
|
|
className={`${styles.formSubmit} ${styles.marginBtm1} ${
|
|
!isLoading ? styles.isActive : ""
|
|
}`}
|
|
onClick={handleSave}
|
|
/>
|
|
{isLoading && (
|
|
<img
|
|
src={progress_activit}
|
|
className={styles.icLoading}
|
|
alt="Loading"
|
|
/>
|
|
)}
|
|
</dd>
|
|
</dl>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|