2025-01-21 05:23:54 +00:00

380 lines
13 KiB
TypeScript

import { AppDispatch } from "app/store";
import React, { useCallback, useEffect, useState } from "react";
import styles from "styles/app.module.scss";
import { useDispatch, useSelector } from "react-redux";
import { useTranslation } from "react-i18next";
import { USER_ROLES } from "components/auth/constants";
import {
changeUpdateAuthorId,
changeUpdateAutoRenew,
changeUpdateEncryption,
changeUpdateEncryptionPassword,
changeUpdateNotification,
changeUpdatePrompt,
changeUpdateRole,
changeHasPasswordMask,
cleanupUpdateUser,
selectHasPasswordMask,
selectIsLoading,
selectUpdateUser,
selectUpdateValidationErrors,
updateUserAsync,
listUsersAsync,
} from "features/user";
import { getTranslationID } from "translation";
import close from "../../assets/images/close.svg";
import progress_activit from "../../assets/images/progress_activit.svg";
interface UserUpdatePopupProps {
isOpen: boolean;
onClose: () => void;
clearUserSearchInputs: () => void;
}
export const UserUpdatePopup: React.FC<UserUpdatePopupProps> = (props) => {
const { isOpen, onClose, clearUserSearchInputs } = props;
const dispatch: AppDispatch = useDispatch();
const { t } = useTranslation();
const closePopup = useCallback(() => {
setIsPushCreateButton(false);
dispatch(cleanupUpdateUser());
onClose();
}, [onClose, dispatch]);
const {
hasErrorEmptyAuthorId,
hasErrorIncorrectAuthorId,
hasErrorIncorrectEncryptionPassword,
} = useSelector(selectUpdateValidationErrors);
const [isPasswordHide, setIsPasswordHide] = useState<boolean>(true);
const [isPushCreateButton, setIsPushCreateButton] = useState<boolean>(false);
const user = useSelector(selectUpdateUser);
const isLoading = useSelector(selectIsLoading);
const hasPasswordMask = useSelector(selectHasPasswordMask);
const [canChangeRole, setCanChangeRole] = useState(true);
// 開閉時のみ実行
useEffect(() => {
setCanChangeRole(user.role === USER_ROLES.NONE);
setIsPasswordHide(true);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isOpen]);
const onUpdateUser = useCallback(async () => {
setIsPushCreateButton(true);
if (
hasErrorEmptyAuthorId ||
hasErrorIncorrectAuthorId ||
hasErrorIncorrectEncryptionPassword
) {
return;
}
const { meta } = await dispatch(updateUserAsync());
setIsPushCreateButton(false);
if (meta.requestStatus === "fulfilled") {
closePopup();
clearUserSearchInputs();
dispatch(listUsersAsync());
}
}, [
dispatch,
closePopup,
hasErrorEmptyAuthorId,
hasErrorIncorrectAuthorId,
hasErrorIncorrectEncryptionPassword,
]);
return (
<div className={`${styles.modal} ${isOpen ? styles.isShow : ""}`}>
<div className={styles.modalBox}>
<p className={styles.modalTitle}>
{t(getTranslationID("userListPage.label.editUser"))}
<button type="button" onClick={closePopup}>
<img src={close} className={styles.modalTitleIcon} alt="close" />
</button>
</p>
<form className={styles.form}>
<dl className={`${styles.formList} ${styles.hasbg}`}>
<dt className={styles.formTitle}>
{t(getTranslationID("userListPage.label.personal"))}
</dt>
<dt>{t(getTranslationID("userListPage.label.name"))}</dt>
<dd>
<input
type="text"
size={40}
value={user.name}
className={styles.formInput}
readOnly
/>
</dd>
<dt>{t(getTranslationID("userListPage.label.email"))}</dt>
<dd>
<input
type="email"
size={40}
value={user.email}
className={styles.formInput}
readOnly
/>
</dd>
<dt>{t(getTranslationID("userListPage.label.role"))}</dt>
<dd>
<label htmlFor={`edit_${USER_ROLES.AUTHOR}`}>
<input
id={`edit_${USER_ROLES.AUTHOR}`}
type="radio"
name="role"
className={styles.formRadio}
checked={user.role === USER_ROLES.AUTHOR}
onChange={() => {
dispatch(changeUpdateRole({ role: USER_ROLES.AUTHOR }));
}}
disabled={!canChangeRole}
/>
{t(getTranslationID("userListPage.label.author"))}
</label>
<label htmlFor={`edit_${USER_ROLES.TYPIST}`}>
<input
id={`edit_${USER_ROLES.TYPIST}`}
type="radio"
name="role"
className={styles.formRadio}
checked={user.role === USER_ROLES.TYPIST}
onChange={() => {
dispatch(changeUpdateRole({ role: USER_ROLES.TYPIST }));
}}
disabled={!canChangeRole}
/>
{t(getTranslationID("userListPage.label.transcriptionist"))}
</label>
<label htmlFor={`edit_${USER_ROLES.NONE}`}>
<input
id={`edit_${USER_ROLES.NONE}`}
type="radio"
name="role"
className={styles.formRadio}
checked={user.role === USER_ROLES.NONE}
onChange={() => {
dispatch(changeUpdateRole({ role: USER_ROLES.NONE }));
}}
disabled={!canChangeRole}
/>
{t(getTranslationID("userListPage.label.none"))}
</label>
</dd>
{/** Author 選択時に表示 */}
{user.role === USER_ROLES.AUTHOR && (
<div className={styles.slideSet}>
<dt>{t(getTranslationID("userListPage.label.authorID"))}</dt>
<dd>
<input
type="text"
size={40}
maxLength={16}
autoComplete="off"
value={user.authorId}
className={styles.formInput}
onChange={(e) => {
dispatch(
changeUpdateAuthorId({
authorId: e.target.value.toUpperCase(),
})
);
}}
/>
{isPushCreateButton && hasErrorEmptyAuthorId && (
<span className={styles.formError}>
{t(
getTranslationID("signupPage.message.inputEmptyError")
)}
</span>
)}
{isPushCreateButton && hasErrorIncorrectAuthorId && (
<span className={styles.formError}>
{t(
getTranslationID(
"userListPage.message.authorIdIncorrectError"
)
)}
</span>
)}
</dd>
<dt>{t(getTranslationID("userListPage.label.encryption"))}</dt>
<dd>
<label htmlFor="Encryption">
<input
type="checkbox"
className={styles.formCheck}
checked={user.encryption}
onChange={(e) => {
dispatch(
changeUpdateEncryption({
encryption: e.target.checked,
})
);
}}
/>
</label>
{/** Encryptionチェックでパスワード欄表示 */}
<p
className={`${styles.encryptionPass} ${
user.encryption ? styles.isShow : ""
}`}
>
{t(
getTranslationID("userListPage.label.encryptionPassword")
)}
<input
type={isPasswordHide ? "password" : "text"}
size={40}
maxLength={16}
autoComplete="new-password"
value={
hasPasswordMask
? "********"
: user.encryptionPassword ?? ""
}
className={`${styles.formInput} ${styles.password}`}
onFocus={() => {
if (hasPasswordMask) {
dispatch(
changeHasPasswordMask({ hasPasswordMask: false })
);
dispatch(
changeUpdateEncryptionPassword({
encryptionPassword: "",
})
);
}
}}
onChange={(e) => {
if (!hasPasswordMask) {
dispatch(
changeUpdateEncryptionPassword({
encryptionPassword: e.target.value,
})
);
}
}}
/>
<span
className={styles.formIconEye}
onClick={() => {
setIsPasswordHide(!isPasswordHide);
}}
onKeyDown={() => {
setIsPasswordHide(!isPasswordHide);
}}
role="button"
tabIndex={0}
aria-label="IconEye"
/>
{isPushCreateButton &&
hasErrorIncorrectEncryptionPassword && (
<span className={styles.formError}>
{t(
getTranslationID(
"userListPage.message.encryptionPasswordCorrectError"
)
)}
</span>
)}
<span className={styles.formComment}>
{t(
getTranslationID(
"userListPage.label.encryptionPasswordTerm"
)
)}
</span>
</p>
</dd>
<dt>{t(getTranslationID("userListPage.label.prompt"))}</dt>
<dd>
<label htmlFor="Prompt">
<input
type="checkbox"
className={styles.formCheck}
checked={user.prompt}
onChange={(e) => {
dispatch(
changeUpdatePrompt({
prompt: e.target.checked,
})
);
}}
/>
</label>
</dd>
</div>
)}
<dt>{t(getTranslationID("userListPage.label.setting"))}</dt>
<dd className="last">
<p>
<label htmlFor="edit_AutoRenew">
<input
type="checkbox"
id="edit_AutoRenew"
className={styles.formCheck}
checked={user.autoRenew}
onChange={(e) => {
dispatch(
changeUpdateAutoRenew({
autoRenew: e.target.checked,
})
);
}}
/>
{t(getTranslationID("userListPage.label.autoRenew"))}
</label>
</p>
<p>
<label htmlFor="edit_Notification">
<input
type="checkbox"
id="edit_Notification"
className={styles.formCheck}
checked={user.notification}
onChange={(e) => {
dispatch(
changeUpdateNotification({
notification: e.target.checked,
})
);
}}
/>
{t(getTranslationID("userListPage.label.notification"))}
</label>
</p>
</dd>
<dd className={`${styles.full} ${styles.alignCenter}`}>
<input
type="button"
name="submit"
value={t(getTranslationID("userListPage.label.editUser"))}
className={`${styles.formSubmit} ${styles.marginBtm1} ${styles.isActive}`}
onClick={onUpdateUser}
/>
<img
style={{ display: isLoading ? "inline" : "none" }}
src={progress_activit}
className={styles.icLoading}
alt="Loading"
/>
</dd>
</dl>
</form>
</div>
</div>
);
};