saito.k a59cb0fffb Merged PR 700: [テストFB対応]User画面でライセンスのStatusの表示を変更したい
## 概要
[Task3506: テスト対応](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/3506)

- ライセンスが割り当たっている状態の表示をLicense Assignedにする
- ライセンスの期限切れ状態の表示をNo Licenseとする
- ヘッダーのOMDSCloudの表記を削除

## レビューポイント
- 修正内容に不足はないか
- 修正の認識ずれはないか
- ほかに修正が影響している箇所はないか

## UIの変更
- 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/Task3506?csf=1&web=1&e=g2Hkr3

## 動作確認状況
- ローカルで確認

## 補足
- 相談、参考資料などがあれば
2024-01-23 11:02:50 +00:00

381 lines
12 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { RootState } from "app/store";
import { USER_ROLES } from "components/auth/constants";
import { convertLocalToUTCDate } from "common/convertLocalToUTCDate";
import {
AddUser,
LicenseStatusType,
RoleType,
UserView,
isLicenseStatusType,
isRoleType,
} from "./types";
import { LICENSE_STATUS, LICENSE_ALLOCATE_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 emailPattern =
/^[a-zA-Z0-9!#$%&'_`/=~+\-?^{|}.]+@[a-zA-Z0-9!#$%&'_`/=~+\-?^{|}.]*\.[a-zA-Z0-9!#$%&'_`/=~+\-?^{|}.]*[a-zA-Z]$/;
const hasErrorIncorrectEmail = email.match(emailPattern)?.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がtrueで、EncryptionPassword変更されていない場合はエラーとしない
if (initEncryption && encryptionPassword === undefined) {
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;
}
// 半角英数字と_の組み合わせで文字まで
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 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
);
// licenseStatus,remaining,expirationの値を変換する
const {
licenseStatus: convertedLicenseStatus,
expiration: convertedExpiration,
remaining: convertedRemaining,
} = convertValueBasedOnLicenseStatus(licenseStatus, expiration, remaining);
// 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: convertedLicenseStatus,
expiration: convertedExpiration,
remaining: convertedRemaining,
...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;
export const selectLicenseAllocateUserId = (state: RootState) =>
state.user.apps.licenseAllocateUser.id;
export const selectLicenseAllocateUserEmail = (state: RootState) =>
state.user.apps.licenseAllocateUser.email;
export const selectLicenseAllocateUserName = (state: RootState) =>
state.user.apps.licenseAllocateUser.name;
export const selectLicenseAllocateUserAuthorId = (state: RootState) =>
state.user.apps.licenseAllocateUser.authorId;
export const selectLicenseAllocateUserStatus = (state: RootState) =>
// ライセンスが割り当てられてるかどうかのステータスを返却する。NORMAL,ALERT,RENEWはすべてライセンス割り当て扱い
state.user.apps.licenseAllocateUser.licenseStatus === LICENSE_STATUS.NOLICENSE
? LICENSE_ALLOCATE_STATUS.NOTALLOCATED
: LICENSE_ALLOCATE_STATUS.ALLOCATED;
export const selectLicenseAllocateUserExpirationDate = (state: RootState) => {
const { licenseStatus, remaining, expiration } =
state.user.apps.licenseAllocateUser;
// ライセンスが割当たっていない場合は-、割当たってる場合はremaining(expiration)の形式で返却
if (licenseStatus === LICENSE_STATUS.NOLICENSE) {
return "-";
}
return `${expiration ?? "-"}(${remaining ?? "-"})`;
};
export const selectSelectedlicenseId = (state: RootState) =>
state.user.apps.selectedlicenseId;
export const selectAllocatableLicenses = (state: RootState) => {
const { allocatableLicenses } = state.user.domain;
// licenseIdはそのまま返却、expiryDateは「nullならundifined」「null以外ならyyyy/mm/dd(現在との差分日数)」を返却
const transformedLicenses = allocatableLicenses.map((license) => ({
licenseId: license.licenseId,
expiryDate: license.expiryDate
? calculateExpiryDate(license.expiryDate)
: undefined,
}));
return transformedLicenses;
};
export const selectInputValidationErrorsForLicenseAcclocation = (
state: RootState
) => {
// 必須項目のチェック(License Acclocation画面用)
// License available選択チェック
// 初期値である0と、「Select a license」選択時のNaNの場合エラーとする
const hasErrorEmptyLicense =
state.user.apps.selectedlicenseId === 0 ||
Number.isNaN(state.user.apps.selectedlicenseId);
return {
hasErrorEmptyLicense,
};
};
// 日付の差分を計算するサブ関数
const calculateExpiryDate = (expiryDate: string) => {
const MILLISECONDS_IN_A_DAY = 24 * 60 * 60 * 1000; // 1日のミリ秒数
const currentDate = new Date();
const expirationDate = new Date(expiryDate);
// タイムゾーンオフセットを考慮して、ローカルタイムでの日付を取得
const currentDateLocal = convertLocalToUTCDate(currentDate);
const expirationDateLocal = convertLocalToUTCDate(expirationDate);
// ライセンスは時刻を考慮しないので時分秒を意識しない日付を取得する
const currentDateWithoutTime = new Date(
currentDateLocal.getFullYear(),
currentDateLocal.getMonth(),
currentDateLocal.getDate()
);
const expirationDateWithoutTime = new Date(
expirationDateLocal.getFullYear(),
expirationDateLocal.getMonth(),
expirationDateLocal.getDate()
);
// 差分日数を取得
const timeDifference =
expirationDateWithoutTime.getTime() - currentDateWithoutTime.getTime();
const daysDifference = Math.ceil(timeDifference / MILLISECONDS_IN_A_DAY);
// yyyy/mm/dd形式の年月日を取得
const expirationYear = expirationDateWithoutTime.getFullYear();
const expirationMonth = expirationDateWithoutTime.getMonth() + 1; // getMonth() の結果は0から始まるため、1を足して実際の月に合わせる
const expirationDay = expirationDateWithoutTime.getDate();
const formattedExpirationDate = `${expirationYear}/${expirationMonth}/${expirationDay}`;
return `${formattedExpirationDate} (${daysDifference})`;
};
// licenseStatus,remainingに応じて値を変換する
const convertValueBasedOnLicenseStatus = (
licenseStatus: LicenseStatusType,
expiration?: string,
remaining?: number
): {
licenseStatus: LicenseStatusType;
expiration?: string;
remaining?: number;
} => {
if (licenseStatus === LICENSE_STATUS.NOLICENSE) {
return {
licenseStatus,
expiration: undefined,
remaining: undefined,
};
}
// remainingが存在し、かつ負の値である場合は、NoLicenseとする
if (remaining && remaining < 0) {
return {
licenseStatus: LICENSE_STATUS.NOLICENSE,
expiration: undefined,
remaining: undefined,
};
}
if (
licenseStatus === LICENSE_STATUS.RENEW ||
licenseStatus === LICENSE_STATUS.NORMAL ||
licenseStatus === LICENSE_STATUS.ALERT
) {
return {
licenseStatus,
expiration,
remaining,
};
}
// ここに到達することはない
return {
licenseStatus,
expiration: undefined,
remaining: undefined,
};
};