Merged PR 348: 画面実装(TypistGroup追加ポップアップ&TypistGroup設定画面)
## 概要 [Task2424: 画面実装(TypistGroup追加ポップアップ&TypistGroup設定画面)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2424) - TypistGroup追加ポップアップを追加しました。 - 言語対応を実装しています。 - 入力エラー時のメッセージ表示を実装しています。 ## レビューポイント - エラーメッセージの出し方は問題ないか - デザイン適用は適切か ## UIの変更 - [Task2424](https://ndstokyo.sharepoint.com/:f:/r/sites/Piranha/Shared%20Documents/General/OMDS/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88/Task2424?csf=1&web=1&e=IVxM43) ## 動作確認状況 - ローカルで確認 ※実際のAPIを呼んでの登録は未検証です
This commit is contained in:
parent
9f2f163141
commit
15d7119306
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,12 @@ 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 {
|
||||
AccountsApi,
|
||||
GetTypistGroupsResponse,
|
||||
GetTypistsResponse,
|
||||
CreateTypistGroupRequest,
|
||||
} from "../../../api/api";
|
||||
import { Configuration } from "../../../api/configuration";
|
||||
import { ErrorObject, createErrorObject } from "../../../common/errors";
|
||||
|
||||
@ -15,7 +20,7 @@ export const listTypistGroupsAsync = createAsyncThunk<
|
||||
error: ErrorObject;
|
||||
};
|
||||
}
|
||||
>("dictations/listTypistGroupsAsync", async (args, thunkApi) => {
|
||||
>("workflow/listTypistGroupsAsync", async (args, thunkApi) => {
|
||||
// apiのConfigurationを取得する
|
||||
const { getState } = thunkApi;
|
||||
const state = getState() as RootState;
|
||||
@ -41,3 +46,88 @@ export const listTypistGroupsAsync = createAsyncThunk<
|
||||
return thunkApi.rejectWithValue({ error });
|
||||
}
|
||||
});
|
||||
|
||||
export const listTypistsAsync = createAsyncThunk<
|
||||
GetTypistsResponse,
|
||||
void,
|
||||
{
|
||||
// rejectした時の返却値の型
|
||||
rejectValue: {
|
||||
error: ErrorObject;
|
||||
};
|
||||
}
|
||||
>("workflow/listTypistsAsync", 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 typists = await accountsApi.getTypists({
|
||||
headers: { authorization: `Bearer ${accessToken}` },
|
||||
});
|
||||
|
||||
return typists.data;
|
||||
} catch (e) {
|
||||
// e ⇒ errorObjectに変換"
|
||||
const error = createErrorObject(e);
|
||||
thunkApi.dispatch(
|
||||
openSnackbar({
|
||||
level: "error",
|
||||
message: getTranslationID("common.message.internalServerError"),
|
||||
})
|
||||
);
|
||||
return thunkApi.rejectWithValue({ error });
|
||||
}
|
||||
});
|
||||
|
||||
export const createTypistGroupAsync = createAsyncThunk<
|
||||
{
|
||||
/* Empty Object */
|
||||
},
|
||||
CreateTypistGroupRequest,
|
||||
{
|
||||
// rejectした時の返却値の型
|
||||
rejectValue: {
|
||||
error: ErrorObject;
|
||||
};
|
||||
}
|
||||
>("workflow/createTypistGroupAsync", 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 {
|
||||
await accountsApi.createTypistGroup(args, {
|
||||
headers: { authorization: `Bearer ${accessToken}` },
|
||||
});
|
||||
thunkApi.dispatch(
|
||||
openSnackbar({
|
||||
level: "info",
|
||||
message: getTranslationID("common.message.success"),
|
||||
})
|
||||
);
|
||||
return {};
|
||||
} catch (e) {
|
||||
// e ⇒ errorObjectに変換"
|
||||
const error = createErrorObject(e);
|
||||
|
||||
const message =
|
||||
error.statusCode === 400
|
||||
? getTranslationID("typistGroupSetting.message.groupAddFailedError")
|
||||
: getTranslationID("common.message.internalServerError");
|
||||
|
||||
thunkApi.dispatch(
|
||||
openSnackbar({
|
||||
level: "error",
|
||||
message,
|
||||
})
|
||||
);
|
||||
return thunkApi.rejectWithValue({ error });
|
||||
}
|
||||
});
|
||||
|
||||
@ -5,3 +5,25 @@ export const selectTypistGroups = (state: RootState) =>
|
||||
|
||||
export const selectIsLoading = (state: RootState) =>
|
||||
state.typistGroup.apps.isLoading;
|
||||
|
||||
export const selectTypists = (state: RootState) =>
|
||||
state.typistGroup.domain.typists;
|
||||
|
||||
export const selectPoolTypists = (state: RootState) =>
|
||||
state.typistGroup.domain.typists.filter(
|
||||
(t) => !state.typistGroup.apps.selectedTypists.some((x) => t.id === x.id)
|
||||
);
|
||||
|
||||
export const selectSelectedTypists = (state: RootState) =>
|
||||
state.typistGroup.apps.selectedTypists;
|
||||
|
||||
export const selectGroupName = (state: RootState) =>
|
||||
state.typistGroup.apps.groupName;
|
||||
|
||||
export const selectAddGroupErrors = (state: RootState) => {
|
||||
const hasErrorEmptyGroupName = state.typistGroup.apps.groupName === "";
|
||||
const hasErrorSelectedTypistsEmpty =
|
||||
state.typistGroup.apps.selectedTypists.length === 0;
|
||||
|
||||
return { hasErrorEmptyGroupName, hasErrorSelectedTypistsEmpty };
|
||||
};
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { TypistGroup } from "../../../api/api";
|
||||
import { Typist, TypistGroup } from "../../../api/api";
|
||||
|
||||
export interface TypistGroupState {
|
||||
apps: Apps;
|
||||
@ -7,8 +7,11 @@ export interface TypistGroupState {
|
||||
|
||||
export interface Apps {
|
||||
isLoading: boolean;
|
||||
selectedTypists: Typist[];
|
||||
groupName: string;
|
||||
}
|
||||
|
||||
export interface Domain {
|
||||
typistGroups: TypistGroup[];
|
||||
typists: Typist[];
|
||||
}
|
||||
|
||||
@ -1,20 +1,54 @@
|
||||
import { createSlice } from "@reduxjs/toolkit";
|
||||
import { PayloadAction, createSlice } from "@reduxjs/toolkit";
|
||||
import { Typist } from "api";
|
||||
import { TypistGroupState } from "./state";
|
||||
import { listTypistGroupsAsync } from "./operations";
|
||||
import { listTypistGroupsAsync, listTypistsAsync } from "./operations";
|
||||
|
||||
const initialState: TypistGroupState = {
|
||||
apps: {
|
||||
isLoading: false,
|
||||
selectedTypists: [],
|
||||
groupName: "",
|
||||
},
|
||||
domain: {
|
||||
typistGroups: [],
|
||||
typists: [],
|
||||
},
|
||||
};
|
||||
|
||||
export const typistGroupSlice = createSlice({
|
||||
name: "typistGroup",
|
||||
initialState,
|
||||
reducers: {},
|
||||
reducers: {
|
||||
cleanupAddCroup: (state) => {
|
||||
state.apps.groupName = "";
|
||||
state.apps.selectedTypists = [];
|
||||
},
|
||||
addSelectedTypist: (state, action: PayloadAction<{ typist: Typist }>) => {
|
||||
const { typist } = action.payload;
|
||||
|
||||
const selectedTypists = [...state.apps.selectedTypists, typist];
|
||||
if (!state.apps.selectedTypists.find((x) => x.id === typist.id)) {
|
||||
state.apps.selectedTypists = selectedTypists.sort(
|
||||
(a, b) => a.id - b.id
|
||||
);
|
||||
}
|
||||
},
|
||||
removeSelectedTypist: (
|
||||
state,
|
||||
action: PayloadAction<{ typist: Typist }>
|
||||
) => {
|
||||
const { typist } = action.payload;
|
||||
|
||||
const selectedTypists = state.apps.selectedTypists.filter(
|
||||
(x) => x.id !== typist.id
|
||||
);
|
||||
state.apps.selectedTypists = selectedTypists.sort((a, b) => a.id - b.id);
|
||||
},
|
||||
changeGroupName: (state, action: PayloadAction<{ groupName: string }>) => {
|
||||
const { groupName } = action.payload;
|
||||
state.apps.groupName = groupName;
|
||||
},
|
||||
},
|
||||
extraReducers: (builder) => {
|
||||
builder.addCase(listTypistGroupsAsync.pending, (state) => {
|
||||
state.apps.isLoading = true;
|
||||
@ -26,7 +60,24 @@ export const typistGroupSlice = createSlice({
|
||||
builder.addCase(listTypistGroupsAsync.rejected, (state) => {
|
||||
state.apps.isLoading = false;
|
||||
});
|
||||
builder.addCase(listTypistsAsync.pending, (state) => {
|
||||
state.apps.isLoading = true;
|
||||
});
|
||||
builder.addCase(listTypistsAsync.fulfilled, (state, action) => {
|
||||
state.domain.typists = action.payload.typists;
|
||||
state.apps.isLoading = false;
|
||||
});
|
||||
builder.addCase(listTypistsAsync.rejected, (state) => {
|
||||
state.apps.isLoading = false;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export const {
|
||||
cleanupAddCroup,
|
||||
addSelectedTypist,
|
||||
removeSelectedTypist,
|
||||
changeGroupName,
|
||||
} = typistGroupSlice.actions;
|
||||
|
||||
export default typistGroupSlice.reducer;
|
||||
|
||||
@ -0,0 +1,203 @@
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import styles from "styles/app.module.scss";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { Typist } from "api";
|
||||
import { AppDispatch } from "app/store";
|
||||
import { getTranslationID } from "translation";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
addSelectedTypist,
|
||||
listTypistsAsync,
|
||||
cleanupAddCroup,
|
||||
removeSelectedTypist,
|
||||
selectPoolTypists,
|
||||
selectSelectedTypists,
|
||||
selectGroupName,
|
||||
changeGroupName,
|
||||
selectAddGroupErrors,
|
||||
} from "features/workflow/typistGroup";
|
||||
import {
|
||||
createTypistGroupAsync,
|
||||
listTypistGroupsAsync,
|
||||
} from "features/workflow/typistGroup/operations";
|
||||
import { openSnackbar } from "features/ui";
|
||||
import close from "../../assets/images/close.svg";
|
||||
|
||||
interface AddTypistGroupPopupProps {
|
||||
onClose: (isChanged: boolean) => void;
|
||||
isOpen: boolean;
|
||||
}
|
||||
|
||||
export const AddTypistGroupPopup: React.FC<AddTypistGroupPopupProps> = (
|
||||
props
|
||||
) => {
|
||||
const { onClose, isOpen } = props;
|
||||
const dispatch: AppDispatch = useDispatch();
|
||||
const [t] = useTranslation();
|
||||
|
||||
const [isPushAddButton, setIsPushAddButton] = useState<boolean>(false);
|
||||
|
||||
const poolTypists = useSelector(selectPoolTypists);
|
||||
const selectedTypists = useSelector(selectSelectedTypists);
|
||||
const groupName = useSelector(selectGroupName);
|
||||
|
||||
const { hasErrorEmptyGroupName, hasErrorSelectedTypistsEmpty } =
|
||||
useSelector(selectAddGroupErrors);
|
||||
|
||||
// 開閉時のみ実行
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
dispatch(cleanupAddCroup());
|
||||
dispatch(listTypistsAsync());
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isOpen]);
|
||||
|
||||
// ポップアップを閉じる処理
|
||||
const closePopup = useCallback(() => {
|
||||
setIsPushAddButton(false);
|
||||
onClose(false);
|
||||
}, [onClose]);
|
||||
|
||||
// グループ追加を実行
|
||||
const addTypistGroup = useCallback(async () => {
|
||||
setIsPushAddButton(true);
|
||||
// 入力チェック
|
||||
if (hasErrorEmptyGroupName || hasErrorSelectedTypistsEmpty) {
|
||||
if (hasErrorSelectedTypistsEmpty) {
|
||||
dispatch(
|
||||
openSnackbar({
|
||||
level: "error",
|
||||
message: t(
|
||||
getTranslationID(
|
||||
"typistGroupSetting.message.selectedTypistEmptyError"
|
||||
)
|
||||
),
|
||||
})
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// グループ追加APIを実行
|
||||
const { meta } = await dispatch(
|
||||
createTypistGroupAsync({
|
||||
typistGroupName: groupName,
|
||||
typistIds: selectedTypists.map((typist) => typist.id),
|
||||
})
|
||||
);
|
||||
setIsPushAddButton(false);
|
||||
if (meta.requestStatus === "fulfilled") {
|
||||
closePopup();
|
||||
dispatch(listTypistGroupsAsync());
|
||||
}
|
||||
}, [
|
||||
t,
|
||||
closePopup,
|
||||
dispatch,
|
||||
groupName,
|
||||
selectedTypists,
|
||||
hasErrorEmptyGroupName,
|
||||
hasErrorSelectedTypistsEmpty,
|
||||
]);
|
||||
|
||||
return (
|
||||
<div className={`${styles.modal} ${isOpen ? styles.isShow : ""}`}>
|
||||
<div className={styles.modalBox}>
|
||||
<p className={styles.modalTitle}>
|
||||
{t(getTranslationID("typistGroupSetting.label.addTypistGroup"))}
|
||||
<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} />
|
||||
<dt>{t(getTranslationID("typistGroupSetting.label.groupName"))}</dt>
|
||||
<dd>
|
||||
<input
|
||||
type="text"
|
||||
size={40}
|
||||
maxLength={50}
|
||||
className={styles.formInput}
|
||||
value={groupName}
|
||||
onChange={(e) =>
|
||||
dispatch(changeGroupName({ groupName: e.target.value }))
|
||||
}
|
||||
/>
|
||||
{isPushAddButton && hasErrorEmptyGroupName && (
|
||||
<span className={styles.formError}>
|
||||
{t(getTranslationID("common.message.inputEmptyError"))}
|
||||
</span>
|
||||
)}
|
||||
</dd>
|
||||
<dt className={styles.formTitle}>
|
||||
{t(getTranslationID("typistGroupSetting.label.transcriptionist"))}
|
||||
</dt>
|
||||
<dd className={`${styles.formChange} ${styles.last}`}>
|
||||
<ul className={styles.chooseMember}>
|
||||
<li className={styles.changeTitle}>
|
||||
{t(getTranslationID("typistGroupSetting.label.selected"))}
|
||||
</li>
|
||||
{selectedTypists.map((typist: Typist) => (
|
||||
<li key={typist.id}>
|
||||
<input
|
||||
type="checkbox"
|
||||
className={styles.formCheck}
|
||||
value={typist.name}
|
||||
id={`${typist.id}`}
|
||||
checked
|
||||
onClick={() => dispatch(removeSelectedTypist({ typist }))}
|
||||
/>
|
||||
<label
|
||||
htmlFor={`${typist.id}`}
|
||||
title={t(
|
||||
getTranslationID("typistGroupSetting.label.remove")
|
||||
)}
|
||||
>
|
||||
{typist.name}
|
||||
</label>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<p />
|
||||
<ul className={styles.holdMember}>
|
||||
<li className={styles.changeTitle}>
|
||||
{t(getTranslationID("typistGroupSetting.label.pool"))}
|
||||
</li>
|
||||
{poolTypists.map((typist: Typist) => (
|
||||
<li key={typist.id}>
|
||||
<input
|
||||
type="checkbox"
|
||||
className={styles.formCheck}
|
||||
value={typist.name}
|
||||
id={`${typist.id}`}
|
||||
onClick={() => dispatch(addSelectedTypist({ typist }))}
|
||||
/>
|
||||
<label
|
||||
htmlFor={`${typist.id}`}
|
||||
title={t(
|
||||
getTranslationID("typistGroupSetting.label.add")
|
||||
)}
|
||||
>
|
||||
{typist.name}
|
||||
</label>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</dd>
|
||||
<dd className={`${styles.full} ${styles.alignCenter}`}>
|
||||
<input
|
||||
type="button"
|
||||
name="submit"
|
||||
value={t(getTranslationID("typistGroupSetting.label.addGroup"))}
|
||||
className={`${styles.formSubmit} ${styles.marginBtm1} ${styles.isActive}`}
|
||||
onClick={addTypistGroup}
|
||||
/>
|
||||
</dd>
|
||||
</dl>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@ -1,4 +1,4 @@
|
||||
import React, { useEffect } from "react";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import Header from "components/header";
|
||||
import Footer from "components/footer";
|
||||
import styles from "styles/app.module.scss";
|
||||
@ -15,6 +15,7 @@ import {
|
||||
import { AppDispatch } from "app/store";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { getTranslationID } from "translation";
|
||||
import { AddTypistGroupPopup } from "./addTypistGroupPopup";
|
||||
|
||||
const TypistGroupSettingPage: React.FC = (): JSX.Element => {
|
||||
const dispatch: AppDispatch = useDispatch();
|
||||
@ -23,95 +24,114 @@ const TypistGroupSettingPage: React.FC = (): JSX.Element => {
|
||||
const isLoading = useSelector(selectIsLoading);
|
||||
const typistGroup = useSelector(selectTypistGroups);
|
||||
|
||||
const [isAddPopupOpen, setIsAddPopupOpen] = useState(false);
|
||||
const onAddPopupOpen = useCallback(() => {
|
||||
// typist一覧を取得
|
||||
setIsAddPopupOpen(true);
|
||||
}, [setIsAddPopupOpen]);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(listTypistGroupsAsync());
|
||||
}, [dispatch]);
|
||||
|
||||
return (
|
||||
<div className={styles.wrap}>
|
||||
<Header userName="XXXXXX" />
|
||||
<UpdateTokenTimer />
|
||||
<main className={styles.main}>
|
||||
<div>
|
||||
<div className={styles.pageHeader}>
|
||||
<h1 className={styles.pageTitle}>
|
||||
{t(getTranslationID("workflowPage.label.title"))}
|
||||
</h1>
|
||||
<p className={styles.pageTx}>{` ${t(
|
||||
getTranslationID("typistGroupSetting.label.title")
|
||||
)}`}</p>
|
||||
</div>
|
||||
|
||||
<section className={styles.workflow}>
|
||||
<div>
|
||||
<ul className={styles.menuAction}>
|
||||
<li>
|
||||
<a
|
||||
href="/workflow"
|
||||
className={`${styles.menuLink} ${styles.isActive}`}
|
||||
>
|
||||
<img src={undo} alt="" className={styles.menuIcon} />
|
||||
{t(getTranslationID("typistGroupSetting.label.return"))}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a className={`${styles.menuLink} ${styles.isActive}`}>
|
||||
<img src={group_add} alt="" className={styles.menuIcon} />
|
||||
|
||||
{t(getTranslationID("typistGroupSetting.label.addGroup"))}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<table className={`${styles.table} ${styles.group}`}>
|
||||
<tr className={styles.tableHeader}>
|
||||
<th className={styles.noLine}>
|
||||
{t(getTranslationID("typistGroupSetting.label.groupName"))}
|
||||
</th>
|
||||
<th>{/** empty th */}</th>
|
||||
</tr>
|
||||
{!isLoading && typistGroup.length === 0 ? (
|
||||
<p style={{ margin: "10px", textAlign: "center" }}>
|
||||
{t(getTranslationID("common.message.listEmpty"))}
|
||||
</p>
|
||||
) : (
|
||||
typistGroup.map((group) => (
|
||||
<tr key={group.id}>
|
||||
<td>{group.name}</td>
|
||||
<td>
|
||||
<ul
|
||||
className={`${styles.menuAction} ${styles.inTable}`}
|
||||
>
|
||||
<li>
|
||||
<a
|
||||
className={`${styles.menuLink} ${styles.isActive}`}
|
||||
>
|
||||
{t(
|
||||
getTranslationID(
|
||||
"typistGroupSetting.label.edit"
|
||||
)
|
||||
)}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
))
|
||||
)}
|
||||
</table>
|
||||
{isLoading && (
|
||||
<img
|
||||
src={progress_activit}
|
||||
className={styles.icLoading}
|
||||
alt="Loading"
|
||||
/>
|
||||
)}
|
||||
<>
|
||||
<AddTypistGroupPopup
|
||||
onClose={() => {
|
||||
setIsAddPopupOpen(false);
|
||||
}}
|
||||
isOpen={isAddPopupOpen}
|
||||
/>
|
||||
<div className={styles.wrap}>
|
||||
<Header userName="XXXXXX" />
|
||||
<UpdateTokenTimer />
|
||||
<main className={styles.main}>
|
||||
<div>
|
||||
<div className={styles.pageHeader}>
|
||||
<h1 className={styles.pageTitle}>
|
||||
{t(getTranslationID("workflowPage.label.title"))}
|
||||
</h1>
|
||||
<p className={styles.pageTx}>{` ${t(
|
||||
getTranslationID("typistGroupSetting.label.title")
|
||||
)}`}</p>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
<Footer />
|
||||
</div>
|
||||
|
||||
<section className={styles.workflow}>
|
||||
<div>
|
||||
<ul className={styles.menuAction}>
|
||||
<li>
|
||||
<a
|
||||
href="/workflow"
|
||||
className={`${styles.menuLink} ${styles.isActive}`}
|
||||
>
|
||||
<img src={undo} alt="" className={styles.menuIcon} />
|
||||
{t(getTranslationID("typistGroupSetting.label.return"))}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
|
||||
<a
|
||||
className={`${styles.menuLink} ${styles.isActive}`}
|
||||
onClick={onAddPopupOpen}
|
||||
>
|
||||
<img src={group_add} alt="" className={styles.menuIcon} />
|
||||
{t(getTranslationID("typistGroupSetting.label.addGroup"))}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<table className={`${styles.table} ${styles.group}`}>
|
||||
<tr className={styles.tableHeader}>
|
||||
<th className={styles.noLine}>
|
||||
{t(
|
||||
getTranslationID("typistGroupSetting.label.groupName")
|
||||
)}
|
||||
</th>
|
||||
<th>{/** empty th */}</th>
|
||||
</tr>
|
||||
{!isLoading && typistGroup.length === 0 ? (
|
||||
<p style={{ margin: "10px", textAlign: "center" }}>
|
||||
{t(getTranslationID("common.message.listEmpty"))}
|
||||
</p>
|
||||
) : (
|
||||
typistGroup.map((group) => (
|
||||
<tr key={group.id}>
|
||||
<td>{group.name}</td>
|
||||
<td>
|
||||
<ul
|
||||
className={`${styles.menuAction} ${styles.inTable}`}
|
||||
>
|
||||
<li>
|
||||
<a
|
||||
className={`${styles.menuLink} ${styles.isActive}`}
|
||||
>
|
||||
{t(
|
||||
getTranslationID(
|
||||
"typistGroupSetting.label.edit"
|
||||
)
|
||||
)}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
))
|
||||
)}
|
||||
</table>
|
||||
{isLoading && (
|
||||
<img
|
||||
src={progress_activit}
|
||||
className={styles.icLoading}
|
||||
alt="Loading"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
<Footer />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"common": {
|
||||
"message": {
|
||||
"inputEmptyError": "(de)Error Message",
|
||||
"inputEmptyError": "(de)この項目の入力は必須です。入力してください。",
|
||||
"passwordIncorrectError": "(de)Error Message",
|
||||
"emailIncorrectError": "(de)Error Message",
|
||||
"internalServerError": "(de)処理に失敗しました。時間をおいて再実行しても解決しない場合はシステム管理者にお問い合わせください。",
|
||||
@ -365,7 +365,17 @@
|
||||
"return": "(de)Return",
|
||||
"addGroup": "(de)Add Group",
|
||||
"groupName": "(de)Group Name",
|
||||
"edit": "(de)Edit"
|
||||
"edit": "(de)Edit",
|
||||
"addTypistGroup": "(de)Add Transcriptionist Group",
|
||||
"transcriptionist": "(de)Transcriptionist",
|
||||
"selected": "(de)Selected",
|
||||
"pool": "(de)Pool",
|
||||
"add": "(de)Add",
|
||||
"remove": "(de)Remove"
|
||||
},
|
||||
"message": {
|
||||
"selectedTypistEmptyError": "(de)TranscriptionistGroupには最低1名のメンバーが必要です。",
|
||||
"groupAddFailedError": "(de)TypistGroupの追加に失敗しました。画面を更新し、再度実行してください"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"common": {
|
||||
"message": {
|
||||
"inputEmptyError": "Error Message",
|
||||
"inputEmptyError": "この項目の入力は必須です。入力してください。",
|
||||
"passwordIncorrectError": "Error Message",
|
||||
"emailIncorrectError": "Error Message",
|
||||
"internalServerError": "処理に失敗しました。時間をおいて再実行しても解決しない場合はシステム管理者にお問い合わせください。",
|
||||
@ -365,7 +365,17 @@
|
||||
"return": "Return",
|
||||
"addGroup": "Add Group",
|
||||
"groupName": "Group Name",
|
||||
"edit": "Edit"
|
||||
"edit": "Edit",
|
||||
"addTypistGroup": "Add Transcriptionist Group",
|
||||
"transcriptionist": "Transcriptionist",
|
||||
"selected": "Selected",
|
||||
"pool": "Pool",
|
||||
"add": "Add",
|
||||
"remove": "Remove"
|
||||
},
|
||||
"message": {
|
||||
"selectedTypistEmptyError": "TranscriptionistGroupには最低1名のメンバーが必要です。",
|
||||
"groupAddFailedError": "TypistGroupの追加に失敗しました。画面を更新し、再度実行してください"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"common": {
|
||||
"message": {
|
||||
"inputEmptyError": "(es)Error Message",
|
||||
"inputEmptyError": "(es)この項目の入力は必須です。入力してください。",
|
||||
"passwordIncorrectError": "(es)Error Message",
|
||||
"emailIncorrectError": "(es)Error Message",
|
||||
"internalServerError": "(es)処理に失敗しました。時間をおいて再実行しても解決しない場合はシステム管理者にお問い合わせください。",
|
||||
@ -365,7 +365,17 @@
|
||||
"return": "(es)Return",
|
||||
"addGroup": "(es)Add Group",
|
||||
"groupName": "(es)Group Name",
|
||||
"edit": "(es)Edit"
|
||||
"edit": "(es)Edit",
|
||||
"addTypistGroup": "(es)Add Transcriptionist Group",
|
||||
"transcriptionist": "(es)Transcriptionist",
|
||||
"selected": "(es)Selected",
|
||||
"pool": "(es)Pool",
|
||||
"add": "(es)Add",
|
||||
"remove": "(es)Remove"
|
||||
},
|
||||
"message": {
|
||||
"selectedTypistEmptyError": "(es)TranscriptionistGroupには最低1名のメンバーが必要です。",
|
||||
"groupAddFailedError": "(es)TypistGroupの追加に失敗しました。画面を更新し、再度実行してください"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"common": {
|
||||
"message": {
|
||||
"inputEmptyError": "(fr)Error Message",
|
||||
"inputEmptyError": "(fr)この項目の入力は必須です。入力してください。",
|
||||
"passwordIncorrectError": "(fr)Error Message",
|
||||
"emailIncorrectError": "(fr)Error Message",
|
||||
"internalServerError": "(fr)処理に失敗しました。時間をおいて再実行しても解決しない場合はシステム管理者にお問い合わせください。",
|
||||
@ -365,7 +365,17 @@
|
||||
"return": "(fr)Return",
|
||||
"addGroup": "(fr)Add Group",
|
||||
"groupName": "(fr)Group Name",
|
||||
"edit": "(fr)Edit"
|
||||
"edit": "(fr)Edit",
|
||||
"addTypistGroup": "(fr)Add Transcriptionist Group",
|
||||
"transcriptionist": "(fr)Transcriptionist",
|
||||
"selected": "(fr)Selected",
|
||||
"pool": "(fr)Pool",
|
||||
"add": "(fr)Add",
|
||||
"remove": "(fr)Remove"
|
||||
},
|
||||
"message": {
|
||||
"selectedTypistEmptyError": "(fr)TranscriptionistGroupには最低1名のメンバーが必要です。",
|
||||
"groupAddFailedError": "(fr)TypistGroupの追加に失敗しました。画面を更新し、再度実行してください"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2293,7 +2293,7 @@
|
||||
"typistIds": {
|
||||
"minItems": 1,
|
||||
"type": "array",
|
||||
"items": { "type": "string" }
|
||||
"items": { "type": "integer" }
|
||||
}
|
||||
},
|
||||
"required": ["typistGroupName", "typistIds"]
|
||||
|
||||
@ -8,6 +8,7 @@ import {
|
||||
Min,
|
||||
ArrayMinSize,
|
||||
MinLength,
|
||||
IsArray,
|
||||
} from 'class-validator';
|
||||
import { IsAdminPasswordvalid } from '../../../common/validators/admin.validator';
|
||||
|
||||
@ -136,8 +137,9 @@ export class CreateTypistGroupRequest {
|
||||
@MinLength(1)
|
||||
@MaxLength(50)
|
||||
typistGroupName: string;
|
||||
@ApiProperty({ minItems: 1 })
|
||||
@ApiProperty({ minItems: 1, isArray: true, type: 'integer' })
|
||||
@ArrayMinSize(1)
|
||||
@IsArray()
|
||||
typistIds: number[];
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user