Merged PR 148: 画面実装(第5階層用ライセンス情報)

## 概要
[Task1842: 画面実装(第5階層用ライセンス情報)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/1842)

- 第5階層用ライセンス情報画面の本実装を行いました
- ボタン押下確認のため、遷移後の画面(注文履歴画面、カードライセンス取り込みポップアップ)も仮実装しています
- このPull Requestでの対象外
 ・api.ts、app.module.scss → openapi.json及びデザイナさんcssを取り込んだもののため
 ・cardLicenseImportPopup.tsx、LicenseOrderHistoryPage → 仮実装画面のため
 ・licenseOrderフォルダ構成を変更しただけのため

## レビューポイント
- License周りの構成について見直しを行っています。
 これまではfeatures/licenseの直下にstateやoperationを配置していましたが、
 LicenseページとURLを同じくする画面が増えるため、サブフォルダを作っています。
 features/license
                      /licenseOrder   // これまで直下にあったもの
                      /licenseSummary // 今回作成したもの
 構成について問題ないか確認をお願いします。

## 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/Task1842?csf=1&web=1&e=OdR2mR

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

## 補足
- 特にありません
This commit is contained in:
masaaki 2023-06-13 07:07:06 +00:00
parent 85d8221186
commit 1203d6bb99
22 changed files with 964 additions and 226 deletions

View File

