import { AppDispatch } from "app/store"; 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 { useDispatch, useSelector } from "react-redux"; import { listUsersAsync, selectUserViews, selectIsLoading, deallocateLicenseAsync, deleteUserAsync, confirmUserForceAsync, } from "features/user"; import { useTranslation } from "react-i18next"; import { getTranslationID } from "translation"; import { UserView } from "features/user/types"; import { LICENSE_STATUS } from "features/user/constants"; import { isApproveTier } from "features/auth"; import { TIERS, USER_ROLES } from "components/auth/constants"; import { changeUpdateUser, changeLicenseAllocateUser, } from "features/user/userSlice"; import { DelegationBar } from "components/delegate"; import { selectDelegationAccessToken } from "features/auth/selectors"; import personAdd from "../../assets/images/person_add.svg"; import checkFill from "../../assets/images/check_fill.svg"; import checkOutline from "../../assets/images/check_outline.svg"; import progress_activit from "../../assets/images/progress_activit.svg"; import upload from "../../assets/images/upload.svg"; import searchIcon from "../../assets/images/search.svg"; import { UserAddPopup } from "./popup"; import { UserUpdatePopup } from "./updatePopup"; import { AllocateLicensePopup } from "./allocateLicensePopup"; import { ImportPopup } from "./importPopup"; const UserListPage: React.FC = (): JSX.Element => { const dispatch: AppDispatch = useDispatch(); const [t] = useTranslation(); // 代行操作用のトークンを取得する const delegationAccessToken = useSelector(selectDelegationAccessToken); const [isPopupOpen, setIsPopupOpen] = useState(false); const [isUpdatePopupOpen, setIsUpdatePopupOpen] = useState(false); const [isAllocateLicensePopupOpen, setIsAllocateLicensePopupOpen] = useState(false); const [isImportPopupOpen, setIsImportPopupOpen] = useState(false); const [searchEmail, setSearchEmail] = useState(""); const [searchUserName, setSearchUserName] = useState(""); const onOpen = useCallback(() => { setIsPopupOpen(true); }, [setIsPopupOpen]); const onUpdateOpen = useCallback( (id: number) => { setIsUpdatePopupOpen(true); dispatch(changeUpdateUser({ id })); }, [setIsUpdatePopupOpen, dispatch] ); const onAllocateLicensePopupOpen = useCallback( (selectedUser: UserView) => { setIsAllocateLicensePopupOpen(true); dispatch(changeLicenseAllocateUser({ selectedUser })); }, [setIsAllocateLicensePopupOpen, dispatch] ); const onImportPopupOpen = useCallback(() => { setIsImportPopupOpen(true); }, [setIsImportPopupOpen]); const onLicenseDeallocation = useCallback( async (userId: number) => { // ダイアログ確認 if ( /* eslint-disable-next-line no-alert */ !window.confirm(t(getTranslationID("common.message.dialogConfirm"))) ) { return; } const { meta } = await dispatch(deallocateLicenseAsync({ userId })); if (meta.requestStatus === "fulfilled") { clearUserSearchInputs(); dispatch(listUsersAsync()); } }, [dispatch, t] ); const onDeleteUser = useCallback( async (userId: number) => { // ダイアログ確認 if ( /* eslint-disable-next-line no-alert */ !window.confirm(t(getTranslationID("common.message.dialogConfirm"))) ) { return; } const { meta } = await dispatch(deleteUserAsync({ userId })); if (meta.requestStatus === "fulfilled") { clearUserSearchInputs(); dispatch(listUsersAsync()); } }, [dispatch, t] ); const onForceEmailVerification = useCallback( async (userId: number) => { // ダイアログ確認 if ( /* eslint-disable-next-line no-alert */ !window.confirm( t( getTranslationID( "userListPage.message.forceEmailVerificationConfirm" ) ) ) ) { return; } const { meta } = await dispatch(confirmUserForceAsync({ userId })); if (meta.requestStatus === "fulfilled") { clearUserSearchInputs(); dispatch(listUsersAsync()); } }, [dispatch, t] ); const requestSearch = (e: React.FormEvent) => { e.preventDefault(); dispatch( listUsersAsync({ userInputUserName: searchUserName, userInputEmail: searchEmail, }) ); }; const clearUserSearchInputs = useCallback(() => { setSearchEmail(""); setSearchUserName(""); }, [setSearchEmail, setSearchUserName]); useEffect(() => { // ユーザ一覧取得処理を呼び出す dispatch(listUsersAsync()); }, [dispatch]); const users = useSelector(selectUserViews); const isLoading = useSelector(selectIsLoading); // ユーザーが第5階層であるかどうかを判定する(代行操作中は第5階層として扱う) const isTier5 = isApproveTier([TIERS.TIER5]) || delegationAccessToken !== null; const getUserRole = (userRole: string): string => { switch (userRole) { case USER_ROLES.AUTHOR: return t(getTranslationID("userListPage.label.author")); case USER_ROLES.TYPIST: return t(getTranslationID("userListPage.label.transcriptionist")); default: return t(getTranslationID("userListPage.label.none")); } }; // ライセンスステータスに応じて、ライセンスステータスの文字列を返す const getLicenseStatus = (licenseStatus: string): string => { switch (licenseStatus) { case LICENSE_STATUS.NOLICENSE: return t(getTranslationID("userListPage.label.notAllocated")); case LICENSE_STATUS.ALERT: return t(getTranslationID("userListPage.label.alert")); case LICENSE_STATUS.RENEW: return t(getTranslationID("userListPage.label.renew")); case LICENSE_STATUS.NORMAL: return t(getTranslationID("userListPage.label.allocated")); default: return licenseStatus; } }; return ( <> { setIsUpdatePopupOpen(false); }} clearUserSearchInputs={clearUserSearchInputs} /> { setIsPopupOpen(false); }} clearUserSearchInputs={clearUserSearchInputs} /> { setIsAllocateLicensePopupOpen(false); }} clearUserSearchInputs={clearUserSearchInputs} /> { setIsImportPopupOpen(false); }} />
{delegationAccessToken && }

{t(getTranslationID("userListPage.label.title"))}

  • {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */} {t(getTranslationID("userListPage.label.addUser"))}
  • {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */} {t(getTranslationID("userListPage.label.bulkImport"))}
  • requestSearch(e)} > setSearchUserName(e.target.value.trimStart()) } className={styles.searchInput} /> setSearchEmail(e.target.value.trimStart()) } className={styles.searchInput} /> {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}
{!isLoading && users.map((user) => ( ))}
{/** th is empty */} {t(getTranslationID("userListPage.label.name"))} {t(getTranslationID("userListPage.label.role"))} {t(getTranslationID("userListPage.label.authorID"))} {t(getTranslationID("userListPage.label.encryption"))} {t(getTranslationID("userListPage.label.prompt"))} {t( getTranslationID("userListPage.label.typistGroup") )} {t(getTranslationID("userListPage.label.email"))} {t(getTranslationID("userListPage.label.status"))} {t(getTranslationID("userListPage.label.expiration"))} {t(getTranslationID("userListPage.label.remaining"))} {t(getTranslationID("userListPage.label.autoRenew"))} {t( getTranslationID("userListPage.label.notification") )} {t( getTranslationID("userListPage.label.emailVerified") )}
{user.name} {getUserRole(user.role)} {user.authorId} {boolToElement(user.encryption)} {boolToElement(user.prompt)} {arrayToElement(user.typistGroupName)} {user.email} {getLicenseStatus(user.licenseStatus)} {user.expiration ?? "-"} {user.remaining ?? "-"} {boolToElement(user.autoRenew)} {boolToElement(user.notification)} {boolToElement(user.emailVerified)}
{!isLoading && users.length === 0 && (

{t(getTranslationID("common.message.listEmpty"))}

)} {isLoading && ( Loading )}
); }; // boolかstringを受け取って、stringの場合はそのまま返し、boolの場合はチェックマークON/OFFを返す const boolToElement = (value: boolean | string): JSX.Element | string => { if (typeof value === "string") { return value; } return value ? ( ) : ( ); }; // 文字列の配列または文字列を受け取って、文字列の場合はそのまま返し、配列の場合は最後の要素以外に
をつけて返す const arrayToElement = ( typistGroupNames: string[] | string ): JSX.Element[] | string => { if (typeof typistGroupNames === "string") { return typistGroupNames; } return typistGroupNames.map((v, i) => ( {v} {i !== typistGroupNames.length - 1 &&
}
)); }; export default UserListPage;