diff --git a/dictation_client/src/app/store.ts b/dictation_client/src/app/store.ts index 3299991..722801d 100644 --- a/dictation_client/src/app/store.ts +++ b/dictation_client/src/app/store.ts @@ -13,6 +13,7 @@ import partnerLicense from "features/license/partnerLicense/partnerLicenseSlice" 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"; export const store = configureStore({ reducer: { @@ -30,6 +31,7 @@ export const store = configureStore({ partnerLicense, dictation, partner, + typistGroup, }, }); diff --git a/dictation_client/src/assets/images/group_add.svg b/dictation_client/src/assets/images/group_add.svg new file mode 100644 index 0000000..5b33700 --- /dev/null +++ b/dictation_client/src/assets/images/group_add.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + diff --git a/dictation_client/src/components/header/constants.ts b/dictation_client/src/components/header/constants.ts index a182ffa..96cac3e 100644 --- a/dictation_client/src/components/header/constants.ts +++ b/dictation_client/src/components/header/constants.ts @@ -28,6 +28,7 @@ export const ADMIN_ONLY_TABS = [ HEADER_MENUS_USER, HEADER_MENUS_WORKFLOW, HEADER_MENUS_PARTNER, + HEADER_MENUS_WORKFLOW, ]; /** diff --git a/dictation_client/src/components/header/index.tsx b/dictation_client/src/components/header/index.tsx index 0cd0085..eb13b31 100644 --- a/dictation_client/src/components/header/index.tsx +++ b/dictation_client/src/components/header/index.tsx @@ -11,7 +11,15 @@ interface HeaderProps { const Header: React.FC = (props) => { const { userName } = props; const location = useLocation(); - return getHeader(location.pathname, userName); + + const splitPaths = location.pathname.split("/"); + + let path = location.pathname; + if (splitPaths.length >= 2) { + path = `/${splitPaths[1]}`; + } + + return getHeader(path, userName); }; export default Header; diff --git a/dictation_client/src/features/workflow/typistGroup/index.ts b/dictation_client/src/features/workflow/typistGroup/index.ts new file mode 100644 index 0000000..6812e34 --- /dev/null +++ b/dictation_client/src/features/workflow/typistGroup/index.ts @@ -0,0 +1,4 @@ +export * from "./typistGroupSlice"; +export * from "./state"; +export * from "./selectors"; +export * from "./operations"; diff --git a/dictation_client/src/features/workflow/typistGroup/operations.ts b/dictation_client/src/features/workflow/typistGroup/operations.ts new file mode 100644 index 0000000..1bc4422 --- /dev/null +++ b/dictation_client/src/features/workflow/typistGroup/operations.ts @@ -0,0 +1,43 @@ +import { createAsyncThunk } from "@reduxjs/toolkit"; +import type { RootState } from "app/store"; +import { openSnackbar } from "features/ui/uiSlice"; +import { getTranslationID } from "translation"; +import { AccountsApi, GetTypistGroupsResponse } from "../../../api/api"; +import { Configuration } from "../../../api/configuration"; +import { ErrorObject, createErrorObject } from "../../../common/errors"; + +export const listTypistGroupsAsync = createAsyncThunk< + GetTypistGroupsResponse, + void, + { + // rejectした時の返却値の型 + rejectValue: { + error: ErrorObject; + }; + } +>("dictations/listTypistGroupsAsync", 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 typistGroup = await accountsApi.getTypistGroups({ + headers: { authorization: `Bearer ${accessToken}` }, + }); + + return typistGroup.data; + } 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/typistGroup/selectors.ts b/dictation_client/src/features/workflow/typistGroup/selectors.ts new file mode 100644 index 0000000..8b37741 --- /dev/null +++ b/dictation_client/src/features/workflow/typistGroup/selectors.ts @@ -0,0 +1,7 @@ +import { RootState } from "app/store"; + +export const selectTypistGroups = (state: RootState) => + state.typistGroup.domain.typistGroups; + +export const selectIsLoading = (state: RootState) => + state.typistGroup.apps.isLoading; diff --git a/dictation_client/src/features/workflow/typistGroup/state.ts b/dictation_client/src/features/workflow/typistGroup/state.ts new file mode 100644 index 0000000..a714e0b --- /dev/null +++ b/dictation_client/src/features/workflow/typistGroup/state.ts @@ -0,0 +1,14 @@ +import { TypistGroup } from "../../../api/api"; + +export interface TypistGroupState { + apps: Apps; + domain: Domain; +} + +export interface Apps { + isLoading: boolean; +} + +export interface Domain { + typistGroups: TypistGroup[]; +} diff --git a/dictation_client/src/features/workflow/typistGroup/typistGroupSlice.ts b/dictation_client/src/features/workflow/typistGroup/typistGroupSlice.ts new file mode 100644 index 0000000..02feb96 --- /dev/null +++ b/dictation_client/src/features/workflow/typistGroup/typistGroupSlice.ts @@ -0,0 +1,32 @@ +import { createSlice } from "@reduxjs/toolkit"; +import { TypistGroupState } from "./state"; +import { listTypistGroupsAsync } from "./operations"; + +const initialState: TypistGroupState = { + apps: { + isLoading: false, + }, + domain: { + typistGroups: [], + }, +}; + +export const typistGroupSlice = createSlice({ + name: "typistGroup", + initialState, + reducers: {}, + extraReducers: (builder) => { + builder.addCase(listTypistGroupsAsync.pending, (state) => { + state.apps.isLoading = true; + }); + builder.addCase(listTypistGroupsAsync.fulfilled, (state, action) => { + state.domain.typistGroups = action.payload.typistGroups; + state.apps.isLoading = false; + }); + builder.addCase(listTypistGroupsAsync.rejected, (state) => { + state.apps.isLoading = false; + }); + }, +}); + +export default typistGroupSlice.reducer; diff --git a/dictation_client/src/pages/TypistGroupSettingPage/index.tsx b/dictation_client/src/pages/TypistGroupSettingPage/index.tsx index 1d8669c..73f7c90 100644 --- a/dictation_client/src/pages/TypistGroupSettingPage/index.tsx +++ b/dictation_client/src/pages/TypistGroupSettingPage/index.tsx @@ -1,18 +1,118 @@ -import React from "react"; +import React, { useEffect } from "react"; import Header from "components/header"; import Footer from "components/footer"; import styles from "styles/app.module.scss"; import { UpdateTokenTimer } from "components/auth/updateTokenTimer"; +import progress_activit from "assets/images/progress_activit.svg"; +import undo from "assets/images/undo.svg"; +import group_add from "assets/images/group_add.svg"; +import { useDispatch, useSelector } from "react-redux"; +import { + selectTypistGroups, + selectIsLoading, + listTypistGroupsAsync, +} from "features/workflow/typistGroup"; +import { AppDispatch } from "app/store"; +import { useTranslation } from "react-i18next"; +import { getTranslationID } from "translation"; -const TypistGroupSettingPage: React.FC = (): JSX.Element => ( - - - - - Transcriptionist Group Setting - - - -); +const TypistGroupSettingPage: React.FC = (): JSX.Element => { + const dispatch: AppDispatch = useDispatch(); + const [t] = useTranslation(); + + const isLoading = useSelector(selectIsLoading); + const typistGroup = useSelector(selectTypistGroups); + + useEffect(() => { + dispatch(listTypistGroupsAsync()); + }, [dispatch]); + + return ( + + + + + + + + {t(getTranslationID("workflowPage.label.title"))} + + {` ${t( + getTranslationID("typistGroupSetting.label.title") + )}`} + + + + + + + + + {t(getTranslationID("typistGroupSetting.label.return"))} + + + + + + + {t(getTranslationID("typistGroupSetting.label.addGroup"))} + + + + + + + + {t(getTranslationID("typistGroupSetting.label.groupName"))} + + {/** empty th */} + + {!isLoading && typistGroup.length === 0 ? ( + + {t(getTranslationID("common.message.listEmpty"))} + + ) : ( + typistGroup.map((group) => ( + + {group.name} + + + + + {t( + getTranslationID( + "typistGroupSetting.label.edit" + ) + )} + + + + + + )) + )} + + {isLoading && ( + + )} + + + + + + + ); +}; export default TypistGroupSettingPage; diff --git a/dictation_client/src/translation/de.json b/dictation_client/src/translation/de.json index 2d3c8a0..a8407fd 100644 --- a/dictation_client/src/translation/de.json +++ b/dictation_client/src/translation/de.json @@ -352,5 +352,19 @@ "inputEmptyError": "(de)この項目の入力は必須です。入力してください。", "licenseAllocationFailure": "(de)ライセンスの割り当てに失敗しました。他のライセンスを選択して再度割り当てをしてください。" } + }, + "workflowPage": { + "label": { + "title": "(de)Workflow" + } + }, + "typistGroupSetting": { + "label": { + "title": "(de)Transctiprionist Group", + "return": "(de)Return", + "addGroup": "(de)Add Group", + "groupName": "(de)Group Name", + "edit": "(de)Edit" + } } -} +} \ No newline at end of file diff --git a/dictation_client/src/translation/en.json b/dictation_client/src/translation/en.json index 41f37df..723c04f 100644 --- a/dictation_client/src/translation/en.json +++ b/dictation_client/src/translation/en.json @@ -352,5 +352,19 @@ "inputEmptyError": "この項目の入力は必須です。入力してください。", "licenseAllocationFailure": "ライセンスの割り当てに失敗しました。他のライセンスを選択して再度割り当てをしてください。" } + }, + "workflowPage": { + "label": { + "title": "Workflow" + } + }, + "typistGroupSetting": { + "label": { + "title": "Transctiprionist Group", + "return": "Return", + "addGroup": "Add Group", + "groupName": "Group Name", + "edit": "Edit" + } } -} +} \ No newline at end of file diff --git a/dictation_client/src/translation/es.json b/dictation_client/src/translation/es.json index 38c00a9..6affad2 100644 --- a/dictation_client/src/translation/es.json +++ b/dictation_client/src/translation/es.json @@ -352,5 +352,19 @@ "inputEmptyError": "(es)この項目の入力は必須です。入力してください。", "licenseAllocationFailure": "(es)ライセンスの割り当てに失敗しました。他のライセンスを選択して再度割り当てをしてください。" } + }, + "workflowPage": { + "label": { + "title": "(es)Workflow" + } + }, + "typistGroupSetting": { + "label": { + "title": "(es)Transctiprionist Group", + "return": "(es)Return", + "addGroup": "(es)Add Group", + "groupName": "(es)Group Name", + "edit": "(es)Edit" + } } -} +} \ No newline at end of file diff --git a/dictation_client/src/translation/fr.json b/dictation_client/src/translation/fr.json index e01647c..ade9c18 100644 --- a/dictation_client/src/translation/fr.json +++ b/dictation_client/src/translation/fr.json @@ -352,5 +352,19 @@ "inputEmptyError": "(fr)この項目の入力は必須です。入力してください。", "licenseAllocationFailure": "(fr)ライセンスの割り当てに失敗しました。他のライセンスを選択して再度割り当てをしてください。" } + }, + "workflowPage": { + "label": { + "title": "(fr)Workflow" + } + }, + "typistGroupSetting": { + "label": { + "title": "(fr)Transctiprionist Group", + "return": "(fr)Return", + "addGroup": "(fr)Add Group", + "groupName": "(fr)Group Name", + "edit": "(fr)Edit" + } } -} +} \ No newline at end of file
{` ${t( + getTranslationID("typistGroupSetting.label.title") + )}`}
+ {t(getTranslationID("common.message.listEmpty"))} +