diff --git a/dictation_client/src/api/api.ts b/dictation_client/src/api/api.ts index 0c2ff5c..d8fa420 100644 --- a/dictation_client/src/api/api.ts +++ b/dictation_client/src/api/api.ts @@ -663,6 +663,19 @@ export interface GetMyAccountResponse { */ 'account': Account; } +/** + * + * @export + * @interface GetOptionItemsResponse + */ +export interface GetOptionItemsResponse { + /** + * + * @type {Array} + * @memberof GetOptionItemsResponse + */ + 'optionItems': Array; +} /** * * @export @@ -908,6 +921,37 @@ export interface GetUsersResponse { */ 'users': Array; } +/** + * + * @export + * @interface GetWorktypeOptionItem + */ +export interface GetWorktypeOptionItem { + /** + * + * @type {string} + * @memberof GetWorktypeOptionItem + */ + 'itemLabel': string; + /** + * Default / Blank / LastInput + * @type {string} + * @memberof GetWorktypeOptionItem + */ + 'defaultValueType': string; + /** + * + * @type {string} + * @memberof GetWorktypeOptionItem + */ + 'initialValue': string; + /** + * + * @type {number} + * @memberof GetWorktypeOptionItem + */ + 'id': number; +} /** * * @export @@ -920,6 +964,12 @@ export interface GetWorktypesResponse { * @memberof GetWorktypesResponse */ 'worktypes': Array; + /** + * Active WorktypeIDに設定されているWorkTypeの内部ID + * @type {number} + * @memberof GetWorktypesResponse + */ + 'acrive'?: number; } /** * @@ -1145,6 +1195,19 @@ export interface PartnerLicenseInfo { */ 'issueRequesting': number; } +/** + * + * @export + * @interface PostActiveWorktypeRequest + */ +export interface PostActiveWorktypeRequest { + /** + * Active WorkTypeIDにするWorktypeの内部ID + * @type {number} + * @memberof PostActiveWorktypeRequest + */ + 'id'?: number; +} /** * * @export @@ -1238,6 +1301,31 @@ export interface PostUpdateUserRequest { */ 'prompt'?: boolean; } +/** + * + * @export + * @interface PostWorktypeOptionItem + */ +export interface PostWorktypeOptionItem { + /** + * + * @type {string} + * @memberof PostWorktypeOptionItem + */ + 'itemLabel': string; + /** + * Default / Blank / LastInput + * @type {string} + * @memberof PostWorktypeOptionItem + */ + 'defaultValueType': string; + /** + * + * @type {string} + * @memberof PostWorktypeOptionItem + */ + 'initialValue': string; +} /** * * @export @@ -1577,6 +1665,19 @@ export interface TypistGroup { */ 'name': string; } +/** + * + * @export + * @interface UpdateOptionItemsRequest + */ +export interface UpdateOptionItemsRequest { + /** + * + * @type {Array} + * @memberof UpdateOptionItemsRequest + */ + 'optionItems': Array; +} /** * * @export @@ -1744,6 +1845,46 @@ export interface Worktype { */ export const AccountsApiAxiosParamCreator = function (configuration?: Configuration) { return { + /** + * + * @summary + * @param {PostActiveWorktypeRequest} postActiveWorktypeRequest + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + activeWorktype: async (postActiveWorktypeRequest: PostActiveWorktypeRequest, options: AxiosRequestConfig = {}): Promise => { + // verify required parameter 'postActiveWorktypeRequest' is not null or undefined + assertParamExists('activeWorktype', 'postActiveWorktypeRequest', postActiveWorktypeRequest) + const localVarPath = `/accounts/active-worktype`; + // 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: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication bearer required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(postActiveWorktypeRequest, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, /** * ライセンス発行をキャンセルします * @summary @@ -2035,6 +2176,44 @@ export const AccountsApiAxiosParamCreator = function (configuration?: Configurat + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @summary + * @param {number} id Worktypeの内部ID + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getOptionItems: async (id: number, options: AxiosRequestConfig = {}): Promise => { + // verify required parameter 'id' is not null or undefined + assertParamExists('getOptionItems', 'id', id) + const localVarPath = `/accounts/worktypes/{id}/option-items` + .replace(`{${"id"}}`, encodeURIComponent(String(id))); + // 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}; @@ -2352,6 +2531,50 @@ export const AccountsApiAxiosParamCreator = function (configuration?: Configurat options: localVarRequestOptions, }; }, + /** + * + * @summary + * @param {number} id Worktypeの内部ID + * @param {UpdateOptionItemsRequest} updateOptionItemsRequest + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + updateOptionItems: async (id: number, updateOptionItemsRequest: UpdateOptionItemsRequest, options: AxiosRequestConfig = {}): Promise => { + // verify required parameter 'id' is not null or undefined + assertParamExists('updateOptionItems', 'id', id) + // verify required parameter 'updateOptionItemsRequest' is not null or undefined + assertParamExists('updateOptionItems', 'updateOptionItemsRequest', updateOptionItemsRequest) + const localVarPath = `/accounts/worktypes/{id}/option-items` + .replace(`{${"id"}}`, encodeURIComponent(String(id))); + // 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: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication bearer required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(updateOptionItemsRequest, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, /** * ログインしているユーザーのアカウント配下でIDで指定されたタイピストグループを更新します * @summary @@ -2450,6 +2673,17 @@ export const AccountsApiAxiosParamCreator = function (configuration?: Configurat export const AccountsApiFp = function(configuration?: Configuration) { const localVarAxiosParamCreator = AccountsApiAxiosParamCreator(configuration) return { + /** + * + * @summary + * @param {PostActiveWorktypeRequest} postActiveWorktypeRequest + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async activeWorktype(postActiveWorktypeRequest: PostActiveWorktypeRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.activeWorktype(postActiveWorktypeRequest, options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, /** * ライセンス発行をキャンセルします * @summary @@ -2536,6 +2770,17 @@ export const AccountsApiFp = function(configuration?: Configuration) { const localVarAxiosArgs = await localVarAxiosParamCreator.getMyAccount(options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, + /** + * + * @summary + * @param {number} id Worktypeの内部ID + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getOptionItems(id: number, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getOptionItems(id, options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, /** * * @summary @@ -2622,6 +2867,18 @@ export const AccountsApiFp = function(configuration?: Configuration) { const localVarAxiosArgs = await localVarAxiosParamCreator.issueLicense(issueLicenseRequest, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, + /** + * + * @summary + * @param {number} id Worktypeの内部ID + * @param {UpdateOptionItemsRequest} updateOptionItemsRequest + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async updateOptionItems(id: number, updateOptionItemsRequest: UpdateOptionItemsRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.updateOptionItems(id, updateOptionItemsRequest, options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, /** * ログインしているユーザーのアカウント配下でIDで指定されたタイピストグループを更新します * @summary @@ -2656,6 +2913,16 @@ export const AccountsApiFp = function(configuration?: Configuration) { export const AccountsApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) { const localVarFp = AccountsApiFp(configuration) return { + /** + * + * @summary + * @param {PostActiveWorktypeRequest} postActiveWorktypeRequest + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + activeWorktype(postActiveWorktypeRequest: PostActiveWorktypeRequest, options?: any): AxiosPromise { + return localVarFp.activeWorktype(postActiveWorktypeRequest, options).then((request) => request(axios, basePath)); + }, /** * ライセンス発行をキャンセルします * @summary @@ -2734,6 +3001,16 @@ export const AccountsApiFactory = function (configuration?: Configuration, baseP getMyAccount(options?: any): AxiosPromise { return localVarFp.getMyAccount(options).then((request) => request(axios, basePath)); }, + /** + * + * @summary + * @param {number} id Worktypeの内部ID + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getOptionItems(id: number, options?: any): AxiosPromise { + return localVarFp.getOptionItems(id, options).then((request) => request(axios, basePath)); + }, /** * * @summary @@ -2812,6 +3089,17 @@ export const AccountsApiFactory = function (configuration?: Configuration, baseP issueLicense(issueLicenseRequest: IssueLicenseRequest, options?: any): AxiosPromise { return localVarFp.issueLicense(issueLicenseRequest, options).then((request) => request(axios, basePath)); }, + /** + * + * @summary + * @param {number} id Worktypeの内部ID + * @param {UpdateOptionItemsRequest} updateOptionItemsRequest + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + updateOptionItems(id: number, updateOptionItemsRequest: UpdateOptionItemsRequest, options?: any): AxiosPromise { + return localVarFp.updateOptionItems(id, updateOptionItemsRequest, options).then((request) => request(axios, basePath)); + }, /** * ログインしているユーザーのアカウント配下でIDで指定されたタイピストグループを更新します * @summary @@ -2844,6 +3132,18 @@ export const AccountsApiFactory = function (configuration?: Configuration, baseP * @extends {BaseAPI} */ export class AccountsApi extends BaseAPI { + /** + * + * @summary + * @param {PostActiveWorktypeRequest} postActiveWorktypeRequest + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof AccountsApi + */ + public activeWorktype(postActiveWorktypeRequest: PostActiveWorktypeRequest, options?: AxiosRequestConfig) { + return AccountsApiFp(this.configuration).activeWorktype(postActiveWorktypeRequest, options).then((request) => request(this.axios, this.basePath)); + } + /** * ライセンス発行をキャンセルします * @summary @@ -2938,6 +3238,18 @@ export class AccountsApi extends BaseAPI { return AccountsApiFp(this.configuration).getMyAccount(options).then((request) => request(this.axios, this.basePath)); } + /** + * + * @summary + * @param {number} id Worktypeの内部ID + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof AccountsApi + */ + public getOptionItems(id: number, options?: AxiosRequestConfig) { + return AccountsApiFp(this.configuration).getOptionItems(id, options).then((request) => request(this.axios, this.basePath)); + } + /** * * @summary @@ -3032,6 +3344,19 @@ export class AccountsApi extends BaseAPI { return AccountsApiFp(this.configuration).issueLicense(issueLicenseRequest, options).then((request) => request(this.axios, this.basePath)); } + /** + * + * @summary + * @param {number} id Worktypeの内部ID + * @param {UpdateOptionItemsRequest} updateOptionItemsRequest + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof AccountsApi + */ + public updateOptionItems(id: number, updateOptionItemsRequest: UpdateOptionItemsRequest, options?: AxiosRequestConfig) { + return AccountsApiFp(this.configuration).updateOptionItems(id, updateOptionItemsRequest, options).then((request) => request(this.axios, this.basePath)); + } + /** * ログインしているユーザーのアカウント配下でIDで指定されたタイピストグループを更新します * @summary diff --git a/dictation_client/src/features/partner/constants.ts b/dictation_client/src/features/partner/constants.ts new file mode 100644 index 0000000..fd3b330 --- /dev/null +++ b/dictation_client/src/features/partner/constants.ts @@ -0,0 +1 @@ +export const LIMIT_PARTNER_VIEW_NUM = 15; diff --git a/dictation_client/src/features/partner/index.ts b/dictation_client/src/features/partner/index.ts index 3de17ae..d6ac63e 100644 --- a/dictation_client/src/features/partner/index.ts +++ b/dictation_client/src/features/partner/index.ts @@ -2,3 +2,4 @@ export * from "./state"; export * from "./operations"; export * from "./selectors"; export * from "./partnerSlice"; +export * from "./constants"; diff --git a/dictation_client/src/features/partner/operations.ts b/dictation_client/src/features/partner/operations.ts index abb662b..e4fed0c 100644 --- a/dictation_client/src/features/partner/operations.ts +++ b/dictation_client/src/features/partner/operations.ts @@ -3,7 +3,11 @@ import type { RootState } from "app/store"; import { ErrorObject, createErrorObject } from "common/errors"; import { getTranslationID } from "translation"; import { openSnackbar } from "features/ui/uiSlice"; -import { AccountsApi, CreatePartnerAccountRequest } from "../../api/api"; +import { + AccountsApi, + CreatePartnerAccountRequest, + GetPartnersResponse, +} from "../../api/api"; import { Configuration } from "../../api/configuration"; export const createPartnerAccountAsync = createAsyncThunk< @@ -62,3 +66,53 @@ export const createPartnerAccountAsync = createAsyncThunk< return thunkApi.rejectWithValue({ error }); } }); + +// パートナー一覧取得APIからパートナーのアカウント情報をもらう +export const getPartnerInfoAsync = createAsyncThunk< + // 正常時の戻り値の型 + GetPartnersResponse, + { + // パラメータ + limit: number; + offset: number; + }, + { + // rejectした時の返却値の型 + rejectValue: { + error: ErrorObject; + }; + } +>("partner/getPartnerInfoAsync", async (args, thunkApi) => { + const { limit, offset } = args; + 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 res = await accountsApi.getPartners(limit, offset, { + headers: { authorization: `Bearer ${accessToken}` }, + }); + const ret = { + partners: res.data.partners, + total: res.data.total, + }; + return ret; + } catch (e) { + const error = createErrorObject(e); + const errorMessage = + error.code === "E000108" + ? getTranslationID("common.message.permissionDeniedError") + : getTranslationID("common.message.internalServerError"); + + thunkApi.dispatch( + openSnackbar({ + level: "error", + message: errorMessage, + }) + ); + + return thunkApi.rejectWithValue({ error }); + } +}); diff --git a/dictation_client/src/features/partner/partnerSlice.ts b/dictation_client/src/features/partner/partnerSlice.ts index 6f73872..8a29d5f 100644 --- a/dictation_client/src/features/partner/partnerSlice.ts +++ b/dictation_client/src/features/partner/partnerSlice.ts @@ -1,8 +1,15 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit"; import { PartnerState } from "./state"; -import { createPartnerAccountAsync } from "./operations"; +import { createPartnerAccountAsync, getPartnerInfoAsync } from "./operations"; +import { LIMIT_PARTNER_VIEW_NUM } from "./constants"; const initialState: PartnerState = { + domain: { + getPartnersInfo: { + total: 0, + partners: [], + }, + }, apps: { addPartner: { companyName: "", @@ -10,6 +17,8 @@ const initialState: PartnerState = { adminName: "", email: "", }, + limit: LIMIT_PARTNER_VIEW_NUM, + offset: 0, isLoading: false, }, }; @@ -37,6 +46,20 @@ export const partnerSlice = createSlice({ cleanupAddPartner: (state) => { state.apps.addPartner = initialState.apps.addPartner; }, + cleanupApps: (state) => { + state.domain = initialState.domain; + }, + savePageInfo: ( + state, + action: PayloadAction<{ + limit: number; + offset: number; + }> + ) => { + const { limit, offset } = action.payload; + state.apps.limit = limit; + state.apps.offset = offset; + }, }, extraReducers: (builder) => { builder.addCase(createPartnerAccountAsync.pending, (state) => { @@ -48,6 +71,17 @@ export const partnerSlice = createSlice({ builder.addCase(createPartnerAccountAsync.rejected, (state) => { state.apps.isLoading = false; }); + builder.addCase(getPartnerInfoAsync.pending, (state) => { + state.apps.isLoading = true; + }); + builder.addCase(getPartnerInfoAsync.fulfilled, (state, action) => { + state.domain.getPartnersInfo.total = action.payload.total; + state.domain.getPartnersInfo.partners = action.payload.partners; + state.apps.isLoading = false; + }); + builder.addCase(getPartnerInfoAsync.rejected, (state) => { + state.apps.isLoading = false; + }); }, }); export const { @@ -56,5 +90,6 @@ export const { changeCompany, changeCountry, cleanupAddPartner, + savePageInfo, } = partnerSlice.actions; export default partnerSlice.reducer; diff --git a/dictation_client/src/features/partner/selectors.ts b/dictation_client/src/features/partner/selectors.ts index 00d1cda..cbfbab6 100644 --- a/dictation_client/src/features/partner/selectors.ts +++ b/dictation_client/src/features/partner/selectors.ts @@ -1,4 +1,5 @@ import { RootState } from "app/store"; +import { ceil, floor } from "lodash"; export const selectInputValidationErrors = (state: RootState) => { // 必須項目のチェック @@ -33,3 +34,22 @@ export const selectEmail = (state: RootState) => state.partner.apps.addPartner.email; export const selectIsLoading = (state: RootState) => state.partner.apps.isLoading; + +export const selectPartnersInfo = (state: RootState) => + state.partner.domain.getPartnersInfo; +export const selectTotal = (state: RootState) => + state.partner.domain.getPartnersInfo.total; +export const seletctLimit = (state: RootState) => state.partner.apps.limit; +export const selectOffset = (state: RootState) => state.partner.apps.offset; +export const selectTotalPage = (state: RootState) => { + const { limit } = state.partner.apps; + const { total } = state.partner.domain.getPartnersInfo; + const page = ceil(total / limit); + return page; +}; + +export const selectCurrentPage = (state: RootState) => { + const { limit, offset } = state.partner.apps; + const page = floor(offset / limit) + 1; + return page; +}; diff --git a/dictation_client/src/features/partner/state.ts b/dictation_client/src/features/partner/state.ts index 6cc9844..6ff5dba 100644 --- a/dictation_client/src/features/partner/state.ts +++ b/dictation_client/src/features/partner/state.ts @@ -1,10 +1,20 @@ -import { CreatePartnerAccountRequest } from "../../api/api"; +import { + CreatePartnerAccountRequest, + GetPartnersResponse, +} from "../../api/api"; export interface PartnerState { + domain: Domain; apps: Apps; } +export interface Domain { + getPartnersInfo: GetPartnersResponse; +} + export interface Apps { + limit: number; + offset: number; addPartner: CreatePartnerAccountRequest; isLoading: boolean; } diff --git a/dictation_client/src/features/workflow/worktype/worktypeSlice.ts b/dictation_client/src/features/workflow/worktype/worktypeSlice.ts index a064ec6..353d342 100644 --- a/dictation_client/src/features/workflow/worktype/worktypeSlice.ts +++ b/dictation_client/src/features/workflow/worktype/worktypeSlice.ts @@ -51,6 +51,7 @@ export const worktypeSlice = createSlice({ state.apps.isLoading = true; }); builder.addCase(listWorktypesAsync.fulfilled, (state, action) => { + // TODO:Active WorktypeIDも取得する const { worktypes } = action.payload; state.domain.worktypes = worktypes; state.apps.isLoading = false; diff --git a/dictation_client/src/pages/PartnerPage/addPartnerAccountPopup.tsx b/dictation_client/src/pages/PartnerPage/addPartnerAccountPopup.tsx index 43453b8..be022d0 100644 --- a/dictation_client/src/pages/PartnerPage/addPartnerAccountPopup.tsx +++ b/dictation_client/src/pages/PartnerPage/addPartnerAccountPopup.tsx @@ -1,5 +1,5 @@ import { AppDispatch } from "app/store"; -import React, { useState, useCallback, useEffect } from "react"; +import React, { useState, useCallback } from "react"; import styles from "styles/app.module.scss"; import { useDispatch, useSelector } from "react-redux"; import { getTranslationID } from "translation"; diff --git a/dictation_client/src/pages/PartnerPage/index.tsx b/dictation_client/src/pages/PartnerPage/index.tsx index e7efb50..03d43c4 100644 --- a/dictation_client/src/pages/PartnerPage/index.tsx +++ b/dictation_client/src/pages/PartnerPage/index.tsx @@ -1,44 +1,89 @@ -import { useMsal } from "@azure/msal-react"; +/* eslint-disable jsx-a11y/control-has-associated-label */ import { AppDispatch } from "app/store"; import { UpdateTokenTimer } from "components/auth/updateTokenTimer"; import Footer from "components/footer"; import Header from "components/header"; -import { clearToken } from "features/auth"; -import React, { useCallback, useState } from "react"; -import { useDispatch } from "react-redux"; +import React, { useCallback, useEffect, useState } from "react"; +import { useDispatch, useSelector } from "react-redux"; import styles from "styles/app.module.scss"; -import { loadAccessToken, isApproveTier } from "features/auth/utils"; -import postAdd from "../../assets/images/post_add.svg"; -import { decodeToken } from "../../common/decodeToken"; +import { isApproveTier } from "features/auth/utils"; +import { + LIMIT_PARTNER_VIEW_NUM, + selectCurrentPage, + selectIsLoading, + selectOffset, + selectTotal, + selectTotalPage, + getPartnerInfoAsync, + selectPartnersInfo, +} from "features/partner/index"; +import { savePageInfo } from "features/partner/partnerSlice"; +import { getTranslationID } from "translation"; +import { useTranslation } from "react-i18next"; +import personAdd from "../../assets/images/person_add.svg"; import { TIERS } from "../../components/auth/constants"; import { AddPartnerAccountPopup } from "./addPartnerAccountPopup"; +import checkFill from "../../assets/images/check_fill.svg"; const PartnerPage: React.FC = (): JSX.Element => { - const { instance } = useMsal(); const dispatch: AppDispatch = useDispatch(); const [isPopupOpen, setIsPopupOpen] = useState(false); + const [t] = useTranslation(); + const total = useSelector(selectTotal); + const totalPage = useSelector(selectTotalPage); + const offset = useSelector(selectOffset); + const currentPage = useSelector(selectCurrentPage); + const isLoading = useSelector(selectIsLoading); - /* XXX 本実装の際に消す想定です。 - POデモ時に階層情報を表示するための実装です。 */ - const getUserTier = () => { - const jwt = loadAccessToken(); // トークンを取得 - const token = jwt && decodeToken(jwt); // トークンをデコード + // apiからの値取得関係 + const partnerInfo = useSelector(selectPartnersInfo); - if (token && token.tier) { - return token.tier.toString(); // ユーザーの階層情報を取得 - } - - return "error!"; // 階層情報が見つからない場合はerror!を返す + // 階層表示用 + const tierNames: { [key: number]: string } = { + // eslint-disable-next-line @typescript-eslint/naming-convention + 1: t(getTranslationID("common.label.tier1")), + // eslint-disable-next-line @typescript-eslint/naming-convention + 2: t(getTranslationID("common.label.tier2")), + // eslint-disable-next-line @typescript-eslint/naming-convention + 3: t(getTranslationID("common.label.tier3")), + // eslint-disable-next-line @typescript-eslint/naming-convention + 4: t(getTranslationID("common.label.tier4")), + // eslint-disable-next-line @typescript-eslint/naming-convention + 5: t(getTranslationID("common.label.tier5")), }; - /* XXX 本実装の際に消す想定です。 - ログインしているアカウントの階層を確認するために実装 */ - const userTier = getUserTier(); // 第1~3階層にボタンを表示する - const isVisible = isApproveTier([TIERS.TIER1, TIERS.TIER2, TIERS.TIER3]); + const isVisibleButton = isApproveTier([ + TIERS.TIER1, + TIERS.TIER2, + TIERS.TIER3, + ]); + + // 第4階層でdealerManagementを表示 + const isVisibleDealerManagement = isApproveTier([TIERS.TIER4]); + const onOpen = useCallback(() => { setIsPopupOpen(true); }, [setIsPopupOpen]); + + // パートナー取得APIを呼び出す + useEffect(() => { + dispatch( + getPartnerInfoAsync({ + limit: LIMIT_PARTNER_VIEW_NUM, + offset, + }) + ); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [dispatch, currentPage]); + + // ページネーションのボタンクリック時のアクション + const movePage = (targetOffset: number) => { + dispatch( + savePageInfo({ limit: LIMIT_PARTNER_VIEW_NUM, offset: targetOffset }) + ); + }; + // HTML return ( <> @@ -52,52 +97,167 @@ const PartnerPage: React.FC = (): JSX.Element => {
-
    -
  • - {isVisible && ( - // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions - - - Add Account - - )} -
  • -
-
-
-
-
-
- -
-
-
+
+

+ {t(getTranslationID("partnerPage.label.title"))} +

+
+
+
+ + + + + + + + + + + + + {!isLoading && + partnerInfo.partners.length !== 0 && + partnerInfo.partners.map((x) => ( + // eslint-disable-next-line react/jsx-key + + + + + + + + + + + ))} +
{/** th is empty */} + {t(getTranslationID("partnerPage.label.name"))} + + {t(getTranslationID("partnerPage.label.category"))} + + {t(getTranslationID("partnerPage.label.accountId"))} + + {t(getTranslationID("partnerPage.label.country"))} + + + {t(getTranslationID("partnerPage.label.primaryAdmin"))} + + + {t(getTranslationID("partnerPage.label.email"))} + + + {t( + getTranslationID("partnerPage.label.dealerManagement") + )} + +
+ + {x.name}{tierNames[x.tier]}{x.accountId}{x.country}{x.primaryAdmin ?? "-"}{x.email ?? "-"} + +
+ {/** pagenation */} +
+ +
+
+
-
- -
+