@ -15,6 +15,7 @@ import SignupCompletePage from "pages/SignupCompletePage";
import UserListPage from "pages/UserListPage";
import LicensePage from "pages/LicensePage";
import DictationPage from "pages/DictationPage";
import LicenseOrderHistoryPage from "pages/LicenseOrderHistoryPage";
const AppRouter: React.FC = () => (
<Routes>
@ -42,6 +43,10 @@ const AppRouter: React.FC = () => (
path="/license"
element={<RouteAuthGuard component={<LicensePage />} />}
/>
<Route
path="/licenseOrderHistory"
element={<RouteAuthGuard component={<LicenseOrderHistoryPage />} />}
/>
<Route
path="/xxx"
element={<RouteAuthGuard component={<SamplePage />} />}

View File

@ -36,6 +36,19 @@ export interface AccessTokenResponse {
*/
'accessToken': string;
}
/**
*
* @export
* @interface Account
*/
export interface Account {
/**
*
* @type {number}
* @memberof Account
*/
'accountId': number;
}
/**
*
* @export
@ -330,6 +343,19 @@ export interface GetLicenseSummaryResponse {
*/
'licenseSummaryInfo': LicenseSummaryInfo;
}
/**
*
* @export
* @interface GetMyAccountResponse
*/
export interface GetMyAccountResponse {
/**
*
* @type {Account}
* @memberof GetMyAccountResponse
*/
'account': Account;
}
/**
*
* @export
@ -398,7 +424,7 @@ export interface GetSortCriteriaResponse {
*/
'direction': string;
/**
* JOB_NUMBER/STATUS/ENCRYPTION/AUTHOR_ID/FILE_NAME/FILE_LENGTH/FILE_SIZE/RECORDING_STARTED_DATE/RECORDING_FINISHED_DATE/UPLOAD_DATE/TRANSCRIPTION_STARTED_DATE/TRANSCRIPTION_FINISHED_DATE
* JOB_NUMBER/STATUS/ENCRYPTION/AUTHOR_ID/WORK_TYPE/FILE_NAME/FILE_LENGTH/FILE_SIZE/RECORDING_STARTED_DATE/RECORDING_FINISHED_DATE/UPLOAD_DATE/TRANSCRIPTION_STARTED_DATE/TRANSCRIPTION_FINISHED_DATE
* @type {string}
* @memberof GetSortCriteriaResponse
*/
@ -547,7 +573,7 @@ export interface PostSortCriteriaRequest {
*/
'direction': string;
/**
* JOB_NUMBER/STATUS/ENCRYPTION/AUTHOR_ID/FILE_NAME/FILE_LENGTH/FILE_SIZE/RECORDING_STARTED_DATE/RECORDING_FINISHED_DATE/UPLOAD_DATE/TRANSCRIPTION_STARTED_DATE/TRANSCRIPTION_FINISHED_DATE
* JOB_NUMBER/STATUS/ENCRYPTION/AUTHOR_ID/WORK_TYPE/FILE_NAME/FILE_LENGTH/FILE_SIZE/RECORDING_STARTED_DATE/RECORDING_FINISHED_DATE/UPLOAD_DATE/TRANSCRIPTION_STARTED_DATE/TRANSCRIPTION_FINISHED_DATE
* @type {string}
* @memberof PostSortCriteriaRequest
*/
@ -1031,6 +1057,40 @@ export const AccountsApiAxiosParamCreator = function (configuration?: Configurat
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
localVarRequestOptions.data = serializeDataIfNeeded(getLicenseSummaryRequest, localVarRequestOptions, configuration)
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
*
* @summary
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
getMyAccount: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/accounts/me`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication bearer required
// http bearer authentication required
await setBearerAuthToObject(localVarHeaderParameter, configuration)
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
@ -1068,6 +1128,16 @@ export const AccountsApiFp = function(configuration?: Configuration) {
const localVarAxiosArgs = await localVarAxiosParamCreator.getLicenseSummary(getLicenseSummaryRequest, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
*
* @summary
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async getMyAccount(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<GetMyAccountResponse>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.getMyAccount(options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
}
};
@ -1098,6 +1168,15 @@ export const AccountsApiFactory = function (configuration?: Configuration, baseP
getLicenseSummary(getLicenseSummaryRequest: GetLicenseSummaryRequest, options?: any): AxiosPromise<GetLicenseSummaryResponse> {
return localVarFp.getLicenseSummary(getLicenseSummaryRequest, options).then((request) => request(axios, basePath));
},
/**
*
* @summary
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
getMyAccount(options?: any): AxiosPromise<GetMyAccountResponse> {
return localVarFp.getMyAccount(options).then((request) => request(axios, basePath));
},
};
};
@ -1131,6 +1210,17 @@ export class AccountsApi extends BaseAPI {
public getLicenseSummary(getLicenseSummaryRequest: GetLicenseSummaryRequest, options?: AxiosRequestConfig) {
return AccountsApiFp(this.configuration).getLicenseSummary(getLicenseSummaryRequest, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof AccountsApi
*/
public getMyAccount(options?: AxiosRequestConfig) {
return AccountsApiFp(this.configuration).getMyAccount(options).then((request) => request(this.axios, this.basePath));
}
}
@ -2174,7 +2264,7 @@ export const TasksApiAxiosParamCreator = function (configuration?: Configuration
* @param {number} [offset]  
* @param {string} [status] (,)許容するステータスの値は次の通り: Uploaded / Pending / InProgress / Finished / Backup
* @param {string} [direction] ASC/DESC
* @param {string} [paramName] JOB_NUMBER/STATUS/ENCRYPTION/AUTHOR_ID/FILE_NAME/FILE_LENGTH/FILE_SIZE/RECORDING_STARTED_DATE/RECORDING_FINISHED_DATE/UPLOAD_DATE/TRANSCRIPTION_STARTED_DATE/TRANSCRIPTION_FINISHED_DATE
* @param {string} [paramName] JOB_NUMBER/STATUS/ENCRYPTION/AUTHOR_ID/WORK_TYPE/FILE_NAME/FILE_LENGTH/FILE_SIZE/RECORDING_STARTED_DATE/RECORDING_FINISHED_DATE/UPLOAD_DATE/TRANSCRIPTION_STARTED_DATE/TRANSCRIPTION_FINISHED_DATE
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
@ -2374,7 +2464,7 @@ export const TasksApiFp = function(configuration?: Configuration) {
* @param {number} [offset]  
* @param {string} [status] (,)許容するステータスの値は次の通り: Uploaded / Pending / InProgress / Finished / Backup
* @param {string} [direction] ASC/DESC
* @param {string} [paramName] JOB_NUMBER/STATUS/ENCRYPTION/AUTHOR_ID/FILE_NAME/FILE_LENGTH/FILE_SIZE/RECORDING_STARTED_DATE/RECORDING_FINISHED_DATE/UPLOAD_DATE/TRANSCRIPTION_STARTED_DATE/TRANSCRIPTION_FINISHED_DATE
* @param {string} [paramName] JOB_NUMBER/STATUS/ENCRYPTION/AUTHOR_ID/WORK_TYPE/FILE_NAME/FILE_LENGTH/FILE_SIZE/RECORDING_STARTED_DATE/RECORDING_FINISHED_DATE/UPLOAD_DATE/TRANSCRIPTION_STARTED_DATE/TRANSCRIPTION_FINISHED_DATE
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
@ -2471,7 +2561,7 @@ export const TasksApiFactory = function (configuration?: Configuration, basePath
* @param {number} [offset]  
* @param {string} [status] (,)許容するステータスの値は次の通り: Uploaded / Pending / InProgress / Finished / Backup
* @param {string} [direction] ASC/DESC
* @param {string} [paramName] JOB_NUMBER/STATUS/ENCRYPTION/AUTHOR_ID/FILE_NAME/FILE_LENGTH/FILE_SIZE/RECORDING_STARTED_DATE/RECORDING_FINISHED_DATE/UPLOAD_DATE/TRANSCRIPTION_STARTED_DATE/TRANSCRIPTION_FINISHED_DATE
* @param {string} [paramName] JOB_NUMBER/STATUS/ENCRYPTION/AUTHOR_ID/WORK_TYPE/FILE_NAME/FILE_LENGTH/FILE_SIZE/RECORDING_STARTED_DATE/RECORDING_FINISHED_DATE/UPLOAD_DATE/TRANSCRIPTION_STARTED_DATE/TRANSCRIPTION_FINISHED_DATE
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
@ -2575,7 +2665,7 @@ export class TasksApi extends BaseAPI {
* @param {number} [offset]  
* @param {string} [status] (,)許容するステータスの値は次の通り: Uploaded / Pending / InProgress / Finished / Backup
* @param {string} [direction] ASC/DESC
* @param {string} [paramName] JOB_NUMBER/STATUS/ENCRYPTION/AUTHOR_ID/FILE_NAME/FILE_LENGTH/FILE_SIZE/RECORDING_STARTED_DATE/RECORDING_FINISHED_DATE/UPLOAD_DATE/TRANSCRIPTION_STARTED_DATE/TRANSCRIPTION_FINISHED_DATE
* @param {string} [paramName] JOB_NUMBER/STATUS/ENCRYPTION/AUTHOR_ID/WORK_TYPE/FILE_NAME/FILE_LENGTH/FILE_SIZE/RECORDING_STARTED_DATE/RECORDING_FINISHED_DATE/UPLOAD_DATE/TRANSCRIPTION_STARTED_DATE/TRANSCRIPTION_FINISHED_DATE
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof TasksApi

View File

@ -5,7 +5,8 @@ import signup from "features/signup/signupSlice";
import verify from "features/verify/verifySlice";
import ui from "features/ui/uiSlice";
import user from "features/user/userSlice";
import license from "features/license/licenseSlice";
import license from "features/license/licenseOrder/licenseSlice";
import licenseSummary from "features/license/licenseSummary/licenseSummarySlice";
import dictation from "features/dictation/dictationSlice";
export const store = configureStore({
@ -17,6 +18,7 @@ export const store = configureStore({
ui,
user,
license,
licenseSummary,
dictation,
},
});

View File

@ -2,9 +2,9 @@ import { createAsyncThunk } from "@reduxjs/toolkit";
import type { RootState } from "app/store";
import { getTranslationID } from "translation";
import { openSnackbar } from "features/ui/uiSlice";
import { LicensesApi } from "../../api/api";
import { Configuration } from "../../api/configuration";
import { ErrorObject, createErrorObject } from "../../common/errors";
import { LicensesApi } from "../../../api/api";
import { Configuration } from "../../../api/configuration";
import { ErrorObject, createErrorObject } from "../../../common/errors";
export const orderLicenseAsync = createAsyncThunk<
{

View File

@ -0,0 +1,4 @@
export * from "./state";
export * from "./operations";
export * from "./selectors";
export * from "./licenseSummarySlice";

View File

@ -0,0 +1,40 @@
import { createSlice } from "@reduxjs/toolkit";
import { LicenseSummaryState } from "./state";
import { getLicenseSummaryAsync } from "./operations";
const initialState: LicenseSummaryState = {
domain: {
licenseSummaryInfo: {
totalLicense: 0,
allocatedLicense: 0,
reusableLicense: 0,
freeLicense: 0,
expiringWithin14daysLicense: 0,
issueRequesting: 0,
numberOfRequesting: 0,
shortage: 0,
storageSize: 0,
usedSize: 0,
isAccountLock: false,
},
},
};
export const licenseSummarySlice = createSlice({
name: "licenseSummary",
initialState,
reducers: {
cleanupApps: (state) => {
state.domain = initialState.domain;
},
},
extraReducers: (builder) => {
builder.addCase(getLicenseSummaryAsync.fulfilled, (state, action) => {
state.domain.licenseSummaryInfo = action.payload.licenseSummaryInfo;
});
},
});
export const { cleanupApps } = licenseSummarySlice.actions;
export default licenseSummarySlice.reducer;

View File

@ -0,0 +1,60 @@
import { createAsyncThunk } from "@reduxjs/toolkit";
import type { RootState } from "app/store";
import { getTranslationID } from "translation";
import { openSnackbar } from "features/ui/uiSlice";
import { AccountsApi, GetLicenseSummaryResponse } from "../../../api/api";
import { Configuration } from "../../../api/configuration";
import { ErrorObject, createErrorObject } from "../../../common/errors";
export const getLicenseSummaryAsync = createAsyncThunk<
// 正常時の戻り値の型
GetLicenseSummaryResponse,
// 引数
void,
{
// rejectした時の返却値の型
rejectValue: {
error: ErrorObject;
};
}
>("licenses/getLicenseSummaryAsync", async (args, thunkApi) => {
// apiのConfigurationを取得する
const { getState } = thunkApi;
const state = getState() as RootState;
const { configuration, accessToken } = state.auth;
const config = new Configuration(configuration);
const accountsApi = new AccountsApi(config);
try {
const getMyAccountResponse = await accountsApi.getMyAccount({
headers: { authorization: `Bearer ${accessToken}` },
});
// 自分のアカウントID取得、取得したアカウントIDを使用して表示情報を取得する
const { accountId } = getMyAccountResponse.data.account;
const getLicenseSummaryResponse = await accountsApi.getLicenseSummary(
{ accountId },
{
headers: { authorization: `Bearer ${accessToken}` },
}
);
return {
licenseSummaryInfo: getLicenseSummaryResponse.data.licenseSummaryInfo,
};
} catch (e) {
// e ⇒ errorObjectに変換"
const error = createErrorObject(e);
const errorMessage = getTranslationID("common.message.internalServerError");
thunkApi.dispatch(
openSnackbar({
level: "error",
message: errorMessage,
})
);
return thunkApi.rejectWithValue({ error });
}
});

View File

@ -0,0 +1,5 @@
import { RootState } from "app/store";
// 各値はそのまま画面に表示するので、licenseSummaryInfoとして値を取得する
export const selecLicenseSummaryInfo = (state: RootState) =>
state.licenseSummary.domain.licenseSummaryInfo;

View File

@ -0,0 +1,9 @@
import { LicenseSummaryInfo } from "../../../api/api";
export interface LicenseSummaryState {
domain: Domain;
}
export interface Domain {
licenseSummaryInfo: LicenseSummaryInfo;
}

View File

@ -0,0 +1,34 @@
import React from "react";
import Footer from "components/footer";
import Header from "components/header";
import styles from "styles/app.module.scss";
import { UpdateTokenTimer } from "components/auth/updateTokenTimer";
const PartnerLicense: React.FC = (): JSX.Element => (
// 表示確認用の仮画面
<div className={styles.wrap}>
<Header userName="XXXXXX" />
<UpdateTokenTimer />
<main className={styles.main}>
<div className="">
<div className={styles.pageHeader}>
<h1 className={styles.pageTitle}>Order History</h1>
</div>
</div>
<ul className={styles.menuAction}>
<li>
<a
href="/license"
className={`${styles.menuLink} ${styles.isActive}`}
>
<img src="images/undo.svg" alt="" className={styles.menuIcon} />
Return
</a>
</li>
</ul>
</main>
<Footer />
</div>
);
export default PartnerLicense;

View File

@ -0,0 +1,58 @@
import React, { useCallback } from "react";
import styles from "styles/app.module.scss";
import close from "../../assets/images/close.svg";
interface CardLicenseImportPopupProps {
onClose: () => void;
}
export const CardLicenseImportPopup: React.FC<CardLicenseImportPopupProps> = (
props
) => {
const { onClose } = props;
// ポップアップを閉じる処理
const closePopup = useCallback(() => {
onClose();
}, [onClose]);
// HTML
return (
<div className={`${styles.modal} ${styles.isShow}`}>
<div className={styles.modalBox}>
<p className={styles.modalTitle}>
Import License Key
<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} />
<dt>Key number</dt>
<dd className="">
<input
type="text"
size={40}
name=""
value=""
maxLength={20}
className={styles.formInput}
/>
</dd>
<dd className={`${styles.full} ${styles.alignCenter}`}>
<input
type="button"
name="submit"
value="Import"
className={`${styles.formSubmit} ${styles.marginBtm1} ${styles.isActive}`}
onClick={closePopup}
/>
</dd>
</dl>
</form>
</div>
</div>
);
};

View File

@ -12,7 +12,7 @@ import {
selectInputValidationErrors,
orderLicenseAsync,
cleanupApps,
} from "features/license";
} from "features/license/licenseOrder";
import close from "../../assets/images/close.svg";
interface LicenseOrderPopupProps {

View File

@ -1,30 +1,48 @@
import { useMsal } from "@azure/msal-react";
import React, { useCallback, useState } from "react";
import { AppDispatch } from "app/store";
import React, { useCallback, useEffect, useState } from "react";
import { UpdateTokenTimer } from "components/auth/updateTokenTimer";
import Footer from "components/footer";
import Header from "components/header";
import { clearToken } from "features/auth";
import { useDispatch } from "react-redux";
import styles from "styles/app.module.scss";
import { getTranslationID } from "translation";
import { useTranslation } from "react-i18next";
import { AppDispatch } from "app/store";
import { useDispatch, useSelector } from "react-redux";
import {
getLicenseSummaryAsync,
selecLicenseSummaryInfo,
} from "features/license/licenseSummary";
import postAdd from "../../assets/images/post_add.svg";
import history from "../../assets/images/history.svg";
import key from "../../assets/images/key.svg";
import lock from "../../assets/images/lock.svg";
import lockOpen from "../../assets/images/lock_open.svg";
import { LicenseOrderPopup } from "./licenseOrderPopup";
import { CardLicenseImportPopup } from "./cardLicenseImportPopup";
const LicenseSummary: React.FC = (): JSX.Element => {
const { instance } = useMsal();
const dispatch: AppDispatch = useDispatch();
const [t] = useTranslation();
// popup制御関係
const [islicenseOrderPopupOpen, setIslicenseOrderPopupOpen] = useState(false);
const [isCardLicenseImportPopupOpen, setIsCardLicenseImportPopupOpen] =
useState(false);
const onlicenseOrderOpen = useCallback(() => {
setIslicenseOrderPopupOpen(true);
}, [setIslicenseOrderPopupOpen]);
const onCardLicenseImportOpen = useCallback(() => {
setIsCardLicenseImportPopupOpen(true);
}, [setIsCardLicenseImportPopupOpen]);
// apiからの値取得関係
const licenseSummaryInfo = useSelector(selecLicenseSummaryInfo);
useEffect(() => {
dispatch(getLicenseSummaryAsync());
}, [dispatch]);
return (
<>
{/* isPopupOpenがfalseの場合はポップアップのhtmlを生成しないように対応。これによりポップアップは都度生成されて初期化の考慮が減る */}
@ -35,7 +53,13 @@ const LicenseSummary: React.FC = (): JSX.Element => {
}}
/>
)}
{/* TODO 現状PBI1221はライセンス注文PUを起動するためのボタンのみ。別途ライセンス注文を実装するPBIで全般的に見直し。 */}
{isCardLicenseImportPopupOpen && (
<CardLicenseImportPopup
onClose={() => {
setIsCardLicenseImportPopupOpen(false);
}}
/>
)}
<div className={styles.wrap}>
<Header userName="XXXXXX" />
@ -44,59 +68,146 @@ const LicenseSummary: React.FC = (): JSX.Element => {
<div className="">
<div className={styles.pageHeader}>
<h1 className={styles.pageTitle}>
{t(getTranslationID("LicensePage.label.title"))}
{t(getTranslationID("LicenseSummaryPage.label.title"))}
</h1>
</div>
<section className={styles.license}>
<div>
<h2 className="">
{t(getTranslationID("LicensePage.label.subTitle"))}
{t(getTranslationID("LicenseSummaryPage.label.subTitle"))}
</h2>
<ul className={styles.menuAction}>
<li>
{/* TODO ライセンス注文ポップアップのタスクにて起動の実装を行うその際buttonに変更する想定 */}
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
<a
className={`${styles.menuLink} ${styles.isActive}`}
onClick={onlicenseOrderOpen}
>
<img src={postAdd} alt="" className={styles.menuIcon} />
{t(getTranslationID("LicensePage.label.orderLicense"))}
{t(
getTranslationID(
"LicenseSummaryPage.label.orderLicense"
)
)}
</a>
</li>
<li>
<a href="" className={`${styles.menuLink}`}>
<a
href="/licenseOrderHistory"
className={`${styles.menuLink} ${styles.isActive}`}
>
<img src={history} alt="" className={styles.menuIcon} />
{t(getTranslationID("LicensePage.label.orderHistory"))}
{t(
getTranslationID(
"LicenseSummaryPage.label.orderHistory"
)
)}
</a>
</li>
<li>
<a href="" className={`${styles.menuLink}`}>
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
<a
className={`${styles.menuLink} ${styles.isActive}`}
onClick={onCardLicenseImportOpen}
>
<img src={key} alt="" className={styles.menuIcon} />
{t(
getTranslationID("LicensePage.label.importLicenseKey")
getTranslationID(
"LicenseSummaryPage.label.importLicenseKey"
)
)}
</a>
</li>
</ul>
<dl className={`${styles.listVertical} ${styles.marginBtm5}`}>
<dt>
{t(
getTranslationID("LicenseSummaryPage.label.totalLicense")
)}
</dt>
<dd>{licenseSummaryInfo.totalLicense}</dd>
<dt>
{t(
getTranslationID(
"LicenseSummaryPage.label.allocatedLicense"
)
)}
</dt>
<dd>{licenseSummaryInfo.allocatedLicense}</dd>
<dt>
{t(
getTranslationID(
"LicenseSummaryPage.label.reusableLicense"
)
)}
</dt>
<dd>{licenseSummaryInfo.reusableLicense}</dd>
<dt>
{t(
getTranslationID("LicenseSummaryPage.label.freeLicense")
)}
</dt>
<dd>{licenseSummaryInfo.freeLicense}</dd>
<dt>
{t(
getTranslationID(
"LicenseSummaryPage.label.expiringWithin14daysLicense"
)
)}
</dt>
<dd>{licenseSummaryInfo.expiringWithin14daysLicense}</dd>
<dt>
{t(
getTranslationID(
"LicenseSummaryPage.label.issueRequesting"
)
)}
</dt>
<dd>{licenseSummaryInfo.issueRequesting}</dd>
<dt>
{t(
getTranslationID(
"LicenseSummaryPage.label.numberOfRequesting"
)
)}
</dt>
<dd>{licenseSummaryInfo.numberOfRequesting}</dd>
<dt>
{t(getTranslationID("LicenseSummaryPage.label.shortage"))}
</dt>
<dd>{licenseSummaryInfo.shortage}</dd>
<dt>
{t(
getTranslationID("LicenseSummaryPage.label.storageSize")
)}
</dt>
<dd>{licenseSummaryInfo.storageSize}GB</dd>
<dt>
{t(getTranslationID("LicenseSummaryPage.label.usedSize"))}
</dt>
<dd>{licenseSummaryInfo.usedSize}GB</dd>
<dt>
{t(
getTranslationID("LicenseSummaryPage.label.accountLock")
)}
</dt>
<dd>
{licenseSummaryInfo.isAccountLock && (
<img src={lock} alt="" className={styles.icCheckCircle} />
)}
{!licenseSummaryInfo.isAccountLock && (
<img
src={lockOpen}
alt=""
className={styles.icCheckCircle}
/>
)}
</dd>
</dl>
</div>
</section>
</div>
</main>
{/* TODO 画面デザインにはないが、試験時に便利なので配置しておく。ライセンス注文を実装するPBIで正式なサインアウトのレイアウトに直す */}
<div>
<button
type="button"
className={styles.buttonText}
onClick={() => {
instance.logout({ postLogoutRedirectUri: "/" });
dispatch(clearToken());
}}
>
sign out
</button>
</div>
<Footer />
</div>
</>

File diff suppressed because it is too large Load Diff

View File

@ -14,6 +14,9 @@
}
},
"topPage": {
"message": {
"logout": "(de)ログイン有効期限が切れました。再度ログイン手続きを行ってください。"
},
"label": {
"displayLanguage": "(de)Display language",
"languageEnglish": "(de)English",
@ -129,13 +132,24 @@
"none": "(de)None"
}
},
"LicensePage": {
"LicenseSummaryPage": {
"label": {
"title": "(de)License",
"subTitle": "(de)EFGI Legal",
"orderLicense": "(de)Order License",
"orderHistory": "(de)Order History",
"importLicenseKey": "(de)Import License Key"
"importLicenseKey": "(de)Import License Key",
"totalLicense": "(de)Total license",
"allocatedLicense": "(de)Allocated license",
"reusableLicense": "(de)Reusable license",
"freeLicense": "(de)Free license",
"expiringWithin14daysLicense": "(de)Expiring within 14days license",
"issueRequesting": "(de)Issue Requesting",
"numberOfRequesting": "(de)Number of Requesting",
"shortage": "(de)Shortage",
"storageSize": "(de)Storage Size",
"usedSize": "(de)Used Size",
"accountLock": "(de)Account Lock"
}
},
"licenseOrderPage": {

View File

@ -14,6 +14,9 @@
}
},
"topPage": {
"message": {
"logout": "ログイン有効期限が切れました。再度ログイン手続きを行ってください。"
},
"label": {
"displayLanguage": "Display language",
"languageEnglish": "English",
@ -129,13 +132,24 @@
"none": "None"
}
},
"LicensePage": {
"LicenseSummaryPage": {
"label": {
"title": "License",
"subTitle": "EFGI Legal",
"orderLicense": "Order License",
"orderHistory": "Order History",
"importLicenseKey": "Import License Key"
"importLicenseKey": "Import License Key",
"totalLicense": "Total license",
"allocatedLicense": "Allocated license",
"reusableLicense": "Reusable license",
"freeLicense": "Free license",
"expiringWithin14daysLicense": "Expiring within 14days license",
"issueRequesting": "Issue Requesting",
"numberOfRequesting": "Number of Requesting",
"shortage": "Shortage",
"storageSize": "Storage Size",
"usedSize": "Used Size",
"accountLock": "Account Lock"
}
},
"licenseOrderPage": {

View File

@ -14,6 +14,9 @@
}
},
"topPage": {
"message": {
"logout": "(es)ログイン有効期限が切れました。再度ログイン手続きを行ってください。"
},
"label": {
"displayLanguage": "(es)Display language",
"languageEnglish": "(es)English",
@ -129,13 +132,24 @@
"none": "(es)None"
}
},
"LicensePage": {
"LicenseSummaryPage": {
"label": {
"title": "(es)License",
"subTitle": "(es)EFGI Legal",
"orderLicense": "(es)Order License",
"orderHistory": "(es)Order History",
"importLicenseKey": "(es)Import License Key"
"importLicenseKey": "(es)Import License Key",
"totalLicense": "(es)Total license",
"allocatedLicense": "(es)Allocated license",
"reusableLicense": "(es)Reusable license",
"freeLicense": "(es)Free license",
"expiringWithin14daysLicense": "(es)Expiring within 14days license",
"issueRequesting": "(es)Issue Requesting",
"numberOfRequesting": "(es)Number of Requesting",
"shortage": "(es)Shortage",
"storageSize": "(es)Storage Size",
"usedSize": "(es)Used Size",
"accountLock": "(es)Account Lock"
}
},
"licenseOrderPage": {

View File

@ -14,6 +14,9 @@
}
},
"topPage": {
"message": {
"logout": "(fr)ログイン有効期限が切れました。再度ログイン手続きを行ってください。"
},
"label": {
"displayLanguage": "(fr)Display language",
"languageEnglish": "(fr)English",
@ -129,13 +132,24 @@
"none": "(fr)None"
}
},
"LicensePage": {
"LicenseSummaryPage": {
"label": {
"title": "(fr)License",
"subTitle": "(fr)EFGI Legal",
"orderLicense": "(fr)Order License",
"orderHistory": "(fr)Order History",
"importLicenseKey": "(fr)Import License Key"
"importLicenseKey": "(fr)Import License Key",
"totalLicense": "(fr)Total license",
"allocatedLicense": "(fr)Allocated license",
"reusableLicense": "(fr)Reusable license",
"freeLicense": "(fr)Free license",
"expiringWithin14daysLicense": "(fr)Expiring within 14days license",
"issueRequesting": "(fr)Issue Requesting",
"numberOfRequesting": "(fr)Number of Requesting",
"shortage": "(fr)Shortage",
"storageSize": "(fr)Storage Size",
"usedSize": "(fr)Used Size",
"accountLock": "(fr)Account Lock"
}
},
"licenseOrderPage": {