diff --git a/dictation_client/src/AppRouter.tsx b/dictation_client/src/AppRouter.tsx index 08b7185..248c80b 100644 --- a/dictation_client/src/AppRouter.tsx +++ b/dictation_client/src/AppRouter.tsx @@ -18,6 +18,7 @@ import DictationPage from "pages/DictationPage"; import PartnerPage from "pages/PartnerPage"; import WorkflowPage from "pages/WorkflowPage"; import TypistGroupSettingPage from "pages/TypistGroupSettingPage"; +import WorktypeIdSettingPage from "pages/WorkTypeIdSettingPage"; const AppRouter: React.FC = () => ( @@ -66,6 +67,10 @@ const AppRouter: React.FC = () => ( path="/workflow/typist-group" element={} />} /> + } />} + /> } />} diff --git a/dictation_client/src/api/api.ts b/dictation_client/src/api/api.ts index e0430ca..429eb58 100644 --- a/dictation_client/src/api/api.ts +++ b/dictation_client/src/api/api.ts @@ -462,6 +462,25 @@ export interface CreateTypistGroupRequest { */ 'typistIds': Array; } +/** + * + * @export + * @interface CreateWorktypesRequest + */ +export interface CreateWorktypesRequest { + /** + * WorktypeID + * @type {string} + * @memberof CreateWorktypesRequest + */ + 'worktypeId': string; + /** + * Worktypeの説明 + * @type {string} + * @memberof CreateWorktypesRequest + */ + 'description'?: string; +} /** * * @export @@ -873,15 +892,15 @@ export interface GetUsersResponse { /** * * @export - * @interface GetWorkTypesResponse + * @interface GetWorktypesResponse */ -export interface GetWorkTypesResponse { +export interface GetWorktypesResponse { /** * - * @type {Array} - * @memberof GetWorkTypesResponse + * @type {Array} + * @memberof GetWorktypesResponse */ - 'workTypes': Array; + 'worktypes': Array; } /** * @@ -1609,25 +1628,25 @@ export interface User { /** * * @export - * @interface WorkType + * @interface Worktype */ -export interface WorkType { +export interface Worktype { /** - * WorkTypeのID + * WorktypeのID * @type {number} - * @memberof WorkType + * @memberof Worktype */ 'id': number; /** - * WorkTypeID + * WorktypeID * @type {string} - * @memberof WorkType + * @memberof Worktype */ - 'workTypeId': string; + 'worktypeId': string; /** - * WorkTypeの説明 + * Worktypeの説明 * @type {string} - * @memberof WorkType + * @memberof Worktype */ 'description'?: string; } @@ -1794,6 +1813,46 @@ export const AccountsApiAxiosParamCreator = function (configuration?: Configurat options: localVarRequestOptions, }; }, + /** + * + * @summary + * @param {CreateWorktypesRequest} createWorktypesRequest + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + createWorktype: async (createWorktypesRequest: CreateWorktypesRequest, options: AxiosRequestConfig = {}): Promise => { + // verify required parameter 'createWorktypesRequest' is not null or undefined + assertParamExists('createWorktype', 'createWorktypesRequest', createWorktypesRequest) + const localVarPath = `/accounts/worktypes`; + // 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(createWorktypesRequest, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, /** * * @summary @@ -2256,6 +2315,17 @@ export const AccountsApiFp = function(configuration?: Configuration) { const localVarAxiosArgs = await localVarAxiosParamCreator.createTypistGroup(createTypistGroupRequest, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, + /** + * + * @summary + * @param {CreateWorktypesRequest} createWorktypesRequest + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async createWorktype(createWorktypesRequest: CreateWorktypesRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.createWorktype(createWorktypesRequest, options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, /** * * @summary @@ -2346,7 +2416,7 @@ export const AccountsApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async getWorktypes(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + async getWorktypes(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.getWorktypes(options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, @@ -2423,6 +2493,16 @@ export const AccountsApiFactory = function (configuration?: Configuration, baseP createTypistGroup(createTypistGroupRequest: CreateTypistGroupRequest, options?: any): AxiosPromise { return localVarFp.createTypistGroup(createTypistGroupRequest, options).then((request) => request(axios, basePath)); }, + /** + * + * @summary + * @param {CreateWorktypesRequest} createWorktypesRequest + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + createWorktype(createWorktypesRequest: CreateWorktypesRequest, options?: any): AxiosPromise { + return localVarFp.createWorktype(createWorktypesRequest, options).then((request) => request(axios, basePath)); + }, /** * * @summary @@ -2505,7 +2585,7 @@ export const AccountsApiFactory = function (configuration?: Configuration, baseP * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getWorktypes(options?: any): AxiosPromise { + getWorktypes(options?: any): AxiosPromise { return localVarFp.getWorktypes(options).then((request) => request(axios, basePath)); }, /** @@ -2587,6 +2667,18 @@ export class AccountsApi extends BaseAPI { return AccountsApiFp(this.configuration).createTypistGroup(createTypistGroupRequest, options).then((request) => request(this.axios, this.basePath)); } + /** + * + * @summary + * @param {CreateWorktypesRequest} createWorktypesRequest + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof AccountsApi + */ + public createWorktype(createWorktypesRequest: CreateWorktypesRequest, options?: AxiosRequestConfig) { + return AccountsApiFp(this.configuration).createWorktype(createWorktypesRequest, options).then((request) => request(this.axios, this.basePath)); + } + /** * * @summary diff --git a/dictation_client/src/app/store.ts b/dictation_client/src/app/store.ts index 722801d..73c16f7 100644 --- a/dictation_client/src/app/store.ts +++ b/dictation_client/src/app/store.ts @@ -14,6 +14,7 @@ import dictation from "features/dictation/dictationSlice"; import partner from "features/partner/partnerSlice"; import licenseOrderHistory from "features/license/licenseOrderHistory/licenseOrderHistorySlice"; import typistGroup from "features/workflow/typistGroup/typistGroupSlice"; +import worktype from "features/workflow/worktype/worktypeSlice"; export const store = configureStore({ reducer: { @@ -32,6 +33,7 @@ export const store = configureStore({ dictation, partner, typistGroup, + worktype, }, }); diff --git a/dictation_client/src/assets/images/worktype_add.svg b/dictation_client/src/assets/images/worktype_add.svg new file mode 100644 index 0000000..a63ac00 --- /dev/null +++ b/dictation_client/src/assets/images/worktype_add.svg @@ -0,0 +1,12 @@ + + + + + + diff --git a/dictation_client/src/features/workflow/worktype/index.ts b/dictation_client/src/features/workflow/worktype/index.ts new file mode 100644 index 0000000..22036b3 --- /dev/null +++ b/dictation_client/src/features/workflow/worktype/index.ts @@ -0,0 +1,4 @@ +export * from "./worktypeSlice"; +export * from "./state"; +export * from "./selectors"; +export * from "./operations"; diff --git a/dictation_client/src/features/workflow/worktype/operations.ts b/dictation_client/src/features/workflow/worktype/operations.ts new file mode 100644 index 0000000..ad05f7c --- /dev/null +++ b/dictation_client/src/features/workflow/worktype/operations.ts @@ -0,0 +1,45 @@ +import { createAsyncThunk } from "@reduxjs/toolkit"; +import type { RootState } from "app/store"; +import { openSnackbar } from "features/ui/uiSlice"; +import { getTranslationID } from "translation"; +import { AccountsApi, GetWorktypesResponse } from "../../../api/api"; +import { Configuration } from "../../../api/configuration"; +import { ErrorObject, createErrorObject } from "../../../common/errors"; + +export const listWorktypesAsync = createAsyncThunk< + GetWorktypesResponse, + void, + { + // rejectした時の返却値の型 + rejectValue: { + error: ErrorObject; + }; + } +>("workflow/listWorktypesAsync", async (args, thunkApi) => { + // apiのConfigurationを取得する + const { getState } = thunkApi; + const state = getState() as RootState; + const { configuration, accessToken } = state.auth; + const config = new Configuration(configuration); + const accountsApi = new AccountsApi(config); + + try { + const worktypes = ( + await accountsApi.getWorktypes({ + headers: { authorization: `Bearer ${accessToken}` }, + }) + ).data; + + return worktypes; + } catch (e) { + // e ⇒ errorObjectに変換" + const error = createErrorObject(e); + thunkApi.dispatch( + openSnackbar({ + level: "error", + message: getTranslationID("common.message.internalServerError"), + }) + ); + return thunkApi.rejectWithValue({ error }); + } +}); diff --git a/dictation_client/src/features/workflow/worktype/selectors.ts b/dictation_client/src/features/workflow/worktype/selectors.ts new file mode 100644 index 0000000..343d665 --- /dev/null +++ b/dictation_client/src/features/workflow/worktype/selectors.ts @@ -0,0 +1,7 @@ +import { RootState } from "app/store"; + +export const selectWorktypes = (state: RootState) => + state.worktype.domain.worktypes; + +export const selectIsLoading = (state: RootState) => + state.worktype.apps.isLoading; diff --git a/dictation_client/src/features/workflow/worktype/state.ts b/dictation_client/src/features/workflow/worktype/state.ts new file mode 100644 index 0000000..365b7b7 --- /dev/null +++ b/dictation_client/src/features/workflow/worktype/state.ts @@ -0,0 +1,14 @@ +import { Worktype } from "api"; + +export interface WorktypeState { + apps: Apps; + domain: Domain; +} + +export interface Apps { + isLoading: boolean; +} + +export interface Domain { + worktypes?: Worktype[]; +} diff --git a/dictation_client/src/features/workflow/worktype/worktypeSlice.ts b/dictation_client/src/features/workflow/worktype/worktypeSlice.ts new file mode 100644 index 0000000..624f3bd --- /dev/null +++ b/dictation_client/src/features/workflow/worktype/worktypeSlice.ts @@ -0,0 +1,31 @@ +import { createSlice } from "@reduxjs/toolkit"; +import { WorktypeState } from "./state"; +import { listWorktypesAsync } from "./operations"; + +const initialState: WorktypeState = { + apps: { + isLoading: false, + }, + domain: {}, +}; + +export const worktypeSlice = createSlice({ + name: "worktype", + initialState, + reducers: {}, + extraReducers: (builder) => { + builder.addCase(listWorktypesAsync.pending, (state) => { + state.apps.isLoading = true; + }); + builder.addCase(listWorktypesAsync.fulfilled, (state, action) => { + const { worktypes } = action.payload; + state.domain.worktypes = worktypes; + state.apps.isLoading = false; + }); + builder.addCase(listWorktypesAsync.rejected, (state) => { + state.apps.isLoading = false; + }); + }, +}); + +export default worktypeSlice.reducer; diff --git a/dictation_client/src/pages/DictationPage/changeTranscriptionistPopup.tsx b/dictation_client/src/pages/DictationPage/changeTranscriptionistPopup.tsx index e13e8dd..98d6b38 100644 --- a/dictation_client/src/pages/DictationPage/changeTranscriptionistPopup.tsx +++ b/dictation_client/src/pages/DictationPage/changeTranscriptionistPopup.tsx @@ -185,7 +185,7 @@ export const ChangeTranscriptionistPopup: React.FC< = ( onClick={returnGui} > - {t(getTranslationID("orderHistoriesPage.label.return"))} + {t(getTranslationID("common.label.return"))} diff --git a/dictation_client/src/pages/LicensePage/licenseSummary.tsx b/dictation_client/src/pages/LicensePage/licenseSummary.tsx index 202e968..1744105 100644 --- a/dictation_client/src/pages/LicensePage/licenseSummary.tsx +++ b/dictation_client/src/pages/LicensePage/licenseSummary.tsx @@ -126,11 +126,7 @@ export const LicenseSummary: React.FC = ( alt="" className={styles.menuIcon} /> - {t( - getTranslationID( - "partnerLicense.label.returnButton" - ) - )} + {t(getTranslationID("common.label.return"))} )} diff --git a/dictation_client/src/pages/LicensePage/partnerLicense.tsx b/dictation_client/src/pages/LicensePage/partnerLicense.tsx index b6653da..c93501d 100644 --- a/dictation_client/src/pages/LicensePage/partnerLicense.tsx +++ b/dictation_client/src/pages/LicensePage/partnerLicense.tsx @@ -277,9 +277,7 @@ const PartnerLicense: React.FC = (): JSX.Element => { alt="" className={styles.menuIcon} /> - {t( - getTranslationID("partnerLicense.label.returnButton") - )} + {t(getTranslationID("common.label.return"))} )} diff --git a/dictation_client/src/pages/TypistGroupSettingPage/addTypistGroupPopup.tsx b/dictation_client/src/pages/TypistGroupSettingPage/addTypistGroupPopup.tsx index 484522b..12000af 100644 --- a/dictation_client/src/pages/TypistGroupSettingPage/addTypistGroupPopup.tsx +++ b/dictation_client/src/pages/TypistGroupSettingPage/addTypistGroupPopup.tsx @@ -190,7 +190,7 @@ export const AddTypistGroupPopup: React.FC = ( diff --git a/dictation_client/src/pages/TypistGroupSettingPage/editTypistGroupPopup.tsx b/dictation_client/src/pages/TypistGroupSettingPage/editTypistGroupPopup.tsx index a20c6c7..faf85d4 100644 --- a/dictation_client/src/pages/TypistGroupSettingPage/editTypistGroupPopup.tsx +++ b/dictation_client/src/pages/TypistGroupSettingPage/editTypistGroupPopup.tsx @@ -184,7 +184,7 @@ export const EditTypistGroupPopup: React.FC = ( diff --git a/dictation_client/src/pages/TypistGroupSettingPage/index.tsx b/dictation_client/src/pages/TypistGroupSettingPage/index.tsx index 2d17ff1..6b1ff06 100644 --- a/dictation_client/src/pages/TypistGroupSettingPage/index.tsx +++ b/dictation_client/src/pages/TypistGroupSettingPage/index.tsx @@ -83,7 +83,7 @@ const TypistGroupSettingPage: React.FC = (): JSX.Element => { className={`${styles.menuLink} ${styles.isActive}`} > - {t(getTranslationID("typistGroupSetting.label.return"))} + {t(getTranslationID("common.label.return"))}
  • @@ -127,11 +127,7 @@ const TypistGroupSettingPage: React.FC = (): JSX.Element => { onEditPopupOpen(group.id); }} > - {t( - getTranslationID( - "typistGroupSetting.label.edit" - ) - )} + {t(getTranslationID("common.label.edit"))}
  • diff --git a/dictation_client/src/pages/WorkTypeIdSettingPage/index.tsx b/dictation_client/src/pages/WorkTypeIdSettingPage/index.tsx new file mode 100644 index 0000000..2a77caf --- /dev/null +++ b/dictation_client/src/pages/WorkTypeIdSettingPage/index.tsx @@ -0,0 +1,170 @@ +import { UpdateTokenTimer } from "components/auth/updateTokenTimer"; +import Footer from "components/footer"; +import Header from "components/header"; +import React, { useEffect, useState } from "react"; +import { getTranslationID } from "translation"; +import styles from "styles/app.module.scss"; +import undo from "assets/images/undo.svg"; +import worktype_add from "assets/images/worktype_add.svg"; +import progress_activit from "assets/images/progress_activit.svg"; +import { useTranslation } from "react-i18next"; +import { useDispatch, useSelector } from "react-redux"; +import { + listWorktypesAsync, + selectIsLoading, + selectWorktypes, +} from "features/workflow/worktype"; +import { AppDispatch } from "app/store"; + +const WorktypeIdSettingPage: React.FC = (): JSX.Element => { + const dispatch: AppDispatch = useDispatch(); + const [t] = useTranslation(); + const isLoading = useSelector(selectIsLoading); + const worktypes = useSelector(selectWorktypes); + const [selectedRow, setSelectedRow] = useState(NaN); + useEffect(() => { + dispatch(listWorktypesAsync()); + }, [dispatch]); + + return ( +
    +
    + +
    +
    +
    +

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

    +

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

    +
    +
    +
    + + + + + + + + {worktypes?.map((worktype) => ( + { + setSelectedRow(worktype.id); + }} + onMouseLeave={() => { + setSelectedRow(NaN); + }} + > + + + + + ))} +
    + {t(getTranslationID("worktypeIdSetting.label.worktypeId"))} + + {t(getTranslationID("worktypeIdSetting.label.description"))} + {/** empty th */}
    {worktype.worktypeId}{worktype.description} + +
    + {!isLoading && worktypes?.length === 0 && ( +

    + {t(getTranslationID("common.message.listEmpty"))} +

    + )} + {isLoading && ( + Loading + )} +
    +
    +
    +
    +
    +
    + ); +}; + +export default WorktypeIdSettingPage; diff --git a/dictation_client/src/pages/WorkflowPage/index.tsx b/dictation_client/src/pages/WorkflowPage/index.tsx index e817a00..6d57be9 100644 --- a/dictation_client/src/pages/WorkflowPage/index.tsx +++ b/dictation_client/src/pages/WorkflowPage/index.tsx @@ -15,6 +15,11 @@ const WorkflowPage: React.FC = (): JSX.Element => ( Transcriptionist Group Setting + + + Worktype ID Setting + +