From eb6b413adb74712bb9ae413a854e09c85f90c2bf Mon Sep 17 00:00:00 2001 From: masaaki Date: Fri, 22 Mar 2024 07:50:58 +0000 Subject: [PATCH] =?UTF-8?q?Merged=20PR=20848:=20=E3=83=91=E3=83=BC?= =?UTF-8?q?=E3=83=88=E3=83=8A=E3=83=BC=E4=B8=80=E8=A6=A7=E7=94=BB=E9=9D=A2?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 概要 [Task3833: パートナー一覧画面修正](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/3833) - パートナー一覧画面のパートナーにカーソルを合わせた際に、Delete Partnerリンクが表示される。 押下した場合は、本当に削除するのかを確認するメッセージが表示され、どのPartnerを削除するかメッセージ欄に表示されること。 ## レビューポイント - 特筆する点はなし ## UIの変更 https://ndstokyo.sharepoint.com/sites/Piranha/Shared%20Documents/Forms/AllItems.aspx?csf=1&web=1&e=hzPw9b&cid=e8e0702d%2D3730%2D4295%2Dbb9d%2D40e6b1998906&FolderCTID=0x012000C0DCEE65AC2177479C3C761CD137C9C9&id=%2Fsites%2FPiranha%2FShared%20Documents%2FGeneral%2FOMDS%2F%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%2FTask3833&viewid=786a81cf%2Dd15f%2D4dc2%2D9e55%2Dc7a729fbc72f ## クエリの変更 なし ## 動作確認状況 - ローカルで確認(APIからの返却値を直接指定する方式で確認) - 行った修正がデグレを発生させていないことを確認できるか 新規機能追加のみなので問題なし ## 補足 - 相談、参考資料などがあれば --- dictation_client/src/api/api.ts | 88 +++++++++++++++++++ dictation_client/src/common/errors/code.ts | 1 + .../src/features/partner/operations.ts | 60 +++++++++++++ .../src/features/partner/partnerSlice.ts | 15 +++- .../src/pages/PartnerPage/index.tsx | 35 +++++++- dictation_client/src/translation/de.json | 4 +- dictation_client/src/translation/en.json | 4 +- dictation_client/src/translation/es.json | 4 +- dictation_client/src/translation/fr.json | 4 +- 9 files changed, 207 insertions(+), 8 deletions(-) diff --git a/dictation_client/src/api/api.ts b/dictation_client/src/api/api.ts index 28ca9ca..c363b52 100644 --- a/dictation_client/src/api/api.ts +++ b/dictation_client/src/api/api.ts @@ -693,6 +693,19 @@ export interface DeleteAccountRequest { */ 'accountId': number; } +/** + * + * @export + * @interface DeletePartnerAccountRequest + */ +export interface DeletePartnerAccountRequest { + /** + * 削除対象のアカウントID + * @type {number} + * @memberof DeletePartnerAccountRequest + */ + 'targetAccountId': number; +} /** * * @export @@ -2857,6 +2870,46 @@ export const AccountsApiAxiosParamCreator = function (configuration?: Configurat options: localVarRequestOptions, }; }, + /** + * + * @summary + * @param {DeletePartnerAccountRequest} deletePartnerAccountRequest + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + deletePartnerAccount: async (deletePartnerAccountRequest: DeletePartnerAccountRequest, options: AxiosRequestConfig = {}): Promise => { + // verify required parameter 'deletePartnerAccountRequest' is not null or undefined + assertParamExists('deletePartnerAccount', 'deletePartnerAccountRequest', deletePartnerAccountRequest) + const localVarPath = `/accounts/partner/delete`; + // 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(deletePartnerAccountRequest, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, /** * ログインしているユーザーのアカウント配下でIDで指定されたタイピストグループを削除します * @summary @@ -3886,6 +3939,19 @@ export const AccountsApiFp = function(configuration?: Configuration) { const operationBasePath = operationServerMap['AccountsApi.deleteAccountAndData']?.[index]?.url; return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, + /** + * + * @summary + * @param {DeletePartnerAccountRequest} deletePartnerAccountRequest + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async deletePartnerAccount(deletePartnerAccountRequest: DeletePartnerAccountRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.deletePartnerAccount(deletePartnerAccountRequest, options); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['AccountsApi.deletePartnerAccount']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); + }, /** * ログインしているユーザーのアカウント配下でIDで指定されたタイピストグループを削除します * @summary @@ -4276,6 +4342,16 @@ export const AccountsApiFactory = function (configuration?: Configuration, baseP deleteAccountAndData(deleteAccountRequest: DeleteAccountRequest, options?: any): AxiosPromise { return localVarFp.deleteAccountAndData(deleteAccountRequest, options).then((request) => request(axios, basePath)); }, + /** + * + * @summary + * @param {DeletePartnerAccountRequest} deletePartnerAccountRequest + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + deletePartnerAccount(deletePartnerAccountRequest: DeletePartnerAccountRequest, options?: any): AxiosPromise { + return localVarFp.deletePartnerAccount(deletePartnerAccountRequest, options).then((request) => request(axios, basePath)); + }, /** * ログインしているユーザーのアカウント配下でIDで指定されたタイピストグループを削除します * @summary @@ -4608,6 +4684,18 @@ export class AccountsApi extends BaseAPI { return AccountsApiFp(this.configuration).deleteAccountAndData(deleteAccountRequest, options).then((request) => request(this.axios, this.basePath)); } + /** + * + * @summary + * @param {DeletePartnerAccountRequest} deletePartnerAccountRequest + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof AccountsApi + */ + public deletePartnerAccount(deletePartnerAccountRequest: DeletePartnerAccountRequest, options?: AxiosRequestConfig) { + return AccountsApiFp(this.configuration).deletePartnerAccount(deletePartnerAccountRequest, options).then((request) => request(this.axios, this.basePath)); + } + /** * ログインしているユーザーのアカウント配下でIDで指定されたタイピストグループを削除します * @summary diff --git a/dictation_client/src/common/errors/code.ts b/dictation_client/src/common/errors/code.ts index 9ba15db..ed1570d 100644 --- a/dictation_client/src/common/errors/code.ts +++ b/dictation_client/src/common/errors/code.ts @@ -81,4 +81,5 @@ export const errorCodes = [ "E017002", // 親アカウント変更不可エラー(階層関係が不正) "E017003", // 親アカウント変更不可エラー(リージョンが同一でない) "E017004", // 親アカウント変更不可エラー(国が同一でない) + "E018001", // パートナーアカウント削除エラー(削除条件を満たしていない) ] as const; diff --git a/dictation_client/src/features/partner/operations.ts b/dictation_client/src/features/partner/operations.ts index d59efbe..2dac369 100644 --- a/dictation_client/src/features/partner/operations.ts +++ b/dictation_client/src/features/partner/operations.ts @@ -8,6 +8,7 @@ import { AccountsApi, CreatePartnerAccountRequest, GetPartnersResponse, + DeletePartnerAccountRequest, } from "../../api/api"; import { Configuration } from "../../api/configuration"; @@ -116,3 +117,62 @@ export const getPartnerInfoAsync = createAsyncThunk< return thunkApi.rejectWithValue({ error }); } }); + +// パートナーアカウント削除 +export const deletePartnerAccountAsync = createAsyncThunk< + { + /* Empty Object */ + }, + { + // パラメータ + accountId: number; + }, + { + // rejectした時の返却値の型 + rejectValue: { + error: ErrorObject; + }; + } +>("partner/deletePartnerAccountAsync", async (args, thunkApi) => { + const { accountId } = args; + // apiのConfigurationを取得する + const { getState } = thunkApi; + const state = getState() as RootState; + const { configuration } = state.auth; + const accessToken = getAccessToken(state.auth); + const config = new Configuration(configuration); + const accountApi = new AccountsApi(config); + + try { + const deletePartnerAccountRequest: DeletePartnerAccountRequest = { + targetAccountId: accountId, + }; + await accountApi.deletePartnerAccount(deletePartnerAccountRequest, { + headers: { authorization: `Bearer ${accessToken}` }, + }); + thunkApi.dispatch( + openSnackbar({ + level: "info", + message: getTranslationID("common.message.success"), + }) + ); + return {}; + } catch (e) { + const error = createErrorObject(e); + + let errorMessage = getTranslationID("common.message.internalServerError"); + if (error.code === "E018001") { + errorMessage = getTranslationID( + "partnerPage.message.partnerDeleteFailedError" + ); + } + 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 0eb0ce4..cf09f4a 100644 --- a/dictation_client/src/features/partner/partnerSlice.ts +++ b/dictation_client/src/features/partner/partnerSlice.ts @@ -1,6 +1,10 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit"; import { PartnerState } from "./state"; -import { createPartnerAccountAsync, getPartnerInfoAsync } from "./operations"; +import { + createPartnerAccountAsync, + getPartnerInfoAsync, + deletePartnerAccountAsync, +} from "./operations"; import { LIMIT_PARTNER_VIEW_NUM } from "./constants"; const initialState: PartnerState = { @@ -97,6 +101,15 @@ export const partnerSlice = createSlice({ builder.addCase(getPartnerInfoAsync.rejected, (state) => { state.apps.isLoading = false; }); + builder.addCase(deletePartnerAccountAsync.pending, (state) => { + state.apps.isLoading = true; + }); + builder.addCase(deletePartnerAccountAsync.fulfilled, (state) => { + state.apps.isLoading = false; + }); + builder.addCase(deletePartnerAccountAsync.rejected, (state) => { + state.apps.isLoading = false; + }); }, }); export const { diff --git a/dictation_client/src/pages/PartnerPage/index.tsx b/dictation_client/src/pages/PartnerPage/index.tsx index 835cfa3..d1006e3 100644 --- a/dictation_client/src/pages/PartnerPage/index.tsx +++ b/dictation_client/src/pages/PartnerPage/index.tsx @@ -16,6 +16,7 @@ import { selectTotalPage, getPartnerInfoAsync, selectPartnersInfo, + deletePartnerAccountAsync, } from "features/partner/index"; import { changeDelegateAccount, @@ -109,6 +110,31 @@ const PartnerPage: React.FC = (): JSX.Element => { [dispatch, navigate, t] ); + // delete account押下時処理 + const onDeleteAccount = useCallback( + async (accountId: number, companyName: string) => { + // ダイアログ確認 + if ( + /* eslint-disable-next-line no-alert */ + !window.confirm( + `${t( + getTranslationID("partnerPage.message.partnerDeleteConfirm") + )} ${companyName}` + ) + ) { + return; + } + + const { meta } = await dispatch(deletePartnerAccountAsync({ accountId })); + if (meta.requestStatus === "fulfilled") { + dispatch( + getPartnerInfoAsync({ limit: LIMIT_PARTNER_VIEW_NUM, offset }) + ); + } + }, + [dispatch, t, offset] + ); + // HTML return ( <> @@ -185,10 +211,14 @@ const PartnerPage: React.FC = (): JSX.Element => {
    - {/* パートナーアカウント削除はCCB後回し分なので非表示 {isVisibleButton && (
  • - + {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */} + { + onDeleteAccount(x.accountId, x.name); + }} + > {t( getTranslationID( "partnerPage.label.deleteAccount" @@ -197,7 +227,6 @@ const PartnerPage: React.FC = (): JSX.Element => {
  • )} - */} {isVisibleDealerManagement && (
  • {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */} diff --git a/dictation_client/src/translation/de.json b/dictation_client/src/translation/de.json index a96efdc..5acb001 100644 --- a/dictation_client/src/translation/de.json +++ b/dictation_client/src/translation/de.json @@ -537,7 +537,9 @@ "message": { "delegateNotAllowedError": "Aktionen im Namen des Partners sind nicht zulässig. Bitte aktualisieren Sie den Bildschirm und überprüfen Sie ihn erneut.", "deleteFailedError": "Der Delegierungsvorgang ist fehlgeschlagen. Bitte aktualisieren Sie den Bildschirm und überprüfen Sie ihn erneut.", - "delegateCancelError": "Der delegierte Vorgang wurde beendet, da die Berechtigung für den delegierten Vorgang widerrufen wurde." + "delegateCancelError": "Der delegierte Vorgang wurde beendet, da die Berechtigung für den delegierten Vorgang widerrufen wurde.", + "partnerDeleteConfirm": "(de)選択したアカウントを削除します。削除したアカウントは復元できませんが本当によろしいですか?対象アカウント:", + "partnerDeleteFailedError": "(de)削除対象アカウントにLower layerアカウントが存在するため削除できません。Lower layerアカウントに対して削除や階層構造変更を行ってください。" } }, "accountPage": { diff --git a/dictation_client/src/translation/en.json b/dictation_client/src/translation/en.json index 57615cc..8936250 100644 --- a/dictation_client/src/translation/en.json +++ b/dictation_client/src/translation/en.json @@ -537,7 +537,9 @@ "message": { "delegateNotAllowedError": "Actions on behalf of partner are not allowed. Please refresh the screen and check again.", "deleteFailedError": "Delegate operation failed. Please refresh the screen and check again.", - "delegateCancelError": "The delegated operation has been terminated because permission for the delegated operation has been revoked." + "delegateCancelError": "The delegated operation has been terminated because permission for the delegated operation has been revoked.", + "partnerDeleteConfirm": "(en)選択したアカウントを削除します。削除したアカウントは復元できませんが本当によろしいですか?対象アカウント:", + "partnerDeleteFailedError": "(en)削除対象アカウントにLower layerアカウントが存在するため削除できません。Lower layerアカウントに対して削除や階層構造変更を行ってください。" } }, "accountPage": { diff --git a/dictation_client/src/translation/es.json b/dictation_client/src/translation/es.json index 47200a8..cb1651b 100644 --- a/dictation_client/src/translation/es.json +++ b/dictation_client/src/translation/es.json @@ -537,7 +537,9 @@ "message": { "delegateNotAllowedError": "No se permiten acciones en nombre del socio. Actualice la pantalla y verifique nuevamente.", "deleteFailedError": "La operación del delegado falló. Actualice la pantalla y verifique nuevamente.", - "delegateCancelError": "La operación delegada finalizó porque se revocó el permiso para la operación delegada." + "delegateCancelError": "La operación delegada finalizó porque se revocó el permiso para la operación delegada.", + "partnerDeleteConfirm": "(es)選択したアカウントを削除します。削除したアカウントは復元できませんが本当によろしいですか?対象アカウント:", + "partnerDeleteFailedError": "(es)削除対象アカウントにLower layerアカウントが存在するため削除できません。Lower layerアカウントに対して削除や階層構造変更を行ってください。" } }, "accountPage": { diff --git a/dictation_client/src/translation/fr.json b/dictation_client/src/translation/fr.json index 4560e2a..034755c 100644 --- a/dictation_client/src/translation/fr.json +++ b/dictation_client/src/translation/fr.json @@ -537,7 +537,9 @@ "message": { "delegateNotAllowedError": "Les actions au nom du partenaire ne sont pas autorisées. Veuillez actualiser l'écran et vérifier à nouveau.", "deleteFailedError": "L’opération de délégation a échoué. Veuillez actualiser l'écran et vérifier à nouveau.", - "delegateCancelError": "L'opération déléguée a été interrompue car l'autorisation pour l'opération déléguée a été révoquée." + "delegateCancelError": "L'opération déléguée a été interrompue car l'autorisation pour l'opération déléguée a été révoquée.", + "partnerDeleteConfirm": "(fr)選択したアカウントを削除します。削除したアカウントは復元できませんが本当によろしいですか?対象アカウント:", + "partnerDeleteFailedError": "(fr)削除対象アカウントにLower layerアカウントが存在するため削除できません。Lower layerアカウントに対して削除や階層構造変更を行ってください。" } }, "accountPage": {