import { RootState } from "app/store"; import { USER_ROLES } from "components/auth/constants"; import { AddUser, RoleType, UserView, isLicenseStatusType, isRoleType, } from "./types"; import { LICENSE_STATUS } from "./constants"; export const selectInputValidationErrors = (state: RootState) => { const { name, email, role, authorId, encryption, encryptionPassword } = state.user.apps.addUser; // 必須項目のチェック const hasErrorEmptyName = name === ""; const hasErrorEmptyEmail = email === ""; // Authorの場合、AuthorIDが必須(空文字,undefinedは不可) const hasErrorEmptyAuthorId = role === USER_ROLES.AUTHOR && (authorId === "" || !authorId); const hasErrorIncorrectAuthorId = checkErrorIncorrectAuthorId( authorId ?? undefined, role ); const hasErrorIncorrectEmail = email.match(/^[^@]+@[^@]+$/)?.length !== 1; const hasErrorIncorrectEncryptionPassword = checkErrorIncorrectEncryptionPassword(encryptionPassword, role, encryption); return { hasErrorEmptyName, hasErrorEmptyEmail, hasErrorEmptyAuthorId, hasErrorIncorrectEmail, hasErrorIncorrectAuthorId, hasErrorIncorrectEncryptionPassword, }; }; export const selectUpdateValidationErrors = (state: RootState) => { const { role, authorId, encryption, encryptionPassword } = state.user.apps.updateUser; const { encryption: initEncryption } = state.user.apps.selectedUser; // Authorの場合、AuthorIDが必須(空文字,undefinedは不可) const hasErrorEmptyAuthorId = role === USER_ROLES.AUTHOR && (authorId === "" || !authorId); const hasErrorIncorrectAuthorId = checkErrorIncorrectAuthorId( authorId ?? undefined, role ); let hasErrorIncorrectEncryptionPassword = false; const passwordError = checkErrorIncorrectEncryptionPassword( encryptionPassword, role, encryption ); if (passwordError) { // 最初にEncryptionがfasleで、Encryptionがtrueに変更された場合、EncryptionPasswordが必須 if (!initEncryption) { hasErrorIncorrectEncryptionPassword = true; // Encryptionがある状態で変更がある場合、EncryptionPasswordが空でもエラーにしない } else if (!encryptionPassword || encryptionPassword === "") { hasErrorIncorrectEncryptionPassword = false; } else { hasErrorIncorrectEncryptionPassword = true; } } return { hasErrorEmptyAuthorId, hasErrorIncorrectAuthorId, hasErrorIncorrectEncryptionPassword, }; }; // encreyptionPasswordのチェック const checkErrorIncorrectEncryptionPassword = ( encryptionPassword: string | undefined, role: RoleType, encryption: boolean | undefined ): boolean => { // roleがAuthor以外の場合、チェックしない if (role !== USER_ROLES.AUTHOR) { return false; } // roleがAuthorかつencryptionがfalseの場合、チェックしない if (!encryption) { return false; } // encryptionPasswordがundefined,空文字の場合、エラー if (!encryptionPassword || encryptionPassword === "") { return true; } // encryptionPasswordがルールに則していない場合、エラー const regex = /^[!-~]{4,16}$/; if (!regex.test(encryptionPassword)) { return true; } // チェックを通ったらエラーではない return false; }; export const checkErrorIncorrectAuthorId = ( authorId: string | undefined, role: string ): boolean => { if (!authorId || role !== USER_ROLES.AUTHOR) { return false; } // 半角英数字と_の組み合わせで16文字まで const charaTypePattern = /^[A-Z0-9_]{1,16}$/; const charaType = new RegExp(charaTypePattern).test(authorId); return !charaType; }; export const selectName = (state: RootState) => state.user.apps.addUser.name; export const selectEmail = (state: RootState) => state.user.apps.addUser.email; export const selectRole = (state: RootState) => state.user.apps.addUser.role; export const selectAuthorId = (state: RootState) => state.user.apps.addUser.authorId; export const selectAutoRenew = (state: RootState) => state.user.apps.addUser.autoRenew; export const selectLicenseAlert = (state: RootState) => state.user.apps.addUser.licenseAlert; export const selectNotification = (state: RootState) => state.user.apps.addUser.notification; // AddUserを返却する export const selectAddUser = (state: RootState): AddUser => state.user.apps.addUser; // usersからUserViewに変換して返却する export const selectUserViews = (state: RootState): UserView[] => { const { users } = state.user.domain; const userViews = users.map((user): UserView => { const { role, authorId, encryption, prompt, typistGroupName, licenseStatus, expiration, remaining, ...rest } = user; // roleの型がstringなので、isRoleTypeで型ガードを行う // roleの型がRoleTypeでなければ、何も返さない if (!isRoleType(role) || !isLicenseStatusType(licenseStatus)) { return {} as UserView; } const convertedValues = convertValueBasedOnRole( role, authorId, encryption, prompt, typistGroupName ); // restのid以外をUserViewに追加する return { typistGroupName: convertedValues.typistGroupName, prompt: convertedValues.prompt, encryption: convertedValues.encryption, authorId: convertedValues.authorId, // roleの一文字目を大文字に変換する role: role.charAt(0).toUpperCase() + role.slice(1), licenseStatus: licenseStatus === LICENSE_STATUS.NORMAL ? "-" : licenseStatus, expiration: expiration ?? "-", remaining: remaining ?? "-", ...rest, }; }); // 空のオブジェクトを除外する return userViews.filter((userView) => Object.keys(userView).length !== 0); }; export const selectIsLoading = (state: RootState) => state.user.apps.isLoading; // roleに応じて値を変換する const convertValueBasedOnRole = ( role: RoleType, authorId: string | undefined, encryption: boolean, prompt: boolean, typistGroupName: string[] ): { authorId: string; encryption: boolean | string; prompt: boolean | string; typistGroupName: string[] | string; } => { if (role === USER_ROLES.AUTHOR && authorId) { return { authorId, encryption, prompt, typistGroupName: "-", }; } if (role === USER_ROLES.TYPIST) { return { authorId: "-", encryption: "-", prompt: "-", typistGroupName, }; } return { authorId: "-", encryption: "-", prompt: "-", typistGroupName: "-", }; }; export const selectUpdateUser = (state: RootState) => state.user.apps.updateUser; export const selectHasPasswordMask = (state: RootState) => state.user.apps.hasPasswordMask;