Merge branch 'develop'
This commit is contained in:
commit
faac4bcdb8
@ -48,6 +48,12 @@ export interface Account {
|
||||
* @memberof Account
|
||||
*/
|
||||
'accountId': number;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof Account
|
||||
*/
|
||||
'companyName': string;
|
||||
}
|
||||
/**
|
||||
*
|
||||
@ -513,19 +519,19 @@ export interface GetOrderHistoriesRequest {
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface GetOrderHistoriesResponce
|
||||
* @interface GetOrderHistoriesResponse
|
||||
*/
|
||||
export interface GetOrderHistoriesResponce {
|
||||
export interface GetOrderHistoriesResponse {
|
||||
/**
|
||||
* 合計件数
|
||||
* @type {number}
|
||||
* @memberof GetOrderHistoriesResponce
|
||||
* @memberof GetOrderHistoriesResponse
|
||||
*/
|
||||
'total': number;
|
||||
/**
|
||||
*
|
||||
* @type {Array<LicenseOrder>}
|
||||
* @memberof GetOrderHistoriesResponce
|
||||
* @memberof GetOrderHistoriesResponse
|
||||
*/
|
||||
'orderHistories': Array<LicenseOrder>;
|
||||
}
|
||||
@ -718,6 +724,25 @@ export interface IssueCardLicensesResponse {
|
||||
*/
|
||||
'cardLicenseKeys': Array<string>;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface IssueLicenseRequest
|
||||
*/
|
||||
export interface IssueLicenseRequest {
|
||||
/**
|
||||
* 注文元アカウントID
|
||||
* @type {number}
|
||||
* @memberof IssueLicenseRequest
|
||||
*/
|
||||
'orderedAccountId': number;
|
||||
/**
|
||||
* POナンバー
|
||||
* @type {string}
|
||||
* @memberof IssueLicenseRequest
|
||||
*/
|
||||
'poNumber': string;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
@ -880,6 +905,67 @@ export interface PostSortCriteriaRequest {
|
||||
*/
|
||||
'paramName': string;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface PostUpdateUserRequest
|
||||
*/
|
||||
export interface PostUpdateUserRequest {
|
||||
/**
|
||||
*
|
||||
* @type {number}
|
||||
* @memberof PostUpdateUserRequest
|
||||
*/
|
||||
'id': number;
|
||||
/**
|
||||
* none/author/typist
|
||||
* @type {string}
|
||||
* @memberof PostUpdateUserRequest
|
||||
*/
|
||||
'role': string;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof PostUpdateUserRequest
|
||||
*/
|
||||
'authorId'?: string;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof PostUpdateUserRequest
|
||||
*/
|
||||
'autoRenew': boolean;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof PostUpdateUserRequest
|
||||
*/
|
||||
'licenseAlart': boolean;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof PostUpdateUserRequest
|
||||
*/
|
||||
'notification': boolean;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof PostUpdateUserRequest
|
||||
*/
|
||||
'encryption'?: boolean;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof PostUpdateUserRequest
|
||||
*/
|
||||
'encryptionPassword'?: string;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof PostUpdateUserRequest
|
||||
*/
|
||||
'prompt'?: boolean;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
@ -923,12 +1009,6 @@ export interface SignupRequest {
|
||||
* @memberof SignupRequest
|
||||
*/
|
||||
'authorId'?: string;
|
||||
/**
|
||||
*
|
||||
* @type {number}
|
||||
* @memberof SignupRequest
|
||||
*/
|
||||
'typistGroupId'?: number;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
@ -953,6 +1033,24 @@ export interface SignupRequest {
|
||||
* @memberof SignupRequest
|
||||
*/
|
||||
'notification': boolean;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof SignupRequest
|
||||
*/
|
||||
'encryption'?: boolean;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof SignupRequest
|
||||
*/
|
||||
'encryptionPassword'?: string;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof SignupRequest
|
||||
*/
|
||||
'prompt'?: boolean;
|
||||
}
|
||||
/**
|
||||
*
|
||||
@ -1623,6 +1721,46 @@ export const AccountsApiAxiosParamCreator = function (configuration?: Configurat
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @summary
|
||||
* @param {IssueLicenseRequest} issueLicenseRequest
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
issueLicense: async (issueLicenseRequest: IssueLicenseRequest, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
// verify required parameter 'issueLicenseRequest' is not null or undefined
|
||||
assertParamExists('issueLicense', 'issueLicenseRequest', issueLicenseRequest)
|
||||
const localVarPath = `/accounts/licenses/issue`;
|
||||
// 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(issueLicenseRequest, localVarRequestOptions, configuration)
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
@ -1688,7 +1826,7 @@ export const AccountsApiFp = function(configuration?: Configuration) {
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async getOrderHistories(getOrderHistoriesRequest: GetOrderHistoriesRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<GetOrderHistoriesResponce>> {
|
||||
async getOrderHistories(getOrderHistoriesRequest: GetOrderHistoriesRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<GetOrderHistoriesResponse>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.getOrderHistories(getOrderHistoriesRequest, options);
|
||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||
},
|
||||
@ -1723,6 +1861,17 @@ export const AccountsApiFp = function(configuration?: Configuration) {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.getTypists(options);
|
||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @summary
|
||||
* @param {IssueLicenseRequest} issueLicenseRequest
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async issueLicense(issueLicenseRequest: IssueLicenseRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<object>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.issueLicense(issueLicenseRequest, options);
|
||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
@ -1779,7 +1928,7 @@ export const AccountsApiFactory = function (configuration?: Configuration, baseP
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
getOrderHistories(getOrderHistoriesRequest: GetOrderHistoriesRequest, options?: any): AxiosPromise<GetOrderHistoriesResponce> {
|
||||
getOrderHistories(getOrderHistoriesRequest: GetOrderHistoriesRequest, options?: any): AxiosPromise<GetOrderHistoriesResponse> {
|
||||
return localVarFp.getOrderHistories(getOrderHistoriesRequest, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
@ -1810,6 +1959,16 @@ export const AccountsApiFactory = function (configuration?: Configuration, baseP
|
||||
getTypists(options?: any): AxiosPromise<GetTypistsResponse> {
|
||||
return localVarFp.getTypists(options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @summary
|
||||
* @param {IssueLicenseRequest} issueLicenseRequest
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
issueLicense(issueLicenseRequest: IssueLicenseRequest, options?: any): AxiosPromise<object> {
|
||||
return localVarFp.issueLicense(issueLicenseRequest, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@ -1912,6 +2071,18 @@ export class AccountsApi extends BaseAPI {
|
||||
public getTypists(options?: AxiosRequestConfig) {
|
||||
return AccountsApiFp(this.configuration).getTypists(options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @summary
|
||||
* @param {IssueLicenseRequest} issueLicenseRequest
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
* @memberof AccountsApi
|
||||
*/
|
||||
public issueLicense(issueLicenseRequest: IssueLicenseRequest, options?: AxiosRequestConfig) {
|
||||
return AccountsApiFp(this.configuration).issueLicense(issueLicenseRequest, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3852,6 +4023,46 @@ export const UsersApiAxiosParamCreator = function (configuration?: Configuration
|
||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||
localVarRequestOptions.data = serializeDataIfNeeded(postSortCriteriaRequest, localVarRequestOptions, configuration)
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
* ユーザーの情報を更新します
|
||||
* @summary
|
||||
* @param {PostUpdateUserRequest} postUpdateUserRequest
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
updateUser: async (postUpdateUserRequest: PostUpdateUserRequest, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
// verify required parameter 'postUpdateUserRequest' is not null or undefined
|
||||
assertParamExists('updateUser', 'postUpdateUserRequest', postUpdateUserRequest)
|
||||
const localVarPath = `/users/update`;
|
||||
// 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(postUpdateUserRequest, localVarRequestOptions, configuration)
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
@ -3941,6 +4152,17 @@ export const UsersApiFp = function(configuration?: Configuration) {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.updateSortCriteria(postSortCriteriaRequest, options);
|
||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||
},
|
||||
/**
|
||||
* ユーザーの情報を更新します
|
||||
* @summary
|
||||
* @param {PostUpdateUserRequest} postUpdateUserRequest
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async updateUser(postUpdateUserRequest: PostUpdateUserRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<object>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.updateUser(postUpdateUserRequest, options);
|
||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
@ -4018,6 +4240,16 @@ export const UsersApiFactory = function (configuration?: Configuration, basePath
|
||||
updateSortCriteria(postSortCriteriaRequest: PostSortCriteriaRequest, options?: any): AxiosPromise<object> {
|
||||
return localVarFp.updateSortCriteria(postSortCriteriaRequest, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
* ユーザーの情報を更新します
|
||||
* @summary
|
||||
* @param {PostUpdateUserRequest} postUpdateUserRequest
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
updateUser(postUpdateUserRequest: PostUpdateUserRequest, options?: any): AxiosPromise<object> {
|
||||
return localVarFp.updateUser(postUpdateUserRequest, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@ -4108,6 +4340,18 @@ export class UsersApi extends BaseAPI {
|
||||
public updateSortCriteria(postSortCriteriaRequest: PostSortCriteriaRequest, options?: AxiosRequestConfig) {
|
||||
return UsersApiFp(this.configuration).updateSortCriteria(postSortCriteriaRequest, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
* ユーザーの情報を更新します
|
||||
* @summary
|
||||
* @param {PostUpdateUserRequest} postUpdateUserRequest
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
* @memberof UsersApi
|
||||
*/
|
||||
public updateUser(postUpdateUserRequest: PostUpdateUserRequest, options?: AxiosRequestConfig) {
|
||||
return UsersApiFp(this.configuration).updateUser(postUpdateUserRequest, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -20,13 +20,26 @@ export const errorCodes = [
|
||||
"E000104", // トークン署名エラー
|
||||
"E000105", // トークン発行元エラー
|
||||
"E000106", // トークンアルゴリズムエラー
|
||||
"E000107", // トークン不足エラー
|
||||
"E000108", // トークン権限エラー
|
||||
"E000301", // ADB2Cへのリクエスト上限超過エラー
|
||||
"E010001", // パラメータ形式不正エラー
|
||||
"E010201", // 未認証ユーザエラー
|
||||
"E010202", // 認証済ユーザエラー
|
||||
"E010203", // 管理ユーザ権限エラー
|
||||
"E010204", // ユーザ不在エラー
|
||||
"E010205", // DBのRoleが想定外の値エラー
|
||||
"E010206", // DBのTierが想定外の値エラー
|
||||
"E010207", // ユーザーのRole変更不可エラー
|
||||
"E010208", // ユーザーの暗号化パスワード不足エラー
|
||||
"E010301", // メールアドレス登録済みエラー
|
||||
"E010302", // authorId重複エラー
|
||||
"E010401", // PONumber重複エラー
|
||||
"E010501", // アカウント不在エラー
|
||||
"E010601", // タスク変更不可エラー(タスクが変更できる状態でない、またはタスクが存在しない)
|
||||
"E010602", // タスク変更権限不足エラー
|
||||
"E010603", // タスク不在エラー
|
||||
"E010701", // Blobファイル不在エラー
|
||||
"E010801", // ライセンス不在エラー
|
||||
"E010802", // ライセンス取り込み済みエラー
|
||||
] as const;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { createSlice } from "@reduxjs/toolkit";
|
||||
import { PayloadAction, createSlice } from "@reduxjs/toolkit";
|
||||
import { LicenseOrderHistoryState } from "./state";
|
||||
import { getLicenseOrderHistoriesAsync } from "./operations";
|
||||
import { LIMIT_ORDER_HISORY_NUM } from "./constants";
|
||||
@ -7,6 +7,7 @@ const initialState: LicenseOrderHistoryState = {
|
||||
domain: {
|
||||
total: 0,
|
||||
orderHistories: [],
|
||||
companyName: "",
|
||||
},
|
||||
apps: {
|
||||
limit: LIMIT_ORDER_HISORY_NUM,
|
||||
@ -23,6 +24,17 @@ export const licenseOrderHistorySlice = createSlice({
|
||||
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(getLicenseOrderHistoriesAsync.pending, (state) => {
|
||||
@ -31,8 +43,9 @@ export const licenseOrderHistorySlice = createSlice({
|
||||
builder.addCase(
|
||||
getLicenseOrderHistoriesAsync.fulfilled,
|
||||
(state, action) => {
|
||||
state.domain.total = action.payload.total;
|
||||
state.domain.orderHistories = action.payload.orderHistories;
|
||||
state.domain.total = action.payload.histories.total;
|
||||
state.domain.orderHistories = action.payload.histories.orderHistories;
|
||||
state.domain.companyName = action.payload.companyName;
|
||||
state.apps.isLoading = false;
|
||||
}
|
||||
);
|
||||
@ -42,6 +55,6 @@ export const licenseOrderHistorySlice = createSlice({
|
||||
},
|
||||
});
|
||||
|
||||
export const { cleanupApps } = licenseOrderHistorySlice.actions;
|
||||
export const { cleanupApps, savePageInfo } = licenseOrderHistorySlice.actions;
|
||||
|
||||
export default licenseOrderHistorySlice.reducer;
|
||||
|
||||
@ -2,13 +2,14 @@ import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import type { RootState } from "app/store";
|
||||
import { getTranslationID } from "translation";
|
||||
import { openSnackbar } from "features/ui/uiSlice";
|
||||
import { AccountsApi, GetOrderHistoriesResponce } from "../../../api/api";
|
||||
import { AccountsApi } from "../../../api/api";
|
||||
import { Configuration } from "../../../api/configuration";
|
||||
import { ErrorObject, createErrorObject } from "../../../common/errors";
|
||||
import { OrderHistoryView } from "./types";
|
||||
|
||||
export const getLicenseOrderHistoriesAsync = createAsyncThunk<
|
||||
// 正常時の戻り値の型
|
||||
GetOrderHistoriesResponce,
|
||||
OrderHistoryView,
|
||||
{
|
||||
// パラメータ
|
||||
limit: number;
|
||||
@ -32,15 +33,18 @@ export const getLicenseOrderHistoriesAsync = createAsyncThunk<
|
||||
try {
|
||||
const { selectedRow } = state.partnerLicense.apps;
|
||||
let accountId = 0;
|
||||
let companyName = "";
|
||||
// 他の画面から指定されていない場合はログインアカウントのidを取得する
|
||||
if (!selectedRow) {
|
||||
const getMyAccountResponse = await accountsApi.getMyAccount({
|
||||
headers: { authorization: `Bearer ${accessToken}` },
|
||||
});
|
||||
// accountIDを返す
|
||||
// アカウントID,アカウント名を返す
|
||||
accountId = getMyAccountResponse.data.account.accountId;
|
||||
companyName = getMyAccountResponse.data.account.companyName;
|
||||
} else {
|
||||
accountId = selectedRow.accountId;
|
||||
companyName = selectedRow.companyName;
|
||||
}
|
||||
|
||||
const res = await accountsApi.getOrderHistories(
|
||||
@ -53,7 +57,11 @@ export const getLicenseOrderHistoriesAsync = createAsyncThunk<
|
||||
headers: { authorization: `Bearer ${accessToken}` },
|
||||
}
|
||||
);
|
||||
return res.data;
|
||||
const ret = {
|
||||
histories: res.data,
|
||||
companyName,
|
||||
};
|
||||
return ret;
|
||||
} catch (e) {
|
||||
// e ⇒ errorObjectに変換"
|
||||
const error = createErrorObject(e);
|
||||
|
||||
@ -4,6 +4,9 @@ import { ceil, floor } from "lodash";
|
||||
export const selectOrderHisory = (state: RootState) =>
|
||||
state.licenseOrderHistory.domain.orderHistories;
|
||||
|
||||
export const selectCompanyName = (state: RootState) =>
|
||||
state.licenseOrderHistory.domain.companyName;
|
||||
|
||||
export const selectTotal = (state: RootState) =>
|
||||
state.licenseOrderHistory.domain.total;
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@ export interface LicenseOrderHistoryState {
|
||||
export interface Domain {
|
||||
total: number;
|
||||
orderHistories: LicenseOrder[];
|
||||
companyName: string;
|
||||
}
|
||||
|
||||
export interface Apps {
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
import { GetOrderHistoriesResponse } from "../../../api/api";
|
||||
|
||||
export interface OrderHistoryView {
|
||||
histories: GetOrderHistoriesResponse;
|
||||
companyName: string;
|
||||
}
|
||||
@ -6,7 +6,7 @@ import { ACCOUNTS_VIEW_LIMIT } from "./constants";
|
||||
|
||||
const initialState: PartnerLicensesState = {
|
||||
domain: {
|
||||
myAccountInfo: { accountId: 0 },
|
||||
myAccountInfo: { accountId: 0, companyName: "" },
|
||||
total: 0,
|
||||
ownPartnerLicense: {
|
||||
accountId: 0,
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import type { RootState } from "app/store";
|
||||
import { getTranslationID } from "translation";
|
||||
import { USER_ROLES } from "components/auth/constants";
|
||||
import { openSnackbar } from "features/ui/uiSlice";
|
||||
import { SignupRequest, UsersApi, GetUsersResponse } from "../../api/api";
|
||||
import { getTranslationID } from "translation";
|
||||
import { GetUsersResponse, UsersApi } from "../../api/api";
|
||||
import { Configuration } from "../../api/configuration";
|
||||
import { ErrorObject, createErrorObject } from "../../common/errors";
|
||||
|
||||
@ -43,7 +44,7 @@ export const addUserAsync = createAsyncThunk<
|
||||
{
|
||||
/* Empty Object */
|
||||
},
|
||||
SignupRequest,
|
||||
void,
|
||||
{
|
||||
// rejectした時の返却値の型
|
||||
rejectValue: {
|
||||
@ -51,40 +52,25 @@ export const addUserAsync = createAsyncThunk<
|
||||
};
|
||||
}
|
||||
>("users/addUserAsync", async (args, thunkApi) => {
|
||||
const {
|
||||
name,
|
||||
email,
|
||||
role,
|
||||
authorId,
|
||||
typistGroupId,
|
||||
autoRenew,
|
||||
licenseAlert,
|
||||
notification,
|
||||
} = args;
|
||||
|
||||
// apiのConfigurationを取得する
|
||||
const { getState } = thunkApi;
|
||||
const state = getState() as RootState;
|
||||
const { configuration, accessToken } = state.auth;
|
||||
const config = new Configuration(configuration);
|
||||
const usersApi = new UsersApi(config);
|
||||
const { addUser } = state.user.apps;
|
||||
// roleがAUTHOR以外の場合、不要なプロパティをundefinedにする
|
||||
if (addUser.role !== USER_ROLES.AUTHOR) {
|
||||
addUser.authorId = undefined;
|
||||
addUser.encryption = undefined;
|
||||
addUser.prompt = undefined;
|
||||
addUser.encryptionPassword = undefined;
|
||||
}
|
||||
|
||||
try {
|
||||
await usersApi.signup(
|
||||
{
|
||||
name,
|
||||
email,
|
||||
role,
|
||||
authorId,
|
||||
typistGroupId,
|
||||
autoRenew,
|
||||
licenseAlert,
|
||||
notification,
|
||||
},
|
||||
{
|
||||
headers: { authorization: `Bearer ${accessToken}` },
|
||||
}
|
||||
);
|
||||
await usersApi.signup(addUser, {
|
||||
headers: { authorization: `Bearer ${accessToken}` },
|
||||
});
|
||||
thunkApi.dispatch(
|
||||
openSnackbar({
|
||||
level: "info",
|
||||
@ -119,3 +105,86 @@ export const addUserAsync = createAsyncThunk<
|
||||
return thunkApi.rejectWithValue({ error });
|
||||
}
|
||||
});
|
||||
|
||||
export const updateUserAsync = createAsyncThunk<
|
||||
{
|
||||
/* Empty Object */
|
||||
},
|
||||
void,
|
||||
{
|
||||
// rejectした時の返却値の型
|
||||
rejectValue: {
|
||||
error: ErrorObject;
|
||||
};
|
||||
}
|
||||
>("users/updateUserAsync", async (args, thunkApi) => {
|
||||
// apiのConfigurationを取得する
|
||||
const { getState } = thunkApi;
|
||||
const state = getState() as RootState;
|
||||
const { configuration, accessToken } = state.auth;
|
||||
const config = new Configuration(configuration);
|
||||
const usersApi = new UsersApi(config);
|
||||
const { updateUser } = state.user.apps;
|
||||
|
||||
const authorId =
|
||||
updateUser.role === USER_ROLES.AUTHOR ? updateUser.authorId : undefined;
|
||||
const encryption =
|
||||
updateUser.role === USER_ROLES.AUTHOR ? updateUser.encryption : undefined;
|
||||
const encryptionPassword =
|
||||
updateUser.role === USER_ROLES.AUTHOR
|
||||
? updateUser.encryptionPassword
|
||||
: undefined;
|
||||
const prompt =
|
||||
updateUser.role === USER_ROLES.AUTHOR ? updateUser.prompt : undefined;
|
||||
|
||||
try {
|
||||
await usersApi.updateUser(
|
||||
{
|
||||
id: updateUser.id,
|
||||
role: updateUser.role,
|
||||
authorId,
|
||||
encryption,
|
||||
encryptionPassword,
|
||||
prompt,
|
||||
autoRenew: updateUser.autoRenew,
|
||||
licenseAlart: updateUser.licenseAlert,
|
||||
notification: updateUser.notification,
|
||||
},
|
||||
{
|
||||
headers: { authorization: `Bearer ${accessToken}` },
|
||||
}
|
||||
);
|
||||
thunkApi.dispatch(
|
||||
openSnackbar({
|
||||
level: "info",
|
||||
message: getTranslationID("common.message.success"),
|
||||
})
|
||||
);
|
||||
return {};
|
||||
} catch (e) {
|
||||
// e ⇒ errorObjectに変換"z
|
||||
const error = createErrorObject(e);
|
||||
|
||||
let errorMessage = getTranslationID("common.message.internalServerError");
|
||||
|
||||
// Roleが変更できない
|
||||
if (error.code === "E010207") {
|
||||
errorMessage = getTranslationID("userListPage.message.roleChangeError");
|
||||
}
|
||||
// AuthorIdが重複している
|
||||
if (error.code === "E010302") {
|
||||
errorMessage = getTranslationID(
|
||||
"userListPage.message.authorIdConflictError"
|
||||
);
|
||||
}
|
||||
|
||||
thunkApi.dispatch(
|
||||
openSnackbar({
|
||||
level: "error",
|
||||
message: errorMessage,
|
||||
})
|
||||
);
|
||||
|
||||
return thunkApi.rejectWithValue({ error });
|
||||
}
|
||||
});
|
||||
|
||||
@ -1,15 +1,24 @@
|
||||
import { RootState } from "app/store";
|
||||
import { USER_ROLES } from "components/auth/constants";
|
||||
import { RoleType, UserView, isLicenseStatusType, isRoleType } from "./types";
|
||||
import {
|
||||
AddUser,
|
||||
RoleType,
|
||||
UserView,
|
||||
isLicenseStatusType,
|
||||
isRoleType,
|
||||
} from "./types";
|
||||
import { LICENSE_STATUS } from "./constants";
|
||||
|
||||
export const selectInputValidationErrors = (state: RootState) => {
|
||||
const { name, email, role, authorId } = state.user.apps.addUser;
|
||||
const { name, email, role, authorId, encryption, encryptionPassword } =
|
||||
state.user.apps.addUser;
|
||||
|
||||
// 必須項目のチェック
|
||||
const hasErrorEmptyName = name === "";
|
||||
const hasErrorEmptyEmail = email === "";
|
||||
const hasErrorEmptyAuthorId = role === USER_ROLES.AUTHOR && authorId === "";
|
||||
// Authorの場合、AuthorIDが必須(空文字,undefinedは不可)
|
||||
const hasErrorEmptyAuthorId =
|
||||
role === USER_ROLES.AUTHOR && (authorId === "" || !authorId);
|
||||
|
||||
const hasErrorIncorrectAuthorId = checkErrorIncorrectAuthorId(
|
||||
authorId ?? undefined,
|
||||
@ -18,14 +27,87 @@ export const selectInputValidationErrors = (state: RootState) => {
|
||||
|
||||
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
|
||||
@ -46,14 +128,15 @@ 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 selectTypistGroupId = (state: RootState) =>
|
||||
state.user.apps.addUser.typistGroupId;
|
||||
export const selectAutoRenew = (state: RootState) =>
|
||||
state.user.apps.addUser.autoRenew;
|
||||
export const selectLicenseAlert = (state: RootState) =>
|
||||
state.user.apps.addUser.licenseAlert;
|
||||
export const selectNtotification = (state: RootState) =>
|
||||
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;
|
||||
@ -138,3 +221,9 @@ const convertValueBasedOnRole = (
|
||||
typistGroupName: "-",
|
||||
};
|
||||
};
|
||||
|
||||
export const selectUpdateUser = (state: RootState) =>
|
||||
state.user.apps.updateUser;
|
||||
|
||||
export const selectHasPasswordMask = (state: RootState) =>
|
||||
state.user.apps.hasPasswordMask;
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { User } from "../../api/api";
|
||||
import { AddUser, UpdateUser } from "./types";
|
||||
|
||||
export interface UsersState {
|
||||
domain: Domain;
|
||||
@ -11,9 +12,8 @@ export interface Domain {
|
||||
|
||||
export interface Apps {
|
||||
addUser: AddUser;
|
||||
selectedUser: UpdateUser;
|
||||
updateUser: UpdateUser;
|
||||
hasPasswordMask: boolean;
|
||||
isLoading: boolean;
|
||||
}
|
||||
|
||||
export interface AddUser extends Omit<User, "id"> {
|
||||
typistGroupId?: number | undefined;
|
||||
}
|
||||
|
||||
@ -23,6 +23,32 @@ export interface UserView
|
||||
expiration: string;
|
||||
remaining: number | string;
|
||||
}
|
||||
export interface AddUser {
|
||||
name: string;
|
||||
role: RoleType;
|
||||
email: string;
|
||||
autoRenew: boolean;
|
||||
licenseAlert: boolean;
|
||||
notification: boolean;
|
||||
authorId?: string;
|
||||
encryption?: boolean;
|
||||
encryptionPassword?: string;
|
||||
prompt?: boolean;
|
||||
}
|
||||
|
||||
export interface UpdateUser {
|
||||
id: number;
|
||||
name: string;
|
||||
email: string;
|
||||
role: RoleType;
|
||||
authorId?: string | undefined;
|
||||
encryption?: boolean | undefined;
|
||||
encryptionPassword?: string | undefined;
|
||||
prompt?: boolean | undefined;
|
||||
autoRenew: boolean;
|
||||
licenseAlert: boolean;
|
||||
notification: boolean;
|
||||
}
|
||||
|
||||
export type RoleType = typeof USER_ROLES[keyof typeof USER_ROLES];
|
||||
|
||||
|
||||
@ -1,26 +1,51 @@
|
||||
import { PayloadAction, createSlice } from "@reduxjs/toolkit";
|
||||
import { USER_ROLES } from "components/auth/constants";
|
||||
import { UsersState } from "./state";
|
||||
import { addUserAsync, listUsersAsync } from "./operations";
|
||||
import { addUserAsync, listUsersAsync, updateUserAsync } from "./operations";
|
||||
import { RoleType } from "./types";
|
||||
|
||||
const initialState: UsersState = {
|
||||
domain: { users: [] },
|
||||
apps: {
|
||||
addUser: {
|
||||
updateUser: {
|
||||
id: 0,
|
||||
name: "",
|
||||
role: USER_ROLES.NONE,
|
||||
authorId: "",
|
||||
typistGroupName: [],
|
||||
email: "",
|
||||
emailVerified: true,
|
||||
role: USER_ROLES.NONE,
|
||||
authorId: undefined,
|
||||
encryption: undefined,
|
||||
encryptionPassword: undefined,
|
||||
prompt: undefined,
|
||||
autoRenew: true,
|
||||
licenseAlert: true,
|
||||
notification: true,
|
||||
encryption: true,
|
||||
licenseStatus: "",
|
||||
prompt: false,
|
||||
},
|
||||
selectedUser: {
|
||||
id: 0,
|
||||
name: "",
|
||||
email: "",
|
||||
role: USER_ROLES.NONE,
|
||||
authorId: undefined,
|
||||
encryption: undefined,
|
||||
encryptionPassword: undefined,
|
||||
prompt: undefined,
|
||||
autoRenew: true,
|
||||
licenseAlert: true,
|
||||
notification: true,
|
||||
},
|
||||
addUser: {
|
||||
name: "",
|
||||
role: USER_ROLES.NONE,
|
||||
email: "",
|
||||
autoRenew: true,
|
||||
licenseAlert: true,
|
||||
notification: true,
|
||||
authorId: "",
|
||||
encryption: false,
|
||||
prompt: false,
|
||||
encryptionPassword: "",
|
||||
},
|
||||
hasPasswordMask: false,
|
||||
isLoading: false,
|
||||
},
|
||||
};
|
||||
@ -48,13 +73,6 @@ export const userSlice = createSlice({
|
||||
const { authorId } = action.payload;
|
||||
state.apps.addUser.authorId = authorId;
|
||||
},
|
||||
changeTypistGroupId: (
|
||||
state,
|
||||
action: PayloadAction<{ typistGroupId: number | undefined }>
|
||||
) => {
|
||||
const { typistGroupId } = action.payload;
|
||||
state.apps.addUser.typistGroupId = typistGroupId;
|
||||
},
|
||||
changeAutoRenew: (state, action: PayloadAction<{ autoRenew: boolean }>) => {
|
||||
const { autoRenew } = action.payload;
|
||||
state.apps.addUser.autoRenew = autoRenew;
|
||||
@ -66,6 +84,24 @@ export const userSlice = createSlice({
|
||||
const { licenseAlert } = action.payload;
|
||||
state.apps.addUser.licenseAlert = licenseAlert;
|
||||
},
|
||||
changeEncryption: (
|
||||
state,
|
||||
action: PayloadAction<{ encryption: boolean }>
|
||||
) => {
|
||||
const { encryption } = action.payload;
|
||||
state.apps.addUser.encryption = encryption;
|
||||
},
|
||||
changePrompt: (state, action: PayloadAction<{ prompt: boolean }>) => {
|
||||
const { prompt } = action.payload;
|
||||
state.apps.addUser.prompt = prompt;
|
||||
},
|
||||
changeEncryptionPassword: (
|
||||
state,
|
||||
action: PayloadAction<{ encryptionPassword: string }>
|
||||
) => {
|
||||
const { encryptionPassword } = action.payload;
|
||||
state.apps.addUser.encryptionPassword = encryptionPassword;
|
||||
},
|
||||
changeNotification: (
|
||||
state,
|
||||
action: PayloadAction<{ notification: boolean }>
|
||||
@ -76,6 +112,108 @@ export const userSlice = createSlice({
|
||||
cleanupAddUser: (state) => {
|
||||
state.apps.addUser = initialState.apps.addUser;
|
||||
},
|
||||
changeUpdateUser: (state, action: PayloadAction<{ id: number }>) => {
|
||||
const { id } = action.payload;
|
||||
|
||||
const user = state.domain.users.find((x) => x.id === id);
|
||||
|
||||
if (!user) {
|
||||
return;
|
||||
}
|
||||
|
||||
state.apps.updateUser.id = user.id;
|
||||
state.apps.updateUser.name = user.name;
|
||||
state.apps.updateUser.email = user.email;
|
||||
state.apps.updateUser.role = user.role as RoleType;
|
||||
state.apps.updateUser.authorId = user.authorId;
|
||||
state.apps.updateUser.encryption = user.encryption;
|
||||
state.apps.updateUser.encryptionPassword = undefined;
|
||||
state.apps.updateUser.prompt = user.prompt;
|
||||
state.apps.updateUser.autoRenew = user.autoRenew;
|
||||
state.apps.updateUser.licenseAlert = user.licenseAlert;
|
||||
state.apps.updateUser.notification = user.notification;
|
||||
|
||||
state.apps.selectedUser.id = user.id;
|
||||
state.apps.selectedUser.name = user.name;
|
||||
state.apps.selectedUser.email = user.email;
|
||||
state.apps.selectedUser.role = user.role as RoleType;
|
||||
state.apps.selectedUser.authorId = user.authorId;
|
||||
state.apps.selectedUser.encryption = user.encryption;
|
||||
state.apps.selectedUser.encryptionPassword = undefined;
|
||||
state.apps.selectedUser.prompt = user.prompt;
|
||||
state.apps.selectedUser.autoRenew = user.autoRenew;
|
||||
state.apps.selectedUser.licenseAlert = user.licenseAlert;
|
||||
state.apps.selectedUser.notification = user.notification;
|
||||
|
||||
state.apps.hasPasswordMask = user.encryption;
|
||||
},
|
||||
changeUpdateRole: (state, action: PayloadAction<{ role: RoleType }>) => {
|
||||
const { role } = action.payload;
|
||||
state.apps.updateUser.role = role;
|
||||
},
|
||||
changeUpdateAuthorId: (
|
||||
state,
|
||||
action: PayloadAction<{ authorId: string }>
|
||||
) => {
|
||||
const { authorId } = action.payload;
|
||||
state.apps.updateUser.authorId = authorId;
|
||||
},
|
||||
changeUpdateEncryption: (
|
||||
state,
|
||||
action: PayloadAction<{ encryption: boolean }>
|
||||
) => {
|
||||
const { encryption } = action.payload;
|
||||
state.apps.updateUser.encryption = encryption;
|
||||
const initEncryption = state.apps.selectedUser.encryption;
|
||||
const password = state.apps.updateUser.encryptionPassword;
|
||||
|
||||
if (initEncryption && encryption && !password) {
|
||||
state.apps.hasPasswordMask = true;
|
||||
}
|
||||
},
|
||||
changeUpdateEncryptionPassword: (
|
||||
state,
|
||||
action: PayloadAction<{ encryptionPassword: string }>
|
||||
) => {
|
||||
const { encryptionPassword } = action.payload;
|
||||
state.apps.updateUser.encryptionPassword =
|
||||
encryptionPassword === "" ? undefined : encryptionPassword;
|
||||
},
|
||||
changeUpdatePrompt: (state, action: PayloadAction<{ prompt: boolean }>) => {
|
||||
const { prompt } = action.payload;
|
||||
state.apps.updateUser.prompt = prompt;
|
||||
},
|
||||
changeUpdateAutoRenew: (
|
||||
state,
|
||||
action: PayloadAction<{ autoRenew: boolean }>
|
||||
) => {
|
||||
const { autoRenew } = action.payload;
|
||||
state.apps.updateUser.autoRenew = autoRenew;
|
||||
},
|
||||
changeUpdateLicenseAlert: (
|
||||
state,
|
||||
action: PayloadAction<{ licenseAlert: boolean }>
|
||||
) => {
|
||||
const { licenseAlert } = action.payload;
|
||||
state.apps.updateUser.licenseAlert = licenseAlert;
|
||||
},
|
||||
changeUpdateNotification: (
|
||||
state,
|
||||
action: PayloadAction<{ notification: boolean }>
|
||||
) => {
|
||||
const { notification } = action.payload;
|
||||
state.apps.updateUser.notification = notification;
|
||||
},
|
||||
changeHasPasswordMask: (
|
||||
state,
|
||||
action: PayloadAction<{ hasPasswordMask: boolean }>
|
||||
) => {
|
||||
const { hasPasswordMask } = action.payload;
|
||||
state.apps.hasPasswordMask = hasPasswordMask;
|
||||
},
|
||||
cleanupUpdateUser: (state) => {
|
||||
state.apps.updateUser = initialState.apps.updateUser;
|
||||
},
|
||||
},
|
||||
extraReducers: (builder) => {
|
||||
builder.addCase(listUsersAsync.pending, (state) => {
|
||||
@ -97,6 +235,15 @@ export const userSlice = createSlice({
|
||||
builder.addCase(addUserAsync.rejected, (state) => {
|
||||
state.apps.isLoading = false;
|
||||
});
|
||||
builder.addCase(updateUserAsync.pending, (state) => {
|
||||
state.apps.isLoading = true;
|
||||
});
|
||||
builder.addCase(updateUserAsync.fulfilled, (state) => {
|
||||
state.apps.isLoading = false;
|
||||
});
|
||||
builder.addCase(updateUserAsync.rejected, (state) => {
|
||||
state.apps.isLoading = false;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@ -105,11 +252,24 @@ export const {
|
||||
changeEmail,
|
||||
changeRole,
|
||||
changeAuthorId,
|
||||
changeTypistGroupId,
|
||||
changeAutoRenew,
|
||||
changeLicenseAlert,
|
||||
changeNotification,
|
||||
cleanupAddUser,
|
||||
changeUpdateUser,
|
||||
changeUpdateRole,
|
||||
changeUpdateAuthorId,
|
||||
changeUpdateEncryption,
|
||||
changeUpdateEncryptionPassword,
|
||||
changeUpdatePrompt,
|
||||
changeUpdateAutoRenew,
|
||||
changeUpdateLicenseAlert,
|
||||
changeUpdateNotification,
|
||||
cleanupUpdateUser,
|
||||
changeEncryption,
|
||||
changePrompt,
|
||||
changeEncryptionPassword,
|
||||
changeHasPasswordMask,
|
||||
} = userSlice.actions;
|
||||
|
||||
export default userSlice.reducer;
|
||||
|
||||
@ -1098,7 +1098,9 @@ const DictationPage: React.FC = (): JSX.Element => {
|
||||
<td className={styles.clm6}>{x.workType}</td>
|
||||
)}
|
||||
{displayColumn.FileName && (
|
||||
<td className={styles.clm7}>{x.fileName}</td>
|
||||
<td className={styles.clm7}>
|
||||
{x.fileName.replace(".zip", "")}
|
||||
</td>
|
||||
)}
|
||||
{displayColumn.FileLength && (
|
||||
<td className={styles.clm8}>{x.audioDuration}</td>
|
||||
|
||||
@ -17,6 +17,9 @@ import {
|
||||
selectOrderHisory,
|
||||
selectTotal,
|
||||
selectTotalPage,
|
||||
selectOffset,
|
||||
savePageInfo,
|
||||
selectCompanyName,
|
||||
} from "features/license/licenseOrderHistory";
|
||||
import { selectSelectedRow } from "features/license/partnerLicense";
|
||||
import undo from "../../assets/images/undo.svg";
|
||||
@ -34,6 +37,7 @@ export const LicenseOrderHistory: React.FC<LicenseOrderHistoryProps> = (
|
||||
const [t] = useTranslation();
|
||||
const total = useSelector(selectTotal);
|
||||
const totalPage = useSelector(selectTotalPage);
|
||||
const offset = useSelector(selectOffset);
|
||||
const currentPage = useSelector(selectCurrentPage);
|
||||
const isLoading = useSelector(selectIsLoading);
|
||||
const selectedRow = useSelector(selectSelectedRow);
|
||||
@ -47,56 +51,25 @@ export const LicenseOrderHistory: React.FC<LicenseOrderHistoryProps> = (
|
||||
}, [isLoading, onReturn]);
|
||||
|
||||
// ページネーションのボタンクリック時のアクション
|
||||
const getFirstPage = useCallback(() => {
|
||||
const movePage = (targetOffset: number) => {
|
||||
dispatch(
|
||||
getLicenseOrderHistoriesAsync({
|
||||
limit: LIMIT_ORDER_HISORY_NUM,
|
||||
offset: 0,
|
||||
})
|
||||
savePageInfo({ limit: LIMIT_ORDER_HISORY_NUM, offset: targetOffset })
|
||||
);
|
||||
}, [dispatch]);
|
||||
|
||||
const getLastPage = useCallback(() => {
|
||||
const lastPageOffset = (totalPage - 1) * LIMIT_ORDER_HISORY_NUM;
|
||||
dispatch(
|
||||
getLicenseOrderHistoriesAsync({
|
||||
limit: LIMIT_ORDER_HISORY_NUM,
|
||||
offset: lastPageOffset,
|
||||
})
|
||||
);
|
||||
}, [dispatch, totalPage]);
|
||||
|
||||
const getPrevPage = useCallback(() => {
|
||||
const prevPageOffset = (currentPage - 2) * LIMIT_ORDER_HISORY_NUM;
|
||||
dispatch(
|
||||
getLicenseOrderHistoriesAsync({
|
||||
limit: LIMIT_ORDER_HISORY_NUM,
|
||||
offset: prevPageOffset,
|
||||
})
|
||||
);
|
||||
}, [dispatch, currentPage]);
|
||||
|
||||
const getNextPage = useCallback(() => {
|
||||
const nextPageOffset = currentPage * LIMIT_ORDER_HISORY_NUM;
|
||||
dispatch(
|
||||
getLicenseOrderHistoriesAsync({
|
||||
limit: LIMIT_ORDER_HISORY_NUM,
|
||||
offset: nextPageOffset,
|
||||
})
|
||||
);
|
||||
}, [dispatch, currentPage]);
|
||||
};
|
||||
|
||||
// apiからの値取得関係
|
||||
const licenseOrderHistory = useSelector(selectOrderHisory);
|
||||
const companyName = useSelector(selectCompanyName);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(
|
||||
getLicenseOrderHistoriesAsync({
|
||||
limit: LIMIT_ORDER_HISORY_NUM,
|
||||
offset: 0,
|
||||
offset,
|
||||
})
|
||||
);
|
||||
}, [dispatch]);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [dispatch, currentPage]);
|
||||
|
||||
return (
|
||||
<div className={styles.wrap}>
|
||||
@ -104,7 +77,7 @@ export const LicenseOrderHistory: React.FC<LicenseOrderHistoryProps> = (
|
||||
|
||||
<UpdateTokenTimer />
|
||||
<main className={styles.main}>
|
||||
<div className="">
|
||||
<div>
|
||||
<div className={styles.pageHeader}>
|
||||
<h1 className={styles.pageTitle}>
|
||||
{t(getTranslationID("orderHistoriesPage.label.title"))}
|
||||
@ -112,13 +85,12 @@ export const LicenseOrderHistory: React.FC<LicenseOrderHistoryProps> = (
|
||||
</div>
|
||||
<section className={styles.license}>
|
||||
<div>
|
||||
<h2 className="">
|
||||
{t(getTranslationID("orderHistoriesPage.label.subTitle"))}
|
||||
<p className={styles.brCrumb}>
|
||||
<img src={history} alt="" className={styles.tlIcon} />
|
||||
{t(getTranslationID("orderHistoriesPage.label.orderHistory"))}
|
||||
</p>
|
||||
</h2>
|
||||
<h2>{companyName}</h2>
|
||||
<p className={styles.brCrumb}>
|
||||
<img src={history} alt="" className={styles.tlIcon} />
|
||||
{t(getTranslationID("orderHistoriesPage.label.orderHistory"))}
|
||||
</p>
|
||||
|
||||
<ul className={styles.menuAction}>
|
||||
<li>
|
||||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
|
||||
@ -166,7 +138,7 @@ export const LicenseOrderHistory: React.FC<LicenseOrderHistoryProps> = (
|
||||
// eslint-disable-next-line react/jsx-key
|
||||
<tr>
|
||||
<td>{x.orderDate}</td>
|
||||
<td>{x.issueDate}</td>
|
||||
<td>{x.issueDate ? x.issueDate : "-"}</td>
|
||||
<td>{x.numberOfOrder}</td>
|
||||
<td>{x.poNumber}</td>
|
||||
<td>
|
||||
@ -267,17 +239,19 @@ export const LicenseOrderHistory: React.FC<LicenseOrderHistoryProps> = (
|
||||
/>
|
||||
)}
|
||||
{/** pagenation */}
|
||||
<div className={styles.pagenation}>
|
||||
<div className={`${styles.pagenation} ${styles.widthMid}`}>
|
||||
<nav className={styles.pagenationNav}>
|
||||
<span className={styles.pagenationTotal}>{`${total} ${t(
|
||||
getTranslationID("orderHistoriesPage.label.title")
|
||||
getTranslationID("orderHistoriesPage.label.histories")
|
||||
)}`}</span>
|
||||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
|
||||
<a
|
||||
className={`${
|
||||
!isLoading && currentPage !== 1 ? styles.isActive : ""
|
||||
}`}
|
||||
onClick={getFirstPage}
|
||||
onClick={() => {
|
||||
movePage(0);
|
||||
}}
|
||||
>
|
||||
«
|
||||
</a>
|
||||
@ -286,11 +260,15 @@ export const LicenseOrderHistory: React.FC<LicenseOrderHistoryProps> = (
|
||||
className={`${
|
||||
!isLoading && currentPage !== 1 ? styles.isActive : ""
|
||||
}`}
|
||||
onClick={getPrevPage}
|
||||
onClick={() => {
|
||||
movePage((currentPage - 2) * LIMIT_ORDER_HISORY_NUM);
|
||||
}}
|
||||
>
|
||||
‹
|
||||
</a>
|
||||
{`${currentPage} of ${totalPage}`}
|
||||
{` ${total !== 0 ? currentPage : 0} of ${
|
||||
total !== 0 ? totalPage : 0
|
||||
} `}
|
||||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
|
||||
<a
|
||||
className={`${
|
||||
@ -298,7 +276,9 @@ export const LicenseOrderHistory: React.FC<LicenseOrderHistoryProps> = (
|
||||
? styles.isActive
|
||||
: ""
|
||||
}`}
|
||||
onClick={getNextPage}
|
||||
onClick={() => {
|
||||
movePage(currentPage * LIMIT_ORDER_HISORY_NUM);
|
||||
}}
|
||||
>
|
||||
›
|
||||
</a>
|
||||
@ -309,7 +289,9 @@ export const LicenseOrderHistory: React.FC<LicenseOrderHistoryProps> = (
|
||||
? styles.isActive
|
||||
: ""
|
||||
}`}
|
||||
onClick={getLastPage}
|
||||
onClick={() => {
|
||||
movePage((totalPage - 1) * LIMIT_ORDER_HISORY_NUM);
|
||||
}}
|
||||
>
|
||||
»
|
||||
</a>
|
||||
|
||||
@ -16,22 +16,33 @@ import { isLicenseStatusType } from "features/user/types";
|
||||
import { LICENSE_STATUS } from "features/user/constants";
|
||||
import { isApproveTier } from "features/auth/utils";
|
||||
import { TIERS } from "components/auth/constants";
|
||||
import { changeUpdateUser } from "features/user/userSlice";
|
||||
import personAdd from "../../assets/images/person_add.svg";
|
||||
import checkFill from "../../assets/images/check_fill.svg";
|
||||
import checkOutline from "../../assets/images/check_outline.svg";
|
||||
import progress_activit from "../../assets/images/progress_activit.svg";
|
||||
import { UserAddPopup } from "./popup";
|
||||
import { UserUpdatePopup } from "./updatePopup";
|
||||
|
||||
const UserListPage: React.FC = (): JSX.Element => {
|
||||
const dispatch: AppDispatch = useDispatch();
|
||||
const [t] = useTranslation();
|
||||
|
||||
const [isPopupOpen, setIsPopupOpen] = useState(false);
|
||||
const [isUpdatePopupOpen, setIsUpdatePopupOpen] = useState(false);
|
||||
|
||||
const onOpen = useCallback(() => {
|
||||
setIsPopupOpen(true);
|
||||
}, [setIsPopupOpen]);
|
||||
|
||||
const onUpdateOpen = useCallback(
|
||||
(id: number) => {
|
||||
setIsUpdatePopupOpen(true);
|
||||
dispatch(changeUpdateUser({ id }));
|
||||
},
|
||||
[setIsUpdatePopupOpen, dispatch]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
// ユーザ一覧取得処理を呼び出す
|
||||
dispatch(listUsersAsync());
|
||||
@ -44,6 +55,13 @@ const UserListPage: React.FC = (): JSX.Element => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<UserUpdatePopup
|
||||
isOpen={isUpdatePopupOpen}
|
||||
onClose={() => {
|
||||
setIsUpdatePopupOpen(false);
|
||||
dispatch(listUsersAsync());
|
||||
}}
|
||||
/>
|
||||
<UserAddPopup
|
||||
isOpen={isPopupOpen}
|
||||
onClose={() => {
|
||||
@ -130,7 +148,12 @@ const UserListPage: React.FC = (): JSX.Element => {
|
||||
<td className={styles.clm0}>
|
||||
<ul className={styles.menuInTable}>
|
||||
<li>
|
||||
<a href="">
|
||||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
|
||||
<a
|
||||
onClick={() => {
|
||||
onUpdateOpen(user.id);
|
||||
}}
|
||||
>
|
||||
{t(
|
||||
getTranslationID(
|
||||
"userListPage.label.editUser"
|
||||
|
||||
@ -9,22 +9,17 @@ import {
|
||||
changeName,
|
||||
changeRole,
|
||||
changeAuthorId,
|
||||
changeTypistGroupId,
|
||||
changeAutoRenew,
|
||||
changeLicenseAlert,
|
||||
changeNotification,
|
||||
cleanupAddUser,
|
||||
selectName,
|
||||
selectEmail,
|
||||
selectRole,
|
||||
selectAuthorId,
|
||||
selectTypistGroupId,
|
||||
selectInputValidationErrors,
|
||||
selectAutoRenew,
|
||||
selectLicenseAlert,
|
||||
selectNtotification,
|
||||
addUserAsync,
|
||||
selectAddUser,
|
||||
selectInputValidationErrors,
|
||||
selectIsLoading,
|
||||
changePrompt,
|
||||
changeEncryption,
|
||||
changeEncryptionPassword,
|
||||
} from "features/user";
|
||||
import { USER_ROLES } from "components/auth/constants";
|
||||
import close from "../../assets/images/close.svg";
|
||||
@ -39,6 +34,9 @@ export const UserAddPopup: React.FC<UserAddPopupProps> = (props) => {
|
||||
const { isOpen, onClose } = props;
|
||||
const dispatch: AppDispatch = useDispatch();
|
||||
const { t } = useTranslation();
|
||||
const [isPasswordHide, setIsPasswordHide] = useState<boolean>(true);
|
||||
// AddUserの情報を取得
|
||||
const addUser = useSelector(selectAddUser);
|
||||
|
||||
const closePopup = useCallback(() => {
|
||||
setIsPushCreateButton(false);
|
||||
@ -52,17 +50,9 @@ export const UserAddPopup: React.FC<UserAddPopupProps> = (props) => {
|
||||
hasErrorEmptyAuthorId,
|
||||
hasErrorIncorrectEmail,
|
||||
hasErrorIncorrectAuthorId,
|
||||
hasErrorIncorrectEncryptionPassword,
|
||||
} = useSelector(selectInputValidationErrors);
|
||||
|
||||
const name = useSelector(selectName);
|
||||
const email = useSelector(selectEmail);
|
||||
const role = useSelector(selectRole);
|
||||
const authorId = useSelector(selectAuthorId);
|
||||
const typistGroupId = useSelector(selectTypistGroupId);
|
||||
const autoRenew = useSelector(selectAutoRenew);
|
||||
const licenseAlert = useSelector(selectLicenseAlert);
|
||||
const notification = useSelector(selectNtotification);
|
||||
|
||||
const [isPushCreateButton, setIsPushCreateButton] = useState<boolean>(false);
|
||||
|
||||
const isLoading = useSelector(selectIsLoading);
|
||||
@ -74,51 +64,27 @@ export const UserAddPopup: React.FC<UserAddPopupProps> = (props) => {
|
||||
hasErrorEmptyEmail ||
|
||||
hasErrorEmptyAuthorId ||
|
||||
hasErrorIncorrectEmail ||
|
||||
hasErrorIncorrectAuthorId
|
||||
hasErrorIncorrectAuthorId ||
|
||||
hasErrorIncorrectEncryptionPassword
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (role !== USER_ROLES.AUTHOR) {
|
||||
changeAuthorId({ authorId: undefined });
|
||||
}
|
||||
if (role !== USER_ROLES.TYPIST) {
|
||||
changeTypistGroupId({ typistGroupId: undefined });
|
||||
}
|
||||
|
||||
const { meta } = await dispatch(
|
||||
addUserAsync({
|
||||
name,
|
||||
email,
|
||||
role,
|
||||
authorId:
|
||||
role === USER_ROLES.AUTHOR ? authorId ?? undefined : undefined,
|
||||
typistGroupId: role === USER_ROLES.TYPIST ? typistGroupId : undefined,
|
||||
autoRenew,
|
||||
licenseAlert,
|
||||
notification,
|
||||
})
|
||||
);
|
||||
const { meta } = await dispatch(addUserAsync());
|
||||
setIsPushCreateButton(false);
|
||||
|
||||
if (meta.requestStatus === "fulfilled") {
|
||||
closePopup();
|
||||
}
|
||||
}, [
|
||||
dispatch,
|
||||
closePopup,
|
||||
hasErrorEmptyName,
|
||||
hasErrorEmptyEmail,
|
||||
hasErrorEmptyAuthorId,
|
||||
hasErrorIncorrectEmail,
|
||||
hasErrorIncorrectAuthorId,
|
||||
name,
|
||||
email,
|
||||
role,
|
||||
authorId,
|
||||
typistGroupId,
|
||||
autoRenew,
|
||||
licenseAlert,
|
||||
notification,
|
||||
hasErrorIncorrectEncryptionPassword,
|
||||
dispatch,
|
||||
closePopup,
|
||||
]);
|
||||
|
||||
return (
|
||||
@ -142,7 +108,7 @@ export const UserAddPopup: React.FC<UserAddPopupProps> = (props) => {
|
||||
size={40}
|
||||
maxLength={255}
|
||||
className={styles.formInput}
|
||||
value={name}
|
||||
value={addUser.name}
|
||||
onChange={(e) => {
|
||||
dispatch(changeName({ name: e.target.value }));
|
||||
}}
|
||||
@ -160,7 +126,7 @@ export const UserAddPopup: React.FC<UserAddPopupProps> = (props) => {
|
||||
size={40}
|
||||
maxLength={255}
|
||||
className={styles.formInput}
|
||||
value={email}
|
||||
value={addUser.email}
|
||||
onChange={(e) => {
|
||||
dispatch(changeEmail({ email: e.target.value }));
|
||||
}}
|
||||
@ -182,10 +148,11 @@ export const UserAddPopup: React.FC<UserAddPopupProps> = (props) => {
|
||||
<dd>
|
||||
<label htmlFor={USER_ROLES.AUTHOR}>
|
||||
<input
|
||||
id={USER_ROLES.AUTHOR}
|
||||
type="radio"
|
||||
name="role"
|
||||
className={styles.formRadio}
|
||||
checked={role === USER_ROLES.AUTHOR}
|
||||
checked={addUser.role === USER_ROLES.AUTHOR}
|
||||
onChange={() => {
|
||||
dispatch(changeRole({ role: USER_ROLES.AUTHOR }));
|
||||
}}
|
||||
@ -194,10 +161,11 @@ export const UserAddPopup: React.FC<UserAddPopupProps> = (props) => {
|
||||
</label>
|
||||
<label htmlFor={USER_ROLES.TYPIST}>
|
||||
<input
|
||||
id={USER_ROLES.TYPIST}
|
||||
type="radio"
|
||||
name="role"
|
||||
className={styles.formRadio}
|
||||
checked={role === USER_ROLES.TYPIST}
|
||||
checked={addUser.role === USER_ROLES.TYPIST}
|
||||
onChange={() => {
|
||||
dispatch(changeRole({ role: USER_ROLES.TYPIST }));
|
||||
}}
|
||||
@ -206,10 +174,11 @@ export const UserAddPopup: React.FC<UserAddPopupProps> = (props) => {
|
||||
</label>
|
||||
<label htmlFor={USER_ROLES.NONE}>
|
||||
<input
|
||||
id={USER_ROLES.NONE}
|
||||
type="radio"
|
||||
name="role"
|
||||
className={styles.formRadio}
|
||||
checked={role === USER_ROLES.NONE}
|
||||
checked={addUser.role === USER_ROLES.NONE}
|
||||
onChange={() => {
|
||||
dispatch(changeRole({ role: USER_ROLES.NONE }));
|
||||
}}
|
||||
@ -218,7 +187,7 @@ export const UserAddPopup: React.FC<UserAddPopupProps> = (props) => {
|
||||
</label>
|
||||
</dd>
|
||||
{/** Author 選択時に表示 */}
|
||||
{role === USER_ROLES.AUTHOR && (
|
||||
{addUser.role === USER_ROLES.AUTHOR && (
|
||||
<div className={styles.slideSet} id="">
|
||||
<dt>{t(getTranslationID("userListPage.label.authorID"))}</dt>
|
||||
<dd>
|
||||
@ -227,7 +196,7 @@ export const UserAddPopup: React.FC<UserAddPopupProps> = (props) => {
|
||||
size={40}
|
||||
maxLength={16}
|
||||
className={styles.formInput}
|
||||
value={authorId ?? undefined}
|
||||
value={addUser.authorId ?? undefined}
|
||||
onChange={(e) => {
|
||||
dispatch(changeAuthorId({ authorId: e.target.value }));
|
||||
}}
|
||||
@ -249,38 +218,88 @@ export const UserAddPopup: React.FC<UserAddPopupProps> = (props) => {
|
||||
</span>
|
||||
)}
|
||||
</dd>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/** Transcriptionist 選択時に表示 */}
|
||||
{role === USER_ROLES.TYPIST && (
|
||||
<div className={styles.slideSet} id="">
|
||||
<dt className={`${styles.overLine} ${styles.marginBtm0}`}>
|
||||
{t(getTranslationID("userListPage.label.addToGroup"))}
|
||||
</dt>
|
||||
<dt>{t(getTranslationID("userListPage.label.encryption"))}</dt>
|
||||
<dd>
|
||||
<select
|
||||
className={styles.formInput}
|
||||
onChange={(e) => {
|
||||
dispatch(
|
||||
changeTypistGroupId({
|
||||
typistGroupId: Number(e.target.value),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
{/** XXX: タイピストグループは後ほど差し替える */}
|
||||
<option value={0}>
|
||||
{t(getTranslationID("userListPage.label.selectGroup"))}
|
||||
</option>
|
||||
<option value={1}>Tgroup A</option>
|
||||
<option value={2}>Tgroup B</option>
|
||||
<option value={3}>Tgroup C</option>
|
||||
</select>
|
||||
<label htmlFor="encryption">
|
||||
<input
|
||||
type="checkbox"
|
||||
className={styles.formCheck}
|
||||
checked={addUser.encryption}
|
||||
onChange={(e) => {
|
||||
dispatch(
|
||||
changeEncryption({ encryption: e.target.checked })
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</label>
|
||||
{addUser.encryption && (
|
||||
<p className={`${styles.encryptionPass} ${styles.isShow}`}>
|
||||
{t(
|
||||
getTranslationID(
|
||||
"userListPage.label.encryptionPassword"
|
||||
)
|
||||
)}
|
||||
<input
|
||||
type={isPasswordHide ? "password" : "text"}
|
||||
size={40}
|
||||
maxLength={16}
|
||||
className={`${styles.formInput} ${styles.password}`}
|
||||
value={addUser.encryptionPassword ?? undefined}
|
||||
onChange={(e) => {
|
||||
dispatch(
|
||||
changeEncryptionPassword({
|
||||
encryptionPassword: e.target.value,
|
||||
})
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<span
|
||||
className={styles.formIconEye}
|
||||
onClick={() => {
|
||||
setIsPasswordHide(!isPasswordHide);
|
||||
}}
|
||||
onKeyDown={() => {
|
||||
setIsPasswordHide(!isPasswordHide);
|
||||
}}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label="IconEye"
|
||||
/>
|
||||
{isPushCreateButton &&
|
||||
hasErrorIncorrectEncryptionPassword && (
|
||||
<span className={styles.formError}>
|
||||
{t(
|
||||
getTranslationID(
|
||||
"userListPage.message.encryptionPasswordCorrectError"
|
||||
)
|
||||
)}
|
||||
</span>
|
||||
)}
|
||||
<span className={styles.formComment}>
|
||||
{t(
|
||||
getTranslationID(
|
||||
"userListPage.label.encryptionPasswordTerm"
|
||||
)
|
||||
)}
|
||||
</span>
|
||||
</p>
|
||||
)}
|
||||
</dd>
|
||||
<dt>{t(getTranslationID("userListPage.label.prompt"))}</dt>
|
||||
<dd>
|
||||
<label htmlFor="prompt">
|
||||
<input
|
||||
type="checkbox"
|
||||
className={styles.formCheck}
|
||||
checked={addUser.prompt}
|
||||
onChange={(e) => {
|
||||
dispatch(changePrompt({ prompt: e.target.checked }));
|
||||
}}
|
||||
/>
|
||||
</label>
|
||||
</dd>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<dt>{t(getTranslationID("userListPage.label.setting"))}</dt>
|
||||
<dd className={styles.last}>
|
||||
<p>
|
||||
@ -288,7 +307,7 @@ export const UserAddPopup: React.FC<UserAddPopupProps> = (props) => {
|
||||
<input
|
||||
type="checkbox"
|
||||
className={styles.formCheck}
|
||||
checked={autoRenew}
|
||||
checked={addUser.autoRenew}
|
||||
onChange={(e) => {
|
||||
dispatch(
|
||||
changeAutoRenew({ autoRenew: e.target.checked })
|
||||
@ -302,7 +321,7 @@ export const UserAddPopup: React.FC<UserAddPopupProps> = (props) => {
|
||||
<label htmlFor="License Alert">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={licenseAlert}
|
||||
checked={addUser.licenseAlert}
|
||||
className={styles.formCheck}
|
||||
onChange={(e) => {
|
||||
dispatch(
|
||||
@ -317,7 +336,7 @@ export const UserAddPopup: React.FC<UserAddPopupProps> = (props) => {
|
||||
<label htmlFor="Notification">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={notification}
|
||||
checked={addUser.notification}
|
||||
className={styles.formCheck}
|
||||
onChange={(e) => {
|
||||
dispatch(
|
||||
|
||||
389
dictation_client/src/pages/UserListPage/updatePopup.tsx
Normal file
389
dictation_client/src/pages/UserListPage/updatePopup.tsx
Normal file
@ -0,0 +1,389 @@
|
||||
import { AppDispatch } from "app/store";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import styles from "styles/app.module.scss";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { USER_ROLES } from "components/auth/constants";
|
||||
import {
|
||||
changeUpdateAuthorId,
|
||||
changeUpdateAutoRenew,
|
||||
changeUpdateEncryption,
|
||||
changeUpdateEncryptionPassword,
|
||||
changeUpdateLicenseAlert,
|
||||
changeUpdateNotification,
|
||||
changeUpdatePrompt,
|
||||
changeUpdateRole,
|
||||
changeHasPasswordMask,
|
||||
cleanupUpdateUser,
|
||||
selectHasPasswordMask,
|
||||
selectIsLoading,
|
||||
selectUpdateUser,
|
||||
selectUpdateValidationErrors,
|
||||
updateUserAsync,
|
||||
} from "features/user";
|
||||
import { getTranslationID } from "translation";
|
||||
import close from "../../assets/images/close.svg";
|
||||
import progress_activit from "../../assets/images/progress_activit.svg";
|
||||
|
||||
interface UserUpdatePopupProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export const UserUpdatePopup: React.FC<UserUpdatePopupProps> = (props) => {
|
||||
const { isOpen, onClose } = props;
|
||||
const dispatch: AppDispatch = useDispatch();
|
||||
const { t } = useTranslation();
|
||||
const closePopup = useCallback(() => {
|
||||
setIsPushCreateButton(false);
|
||||
dispatch(cleanupUpdateUser());
|
||||
onClose();
|
||||
}, [onClose, dispatch]);
|
||||
|
||||
const {
|
||||
hasErrorEmptyAuthorId,
|
||||
hasErrorIncorrectAuthorId,
|
||||
hasErrorIncorrectEncryptionPassword,
|
||||
} = useSelector(selectUpdateValidationErrors);
|
||||
|
||||
const [isPasswordHide, setIsPasswordHide] = useState<boolean>(true);
|
||||
const [isPushCreateButton, setIsPushCreateButton] = useState<boolean>(false);
|
||||
const user = useSelector(selectUpdateUser);
|
||||
|
||||
const isLoading = useSelector(selectIsLoading);
|
||||
|
||||
const hasPasswordMask = useSelector(selectHasPasswordMask);
|
||||
|
||||
const [canChangeRole, setCanChangeRole] = useState(true);
|
||||
|
||||
// 開閉時のみ実行
|
||||
useEffect(() => {
|
||||
setCanChangeRole(user.role === USER_ROLES.NONE);
|
||||
setIsPasswordHide(true);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isOpen]);
|
||||
|
||||
const onUpdateUser = useCallback(async () => {
|
||||
setIsPushCreateButton(true);
|
||||
|
||||
if (
|
||||
hasErrorEmptyAuthorId ||
|
||||
hasErrorIncorrectAuthorId ||
|
||||
hasErrorIncorrectEncryptionPassword
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { meta } = await dispatch(updateUserAsync());
|
||||
setIsPushCreateButton(false);
|
||||
|
||||
if (meta.requestStatus === "fulfilled") {
|
||||
closePopup();
|
||||
}
|
||||
}, [
|
||||
dispatch,
|
||||
closePopup,
|
||||
hasErrorEmptyAuthorId,
|
||||
hasErrorIncorrectAuthorId,
|
||||
hasErrorIncorrectEncryptionPassword,
|
||||
]);
|
||||
|
||||
return (
|
||||
<div className={`${styles.modal} ${isOpen ? styles.isShow : ""}`}>
|
||||
<div className={styles.modalBox}>
|
||||
<p className={styles.modalTitle}>
|
||||
{t(getTranslationID("userListPage.label.editUser"))}
|
||||
<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}>
|
||||
{t(getTranslationID("userListPage.label.personal"))}
|
||||
</dt>
|
||||
<dt>{t(getTranslationID("userListPage.label.name"))}</dt>
|
||||
<dd>
|
||||
<input
|
||||
type="text"
|
||||
size={40}
|
||||
value={user.name}
|
||||
className={styles.formInput}
|
||||
readOnly
|
||||
/>
|
||||
</dd>
|
||||
<dt>{t(getTranslationID("userListPage.label.email"))}</dt>
|
||||
<dd>
|
||||
<input
|
||||
type="email"
|
||||
size={40}
|
||||
value={user.email}
|
||||
className={styles.formInput}
|
||||
readOnly
|
||||
/>
|
||||
</dd>
|
||||
<dt>{t(getTranslationID("userListPage.label.role"))}</dt>
|
||||
<dd>
|
||||
<label htmlFor={USER_ROLES.AUTHOR}>
|
||||
<input
|
||||
id={USER_ROLES.AUTHOR}
|
||||
type="radio"
|
||||
name="role"
|
||||
className={styles.formRadio}
|
||||
checked={user.role === USER_ROLES.AUTHOR}
|
||||
onChange={() => {
|
||||
dispatch(changeUpdateRole({ role: USER_ROLES.AUTHOR }));
|
||||
}}
|
||||
disabled={!canChangeRole}
|
||||
/>
|
||||
{t(getTranslationID("userListPage.label.author"))}
|
||||
</label>
|
||||
<label htmlFor={USER_ROLES.TYPIST}>
|
||||
<input
|
||||
id={USER_ROLES.TYPIST}
|
||||
type="radio"
|
||||
name="role"
|
||||
className={styles.formRadio}
|
||||
checked={user.role === USER_ROLES.TYPIST}
|
||||
onChange={() => {
|
||||
dispatch(changeUpdateRole({ role: USER_ROLES.TYPIST }));
|
||||
}}
|
||||
disabled={!canChangeRole}
|
||||
/>
|
||||
{t(getTranslationID("userListPage.label.transcriptionist"))}
|
||||
</label>
|
||||
<label htmlFor={USER_ROLES.NONE}>
|
||||
<input
|
||||
id={USER_ROLES.NONE}
|
||||
type="radio"
|
||||
name="role"
|
||||
className={styles.formRadio}
|
||||
checked={user.role === USER_ROLES.NONE}
|
||||
onChange={() => {
|
||||
dispatch(changeUpdateRole({ role: USER_ROLES.NONE }));
|
||||
}}
|
||||
disabled={!canChangeRole}
|
||||
/>
|
||||
{t(getTranslationID("userListPage.label.none"))}
|
||||
</label>
|
||||
</dd>
|
||||
|
||||
{/** Author 選択時に表示 */}
|
||||
{user.role === USER_ROLES.AUTHOR && (
|
||||
<div className={styles.slideSet}>
|
||||
<dt>{t(getTranslationID("userListPage.label.authorID"))}</dt>
|
||||
<dd>
|
||||
<input
|
||||
type="text"
|
||||
size={40}
|
||||
maxLength={16}
|
||||
autoComplete="off"
|
||||
value={user.authorId}
|
||||
className={styles.formInput}
|
||||
onChange={(e) => {
|
||||
dispatch(
|
||||
changeUpdateAuthorId({ authorId: e.target.value })
|
||||
);
|
||||
}}
|
||||
/>
|
||||
{isPushCreateButton && hasErrorEmptyAuthorId && (
|
||||
<span className={styles.formError}>
|
||||
{t(
|
||||
getTranslationID("signupPage.message.inputEmptyError")
|
||||
)}
|
||||
</span>
|
||||
)}
|
||||
{isPushCreateButton && hasErrorIncorrectAuthorId && (
|
||||
<span className={styles.formError}>
|
||||
{t(
|
||||
getTranslationID(
|
||||
"userListPage.message.authorIdIncorrectError"
|
||||
)
|
||||
)}
|
||||
</span>
|
||||
)}
|
||||
</dd>
|
||||
<dt>{t(getTranslationID("userListPage.label.encryption"))}</dt>
|
||||
<dd>
|
||||
<label htmlFor="Encryption">
|
||||
<input
|
||||
type="checkbox"
|
||||
className={styles.formCheck}
|
||||
checked={user.encryption}
|
||||
onChange={(e) => {
|
||||
dispatch(
|
||||
changeUpdateEncryption({
|
||||
encryption: e.target.checked,
|
||||
})
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</label>
|
||||
{/** Encryptionチェックでパスワード欄表示 */}
|
||||
<p
|
||||
className={`${styles.encryptionPass} ${
|
||||
user.encryption ? styles.isShow : ""
|
||||
}`}
|
||||
>
|
||||
{t(
|
||||
getTranslationID("userListPage.label.encryptionPassword")
|
||||
)}
|
||||
<input
|
||||
type={isPasswordHide ? "password" : "text"}
|
||||
size={40}
|
||||
maxLength={16}
|
||||
autoComplete="new-password"
|
||||
value={
|
||||
hasPasswordMask
|
||||
? "********"
|
||||
: user.encryptionPassword ?? ""
|
||||
}
|
||||
className={`${styles.formInput} ${styles.password}`}
|
||||
onFocus={() => {
|
||||
if (hasPasswordMask) {
|
||||
dispatch(
|
||||
changeHasPasswordMask({ hasPasswordMask: false })
|
||||
);
|
||||
dispatch(
|
||||
changeUpdateEncryptionPassword({
|
||||
encryptionPassword: "",
|
||||
})
|
||||
);
|
||||
}
|
||||
}}
|
||||
onChange={(e) => {
|
||||
if (!hasPasswordMask) {
|
||||
dispatch(
|
||||
changeUpdateEncryptionPassword({
|
||||
encryptionPassword: e.target.value,
|
||||
})
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<span
|
||||
className={styles.formIconEye}
|
||||
onClick={() => {
|
||||
setIsPasswordHide(!isPasswordHide);
|
||||
}}
|
||||
onKeyDown={() => {
|
||||
setIsPasswordHide(!isPasswordHide);
|
||||
}}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label="IconEye"
|
||||
/>
|
||||
{isPushCreateButton &&
|
||||
hasErrorIncorrectEncryptionPassword && (
|
||||
<span className={styles.formError}>
|
||||
{t(
|
||||
getTranslationID(
|
||||
"userListPage.message.encryptionPasswordCorrectError"
|
||||
)
|
||||
)}
|
||||
</span>
|
||||
)}
|
||||
<span className={styles.formComment}>
|
||||
{t(
|
||||
getTranslationID(
|
||||
"userListPage.label.encryptionPasswordTerm"
|
||||
)
|
||||
)}
|
||||
</span>
|
||||
</p>
|
||||
</dd>
|
||||
<dt>{t(getTranslationID("userListPage.label.prompt"))}</dt>
|
||||
<dd>
|
||||
<label htmlFor="Prompt">
|
||||
<input
|
||||
type="checkbox"
|
||||
className={styles.formCheck}
|
||||
checked={user.prompt}
|
||||
onChange={(e) => {
|
||||
dispatch(
|
||||
changeUpdatePrompt({
|
||||
prompt: e.target.checked,
|
||||
})
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</label>
|
||||
</dd>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<dt>{t(getTranslationID("userListPage.label.setting"))}</dt>
|
||||
<dd className="last">
|
||||
<p>
|
||||
<label htmlFor="Auto renew">
|
||||
<input
|
||||
type="checkbox"
|
||||
className={styles.formCheck}
|
||||
checked={user.autoRenew}
|
||||
onChange={(e) => {
|
||||
dispatch(
|
||||
changeUpdateAutoRenew({
|
||||
autoRenew: e.target.checked,
|
||||
})
|
||||
);
|
||||
}}
|
||||
/>
|
||||
{t(getTranslationID("userListPage.label.autoRenew"))}
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label htmlFor="License Alert">
|
||||
<input
|
||||
type="checkbox"
|
||||
className={styles.formCheck}
|
||||
checked={user.licenseAlert}
|
||||
onChange={(e) => {
|
||||
dispatch(
|
||||
changeUpdateLicenseAlert({
|
||||
licenseAlert: e.target.checked,
|
||||
})
|
||||
);
|
||||
}}
|
||||
/>
|
||||
{t(getTranslationID("userListPage.label.licenseAlert"))}
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label htmlFor="Notification">
|
||||
<input
|
||||
type="checkbox"
|
||||
className={styles.formCheck}
|
||||
checked={user.notification}
|
||||
onChange={(e) => {
|
||||
dispatch(
|
||||
changeUpdateNotification({
|
||||
notification: e.target.checked,
|
||||
})
|
||||
);
|
||||
}}
|
||||
/>
|
||||
{t(getTranslationID("userListPage.label.notification"))}
|
||||
</label>
|
||||
</p>
|
||||
</dd>
|
||||
<dd className={`${styles.full} ${styles.alignCenter}`}>
|
||||
<input
|
||||
type="button"
|
||||
name="submit"
|
||||
value={t(getTranslationID("userListPage.label.editUser"))}
|
||||
className={`${styles.formSubmit} ${styles.marginBtm1} ${styles.isActive}`}
|
||||
onClick={onUpdateUser}
|
||||
/>
|
||||
<img
|
||||
style={{ display: isLoading ? "inline" : "none" }}
|
||||
src={progress_activit}
|
||||
className={styles.icLoading}
|
||||
alt="Loading"
|
||||
/>
|
||||
</dd>
|
||||
</dl>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@ -331,8 +331,19 @@ _:-ms-lang(x)::-ms-backdrop,
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
h2,
|
||||
h3 {
|
||||
display: inline-block;
|
||||
max-width: 72%;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
h2 .brCrumb,
|
||||
h3 .brCrumb {
|
||||
h2 + .brCrumb,
|
||||
h3 .brCrumb,
|
||||
h3 + .brCrumb {
|
||||
display: inline;
|
||||
margin-left: 1rem;
|
||||
font-size: 1.5rem;
|
||||
@ -341,11 +352,15 @@ h3 .brCrumb {
|
||||
font-weight: normal;
|
||||
}
|
||||
h2 .brCrumb::before,
|
||||
h3 .brCrumb::before {
|
||||
h2 + .brCrumb::before,
|
||||
h3 .brCrumb::before,
|
||||
h3 + .brCrumb::before {
|
||||
content: "-";
|
||||
}
|
||||
h2 .brCrumb .tlIcon,
|
||||
h3 .brCrumb .tlIcon {
|
||||
h2 + .brCrumb .tlIcon,
|
||||
h3 .brCrumb .tlIcon,
|
||||
h3 + .brCrumb .tlIcon {
|
||||
width: 1.6rem;
|
||||
margin: 0 0.2rem 0 0.5rem;
|
||||
vertical-align: text-top;
|
||||
@ -942,7 +957,7 @@ h3 .brCrumb .tlIcon {
|
||||
}
|
||||
.pageTitle {
|
||||
display: inline-block;
|
||||
padding-right: 1rem;
|
||||
padding-right: 1.5rem;
|
||||
font-size: 1.4rem;
|
||||
line-height: 1.4rem;
|
||||
letter-spacing: 0.07rem;
|
||||
@ -950,6 +965,22 @@ h3 .brCrumb .tlIcon {
|
||||
}
|
||||
.pageTx {
|
||||
display: inline-block;
|
||||
padding-left: 2rem;
|
||||
font-size: 1.4rem;
|
||||
line-height: 1.4rem;
|
||||
letter-spacing: 0.07rem;
|
||||
font-weight: 500;
|
||||
position: relative;
|
||||
}
|
||||
.pageTx::before {
|
||||
content: "";
|
||||
border-top: 6px transparent solid;
|
||||
border-bottom: 6px transparent solid;
|
||||
border-left: 8px #ffffff solid;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.pagenation {
|
||||
@ -988,6 +1019,15 @@ h3 .brCrumb .tlIcon {
|
||||
.pagenationTotal {
|
||||
color: #999999;
|
||||
}
|
||||
.pagenation.widthMid {
|
||||
width: 1000px;
|
||||
}
|
||||
.pagenation.widthSml {
|
||||
width: 750px;
|
||||
}
|
||||
.pagenation.widthMin {
|
||||
width: 600px;
|
||||
}
|
||||
|
||||
_:-ms-lang(x)::-ms-backdrop,
|
||||
.pagenationNav a {
|
||||
@ -1262,7 +1302,8 @@ _:-ms-lang(x)::-ms-backdrop,
|
||||
.user > div,
|
||||
.license > div,
|
||||
.dictation > div,
|
||||
.partners > div {
|
||||
.partners > div,
|
||||
.workflow > div {
|
||||
padding: 0 2rem;
|
||||
position: relative;
|
||||
}
|
||||
@ -1270,7 +1311,8 @@ _:-ms-lang(x)::-ms-backdrop,
|
||||
.user > div .icLoading,
|
||||
.license > div .icLoading,
|
||||
.dictation > div .icLoading,
|
||||
.partners > div .icLoading {
|
||||
.partners > div .icLoading,
|
||||
.workflow > div .icLoading {
|
||||
top: 5.5rem;
|
||||
left: calc(50% - 25px);
|
||||
}
|
||||
@ -1278,7 +1320,8 @@ _:-ms-lang(x)::-ms-backdrop,
|
||||
.user .table tr.tableHeader th.clm0,
|
||||
.license .table tr.tableHeader th.clm0,
|
||||
.dictation .table tr.tableHeader th.clm0,
|
||||
.partners .table tr.tableHeader th.clm0 {
|
||||
.partners .table tr.tableHeader th.clm0,
|
||||
.workflow .table tr.tableHeader th.clm0 {
|
||||
width: 0px;
|
||||
padding: 0 0;
|
||||
}
|
||||
@ -1286,21 +1329,24 @@ _:-ms-lang(x)::-ms-backdrop,
|
||||
.user .table tr:not(.tableHeader),
|
||||
.license .table tr:not(.tableHeader),
|
||||
.dictation .table tr:not(.tableHeader),
|
||||
.partners .table tr:not(.tableHeader) {
|
||||
.partners .table tr:not(.tableHeader),
|
||||
.workflow .table tr:not(.tableHeader) {
|
||||
position: relative;
|
||||
}
|
||||
.account .table tr:not(.tableHeader):hover .menuInTable,
|
||||
.user .table tr:not(.tableHeader):hover .menuInTable,
|
||||
.license .table tr:not(.tableHeader):hover .menuInTable,
|
||||
.dictation .table tr:not(.tableHeader):hover .menuInTable,
|
||||
.partners .table tr:not(.tableHeader):hover .menuInTable {
|
||||
.partners .table tr:not(.tableHeader):hover .menuInTable,
|
||||
.workflow .table tr:not(.tableHeader):hover .menuInTable {
|
||||
opacity: 1;
|
||||
}
|
||||
.account .table tr:not(.tableHeader).isSelected,
|
||||
.user .table tr:not(.tableHeader).isSelected,
|
||||
.license .table tr:not(.tableHeader).isSelected,
|
||||
.dictation .table tr:not(.tableHeader).isSelected,
|
||||
.partners .table tr:not(.tableHeader).isSelected {
|
||||
.partners .table tr:not(.tableHeader).isSelected,
|
||||
.workflow .table tr:not(.tableHeader).isSelected {
|
||||
background: #0084b2;
|
||||
color: #ffffff;
|
||||
}
|
||||
@ -1308,21 +1354,24 @@ _:-ms-lang(x)::-ms-backdrop,
|
||||
.user .table tr:not(.tableHeader).isSelected:hover,
|
||||
.license .table tr:not(.tableHeader).isSelected:hover,
|
||||
.dictation .table tr:not(.tableHeader).isSelected:hover,
|
||||
.partners .table tr:not(.tableHeader).isSelected:hover {
|
||||
.partners .table tr:not(.tableHeader).isSelected:hover,
|
||||
.workflow .table tr:not(.tableHeader).isSelected:hover {
|
||||
color: #ffffff;
|
||||
}
|
||||
.account .table tr:not(.tableHeader).isSelected .menuInTable,
|
||||
.user .table tr:not(.tableHeader).isSelected .menuInTable,
|
||||
.license .table tr:not(.tableHeader).isSelected .menuInTable,
|
||||
.dictation .table tr:not(.tableHeader).isSelected .menuInTable,
|
||||
.partners .table tr:not(.tableHeader).isSelected .menuInTable {
|
||||
.partners .table tr:not(.tableHeader).isSelected .menuInTable,
|
||||
.workflow .table tr:not(.tableHeader).isSelected .menuInTable {
|
||||
display: block;
|
||||
}
|
||||
.account .table td,
|
||||
.user .table td,
|
||||
.license .table td,
|
||||
.dictation .table td,
|
||||
.partners .table td {
|
||||
.partners .table td,
|
||||
.workflow .table td {
|
||||
max-width: 300px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@ -1333,7 +1382,8 @@ _:-ms-lang(x)::-ms-backdrop,
|
||||
.user .table td.clm0,
|
||||
.license .table td.clm0,
|
||||
.dictation .table td.clm0,
|
||||
.partners .table td.clm0 {
|
||||
.partners .table td.clm0,
|
||||
.workflow .table td.clm0 {
|
||||
width: 0px;
|
||||
padding: 0 0;
|
||||
overflow: visible;
|
||||
@ -1345,14 +1395,24 @@ _:-ms-lang(x)::-ms-backdrop,
|
||||
.user .table.user,
|
||||
.license .table.user,
|
||||
.dictation .table.user,
|
||||
.partners .table.user {
|
||||
.partners .table.user,
|
||||
.workflow .table.user {
|
||||
margin-bottom: 5rem;
|
||||
}
|
||||
.account .table.user th::after,
|
||||
.user .table.user th::after,
|
||||
.license .table.user th::after,
|
||||
.dictation .table.user th::after,
|
||||
.partners .table.user th::after,
|
||||
.workflow .table.user th::after {
|
||||
display: none;
|
||||
}
|
||||
.account .table.user tr:not(.tableHeader) td,
|
||||
.user .table.user tr:not(.tableHeader) td,
|
||||
.license .table.user tr:not(.tableHeader) td,
|
||||
.dictation .table.user tr:not(.tableHeader) td,
|
||||
.partners .table.user tr:not(.tableHeader) td {
|
||||
.partners .table.user tr:not(.tableHeader) td,
|
||||
.workflow .table.user tr:not(.tableHeader) td {
|
||||
padding-bottom: 2rem;
|
||||
vertical-align: top;
|
||||
}
|
||||
@ -1360,21 +1420,24 @@ _:-ms-lang(x)::-ms-backdrop,
|
||||
.user.account .listVertical,
|
||||
.license.account .listVertical,
|
||||
.dictation.account .listVertical,
|
||||
.partners.account .listVertical {
|
||||
.partners.account .listVertical,
|
||||
.workflow.account .listVertical {
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
.account.account .listVertical dd .formInput,
|
||||
.user.account .listVertical dd .formInput,
|
||||
.license.account .listVertical dd .formInput,
|
||||
.dictation.account .listVertical dd .formInput,
|
||||
.partners.account .listVertical dd .formInput {
|
||||
.partners.account .listVertical dd .formInput,
|
||||
.workflow.account .listVertical dd .formInput {
|
||||
max-width: 100%;
|
||||
}
|
||||
.account.account .listVertical dd .formCheckToggle,
|
||||
.user.account .listVertical dd .formCheckToggle,
|
||||
.license.account .listVertical dd .formCheckToggle,
|
||||
.dictation.account .listVertical dd .formCheckToggle,
|
||||
.partners.account .listVertical dd .formCheckToggle {
|
||||
.partners.account .listVertical dd .formCheckToggle,
|
||||
.workflow.account .listVertical dd .formCheckToggle {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
@ -1382,7 +1445,8 @@ _:-ms-lang(x)::-ms-backdrop,
|
||||
.user.account .listVertical dd .formCheckToggle .toggleBase,
|
||||
.license.account .listVertical dd .formCheckToggle .toggleBase,
|
||||
.dictation.account .listVertical dd .formCheckToggle .toggleBase,
|
||||
.partners.account .listVertical dd .formCheckToggle .toggleBase {
|
||||
.partners.account .listVertical dd .formCheckToggle .toggleBase,
|
||||
.workflow.account .listVertical dd .formCheckToggle .toggleBase {
|
||||
display: inline-block;
|
||||
width: 2.8rem;
|
||||
height: 1.6rem;
|
||||
@ -1400,7 +1464,8 @@ _:-ms-lang(x)::-ms-backdrop,
|
||||
.user.account .listVertical dd .formCheckToggle .toggleBase::after,
|
||||
.license.account .listVertical dd .formCheckToggle .toggleBase::after,
|
||||
.dictation.account .listVertical dd .formCheckToggle .toggleBase::after,
|
||||
.partners.account .listVertical dd .formCheckToggle .toggleBase::after {
|
||||
.partners.account .listVertical dd .formCheckToggle .toggleBase::after,
|
||||
.workflow.account .listVertical dd .formCheckToggle .toggleBase::after {
|
||||
content: "";
|
||||
width: 1.3rem;
|
||||
height: 1.3rem;
|
||||
@ -1418,7 +1483,8 @@ _:-ms-lang(x)::-ms-backdrop,
|
||||
.user.account .listVertical dd .formCheckToggle input,
|
||||
.license.account .listVertical dd .formCheckToggle input,
|
||||
.dictation.account .listVertical dd .formCheckToggle input,
|
||||
.partners.account .listVertical dd .formCheckToggle input {
|
||||
.partners.account .listVertical dd .formCheckToggle input,
|
||||
.workflow.account .listVertical dd .formCheckToggle input {
|
||||
position: absolute;
|
||||
width: 0;
|
||||
heigh: 0;
|
||||
@ -1432,7 +1498,8 @@ _:-ms-lang(x)::-ms-backdrop,
|
||||
.formCheckToggle
|
||||
input:checked
|
||||
~ .toggleBase,
|
||||
.partners.account
|
||||
.partners.account .listVertical dd .formCheckToggle input:checked ~ .toggleBase,
|
||||
.workflow.account
|
||||
.listVertical
|
||||
dd
|
||||
.formCheckToggle
|
||||
@ -1465,6 +1532,12 @@ _:-ms-lang(x)::-ms-backdrop,
|
||||
input:checked
|
||||
~ .toggleBase::after,
|
||||
.partners.account
|
||||
.listVertical
|
||||
dd
|
||||
.formCheckToggle
|
||||
input:checked
|
||||
~ .toggleBase::after,
|
||||
.workflow.account
|
||||
.listVertical
|
||||
dd
|
||||
.formCheckToggle
|
||||
@ -1482,6 +1555,9 @@ _:-ms-lang(x)::-ms-backdrop,
|
||||
display: inline-block;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
.menuAction li:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
.menuAction.inTable {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
@ -1489,6 +1565,9 @@ _:-ms-lang(x)::-ms-backdrop,
|
||||
padding: 0.3rem 0.5rem 0.3rem 0.5rem;
|
||||
opacity: 0;
|
||||
}
|
||||
.menuAction.inTable .menuLink .menuIcon {
|
||||
width: 1.2rem;
|
||||
}
|
||||
.menuAction.inTable .menuLink.isActive {
|
||||
opacity: 1;
|
||||
}
|
||||
@ -1521,9 +1600,6 @@ _:-ms-lang(x)::-ms-backdrop,
|
||||
.menuAction.inTable .colorLink.isActive:hover {
|
||||
background: rgba(0, 94, 184, 0.7);
|
||||
}
|
||||
.menuAction.alignRight {
|
||||
margin-top: -1rem;
|
||||
}
|
||||
.menuLink {
|
||||
display: block;
|
||||
padding: 0.3rem 0.5rem 0.3rem 0.3rem;
|
||||
@ -1697,6 +1773,9 @@ tr.isSelected .menuInTable li a {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.dictation .menuAction {
|
||||
margin-top: -1rem;
|
||||
}
|
||||
.dictation .displayOptions {
|
||||
display: none;
|
||||
margin-bottom: 0.6rem;
|
||||
@ -2077,6 +2156,9 @@ tr.isSelected .menuInTable li a {
|
||||
background: #282828;
|
||||
z-index: 1;
|
||||
}
|
||||
.partners .table.partner tr.tableHeader th::after {
|
||||
display: none;
|
||||
}
|
||||
.partners .table.partner td {
|
||||
padding-bottom: 2rem;
|
||||
vertical-align: top;
|
||||
@ -2098,6 +2180,113 @@ tr.isSelected .menuInTable li a {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.workflow .table {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.workflow .table.workflow {
|
||||
min-width: 100%;
|
||||
}
|
||||
.workflow .table.workflow tr {
|
||||
position: relative;
|
||||
}
|
||||
.workflow .table.workflow th::after {
|
||||
display: none;
|
||||
}
|
||||
.workflow .table.workflow td {
|
||||
padding-bottom: 2rem;
|
||||
vertical-align: top;
|
||||
}
|
||||
.workflow .table.workflow td.txWsline {
|
||||
white-space: pre;
|
||||
}
|
||||
.workflow .table.group {
|
||||
width: 600px;
|
||||
}
|
||||
.workflow .table.group td:last-child {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.formList dd.formChange {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 92%;
|
||||
padding: 0 4%;
|
||||
}
|
||||
.formList dd.formChange ul.chooseMember,
|
||||
.formList dd.formChange ul.holdMember {
|
||||
width: calc(40% - 2px);
|
||||
border: 1px #999999 solid;
|
||||
}
|
||||
.formChange ul.chooseMember,
|
||||
.formChange ul.holdMember {
|
||||
height: 250px;
|
||||
overflow-y: scroll;
|
||||
padding: 0.5rem;
|
||||
background: #ffffff;
|
||||
}
|
||||
.formChange ul.chooseMember li.changeTitle,
|
||||
.formChange ul.holdMember li.changeTitle {
|
||||
font-weight: 600;
|
||||
}
|
||||
.formChange ul.chooseMember li .formCheck,
|
||||
.formChange ul.holdMember li .formCheck {
|
||||
display: none;
|
||||
}
|
||||
.formChange ul.chooseMember li input + label,
|
||||
.formChange ul.holdMember li input + label {
|
||||
display: block;
|
||||
padding: 0.2rem 0 0.2rem 1.5rem;
|
||||
margin-right: 0;
|
||||
background: url(../assets/images/circle.svg) no-repeat left center;
|
||||
background-size: 1.3rem;
|
||||
}
|
||||
.formChange ul.chooseMember li input + label:hover,
|
||||
.formChange ul.holdMember li input + label:hover {
|
||||
background: #e6e6e6 url(../assets/images/arrow_circle_left.svg) no-repeat left
|
||||
center;
|
||||
background-size: 1.3rem;
|
||||
}
|
||||
.formChange ul.chooseMember li input:checked + label,
|
||||
.formChange ul.holdMember li input:checked + label {
|
||||
padding: 0.2rem 1rem 0.2rem 0;
|
||||
background: url(../assets/images/check_circle_fill.svg) no-repeat right center;
|
||||
background-size: 1.3rem;
|
||||
}
|
||||
.formChange ul.chooseMember li input:checked + label:hover,
|
||||
.formChange ul.holdMember li input:checked + label:hover {
|
||||
background: #e6e6e6 url(../assets/images/arrow_circle_right.svg) no-repeat
|
||||
right center;
|
||||
background-size: 1.3rem;
|
||||
}
|
||||
.formChange > p {
|
||||
width: 6%;
|
||||
height: 20px;
|
||||
background: #e6e6e6;
|
||||
position: relative;
|
||||
}
|
||||
.formChange > p::before {
|
||||
content: "";
|
||||
border-top: 20px transparent solid;
|
||||
border-right: 20px #e6e6e6 solid;
|
||||
border-bottom: 20px transparent solid;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: -15px;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
.formChange > p::after {
|
||||
content: "";
|
||||
border-top: 20px transparent solid;
|
||||
border-bottom: 20px transparent solid;
|
||||
border-left: 20px #e6e6e6 solid;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: -15px;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.alignCenter {
|
||||
text-align: center;
|
||||
}
|
||||
@ -2108,6 +2297,16 @@ tr.isSelected .menuInTable li a {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.floatNone {
|
||||
float: none;
|
||||
}
|
||||
.floatLeft {
|
||||
float: left;
|
||||
}
|
||||
.floatRight {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.linkTx {
|
||||
color: #0084b2;
|
||||
text-decoration: none;
|
||||
|
||||
11
dictation_client/src/styles/app.module.scss.d.ts
vendored
11
dictation_client/src/styles/app.module.scss.d.ts
vendored
@ -67,6 +67,9 @@ declare const classNames: {
|
||||
readonly pagenation: "pagenation";
|
||||
readonly pagenationNav: "pagenationNav";
|
||||
readonly pagenationTotal: "pagenationTotal";
|
||||
readonly widthMid: "widthMid";
|
||||
readonly widthSml: "widthSml";
|
||||
readonly widthMin: "widthMin";
|
||||
readonly snackbar: "snackbar";
|
||||
readonly isAlert: "isAlert";
|
||||
readonly snackbarMessage: "snackbarMessage";
|
||||
@ -88,6 +91,7 @@ declare const classNames: {
|
||||
readonly license: "license";
|
||||
readonly dictation: "dictation";
|
||||
readonly partners: "partners";
|
||||
readonly workflow: "workflow";
|
||||
readonly clm0: "clm0";
|
||||
readonly menuInTable: "menuInTable";
|
||||
readonly isSelected: "isSelected";
|
||||
@ -97,7 +101,6 @@ declare const classNames: {
|
||||
readonly inTable: "inTable";
|
||||
readonly menuLink: "menuLink";
|
||||
readonly colorLink: "colorLink";
|
||||
readonly alignRight: "alignRight";
|
||||
readonly menuIcon: "menuIcon";
|
||||
readonly isDisable: "isDisable";
|
||||
readonly icCheckCircle: "icCheckCircle";
|
||||
@ -174,8 +177,13 @@ declare const classNames: {
|
||||
readonly holdMember: "holdMember";
|
||||
readonly changeTitle: "changeTitle";
|
||||
readonly role4: "role4";
|
||||
readonly group: "group";
|
||||
readonly alignCenter: "alignCenter";
|
||||
readonly alignLeft: "alignLeft";
|
||||
readonly alignRight: "alignRight";
|
||||
readonly floatNone: "floatNone";
|
||||
readonly floatLeft: "floatLeft";
|
||||
readonly floatRight: "floatRight";
|
||||
readonly linkTx: "linkTx";
|
||||
readonly linkBottom: "linkBottom";
|
||||
readonly borderTop: "borderTop";
|
||||
@ -195,5 +203,6 @@ declare const classNames: {
|
||||
readonly txNormal: "txNormal";
|
||||
readonly txIcon: "txIcon";
|
||||
readonly txWswrap: "txWswrap";
|
||||
readonly widthMid: "widthMid";
|
||||
};
|
||||
export = classNames;
|
||||
|
||||
@ -110,7 +110,9 @@
|
||||
"message": {
|
||||
"addUserSuccess": "(de)メールアドレス宛に認証用メールを送信しました。",
|
||||
"authorIdConflictError": "(de)このAuthor IDは既に登録されています。他のAuthor IDで登録してください。",
|
||||
"authorIdIncorrectError": "(de)Author IDの形式が不正です。Author IDは半角英数字(大文字)と\"_\"のみ入力可能です。"
|
||||
"authorIdIncorrectError": "(de)Author IDの形式が不正です。Author IDは半角英数字(大文字)と\"_\"のみ入力可能です。",
|
||||
"roleChangeError": "(de)Roleの変更に失敗しました。画面を更新して再度ユーザー情報を取得してください。",
|
||||
"encryptionPasswordCorrectError": "(de)EncryptionPasswordがルールを満たしていません。"
|
||||
},
|
||||
"label": {
|
||||
"title": "(de)User",
|
||||
@ -143,7 +145,9 @@
|
||||
"editUser": "(de)Edit User",
|
||||
"licenseDeallocation": "(de)License Deallocation",
|
||||
"deleteUser": "(de)Delete User",
|
||||
"none": "(de)None"
|
||||
"none": "(de)None",
|
||||
"encryptionPassword": "(de)Password:",
|
||||
"encryptionPasswordTerm": "(de)Please set your password using 4 to 16 ASCII characters.\nYour password may include letters, numbers, and symbols."
|
||||
}
|
||||
},
|
||||
"LicenseSummaryPage": {
|
||||
@ -306,7 +310,6 @@
|
||||
"orderHistoriesPage": {
|
||||
"label": {
|
||||
"title": "(de)License",
|
||||
"subTitle": "(de)EFGI Legal",
|
||||
"orderHistory": "(de)Order History",
|
||||
"return": "(de)Return",
|
||||
"orderDate": "(de)Order date",
|
||||
@ -319,7 +322,8 @@
|
||||
"orderCanceled": "(de)Order Canceled",
|
||||
"issue": "(de)Issue",
|
||||
"issueCancel": "(de)Issue Cancel",
|
||||
"orderCancel": "(de)Order Cancel"
|
||||
"orderCancel": "(de)Order Cancel",
|
||||
"histories": "(de)histories"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,7 +110,9 @@
|
||||
"message": {
|
||||
"addUserSuccess": "メールアドレス宛に認証用メールを送信しました。",
|
||||
"authorIdConflictError": "このAuthor IDは既に登録されています。他のAuthor IDで登録してください。",
|
||||
"authorIdIncorrectError": "Author IDの形式が不正です。Author IDは半角英数字(大文字)と\"_\"のみ入力可能です。"
|
||||
"authorIdIncorrectError": "Author IDの形式が不正です。Author IDは半角英数字(大文字)と\"_\"のみ入力可能です。",
|
||||
"roleChangeError": "Roleの変更に失敗しました。画面を更新して再度ユーザー情報を取得してください。",
|
||||
"encryptionPasswordCorrectError": "EncryptionPasswordがルールを満たしていません。"
|
||||
},
|
||||
"label": {
|
||||
"title": "User",
|
||||
@ -143,7 +145,9 @@
|
||||
"editUser": "Edit User",
|
||||
"licenseDeallocation": "License Deallocation",
|
||||
"deleteUser": "Delete User",
|
||||
"none": "None"
|
||||
"none": "None",
|
||||
"encryptionPassword": "Password:",
|
||||
"encryptionPasswordTerm": "Please set your password using 4 to 16 ASCII characters.\nYour password may include letters, numbers, and symbols."
|
||||
}
|
||||
},
|
||||
"LicenseSummaryPage": {
|
||||
@ -306,7 +310,6 @@
|
||||
"orderHistoriesPage": {
|
||||
"label": {
|
||||
"title": "License",
|
||||
"subTitle": "EFGI Legal",
|
||||
"orderHistory": "Order History",
|
||||
"return": "Return",
|
||||
"orderDate": "Order date",
|
||||
@ -319,7 +322,8 @@
|
||||
"orderCanceled": "Order Canceled",
|
||||
"issue": "Issue",
|
||||
"issueCancel": "Issue Cancel",
|
||||
"orderCancel": "Order Cancel"
|
||||
"orderCancel": "Order Cancel",
|
||||
"histories": "histories"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,7 +110,9 @@
|
||||
"message": {
|
||||
"addUserSuccess": "(es)メールアドレス宛に認証用メールを送信しました。",
|
||||
"authorIdConflictError": "(es)このAuthor IDは既に登録されています。他のAuthor IDで登録してください。",
|
||||
"authorIdIncorrectError": "(es)Author IDの形式が不正です。Author IDは半角英数字(大文字)と\"_\"のみ入力可能です。"
|
||||
"authorIdIncorrectError": "(es)Author IDの形式が不正です。Author IDは半角英数字(大文字)と\"_\"のみ入力可能です。",
|
||||
"roleChangeError": "(es)Roleの変更に失敗しました。画面を更新して再度ユーザー情報を取得してください。",
|
||||
"encryptionPasswordCorrectError": "(es)EncryptionPasswordがルールを満たしていません。"
|
||||
},
|
||||
"label": {
|
||||
"title": "(es)User",
|
||||
@ -143,7 +145,9 @@
|
||||
"editUser": "(es)Edit User",
|
||||
"licenseDeallocation": "(es)License Deallocation",
|
||||
"deleteUser": "(es)Delete User",
|
||||
"none": "(es)None"
|
||||
"none": "(es)None",
|
||||
"encryptionPassword": "(es)Password:",
|
||||
"encryptionPasswordTerm": "(es)Please set your password using 4 to 16 ASCII characters.\nYour password may include letters, numbers, and symbols."
|
||||
}
|
||||
},
|
||||
"LicenseSummaryPage": {
|
||||
@ -306,7 +310,6 @@
|
||||
"orderHistoriesPage": {
|
||||
"label": {
|
||||
"title": "(es)License",
|
||||
"subTitle": "(es)EFGI Legal",
|
||||
"orderHistory": "(es)Order History",
|
||||
"return": "(es)Return",
|
||||
"orderDate": "(es)Order date",
|
||||
@ -319,7 +322,8 @@
|
||||
"orderCanceled": "(es)Order Canceled",
|
||||
"issue": "(es)Issue",
|
||||
"issueCancel": "(es)Issue Cancel",
|
||||
"orderCancel": "(es)Order Cancel"
|
||||
"orderCancel": "(es)Order Cancel",
|
||||
"histories": "(es)histories"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,7 +110,9 @@
|
||||
"message": {
|
||||
"addUserSuccess": "(fr)メールアドレス宛に認証用メールを送信しました。",
|
||||
"authorIdConflictError": "(fr)このAuthor IDは既に登録されています。他のAuthor IDで登録してください。",
|
||||
"authorIdIncorrectError": "(fr)Author IDの形式が不正です。Author IDは半角英数字(大文字)と\"_\"のみ入力可能です。"
|
||||
"authorIdIncorrectError": "(fr)Author IDの形式が不正です。Author IDは半角英数字(大文字)と\"_\"のみ入力可能です。",
|
||||
"roleChangeError": "(fr)Roleの変更に失敗しました。画面を更新して再度ユーザー情報を取得してください。",
|
||||
"encryptionPasswordCorrectError": "(fr)EncryptionPasswordがルールを満たしていません。"
|
||||
},
|
||||
"label": {
|
||||
"title": "(fr)User",
|
||||
@ -143,7 +145,9 @@
|
||||
"editUser": "(fr)Edit User",
|
||||
"licenseDeallocation": "(fr)License Deallocation",
|
||||
"deleteUser": "(fr)Delete User",
|
||||
"none": "(fr)None"
|
||||
"none": "(fr)None",
|
||||
"encryptionPassword": "(fr)Password:",
|
||||
"encryptionPasswordTerm": "(fr)Please set your password using 4 to 16 ASCII characters.\nYour password may include letters, numbers, and symbols."
|
||||
}
|
||||
},
|
||||
"LicenseSummaryPage": {
|
||||
@ -306,7 +310,6 @@
|
||||
"orderHistoriesPage": {
|
||||
"label": {
|
||||
"title": "(fr)License",
|
||||
"subTitle": "(fr)EFGI Legal",
|
||||
"orderHistory": "(fr)Order History",
|
||||
"return": "(fr)Return",
|
||||
"orderDate": "(fr)Order date",
|
||||
@ -319,7 +322,8 @@
|
||||
"orderCanceled": "(fr)Order Canceled",
|
||||
"issue": "(fr)Issue",
|
||||
"issueCancel": "(fr)Issue Cancel",
|
||||
"orderCancel": "(fr)Order Cancel"
|
||||
"orderCancel": "(fr)Order Cancel",
|
||||
"histories": "(fr)histories"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -502,6 +502,32 @@
|
||||
"security": [{ "bearer": [] }]
|
||||
}
|
||||
},
|
||||
"/accounts/dealers": {
|
||||
"get": {
|
||||
"operationId": "getDealers",
|
||||
"summary": "",
|
||||
"parameters": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "成功時のレスポンス",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": { "$ref": "#/components/schemas/GetDealersResponse" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "想定外のサーバーエラー",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": { "$ref": "#/components/schemas/ErrorResponse" }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": ["accounts"]
|
||||
}
|
||||
},
|
||||
"/users/confirm": {
|
||||
"post": {
|
||||
"operationId": "confirmUser",
|
||||
@ -1955,8 +1981,11 @@
|
||||
},
|
||||
"Account": {
|
||||
"type": "object",
|
||||
"properties": { "accountId": { "type": "number" } },
|
||||
"required": ["accountId"]
|
||||
"properties": {
|
||||
"accountId": { "type": "number" },
|
||||
"companyName": { "type": "string" }
|
||||
},
|
||||
"required": ["accountId", "companyName"]
|
||||
},
|
||||
"GetMyAccountResponse": {
|
||||
"type": "object",
|
||||
@ -2120,6 +2149,28 @@
|
||||
"required": ["orderedAccountId", "poNumber"]
|
||||
},
|
||||
"IssueLicenseResponse": { "type": "object", "properties": {} },
|
||||
"Dealer": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": { "type": "number", "description": "アカウントID" },
|
||||
"name": { "type": "string", "description": "会社名" },
|
||||
"country": {
|
||||
"type": "string",
|
||||
"description": "国名(ISO 3166-1 alpha-2)"
|
||||
}
|
||||
},
|
||||
"required": ["id", "name", "country"]
|
||||
},
|
||||
"GetDealersResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"dealers": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/components/schemas/Dealer" }
|
||||
}
|
||||
},
|
||||
"required": ["dealers"]
|
||||
},
|
||||
"ConfirmRequest": {
|
||||
"type": "object",
|
||||
"properties": { "token": { "type": "string" } },
|
||||
@ -2179,11 +2230,13 @@
|
||||
"name": { "type": "string" },
|
||||
"role": { "type": "string", "description": "none/author/typist" },
|
||||
"authorId": { "type": "string" },
|
||||
"typistGroupId": { "type": "number" },
|
||||
"email": { "type": "string" },
|
||||
"autoRenew": { "type": "boolean" },
|
||||
"licenseAlert": { "type": "boolean" },
|
||||
"notification": { "type": "boolean" }
|
||||
"notification": { "type": "boolean" },
|
||||
"encryption": { "type": "boolean" },
|
||||
"encryptionPassword": { "type": "string" },
|
||||
"prompt": { "type": "boolean" }
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
|
||||
@ -6,3 +6,5 @@ import { ADMIN_ROLES, USER_ROLES } from '../../../constants';
|
||||
export type Roles =
|
||||
| (typeof ADMIN_ROLES)[keyof typeof ADMIN_ROLES]
|
||||
| (typeof USER_ROLES)[keyof typeof USER_ROLES];
|
||||
|
||||
export type UserRoles = (typeof USER_ROLES)[keyof typeof USER_ROLES];
|
||||
|
||||
@ -1,4 +1,9 @@
|
||||
import { registerDecorator, ValidationOptions } from 'class-validator';
|
||||
import {
|
||||
registerDecorator,
|
||||
ValidationArguments,
|
||||
ValidationOptions,
|
||||
} from 'class-validator';
|
||||
import { SignupRequest } from '../../features/users/types/types';
|
||||
|
||||
export const IsPasswordvalid = (validationOptions?: ValidationOptions) => {
|
||||
return (object: any, propertyName: string) => {
|
||||
@ -30,3 +35,29 @@ export const IsPasswordvalid = (validationOptions?: ValidationOptions) => {
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
export const IsEncryptionPasswordPresent = (
|
||||
validationOptions?: ValidationOptions,
|
||||
) => {
|
||||
return (object: SignupRequest, propertyName: string) => {
|
||||
registerDecorator({
|
||||
name: 'IsEncryptionPasswordValid',
|
||||
target: object.constructor,
|
||||
propertyName: propertyName,
|
||||
constraints: [],
|
||||
options: validationOptions,
|
||||
validator: {
|
||||
validate: (value: string | undefined, args: ValidationArguments) => {
|
||||
const { encryption } = args.object as SignupRequest;
|
||||
if (encryption === true && !value) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
defaultMessage: () => {
|
||||
return 'Encryption password is required when encryption is enabled';
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import {
|
||||
registerDecorator,
|
||||
ValidationOptions,
|
||||
ValidationArguments,
|
||||
ValidationOptions,
|
||||
} from 'class-validator';
|
||||
import { USER_ROLES } from '../../constants';
|
||||
import {
|
||||
SignupRequest,
|
||||
PostUpdateUserRequest,
|
||||
SignupRequest,
|
||||
} from '../../features/users/types/types';
|
||||
import { USER_ROLES } from '../../constants';
|
||||
|
||||
export const IsRoleAuthorDataValid = <
|
||||
T extends SignupRequest | PostUpdateUserRequest,
|
||||
@ -22,7 +22,7 @@ export const IsRoleAuthorDataValid = <
|
||||
constraints: [],
|
||||
options: validationOptions,
|
||||
validator: {
|
||||
validate: (value: boolean | undefined, args: ValidationArguments) => {
|
||||
validate: (value: any, args: ValidationArguments) => {
|
||||
const request = args.object as T;
|
||||
const { role } = request;
|
||||
if (role === USER_ROLES.AUTHOR && value === undefined) {
|
||||
|
||||
@ -32,6 +32,7 @@ import {
|
||||
GetOrderHistoriesResponse,
|
||||
IssueLicenseRequest,
|
||||
IssueLicenseResponse,
|
||||
GetDealersResponse,
|
||||
} from './types/types';
|
||||
import { USER_ROLES, ADMIN_ROLES, TIERS } from '../../constants';
|
||||
import { AuthGuard } from '../../common/guards/auth/authguards';
|
||||
@ -114,9 +115,7 @@ export class AccountsController {
|
||||
})
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(AuthGuard)
|
||||
@UseGuards(
|
||||
RoleGuard.requireds({ roles: [ADMIN_ROLES.ADMIN] }),
|
||||
)
|
||||
@UseGuards(RoleGuard.requireds({ roles: [ADMIN_ROLES.ADMIN] }))
|
||||
@Post('licenses/summary')
|
||||
async getLicenseSummary(
|
||||
@Req() req: Request,
|
||||
@ -166,12 +165,8 @@ export class AccountsController {
|
||||
const accessToken = retrieveAuthorizationToken(req);
|
||||
const payload = jwt.decode(accessToken, { json: true }) as AccessToken;
|
||||
//アカウントID取得処理
|
||||
const accountId = await this.accountService.getMyAccountInfo(payload);
|
||||
return {
|
||||
account: {
|
||||
accountId: accountId,
|
||||
},
|
||||
};
|
||||
const accountInfo = await this.accountService.getMyAccountInfo(payload);
|
||||
return accountInfo;
|
||||
}
|
||||
|
||||
@ApiResponse({
|
||||
@ -414,4 +409,20 @@ export class AccountsController {
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@Get('/dealers')
|
||||
@ApiResponse({
|
||||
status: HttpStatus.OK,
|
||||
type: GetDealersResponse,
|
||||
description: '成功時のレスポンス',
|
||||
})
|
||||
@ApiResponse({
|
||||
status: HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
description: '想定外のサーバーエラー',
|
||||
type: ErrorResponse,
|
||||
})
|
||||
@ApiOperation({ operationId: 'getDealers' })
|
||||
async getDealers(): Promise<GetDealersResponse> {
|
||||
return await this.accountService.getDealers();
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,6 +18,7 @@ import {
|
||||
import { DataSource } from 'typeorm';
|
||||
import { makeTestingModule } from '../../common/test/modules';
|
||||
import { AccountsService } from './accounts.service';
|
||||
import { TIERS } from '../../constants';
|
||||
|
||||
describe('AccountsService', () => {
|
||||
it('アカウントに紐づくライセンス情報を取得する', async () => {
|
||||
@ -549,3 +550,74 @@ describe('getOrderHistories', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getDealers', () => {
|
||||
let source: DataSource = null;
|
||||
beforeEach(async () => {
|
||||
source = new DataSource({
|
||||
type: 'sqlite',
|
||||
database: ':memory:',
|
||||
logging: false,
|
||||
entities: [__dirname + '/../../**/*.entity{.ts,.js}'],
|
||||
synchronize: true, // trueにすると自動的にmigrationが行われるため注意
|
||||
});
|
||||
return source.initialize();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await source.destroy();
|
||||
source = null;
|
||||
});
|
||||
|
||||
it('Dealerを取得できる', async () => {
|
||||
const module = await makeTestingModule(source);
|
||||
const { accountId: accountId_1 } = await createAccount(
|
||||
source,
|
||||
1,
|
||||
TIERS.TIER4,
|
||||
'DEALER_1',
|
||||
);
|
||||
const { accountId: accountId_2 } = await createAccount(
|
||||
source,
|
||||
2,
|
||||
TIERS.TIER4,
|
||||
'DEALER_2',
|
||||
);
|
||||
const { accountId: accountId_3 } = await createAccount(
|
||||
source,
|
||||
3,
|
||||
TIERS.TIER4,
|
||||
'DEALER_3',
|
||||
);
|
||||
const service = module.get<AccountsService>(AccountsService);
|
||||
|
||||
expect(await service.getDealers()).toEqual({
|
||||
dealers: [
|
||||
{
|
||||
country: 'JP',
|
||||
id: accountId_1,
|
||||
name: 'DEALER_1',
|
||||
},
|
||||
{
|
||||
country: 'JP',
|
||||
id: accountId_2,
|
||||
name: 'DEALER_2',
|
||||
},
|
||||
{
|
||||
country: 'JP',
|
||||
id: accountId_3,
|
||||
name: 'DEALER_3',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
it('0件でもDealerを取得できる', async () => {
|
||||
const module = await makeTestingModule(source);
|
||||
|
||||
const service = module.get<AccountsService>(AccountsService);
|
||||
|
||||
expect(await service.getDealers()).toEqual({
|
||||
dealers: [],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -22,6 +22,9 @@ import {
|
||||
PartnerLicenseInfo,
|
||||
GetOrderHistoriesResponse,
|
||||
LicenseOrder,
|
||||
GetDealersResponse,
|
||||
Dealer,
|
||||
GetMyAccountResponse,
|
||||
} from './types/types';
|
||||
import { DateWithZeroTime } from '../licenses/types/types';
|
||||
import { GetLicenseSummaryResponse, Typist } from './types/types';
|
||||
@ -30,6 +33,7 @@ import { UserNotFoundError } from '../../repositories/users/errors/types';
|
||||
import { UserGroupsRepositoryService } from '../../repositories/user_groups/user_groups.repository.service';
|
||||
import { makePassword } from '../../common/password';
|
||||
import { LicensesRepositoryService } from '../../repositories/licenses/licenses.repository.service';
|
||||
import { AccountNotFoundError } from '../../repositories/accounts/errors/types';
|
||||
@Injectable()
|
||||
export class AccountsService {
|
||||
constructor(
|
||||
@ -215,7 +219,7 @@ export class AccountsService {
|
||||
* @param token
|
||||
* @returns accountId
|
||||
*/
|
||||
async getMyAccountInfo(token: AccessToken): Promise<number> {
|
||||
async getMyAccountInfo(token: AccessToken): Promise<GetMyAccountResponse> {
|
||||
this.logger.log(`[IN] ${this.getMyAccountInfo.name}`);
|
||||
|
||||
let userInfo: User;
|
||||
@ -236,8 +240,33 @@ export class AccountsService {
|
||||
}
|
||||
}
|
||||
|
||||
let accountInfo: Account;
|
||||
try {
|
||||
accountInfo = await this.accountRepository.findAccountById(
|
||||
userInfo.account_id,
|
||||
);
|
||||
} catch (e) {
|
||||
switch (e.constructor) {
|
||||
case AccountNotFoundError:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E010501'),
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
default:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
this.logger.log(`[OUT] ${this.getMyAccountInfo.name}`);
|
||||
return userInfo.account_id;
|
||||
return {
|
||||
account: {
|
||||
accountId: userInfo.account_id,
|
||||
companyName: accountInfo.company_name,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async getTypistGroups(externalId: string): Promise<TypistGroup[]> {
|
||||
@ -557,4 +586,33 @@ export class AccountsService {
|
||||
this.logger.log(`[OUT] ${this.getOrderHistories.name}`);
|
||||
}
|
||||
}
|
||||
|
||||
// dealersのアカウント情報を取得する
|
||||
async getDealers(): Promise<GetDealersResponse> {
|
||||
this.logger.log(`[IN] ${this.getDealers.name}`);
|
||||
|
||||
try {
|
||||
const dealerAccounts = await this.accountRepository.findDealerAccounts();
|
||||
|
||||
const dealers: GetDealersResponse = {
|
||||
dealers: dealerAccounts.map((dealerAccount): Dealer => {
|
||||
return {
|
||||
id: dealerAccount.id,
|
||||
name: dealerAccount.company_name,
|
||||
country: dealerAccount.country,
|
||||
};
|
||||
}),
|
||||
};
|
||||
|
||||
return dealers;
|
||||
} catch (e) {
|
||||
this.logger.error(e);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(`[OUT] ${this.getDealers.name}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,6 +81,8 @@ export class GetLicenseSummaryResponse {
|
||||
export class Account {
|
||||
@ApiProperty()
|
||||
accountId: number;
|
||||
@ApiProperty()
|
||||
companyName: string;
|
||||
}
|
||||
|
||||
export class GetMyAccountResponse {
|
||||
@ -234,3 +236,16 @@ export class IssueLicenseRequest {
|
||||
}
|
||||
|
||||
export class IssueLicenseResponse {}
|
||||
|
||||
export class Dealer {
|
||||
@ApiProperty({ description: 'アカウントID' })
|
||||
id: number;
|
||||
@ApiProperty({ description: '会社名' })
|
||||
name: string;
|
||||
@ApiProperty({ description: '国名(ISO 3166-1 alpha-2)' })
|
||||
country: string;
|
||||
}
|
||||
export class GetDealersResponse {
|
||||
@ApiProperty({ type: [Dealer] })
|
||||
dealers: Dealer[];
|
||||
}
|
||||
|
||||
@ -213,13 +213,11 @@ export class FilesService {
|
||||
//DBから国情報とアカウントIDを取得する
|
||||
let accountId: number;
|
||||
let country: string;
|
||||
let userId: number;
|
||||
try {
|
||||
const user = await this.usersRepository.findUserByExternalId(
|
||||
token.userId,
|
||||
);
|
||||
accountId = user.account.id;
|
||||
userId = user.id;
|
||||
country = user.account.country;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
@ -259,7 +257,6 @@ export class FilesService {
|
||||
const url = await this.blobStorageService.publishUploadSas(
|
||||
context,
|
||||
accountId,
|
||||
userId,
|
||||
country,
|
||||
);
|
||||
return url;
|
||||
@ -301,7 +298,6 @@ export class FilesService {
|
||||
const user = await this.usersRepository.findUserByExternalId(externalId);
|
||||
accountId = user.account.id;
|
||||
userId = user.id;
|
||||
userId = user.id;
|
||||
country = user.account.country;
|
||||
isTypist = user.role === USER_ROLES.TYPIST;
|
||||
authorId = user.author_id;
|
||||
@ -351,7 +347,7 @@ export class FilesService {
|
||||
);
|
||||
}
|
||||
|
||||
const filePath = `${file.owner_user_id}/${file.file_name}`;
|
||||
const filePath = `${file.file_name}`;
|
||||
|
||||
const isFileExist = await this.blobStorageService.fileExists(
|
||||
context,
|
||||
|
||||
@ -98,7 +98,8 @@ export class TasksController {
|
||||
decodedToken,
|
||||
offset,
|
||||
limit,
|
||||
status?.split(',') ?? [],
|
||||
// statusが指定されていない場合は全てのステータスを取得する
|
||||
status?.split(','),
|
||||
paramName,
|
||||
direction,
|
||||
);
|
||||
|
||||
@ -51,7 +51,7 @@ export class TasksService {
|
||||
accessToken: AccessToken,
|
||||
offset: number,
|
||||
limit: number,
|
||||
status: string[],
|
||||
status?: string[],
|
||||
paramName?: TaskListSortableAttribute,
|
||||
direction?: SortDirection,
|
||||
): Promise<{ tasks: Task[]; total: number }> {
|
||||
@ -66,6 +66,8 @@ export class TasksService {
|
||||
// パラメータが省略された場合のデフォルト値: 保存するソート条件の値の初期値と揃える
|
||||
const defaultParamName: TaskListSortableAttribute = 'JOB_NUMBER';
|
||||
const defaultDirection: SortDirection = 'ASC';
|
||||
// statusが省略された場合のデフォルト値: 全てのステータス
|
||||
const defaultStatus = Object.values(TASK_STATUS);
|
||||
|
||||
try {
|
||||
const { account_id, author_id } =
|
||||
@ -78,7 +80,7 @@ export class TasksService {
|
||||
limit,
|
||||
paramName ?? defaultParamName,
|
||||
direction ?? defaultDirection,
|
||||
status,
|
||||
status ?? defaultStatus,
|
||||
);
|
||||
|
||||
// B2Cからユーザー名を取得する
|
||||
@ -101,7 +103,7 @@ export class TasksService {
|
||||
limit,
|
||||
paramName ?? defaultParamName,
|
||||
direction ?? defaultDirection,
|
||||
status,
|
||||
status ?? defaultStatus,
|
||||
);
|
||||
|
||||
// B2Cからユーザー名を取得する
|
||||
@ -122,7 +124,7 @@ export class TasksService {
|
||||
limit,
|
||||
paramName ?? defaultParamName,
|
||||
direction ?? defaultDirection,
|
||||
status,
|
||||
status ?? defaultStatus,
|
||||
);
|
||||
// B2Cからユーザー名を取得する
|
||||
const b2cUsers = await this.getB2cUsers(
|
||||
|
||||
@ -5,8 +5,11 @@ import {
|
||||
USER_LICENSE_STATUS,
|
||||
} from '../../../constants';
|
||||
import { USER_ROLES } from '../../../constants';
|
||||
import {
|
||||
IsEncryptionPasswordPresent,
|
||||
IsPasswordvalid,
|
||||
} from '../../../common/validators/encryptionPassword.validator';
|
||||
import { IsRoleAuthorDataValid } from '../../../common/validators/roleAuthor.validator';
|
||||
import { IsPasswordvalid } from '../../../common/validators/encryptionPassword.validator';
|
||||
|
||||
export class ConfirmRequest {
|
||||
@ApiProperty()
|
||||
@ -81,11 +84,9 @@ export class SignupRequest {
|
||||
role: string;
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsRoleAuthorDataValid()
|
||||
authorId?: string | undefined;
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
typistGroupId?: number | undefined;
|
||||
|
||||
@ApiProperty()
|
||||
email: string;
|
||||
|
||||
@ -97,6 +98,19 @@ export class SignupRequest {
|
||||
|
||||
@ApiProperty()
|
||||
notification: boolean;
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsRoleAuthorDataValid()
|
||||
encryption?: boolean | undefined;
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsPasswordvalid()
|
||||
@IsEncryptionPasswordPresent()
|
||||
encryptionPassword?: string | undefined;
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsRoleAuthorDataValid()
|
||||
prompt?: boolean | undefined;
|
||||
}
|
||||
|
||||
export class SignupResponse {}
|
||||
|
||||
@ -44,6 +44,7 @@ import {
|
||||
import { ADMIN_ROLES } from '../../constants';
|
||||
import { RoleGuard } from '../../common/guards/role/roleguards';
|
||||
import { makeContext } from '../../common/log';
|
||||
import { UserRoles } from '../../common/types/role';
|
||||
|
||||
@ApiTags('users')
|
||||
@Controller('users')
|
||||
@ -162,7 +163,9 @@ export class UsersController {
|
||||
licenseAlert,
|
||||
notification,
|
||||
authorId,
|
||||
typistGroupId,
|
||||
encryption,
|
||||
encryptionPassword,
|
||||
prompt,
|
||||
} = body;
|
||||
|
||||
const accessToken = retrieveAuthorizationToken(req);
|
||||
@ -172,13 +175,15 @@ export class UsersController {
|
||||
await this.usersService.createUser(
|
||||
payload,
|
||||
name,
|
||||
role,
|
||||
role as UserRoles,
|
||||
email,
|
||||
autoRenew,
|
||||
licenseAlert,
|
||||
notification,
|
||||
authorId,
|
||||
typistGroupId,
|
||||
encryption,
|
||||
encryptionPassword,
|
||||
prompt,
|
||||
);
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -285,7 +285,7 @@ describe('UsersService.confirmUser', () => {
|
||||
sortCriteriaRepositoryMockValue,
|
||||
);
|
||||
const name = 'test_user1';
|
||||
const role = 'None';
|
||||
const role = USER_ROLES.NONE;
|
||||
const email = 'test1@example.co.jp';
|
||||
const autoRenew = true;
|
||||
const licenseAlert = true;
|
||||
@ -306,7 +306,7 @@ describe('UsersService.confirmUser', () => {
|
||||
});
|
||||
|
||||
describe('UsersService.createUser', () => {
|
||||
it('管理者権限のあるアクセストークンを使用して、新規ユーザが追加される(role:Author)', async () => {
|
||||
it('管理者権限のあるアクセストークンを使用して、新規ユーザが追加される(role:Author; 暗号化あり)', async () => {
|
||||
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
|
||||
const adb2cParam = makeDefaultAdB2cMockValue();
|
||||
const sendgridMockValue = makeDefaultSendGridlValue();
|
||||
@ -321,12 +321,15 @@ describe('UsersService.createUser', () => {
|
||||
sortCriteriaRepositoryMockValue,
|
||||
);
|
||||
const name = 'test_user2';
|
||||
const role = 'Author';
|
||||
const role = USER_ROLES.AUTHOR;
|
||||
const email = 'test2@example.co.jp';
|
||||
const autoRenew = true;
|
||||
const licenseAlert = true;
|
||||
const notification = true;
|
||||
const authorId = 'testID';
|
||||
const encryption = true;
|
||||
const prompt = true;
|
||||
const encryptionPassword = 'testPassword';
|
||||
const token: AccessToken = { userId: '0001', role: '', tier: 5 };
|
||||
expect(
|
||||
await service.createUser(
|
||||
@ -338,6 +341,51 @@ describe('UsersService.createUser', () => {
|
||||
licenseAlert,
|
||||
notification,
|
||||
authorId,
|
||||
encryption,
|
||||
encryptionPassword,
|
||||
prompt,
|
||||
),
|
||||
).toEqual(undefined);
|
||||
});
|
||||
|
||||
it('管理者権限のあるアクセストークンを使用して、新規ユーザが追加される(role:Author; 暗号化無し)', async () => {
|
||||
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
|
||||
const adb2cParam = makeDefaultAdB2cMockValue();
|
||||
const sendgridMockValue = makeDefaultSendGridlValue();
|
||||
const configMockValue = makeDefaultConfigValue();
|
||||
const sortCriteriaRepositoryMockValue =
|
||||
makeDefaultSortCriteriaRepositoryMockValue();
|
||||
const service = await makeUsersServiceMock(
|
||||
usersRepositoryMockValue,
|
||||
adb2cParam,
|
||||
sendgridMockValue,
|
||||
configMockValue,
|
||||
sortCriteriaRepositoryMockValue,
|
||||
);
|
||||
const name = 'test_user2';
|
||||
const role = USER_ROLES.AUTHOR;
|
||||
const email = 'test2@example.co.jp';
|
||||
const autoRenew = true;
|
||||
const licenseAlert = true;
|
||||
const notification = true;
|
||||
const authorId = 'testID';
|
||||
const encryption = false;
|
||||
const prompt = true;
|
||||
const encryptionPassword = undefined;
|
||||
const token: AccessToken = { userId: '0001', role: '', tier: 5 };
|
||||
expect(
|
||||
await service.createUser(
|
||||
token,
|
||||
name,
|
||||
role,
|
||||
email,
|
||||
autoRenew,
|
||||
licenseAlert,
|
||||
notification,
|
||||
authorId,
|
||||
encryption,
|
||||
encryptionPassword,
|
||||
prompt,
|
||||
),
|
||||
).toEqual(undefined);
|
||||
});
|
||||
@ -357,12 +405,11 @@ describe('UsersService.createUser', () => {
|
||||
sortCriteriaRepositoryMockValue,
|
||||
);
|
||||
const name = 'test_user3';
|
||||
const role = 'Transcriptioninst';
|
||||
const role = USER_ROLES.TYPIST;
|
||||
const email = 'test3@example.co.jp';
|
||||
const autoRenew = true;
|
||||
const licenseAlert = true;
|
||||
const notification = true;
|
||||
const typistGroupId = 111;
|
||||
const token: AccessToken = { userId: '0001', role: '', tier: 5 };
|
||||
expect(
|
||||
await service.createUser(
|
||||
@ -374,7 +421,6 @@ describe('UsersService.createUser', () => {
|
||||
licenseAlert,
|
||||
notification,
|
||||
undefined,
|
||||
typistGroupId,
|
||||
),
|
||||
).toEqual(undefined);
|
||||
});
|
||||
@ -394,7 +440,7 @@ describe('UsersService.createUser', () => {
|
||||
sortCriteriaRepositoryMockValue,
|
||||
);
|
||||
const name = 'test_user5';
|
||||
const role = 'Transcriptioninst';
|
||||
const role = USER_ROLES.TYPIST;
|
||||
const email = 'test5@example.co.jp';
|
||||
const autoRenew = true;
|
||||
const licenseAlert = true;
|
||||
@ -433,7 +479,7 @@ describe('UsersService.createUser', () => {
|
||||
sortCriteriaRepositoryMockValue,
|
||||
);
|
||||
const name = 'test_user6';
|
||||
const role = 'Transcriptioninst';
|
||||
const role = USER_ROLES.TYPIST;
|
||||
const email = 'test6@example.co.jp';
|
||||
const autoRenew = true;
|
||||
const licenseAlert = true;
|
||||
@ -472,7 +518,7 @@ describe('UsersService.createUser', () => {
|
||||
sortCriteriaRepositoryMockValue,
|
||||
);
|
||||
const name = 'test_user7';
|
||||
const role = 'Transcriptioninst';
|
||||
const role = USER_ROLES.TYPIST;
|
||||
const email = 'test7@example.co.jp';
|
||||
const autoRenew = true;
|
||||
const licenseAlert = true;
|
||||
@ -510,7 +556,7 @@ describe('UsersService.createUser', () => {
|
||||
sortCriteriaRepositoryMockValue,
|
||||
);
|
||||
const name = 'test_user8';
|
||||
const role = 'Author';
|
||||
const role = USER_ROLES.AUTHOR;
|
||||
const email = 'test8@example.co.jp';
|
||||
const autoRenew = true;
|
||||
const licenseAlert = true;
|
||||
@ -550,7 +596,7 @@ describe('UsersService.createUser', () => {
|
||||
sortCriteriaRepositoryMockValue,
|
||||
);
|
||||
const name = 'test_user9';
|
||||
const role = 'Author';
|
||||
const role = USER_ROLES.AUTHOR;
|
||||
const email = 'test9@example.co.jp';
|
||||
const autoRenew = true;
|
||||
const licenseAlert = true;
|
||||
|
||||
@ -18,7 +18,10 @@ import {
|
||||
} from '../../gateways/adb2c/adb2c.service';
|
||||
import { SendGridService } from '../../gateways/sendgrid/sendgrid.service';
|
||||
import { SortCriteriaRepositoryService } from '../../repositories/sort_criteria/sort_criteria.repository.service';
|
||||
import { User as EntityUser } from '../../repositories/users/entity/user.entity';
|
||||
import {
|
||||
User as EntityUser,
|
||||
newUser,
|
||||
} from '../../repositories/users/entity/user.entity';
|
||||
import { UsersRepositoryService } from '../../repositories/users/users.repository.service';
|
||||
import { GetRelationsResponse, User } from './types/types';
|
||||
import {
|
||||
@ -31,9 +34,11 @@ import {
|
||||
import {
|
||||
LICENSE_EXPIRATION_THRESHOLD_DAYS,
|
||||
USER_LICENSE_STATUS,
|
||||
USER_ROLES,
|
||||
} from '../../constants';
|
||||
import { DateWithZeroTime } from '../licenses/types/types';
|
||||
import { Context } from '../../common/log';
|
||||
import { UserRoles } from '../../common/types/role';
|
||||
|
||||
@Injectable()
|
||||
export class UsersService {
|
||||
@ -71,7 +76,7 @@ export class UsersService {
|
||||
const userId = decodedToken.userId;
|
||||
await this.usersRepository.updateUserVerified(userId);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
this.logger.error(e);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case EmailAlreadyVerifiedError:
|
||||
@ -87,7 +92,6 @@ export class UsersService {
|
||||
}
|
||||
}
|
||||
|
||||
this.logger.error(`error=${e}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
@ -96,20 +100,32 @@ export class UsersService {
|
||||
}
|
||||
|
||||
/**
|
||||
* ユーザを作成する
|
||||
* @param token
|
||||
* @returns account
|
||||
* Creates user
|
||||
* @param accessToken
|
||||
* @param name
|
||||
* @param role
|
||||
* @param email
|
||||
* @param autoRenew
|
||||
* @param licenseAlert
|
||||
* @param notification
|
||||
* @param [authorId]
|
||||
* @param [encryption]
|
||||
* @param [encryptionPassword]
|
||||
* @param [prompt]
|
||||
* @returns void
|
||||
*/
|
||||
async createUser(
|
||||
accessToken: AccessToken,
|
||||
name: string,
|
||||
role: string,
|
||||
role: UserRoles,
|
||||
email: string,
|
||||
autoRenew: boolean,
|
||||
licenseAlert: boolean,
|
||||
notification: boolean,
|
||||
authorId?: string | undefined,
|
||||
groupID?: number | undefined,
|
||||
encryption?: boolean | undefined,
|
||||
encryptionPassword?: string | undefined,
|
||||
prompt?: boolean | undefined,
|
||||
): Promise<void> {
|
||||
this.logger.log(`[IN] ${this.createUser.name}`);
|
||||
|
||||
@ -120,6 +136,7 @@ export class UsersService {
|
||||
accessToken.userId,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
@ -137,6 +154,7 @@ export class UsersService {
|
||||
authorId,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
@ -163,7 +181,8 @@ export class UsersService {
|
||||
name,
|
||||
);
|
||||
} catch (e) {
|
||||
console.log('create externalUser failed');
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error('create externalUser failed');
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
@ -180,22 +199,26 @@ export class UsersService {
|
||||
|
||||
//Azure AD B2Cに登録したユーザー情報のID(sub)と受け取った情報を使ってDBにユーザーを登録する
|
||||
let newUser: EntityUser;
|
||||
// TODO [Task2246] 本来はNULLだが、テーブル定義に誤ってNOTNULLが付いているため、一時的に適当な値を設定
|
||||
const accepted_terms_version = 'xxx';
|
||||
|
||||
try {
|
||||
// ユーザ作成
|
||||
newUser = await this.usersRepository.createNormalUser(
|
||||
//roleに応じてユーザー情報を作成する
|
||||
const newUserInfo = this.createNewUserInfo(
|
||||
role,
|
||||
accountId,
|
||||
externalUser.sub,
|
||||
role,
|
||||
autoRenew,
|
||||
licenseAlert,
|
||||
notification,
|
||||
authorId,
|
||||
accepted_terms_version,
|
||||
encryption,
|
||||
encryptionPassword,
|
||||
prompt,
|
||||
);
|
||||
// ユーザ作成
|
||||
newUser = await this.usersRepository.createNormalUser(newUserInfo);
|
||||
} catch (e) {
|
||||
console.log('create user failed');
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error('create user failed');
|
||||
switch (e.code) {
|
||||
case 'ER_DUP_ENTRY':
|
||||
//AuthorID重複エラー
|
||||
@ -227,8 +250,9 @@ export class UsersService {
|
||||
//SendGridAPIを呼び出してメールを送信する
|
||||
await this.sendgridService.sendMail(email, from, subject, text, html);
|
||||
} catch (e) {
|
||||
console.log('create user failed');
|
||||
console.log(`[NOT IMPLEMENT] [RECOVER] delete user: ${newUser.id}`);
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error('create user failed');
|
||||
this.logger.error(`[NOT IMPLEMENT] [RECOVER] delete user: ${newUser.id}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
@ -237,6 +261,54 @@ export class UsersService {
|
||||
this.logger.log(`[OUT] ${this.createUser.name}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// roleを受け取って、roleに応じたnewUserを作成して返却する
|
||||
private createNewUserInfo(
|
||||
role: UserRoles,
|
||||
accountId: number,
|
||||
externalId: string,
|
||||
autoRenew: boolean,
|
||||
licenseAlert: boolean,
|
||||
notification: boolean,
|
||||
authorId?: string | undefined,
|
||||
encryption?: boolean | undefined,
|
||||
encryptionPassword?: string | undefined,
|
||||
prompt?: boolean | undefined,
|
||||
): newUser {
|
||||
switch (role) {
|
||||
case USER_ROLES.NONE:
|
||||
case USER_ROLES.TYPIST:
|
||||
return {
|
||||
account_id: accountId,
|
||||
external_id: externalId,
|
||||
auto_renew: autoRenew,
|
||||
license_alert: licenseAlert,
|
||||
notification,
|
||||
role,
|
||||
};
|
||||
case USER_ROLES.AUTHOR:
|
||||
return {
|
||||
account_id: accountId,
|
||||
external_id: externalId,
|
||||
auto_renew: autoRenew,
|
||||
license_alert: licenseAlert,
|
||||
notification,
|
||||
role,
|
||||
author_id: authorId,
|
||||
encryption,
|
||||
encryption_password: encryptionPassword,
|
||||
prompt,
|
||||
};
|
||||
default:
|
||||
//不正なroleが指定された場合はログを出力してエラーを返す
|
||||
this.logger.error(`[NOT IMPLEMENT] [RECOVER] role: ${role}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* confirm User And Init Password
|
||||
* @param token ユーザ仮登録時に払いだされるトークン
|
||||
|
||||
@ -124,14 +124,12 @@ export class BlobstorageService {
|
||||
/**
|
||||
* SASトークン付きのBlobStorageアップロードURLを生成し返却します
|
||||
* @param accountId
|
||||
* @param userId
|
||||
* @param country
|
||||
* @returns upload sas
|
||||
*/
|
||||
async publishUploadSas(
|
||||
context: Context,
|
||||
accountId: number,
|
||||
userId: number,
|
||||
country: string,
|
||||
): Promise<string> {
|
||||
this.logger.log(
|
||||
@ -175,11 +173,12 @@ export class BlobstorageService {
|
||||
);
|
||||
|
||||
const url = new URL(containerClient.url);
|
||||
url.pathname += `/${userId}`;
|
||||
url.search = `${sasToken}`;
|
||||
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.publishUploadSas.name}`,
|
||||
`[OUT] [${context.trackingId}] ${
|
||||
this.publishUploadSas.name
|
||||
} url=${url.toString()}`,
|
||||
);
|
||||
return url.toString();
|
||||
}
|
||||
@ -246,7 +245,9 @@ export class BlobstorageService {
|
||||
url.search = `${sasToken}`;
|
||||
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.publishDownloadSas.name}`,
|
||||
`[OUT] [${context.trackingId}] ${
|
||||
this.publishDownloadSas.name
|
||||
}, url=${url.toString()}`,
|
||||
);
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
@ -21,6 +21,7 @@ import {
|
||||
import {
|
||||
LICENSE_ALLOCATED_STATUS,
|
||||
LICENSE_STATUS_ISSUE_REQUESTING,
|
||||
TIERS,
|
||||
} from '../../constants';
|
||||
import {
|
||||
LicenseSummaryInfo,
|
||||
@ -551,4 +552,18 @@ export class AccountsRepositoryService {
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Dealer(Tier4)アカウント情報を取得する
|
||||
* @returns dealer accounts
|
||||
*/
|
||||
async findDealerAccounts(): Promise<Account[]> {
|
||||
const accounts = await this.dataSource.getRepository(Account).find({
|
||||
where: {
|
||||
tier: TIERS.TIER4,
|
||||
},
|
||||
});
|
||||
|
||||
return accounts;
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,8 +30,8 @@ export class User {
|
||||
@Column({ nullable: true })
|
||||
author_id?: string;
|
||||
|
||||
@Column()
|
||||
accepted_terms_version: string;
|
||||
@Column({ nullable: true })
|
||||
accepted_terms_version?: string;
|
||||
|
||||
@Column()
|
||||
email_verified: boolean;
|
||||
@ -45,14 +45,14 @@ export class User {
|
||||
@Column()
|
||||
notification: boolean;
|
||||
|
||||
@Column()
|
||||
encryption: boolean;
|
||||
@Column({ nullable: true })
|
||||
encryption?: boolean;
|
||||
|
||||
@Column({ nullable: true })
|
||||
encryption_password?: string;
|
||||
|
||||
@Column()
|
||||
prompt: boolean;
|
||||
@Column({ nullable: true })
|
||||
prompt?: boolean;
|
||||
|
||||
@Column({ nullable: true })
|
||||
deleted_at?: Date;
|
||||
@ -79,3 +79,17 @@ export class User {
|
||||
@OneToMany(() => UserGroupMember, (userGroupMember) => userGroupMember.user)
|
||||
userGroupMembers?: UserGroupMember[];
|
||||
}
|
||||
|
||||
export type newUser = Omit<
|
||||
User,
|
||||
| 'id'
|
||||
| 'deleted_at'
|
||||
| 'created_at'
|
||||
| 'updated_at'
|
||||
| 'updated_by'
|
||||
| 'created_by'
|
||||
| 'account'
|
||||
| 'license'
|
||||
| 'userGroupMembers'
|
||||
| 'email_verified'
|
||||
>;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { User, newUser } from './entity/user.entity';
|
||||
import { DataSource, IsNull, Not, UpdateResult } from 'typeorm';
|
||||
import { User } from './entity/user.entity';
|
||||
import { SortCriteria } from '../sort_criteria/entity/sort_criteria.entity';
|
||||
import {
|
||||
getDirection,
|
||||
@ -45,41 +45,42 @@ export class UsersRepositoryService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 一般ユーザを作成する
|
||||
* @param account_id
|
||||
* @param external_id
|
||||
* @param role
|
||||
* @param autoRenew
|
||||
* @param licenseAlert
|
||||
* @param notification
|
||||
* @param authorId
|
||||
* 一般ユーザーを作成する
|
||||
* @param user
|
||||
* @returns User
|
||||
*/
|
||||
async createNormalUser(
|
||||
accountId: number,
|
||||
externalUserId: string,
|
||||
role: string,
|
||||
auto_renew: boolean,
|
||||
license_alert: boolean,
|
||||
notification: boolean,
|
||||
author_id: string,
|
||||
accepted_terms_version: string,
|
||||
): Promise<User> {
|
||||
const user = new User();
|
||||
async createNormalUser(user: newUser): Promise<User> {
|
||||
const {
|
||||
account_id: accountId,
|
||||
external_id: externalUserId,
|
||||
role,
|
||||
auto_renew,
|
||||
license_alert,
|
||||
notification,
|
||||
author_id,
|
||||
accepted_terms_version,
|
||||
encryption,
|
||||
encryption_password: encryptionPassword,
|
||||
prompt,
|
||||
} = user;
|
||||
const userEntity = new User();
|
||||
|
||||
user.role = role;
|
||||
user.account_id = accountId;
|
||||
user.external_id = externalUserId;
|
||||
user.auto_renew = auto_renew;
|
||||
user.license_alert = license_alert;
|
||||
user.notification = notification;
|
||||
user.author_id = author_id;
|
||||
user.accepted_terms_version = accepted_terms_version;
|
||||
userEntity.role = role;
|
||||
userEntity.account_id = accountId;
|
||||
userEntity.external_id = externalUserId;
|
||||
userEntity.auto_renew = auto_renew;
|
||||
userEntity.license_alert = license_alert;
|
||||
userEntity.notification = notification;
|
||||
userEntity.author_id = author_id;
|
||||
userEntity.accepted_terms_version = accepted_terms_version;
|
||||
userEntity.encryption = encryption;
|
||||
userEntity.encryption_password = encryptionPassword;
|
||||
userEntity.prompt = prompt;
|
||||
|
||||
const createdEntity = await this.dataSource.transaction(
|
||||
async (entityManager) => {
|
||||
const repo = entityManager.getRepository(User);
|
||||
const newUser = repo.create(user);
|
||||
const newUser = repo.create(userEntity);
|
||||
const persisted = await repo.save(newUser);
|
||||
|
||||
// ユーザーのタスクソート条件を作成
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user