1877 lines
68 KiB
TypeScript
1877 lines
68 KiB
TypeScript
import React, { useCallback, useEffect, useState } from "react";
|
||
import { AppDispatch } from "app/store";
|
||
import { useTranslation } from "react-i18next";
|
||
import { useDispatch, useSelector } from "react-redux";
|
||
import styles from "styles/app.module.scss";
|
||
import Footer from "components/footer";
|
||
import Header from "components/header";
|
||
import {
|
||
listTasksAsync,
|
||
selectCurrentPage,
|
||
selectTasks,
|
||
selectTotal,
|
||
selectTotalPage,
|
||
DIRECTION,
|
||
DisplayInfoType,
|
||
INIT_DISPLAY_INFO,
|
||
SORTABLE_COLUMN,
|
||
selectDisplayInfo,
|
||
changeDisplayInfo,
|
||
getSortColumnAsync,
|
||
selectParamName,
|
||
selectDirection,
|
||
changeParamName,
|
||
changeDirection,
|
||
changeAuthorId,
|
||
changeFileName,
|
||
changeSelectedTask,
|
||
openFilePropertyInfo,
|
||
SortableColumnType,
|
||
changeAssignee,
|
||
listTypistsAsync,
|
||
listTypistGroupsAsync,
|
||
DirectionType,
|
||
selectIsLoading,
|
||
playbackAsync,
|
||
cancelAsync,
|
||
reopenAsync,
|
||
PRIORITY,
|
||
deleteTaskAsync,
|
||
isSortableColumnType,
|
||
isDirectionType,
|
||
getTaskFiltersAsync,
|
||
selectAuthorId,
|
||
selectFilename,
|
||
updateTaskFiltersAsync,
|
||
updateSortColumnAsync,
|
||
} from "features/dictation";
|
||
import { getTranslationID } from "translation";
|
||
import { Task } from "api/api";
|
||
import { isAdminUser, isAuthorUser, isTypistUser } from "features/auth";
|
||
import { STATUS, LIMIT_TASK_NUM } from "../../features/dictation";
|
||
import uploaded from "../../assets/images/uploaded.svg";
|
||
import pending from "../../assets/images/pending.svg";
|
||
import inprogress from "../../assets/images/inprogress.svg";
|
||
import finished from "../../assets/images/finished.svg";
|
||
import backup from "../../assets/images/backup.svg";
|
||
import lock from "../../assets/images/lock.svg";
|
||
import progress_activit from "../../assets/images/progress_activit.svg";
|
||
import download from "../../assets/images/download.svg";
|
||
import open_in_new from "../../assets/images/open_in_new.svg";
|
||
import { DisPlayInfo } from "./displayInfo";
|
||
import { ChangeTranscriptionistPopup } from "./changeTranscriptionistPopup";
|
||
import { BackupPopup } from "./backupPopup";
|
||
import { FilePropertyPopup } from "./filePropertyPopup";
|
||
import searchIcon from "../../assets/images/search.svg";
|
||
|
||
const DictationPage: React.FC = (): JSX.Element => {
|
||
const dispatch: AppDispatch = useDispatch();
|
||
const [t] = useTranslation();
|
||
|
||
const isAdmin = isAdminUser();
|
||
const isAuthor = isAuthorUser();
|
||
const isTypist = isTypistUser();
|
||
const isNone = !isAuthor && !isTypist;
|
||
|
||
const isDeletableRole = isAdmin || isAuthor;
|
||
|
||
// popup制御関係
|
||
const [
|
||
isChangeTranscriptionistPopupOpen,
|
||
setIsChangeTranscriptionistPopupOpen,
|
||
] = useState(false);
|
||
const [isFilePropertyPopupOpen, setIsFilePropertyPopupOpen] = useState(false);
|
||
const [isBackupPopupOpen, setIsBackupPopupOpen] = useState(false);
|
||
|
||
const onChangeTranscriptionistPopupOpen = useCallback(
|
||
(task: Task) => {
|
||
dispatch(changeAssignee({ selected: task.assignees }));
|
||
dispatch(changeSelectedTask({ task }));
|
||
setIsChangeTranscriptionistPopupOpen(true);
|
||
},
|
||
[dispatch, setIsChangeTranscriptionistPopupOpen]
|
||
);
|
||
|
||
const onClickFileProperty = useCallback(
|
||
(task: Task) => {
|
||
dispatch(openFilePropertyInfo({ task }));
|
||
setIsFilePropertyPopupOpen(true);
|
||
},
|
||
[dispatch, setIsFilePropertyPopupOpen]
|
||
);
|
||
// 各カラムの表示/非表示
|
||
const displayColumn = useSelector(selectDisplayInfo);
|
||
|
||
// フィルターするステータス
|
||
const [filterUploaded, setFilterUploaded] = useState(true);
|
||
const [filterPending, setFilterPending] = useState(true);
|
||
const [filterInProgress, setFilterInProgress] = useState(true);
|
||
const [filterFinished, setFilterFinished] = useState(true);
|
||
const [filterBackup, setFilterBackup] = useState(false);
|
||
|
||
// 検索条件の入力値
|
||
const [filterConditionAuthorId, setFilterConditionAuthorId] = useState("");
|
||
const [filterConditionFileName, setFilterConditionFileName] = useState("");
|
||
|
||
// ソート対象カラム
|
||
const sortableParamName = useSelector(selectParamName);
|
||
const sortDirection = useSelector(selectDirection);
|
||
|
||
// task_filtersテーブルの検索条件
|
||
const authorId = useSelector(selectAuthorId);
|
||
const fileName = useSelector(selectFilename);
|
||
|
||
const tasks = useSelector(selectTasks);
|
||
const total = useSelector(selectTotal);
|
||
const totalPage = useSelector(selectTotalPage);
|
||
const currentPage = useSelector(selectCurrentPage);
|
||
|
||
const isLoading = useSelector(selectIsLoading);
|
||
|
||
// ページネーションのボタンクリック時のアクション
|
||
const getFirstPage = useCallback(() => {
|
||
const filter = getFilter(
|
||
filterUploaded,
|
||
filterInProgress,
|
||
filterPending,
|
||
filterFinished,
|
||
filterBackup
|
||
);
|
||
dispatch(
|
||
listTasksAsync({
|
||
limit: LIMIT_TASK_NUM,
|
||
offset: 0,
|
||
filter,
|
||
direction: sortDirection,
|
||
paramName: sortableParamName,
|
||
authorId,
|
||
fileName,
|
||
})
|
||
);
|
||
dispatch(listTypistsAsync());
|
||
dispatch(listTypistGroupsAsync());
|
||
}, [
|
||
dispatch,
|
||
filterUploaded,
|
||
filterInProgress,
|
||
filterPending,
|
||
filterFinished,
|
||
filterBackup,
|
||
sortDirection,
|
||
sortableParamName,
|
||
authorId,
|
||
fileName,
|
||
]);
|
||
|
||
const getLastPage = useCallback(() => {
|
||
const filter = getFilter(
|
||
filterUploaded,
|
||
filterInProgress,
|
||
filterPending,
|
||
filterFinished,
|
||
filterBackup
|
||
);
|
||
const lastPageOffset = (totalPage - 1) * LIMIT_TASK_NUM;
|
||
dispatch(
|
||
listTasksAsync({
|
||
limit: LIMIT_TASK_NUM,
|
||
offset: lastPageOffset,
|
||
filter,
|
||
direction: sortDirection,
|
||
paramName: sortableParamName,
|
||
authorId,
|
||
fileName,
|
||
})
|
||
);
|
||
dispatch(listTypistsAsync());
|
||
dispatch(listTypistGroupsAsync());
|
||
}, [
|
||
dispatch,
|
||
totalPage,
|
||
filterUploaded,
|
||
filterInProgress,
|
||
filterPending,
|
||
filterFinished,
|
||
filterBackup,
|
||
sortDirection,
|
||
sortableParamName,
|
||
authorId,
|
||
fileName,
|
||
]);
|
||
|
||
const getPrevPage = useCallback(() => {
|
||
const filter = getFilter(
|
||
filterUploaded,
|
||
filterInProgress,
|
||
filterPending,
|
||
filterFinished,
|
||
filterBackup
|
||
);
|
||
const prevPageOffset = (currentPage - 2) * LIMIT_TASK_NUM;
|
||
dispatch(
|
||
listTasksAsync({
|
||
limit: LIMIT_TASK_NUM,
|
||
offset: prevPageOffset,
|
||
filter,
|
||
direction: sortDirection,
|
||
paramName: sortableParamName,
|
||
authorId,
|
||
fileName,
|
||
})
|
||
);
|
||
dispatch(listTypistsAsync());
|
||
dispatch(listTypistGroupsAsync());
|
||
}, [
|
||
dispatch,
|
||
currentPage,
|
||
filterUploaded,
|
||
filterInProgress,
|
||
filterPending,
|
||
filterFinished,
|
||
filterBackup,
|
||
sortDirection,
|
||
sortableParamName,
|
||
authorId,
|
||
fileName,
|
||
]);
|
||
|
||
const getNextPage = useCallback(() => {
|
||
const filter = getFilter(
|
||
filterUploaded,
|
||
filterInProgress,
|
||
filterPending,
|
||
filterFinished,
|
||
filterBackup
|
||
);
|
||
const nextPageOffset = currentPage * LIMIT_TASK_NUM;
|
||
dispatch(
|
||
listTasksAsync({
|
||
limit: LIMIT_TASK_NUM,
|
||
offset: nextPageOffset,
|
||
filter,
|
||
direction: sortDirection,
|
||
paramName: sortableParamName,
|
||
authorId,
|
||
fileName,
|
||
})
|
||
);
|
||
dispatch(listTypistsAsync());
|
||
dispatch(listTypistGroupsAsync());
|
||
}, [
|
||
dispatch,
|
||
currentPage,
|
||
filterUploaded,
|
||
filterInProgress,
|
||
filterPending,
|
||
filterFinished,
|
||
filterBackup,
|
||
sortDirection,
|
||
sortableParamName,
|
||
authorId,
|
||
fileName,
|
||
]);
|
||
|
||
const updateSortColumn = useCallback(
|
||
(paramName: SortableColumnType) => {
|
||
const currentDirection =
|
||
sortableParamName === paramName && sortDirection === DIRECTION.ASC
|
||
? DIRECTION.DESC
|
||
: DIRECTION.ASC;
|
||
dispatch(changeDirection({ direction: currentDirection }));
|
||
dispatch(changeParamName({ paramName }));
|
||
|
||
// ローカルストレージにソート情報を保存する
|
||
localStorage.setItem(
|
||
"sortCriteria",
|
||
`direction:${currentDirection},paramName:${paramName}`
|
||
);
|
||
|
||
const filter = getFilter(
|
||
filterUploaded,
|
||
filterInProgress,
|
||
filterPending,
|
||
filterFinished,
|
||
filterBackup
|
||
);
|
||
|
||
dispatch(
|
||
listTasksAsync({
|
||
limit: LIMIT_TASK_NUM,
|
||
offset: 0,
|
||
filter,
|
||
direction: currentDirection,
|
||
paramName,
|
||
authorId,
|
||
fileName,
|
||
})
|
||
);
|
||
dispatch(listTypistsAsync());
|
||
dispatch(listTypistGroupsAsync());
|
||
},
|
||
[
|
||
dispatch,
|
||
sortableParamName,
|
||
sortDirection,
|
||
filterUploaded,
|
||
filterInProgress,
|
||
filterPending,
|
||
filterFinished,
|
||
filterBackup,
|
||
authorId,
|
||
fileName,
|
||
]
|
||
);
|
||
|
||
const getFilter = (
|
||
hasUploaded: boolean,
|
||
hasInProgress: boolean,
|
||
hasPending: boolean,
|
||
hasFinished: boolean,
|
||
hasBackup: boolean
|
||
): string | undefined => {
|
||
const filterStatus = [];
|
||
if (hasUploaded) {
|
||
filterStatus.push(STATUS.UPLOADED);
|
||
}
|
||
if (hasInProgress) {
|
||
filterStatus.push(STATUS.INPROGRESS);
|
||
}
|
||
if (hasPending) {
|
||
filterStatus.push(STATUS.PENDING);
|
||
}
|
||
if (hasFinished) {
|
||
filterStatus.push(STATUS.FINISHED);
|
||
}
|
||
if (hasBackup) {
|
||
filterStatus.push(STATUS.BACKUP);
|
||
}
|
||
|
||
if (filterStatus.length === 0) {
|
||
return undefined;
|
||
}
|
||
return filterStatus.join(",");
|
||
};
|
||
|
||
// ステータスフィルターの変更時アクション
|
||
const updateFilter = useCallback(
|
||
(
|
||
hasUploaded: boolean,
|
||
hasInProgress: boolean,
|
||
hasPending: boolean,
|
||
hasFinished: boolean,
|
||
hasBackup: boolean
|
||
) => {
|
||
const filter = getFilter(
|
||
hasUploaded,
|
||
hasInProgress,
|
||
hasPending,
|
||
hasFinished,
|
||
hasBackup
|
||
);
|
||
|
||
// フィルターの状態をローカルストレージに保存する
|
||
localStorage.setItem(
|
||
"filterCriteria",
|
||
JSON.stringify({
|
||
Uploaded: hasUploaded,
|
||
InProgress: hasInProgress,
|
||
Pending: hasPending,
|
||
Finished: hasFinished,
|
||
Backup: hasBackup,
|
||
})
|
||
);
|
||
|
||
dispatch(
|
||
listTasksAsync({
|
||
limit: LIMIT_TASK_NUM,
|
||
offset: 0,
|
||
filter,
|
||
direction: sortDirection,
|
||
paramName: sortableParamName,
|
||
authorId,
|
||
fileName,
|
||
})
|
||
);
|
||
dispatch(listTypistsAsync());
|
||
dispatch(listTypistGroupsAsync());
|
||
},
|
||
[dispatch, sortDirection, sortableParamName, authorId, fileName]
|
||
);
|
||
|
||
const onPlayBack = useCallback(
|
||
async (audioFileId: number) => {
|
||
if (
|
||
/* eslint-disable-next-line no-alert */
|
||
!window.confirm(t(getTranslationID("common.message.dialogConfirm")))
|
||
) {
|
||
return;
|
||
}
|
||
const { meta } = await dispatch(
|
||
playbackAsync({
|
||
audioFileId,
|
||
direction: sortDirection,
|
||
paramName: sortableParamName,
|
||
filterConditionAuthorId: authorId,
|
||
filterConditionFileName: fileName,
|
||
})
|
||
);
|
||
if (meta.requestStatus === "fulfilled") {
|
||
// ローカルストレージにソート情報を削除する
|
||
localStorage.removeItem("sortCriteria");
|
||
const filter = getFilter(
|
||
filterUploaded,
|
||
filterInProgress,
|
||
filterPending,
|
||
filterFinished,
|
||
filterBackup
|
||
);
|
||
dispatch(
|
||
listTasksAsync({
|
||
limit: LIMIT_TASK_NUM,
|
||
offset: 0,
|
||
filter,
|
||
direction: sortDirection,
|
||
paramName: sortableParamName,
|
||
authorId,
|
||
fileName,
|
||
})
|
||
);
|
||
dispatch(listTypistsAsync());
|
||
dispatch(listTypistGroupsAsync());
|
||
|
||
const url = `${import.meta.env.VITE_DESK_TOP_APP_SCHEME
|
||
}:playback?audioId=${audioFileId}`;
|
||
const a = document.createElement("a");
|
||
a.href = url;
|
||
document.body.appendChild(a);
|
||
a.click();
|
||
document.body.removeChild(a);
|
||
}
|
||
},
|
||
[
|
||
dispatch,
|
||
filterBackup,
|
||
filterFinished,
|
||
filterInProgress,
|
||
filterPending,
|
||
filterUploaded,
|
||
sortDirection,
|
||
sortableParamName,
|
||
authorId,
|
||
fileName,
|
||
t,
|
||
]
|
||
);
|
||
|
||
const onClosePopup = useCallback(
|
||
(isChanged: boolean) => {
|
||
if (isChanged) {
|
||
const filter = getFilter(
|
||
filterUploaded,
|
||
filterInProgress,
|
||
filterPending,
|
||
filterFinished,
|
||
filterBackup
|
||
);
|
||
dispatch(
|
||
listTasksAsync({
|
||
limit: LIMIT_TASK_NUM,
|
||
offset: 0,
|
||
filter,
|
||
direction: sortDirection,
|
||
paramName: sortableParamName,
|
||
authorId,
|
||
fileName,
|
||
})
|
||
);
|
||
}
|
||
setIsChangeTranscriptionistPopupOpen(false);
|
||
},
|
||
[
|
||
dispatch,
|
||
filterUploaded,
|
||
filterInProgress,
|
||
filterPending,
|
||
filterFinished,
|
||
filterBackup,
|
||
sortDirection,
|
||
sortableParamName,
|
||
authorId,
|
||
fileName,
|
||
]
|
||
);
|
||
|
||
const onCancel = useCallback(
|
||
async (audioFileId: number) => {
|
||
if (
|
||
/* eslint-disable-next-line no-alert */
|
||
!window.confirm(t(getTranslationID("common.message.dialogConfirm")))
|
||
) {
|
||
return;
|
||
}
|
||
const { meta } = await dispatch(
|
||
cancelAsync({
|
||
audioFileId,
|
||
direction: sortDirection,
|
||
paramName: sortableParamName,
|
||
isTypist,
|
||
filterConditionAuthorId: authorId,
|
||
filterConditionFileName: fileName,
|
||
})
|
||
);
|
||
if (meta.requestStatus === "fulfilled") {
|
||
const filter = getFilter(
|
||
filterUploaded,
|
||
filterInProgress,
|
||
filterPending,
|
||
filterFinished,
|
||
filterBackup
|
||
);
|
||
dispatch(
|
||
listTasksAsync({
|
||
limit: LIMIT_TASK_NUM,
|
||
offset: 0,
|
||
filter,
|
||
direction: sortDirection,
|
||
paramName: sortableParamName,
|
||
authorId,
|
||
fileName,
|
||
})
|
||
);
|
||
dispatch(listTypistsAsync());
|
||
dispatch(listTypistGroupsAsync());
|
||
}
|
||
},
|
||
[
|
||
dispatch,
|
||
filterBackup,
|
||
filterFinished,
|
||
filterInProgress,
|
||
filterPending,
|
||
filterUploaded,
|
||
isTypist,
|
||
sortDirection,
|
||
sortableParamName,
|
||
authorId,
|
||
fileName,
|
||
t,
|
||
]
|
||
);
|
||
|
||
const onReopen = useCallback(
|
||
async (audioFileId: number) => {
|
||
if (
|
||
/* eslint-disable-next-line no-alert */
|
||
!window.confirm(t(getTranslationID("common.message.dialogConfirm")))
|
||
) {
|
||
return;
|
||
}
|
||
|
||
const { meta } = await dispatch(
|
||
reopenAsync({
|
||
audioFileId,
|
||
direction: sortDirection,
|
||
paramName: sortableParamName,
|
||
isTypist,
|
||
filterConditionAuthorId: authorId,
|
||
filterConditionFileName: fileName,
|
||
})
|
||
);
|
||
|
||
if (meta.requestStatus === "fulfilled") {
|
||
const filter = getFilter(
|
||
filterUploaded,
|
||
filterInProgress,
|
||
filterPending,
|
||
filterFinished,
|
||
filterBackup
|
||
);
|
||
dispatch(
|
||
listTasksAsync({
|
||
limit: LIMIT_TASK_NUM,
|
||
offset: 0,
|
||
filter,
|
||
direction: sortDirection,
|
||
paramName: sortableParamName,
|
||
authorId,
|
||
fileName,
|
||
})
|
||
);
|
||
dispatch(listTypistsAsync());
|
||
dispatch(listTypistGroupsAsync());
|
||
}
|
||
},
|
||
[
|
||
dispatch,
|
||
filterBackup,
|
||
filterFinished,
|
||
filterInProgress,
|
||
filterPending,
|
||
filterUploaded,
|
||
isTypist,
|
||
sortDirection,
|
||
sortableParamName,
|
||
authorId,
|
||
fileName,
|
||
t,
|
||
]
|
||
);
|
||
|
||
const onCloseBackupPopup = useCallback(() => {
|
||
setIsBackupPopupOpen(false);
|
||
}, []);
|
||
|
||
const onClickBackup = useCallback(() => {
|
||
setIsBackupPopupOpen(true);
|
||
}, []);
|
||
|
||
const onCloseFilePropertyPopup = useCallback(
|
||
(isChanged: boolean) => {
|
||
if (isChanged) {
|
||
const filter = getFilter(
|
||
filterUploaded,
|
||
filterInProgress,
|
||
filterPending,
|
||
filterFinished,
|
||
filterBackup
|
||
);
|
||
dispatch(
|
||
listTasksAsync({
|
||
limit: LIMIT_TASK_NUM,
|
||
offset: 0,
|
||
filter,
|
||
direction: sortDirection,
|
||
paramName: sortableParamName,
|
||
authorId,
|
||
fileName,
|
||
})
|
||
);
|
||
}
|
||
setIsFilePropertyPopupOpen(false);
|
||
},
|
||
[
|
||
dispatch,
|
||
filterUploaded,
|
||
filterInProgress,
|
||
filterPending,
|
||
filterFinished,
|
||
filterBackup,
|
||
sortDirection,
|
||
sortableParamName,
|
||
authorId,
|
||
fileName,
|
||
]
|
||
);
|
||
|
||
const onChangeFilterConditionFileName = useCallback(
|
||
(e: React.ChangeEvent<HTMLInputElement>) => {
|
||
setFilterConditionFileName(e.target.value.trimStart());
|
||
},
|
||
[setFilterConditionFileName]
|
||
);
|
||
|
||
const onChangeFilterConditionAuthorId = useCallback(
|
||
(e: React.ChangeEvent<HTMLInputElement>) => {
|
||
// 先頭に%が入力されるとWAFのルールでブロックされてしまう。
|
||
// Authorの登録時に「_」以外の記号は許可されていないため、「_」と半角英数字以外の文字は除去。
|
||
const correctAuthorId = e.target.value.replace(/[^a-zA-Z0-9_]/g, "");
|
||
setFilterConditionAuthorId(correctAuthorId);
|
||
},
|
||
[setFilterConditionAuthorId]
|
||
);
|
||
|
||
const sortIconClass = (
|
||
currentParam: SortableColumnType,
|
||
currentDirection: DirectionType,
|
||
column: SortableColumnType
|
||
) => {
|
||
if (currentParam !== column) {
|
||
return "";
|
||
}
|
||
if (currentDirection === DIRECTION.DESC) {
|
||
return styles.isActiveZa;
|
||
}
|
||
return styles.isActiveAz;
|
||
};
|
||
|
||
const onDeleteTask = useCallback(
|
||
async (audioFileId: number) => {
|
||
if (
|
||
/* eslint-disable-next-line no-alert */
|
||
!window.confirm(t(getTranslationID("common.message.dialogConfirm")))
|
||
) {
|
||
return;
|
||
}
|
||
const { meta } = await dispatch(
|
||
deleteTaskAsync({
|
||
audioFileId,
|
||
})
|
||
);
|
||
if (meta.requestStatus === "fulfilled") {
|
||
const filter = getFilter(
|
||
filterUploaded,
|
||
filterInProgress,
|
||
filterPending,
|
||
filterFinished,
|
||
filterBackup
|
||
);
|
||
dispatch(
|
||
listTasksAsync({
|
||
limit: LIMIT_TASK_NUM,
|
||
offset: 0,
|
||
filter,
|
||
direction: sortDirection,
|
||
paramName: sortableParamName,
|
||
authorId,
|
||
fileName,
|
||
})
|
||
);
|
||
dispatch(listTypistsAsync());
|
||
dispatch(listTypistGroupsAsync());
|
||
}
|
||
},
|
||
[
|
||
dispatch,
|
||
filterBackup,
|
||
filterFinished,
|
||
filterInProgress,
|
||
filterPending,
|
||
filterUploaded,
|
||
sortDirection,
|
||
sortableParamName,
|
||
authorId,
|
||
fileName,
|
||
t,
|
||
]
|
||
);
|
||
|
||
const requestSearch = useCallback(
|
||
async (e: React.FormEvent<HTMLFormElement>) => {
|
||
e.preventDefault();
|
||
const { meta: taskFilterMeta } = await dispatch(
|
||
updateTaskFiltersAsync({
|
||
filterConditionFileName,
|
||
filterConditionAuthorId,
|
||
})
|
||
);
|
||
const { meta: sortCriteriaMeta } = await dispatch(
|
||
updateSortColumnAsync({
|
||
direction: sortDirection,
|
||
paramName: sortableParamName,
|
||
})
|
||
);
|
||
if (
|
||
taskFilterMeta.requestStatus === "fulfilled" &&
|
||
sortCriteriaMeta.requestStatus === "fulfilled"
|
||
) {
|
||
const filter = getFilter(
|
||
filterUploaded,
|
||
filterInProgress,
|
||
filterPending,
|
||
filterFinished,
|
||
filterBackup
|
||
);
|
||
dispatch(changeAuthorId({ authorId: filterConditionAuthorId }));
|
||
dispatch(changeFileName({ fileName: filterConditionFileName }));
|
||
// 検索した条件でタスク一覧を取得する
|
||
dispatch(
|
||
listTasksAsync({
|
||
limit: LIMIT_TASK_NUM,
|
||
offset: 0,
|
||
filter,
|
||
direction: sortDirection,
|
||
paramName: sortableParamName,
|
||
authorId: filterConditionAuthorId,
|
||
fileName: filterConditionFileName,
|
||
})
|
||
);
|
||
}
|
||
},
|
||
[
|
||
dispatch,
|
||
filterBackup,
|
||
filterFinished,
|
||
filterInProgress,
|
||
filterPending,
|
||
filterUploaded,
|
||
sortDirection,
|
||
sortableParamName,
|
||
filterConditionAuthorId,
|
||
filterConditionFileName,
|
||
]
|
||
);
|
||
|
||
// 初回読み込み処理
|
||
useEffect(() => {
|
||
(async () => {
|
||
const displayInfoValue = localStorage.getItem("displayInfo");
|
||
|
||
let displayInfo: DisplayInfoType;
|
||
if (displayInfoValue) {
|
||
displayInfo = JSON.parse(displayInfoValue);
|
||
} else {
|
||
displayInfo = INIT_DISPLAY_INFO;
|
||
localStorage.setItem("displayInfo", JSON.stringify(displayInfo));
|
||
}
|
||
|
||
dispatch(changeDisplayInfo({ column: displayInfo }));
|
||
|
||
// フィルター状態をローカルストレージから取得する
|
||
const filterValue = localStorage.getItem("filterCriteria");
|
||
|
||
let filter: string | undefined;
|
||
if (filterValue) {
|
||
const parsedFilter = JSON.parse(filterValue);
|
||
setFilterUploaded(parsedFilter.Uploaded);
|
||
setFilterInProgress(parsedFilter.InProgress);
|
||
setFilterPending(parsedFilter.Pending);
|
||
setFilterFinished(parsedFilter.Finished);
|
||
setFilterBackup(parsedFilter.Backup);
|
||
|
||
filter = getFilter(
|
||
parsedFilter.Uploaded,
|
||
parsedFilter.InProgress,
|
||
parsedFilter.Pending,
|
||
parsedFilter.Finished,
|
||
parsedFilter.Backup
|
||
);
|
||
} else {
|
||
filter = getFilter(true, true, true, true, false);
|
||
localStorage.setItem(
|
||
"filterCriteria",
|
||
JSON.stringify({
|
||
Uploaded: true,
|
||
InProgress: true,
|
||
Pending: true,
|
||
Finished: true,
|
||
Backup: false,
|
||
})
|
||
);
|
||
}
|
||
// タスクフィルター条件
|
||
const { meta: taskFilterMeta, payload: taskfilterPayload } =
|
||
await dispatch(getTaskFiltersAsync());
|
||
let payloadAuthorId: string | undefined;
|
||
let payloadFileName: string | undefined;
|
||
if (
|
||
taskFilterMeta.requestStatus === "fulfilled" &&
|
||
taskfilterPayload &&
|
||
!("error" in taskfilterPayload)
|
||
) {
|
||
payloadAuthorId = taskfilterPayload.authorId ?? "";
|
||
payloadFileName = taskfilterPayload.fileName ?? "";
|
||
|
||
dispatch(changeAuthorId({ authorId: payloadAuthorId }));
|
||
dispatch(changeFileName({ fileName: payloadFileName }));
|
||
// 初回表示時に検索フォームにtask_filtersテーブルの値を設定する。
|
||
setFilterConditionAuthorId(payloadAuthorId);
|
||
setFilterConditionFileName(payloadFileName);
|
||
}
|
||
|
||
// ソート条件
|
||
const { meta: sortCriteriaMeta, payload: sortCriteriaPayload } =
|
||
await dispatch(getSortColumnAsync());
|
||
let direction: DirectionType = "ASC";
|
||
let paramName: SortableColumnType = "JOB_NUMBER";
|
||
if (
|
||
sortCriteriaMeta.requestStatus === "fulfilled" &&
|
||
sortCriteriaPayload &&
|
||
!("error" in sortCriteriaPayload)
|
||
) {
|
||
// ソート情報をローカルストレージから取得する
|
||
const sortColumnValue = localStorage.getItem("sortCriteria") ?? "";
|
||
if (sortColumnValue === "") {
|
||
direction = sortCriteriaPayload.direction;
|
||
paramName = sortCriteriaPayload.paramName;
|
||
} else {
|
||
// ソート情報をDirectionとParamNameに分割する
|
||
const sortColumn = sortColumnValue?.split(",");
|
||
const localStorageDirection = sortColumn[0].split(":")[1] ?? "";
|
||
|
||
const localStorageParamName = sortColumn[1]?.split(":")[1] ?? "";
|
||
|
||
// 正常なソート情報がローカルストレージに存在する場合はローカルストレージの情報を使用する
|
||
direction = isDirectionType(localStorageDirection)
|
||
? localStorageDirection
|
||
: sortCriteriaPayload.direction;
|
||
paramName = isSortableColumnType(localStorageParamName)
|
||
? localStorageParamName
|
||
: sortCriteriaPayload.paramName;
|
||
|
||
dispatch(changeDirection({ direction }));
|
||
dispatch(changeParamName({ paramName }));
|
||
}
|
||
}
|
||
|
||
// タスク一覧を取得する
|
||
if (isDirectionType(direction) && isSortableColumnType(paramName)) {
|
||
dispatch(
|
||
listTasksAsync({
|
||
limit: LIMIT_TASK_NUM,
|
||
offset: 0,
|
||
filter,
|
||
direction,
|
||
paramName,
|
||
authorId: payloadAuthorId,
|
||
fileName: payloadFileName,
|
||
})
|
||
);
|
||
dispatch(listTypistsAsync());
|
||
dispatch(listTypistGroupsAsync());
|
||
}
|
||
})();
|
||
}, [dispatch]);
|
||
|
||
return (
|
||
<>
|
||
<BackupPopup isOpen={isBackupPopupOpen} onClose={onCloseBackupPopup} />
|
||
<FilePropertyPopup
|
||
isOpen={isFilePropertyPopupOpen}
|
||
onClose={onCloseFilePropertyPopup}
|
||
/>
|
||
<ChangeTranscriptionistPopup
|
||
isOpen={isChangeTranscriptionistPopupOpen}
|
||
onClose={onClosePopup}
|
||
/>
|
||
<div className={styles.wrap}>
|
||
<Header />
|
||
<main className={styles.main}>
|
||
<div className="">
|
||
<div className={styles.pageHeader}>
|
||
<h1 className={styles.pageTitle}>
|
||
{t(getTranslationID("dictationPage.label.title"))}
|
||
</h1>
|
||
</div>
|
||
|
||
<section className={styles.dictation}>
|
||
<div>
|
||
<DisPlayInfo />
|
||
<ul className={styles.menuAction}>
|
||
<li>
|
||
<ul className={styles.tableFilter}>
|
||
<li>
|
||
{t(getTranslationID("dictationPage.label.filter"))}:
|
||
</li>
|
||
<li>
|
||
<label htmlFor="uploaded">
|
||
<input
|
||
id="uploaded"
|
||
type="checkbox"
|
||
value="flUploaded"
|
||
className={styles.formCheck}
|
||
checked={filterUploaded}
|
||
disabled={isLoading}
|
||
onChange={(e) => {
|
||
setFilterUploaded(e.target.checked);
|
||
updateFilter(
|
||
e.target.checked,
|
||
filterInProgress,
|
||
filterPending,
|
||
filterFinished,
|
||
filterBackup
|
||
);
|
||
}}
|
||
/>
|
||
{t(getTranslationID("dictationPage.label.uploaded"))}
|
||
</label>
|
||
</li>
|
||
<li>
|
||
<label htmlFor="inProgress">
|
||
<input
|
||
id="inProgress"
|
||
type="checkbox"
|
||
value="flInProgress"
|
||
className={styles.formCheck}
|
||
checked={filterInProgress}
|
||
disabled={isLoading}
|
||
onChange={(e) => {
|
||
setFilterInProgress(e.target.checked);
|
||
updateFilter(
|
||
filterUploaded,
|
||
e.target.checked,
|
||
filterPending,
|
||
filterFinished,
|
||
filterBackup
|
||
);
|
||
}}
|
||
/>
|
||
{t(
|
||
getTranslationID("dictationPage.label.inProgress")
|
||
)}
|
||
</label>
|
||
</li>
|
||
<li>
|
||
<label htmlFor="pending">
|
||
<input
|
||
id="pending"
|
||
type="checkbox"
|
||
value="flPending"
|
||
className={styles.formCheck}
|
||
checked={filterPending}
|
||
disabled={isLoading}
|
||
onChange={(e) => {
|
||
setFilterPending(e.target.checked);
|
||
updateFilter(
|
||
filterUploaded,
|
||
filterInProgress,
|
||
e.target.checked,
|
||
filterFinished,
|
||
filterBackup
|
||
);
|
||
}}
|
||
/>
|
||
{t(getTranslationID("dictationPage.label.pending"))}
|
||
</label>
|
||
</li>
|
||
<li>
|
||
<label htmlFor="finished">
|
||
<input
|
||
id="finished"
|
||
type="checkbox"
|
||
value="flFinished"
|
||
className={styles.formCheck}
|
||
checked={filterFinished}
|
||
disabled={isLoading}
|
||
onChange={(e) => {
|
||
setFilterFinished(e.target.checked);
|
||
updateFilter(
|
||
filterUploaded,
|
||
filterInProgress,
|
||
filterPending,
|
||
e.target.checked,
|
||
filterBackup
|
||
);
|
||
}}
|
||
/>
|
||
{t(getTranslationID("dictationPage.label.finished"))}
|
||
</label>
|
||
</li>
|
||
<li>
|
||
<label htmlFor="backup">
|
||
<input
|
||
id="backup"
|
||
type="checkbox"
|
||
value="flBackup"
|
||
className={styles.formCheck}
|
||
checked={filterBackup}
|
||
disabled={isLoading}
|
||
onChange={(e) => {
|
||
setFilterBackup(e.target.checked);
|
||
updateFilter(
|
||
filterUploaded,
|
||
filterInProgress,
|
||
filterPending,
|
||
filterFinished,
|
||
e.target.checked
|
||
);
|
||
}}
|
||
/>
|
||
{t(getTranslationID("dictationPage.label.backup"))}
|
||
</label>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li className={styles.floatRight}>
|
||
<form
|
||
className={styles.searchBar}
|
||
onSubmit={(e) => requestSearch(e)}
|
||
>
|
||
<input
|
||
type="text"
|
||
placeholder={t(
|
||
getTranslationID("dictationPage.label.fileName")
|
||
)}
|
||
value={filterConditionFileName}
|
||
onChange={(e) => onChangeFilterConditionFileName(e)}
|
||
className={styles.searchInput}
|
||
/>
|
||
<input
|
||
type="text"
|
||
placeholder={t(
|
||
getTranslationID("dictationPage.label.authorId")
|
||
)}
|
||
value={filterConditionAuthorId}
|
||
onChange={(e) => onChangeFilterConditionAuthorId(e)}
|
||
className={styles.searchInput}
|
||
/>
|
||
|
||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}
|
||
<button
|
||
type="submit"
|
||
className={`${styles.menuLink} ${!isLoading ? styles.isActive : ""
|
||
}`}
|
||
>
|
||
<img
|
||
src={searchIcon}
|
||
alt="search"
|
||
className={styles.menuIcon}
|
||
/>
|
||
{t(getTranslationID("dictationPage.label.search"))}
|
||
</button>
|
||
</form>
|
||
</li>
|
||
</ul>
|
||
<div className={styles.tableWrap}>
|
||
<table className={`${styles.table} ${styles.dictation}`}>
|
||
<tr className={styles.tableHeader}>
|
||
<th className={styles.clm0}>{/** th is empty */}</th>
|
||
{displayColumn.JobNumber && (
|
||
<th className={styles.clm1}>
|
||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
|
||
<a
|
||
className={`${styles.hasSort} ${sortIconClass(
|
||
sortableParamName,
|
||
sortDirection,
|
||
SORTABLE_COLUMN.JobNumber
|
||
)}`}
|
||
onClick={() =>
|
||
updateSortColumn(SORTABLE_COLUMN.JobNumber)
|
||
}
|
||
style={{
|
||
pointerEvents: isLoading ? "none" : "auto",
|
||
}}
|
||
>
|
||
{t(
|
||
getTranslationID("dictationPage.label.jobNumber")
|
||
)}
|
||
</a>
|
||
</th>
|
||
)}
|
||
{displayColumn.Status && (
|
||
<th className={styles.clm2}>
|
||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
|
||
<a
|
||
className={`${styles.hasSort} ${sortIconClass(
|
||
sortableParamName,
|
||
sortDirection,
|
||
SORTABLE_COLUMN.Status
|
||
)}`}
|
||
onClick={() =>
|
||
updateSortColumn(SORTABLE_COLUMN.Status)
|
||
}
|
||
style={{
|
||
pointerEvents: isLoading ? "none" : "auto",
|
||
}}
|
||
>
|
||
{t(getTranslationID("dictationPage.label.status"))}
|
||
</a>
|
||
</th>
|
||
)}
|
||
{displayColumn.Priority && (
|
||
<th className={styles.clm3}>Priority</th>
|
||
)}
|
||
{displayColumn.Encryption && (
|
||
<th className={styles.clm4}>
|
||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
|
||
<a
|
||
className={`${styles.hasSort} ${sortIconClass(
|
||
sortableParamName,
|
||
sortDirection,
|
||
SORTABLE_COLUMN.Encryption
|
||
)}`}
|
||
onClick={() =>
|
||
updateSortColumn(SORTABLE_COLUMN.Encryption)
|
||
}
|
||
style={{
|
||
pointerEvents: isLoading ? "none" : "auto",
|
||
}}
|
||
>
|
||
{t(
|
||
getTranslationID("dictationPage.label.encryption")
|
||
)}
|
||
</a>
|
||
</th>
|
||
)}
|
||
{displayColumn.AuthorId && (
|
||
<th className={styles.clm5}>
|
||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
|
||
<a
|
||
className={`${styles.hasSort} ${sortIconClass(
|
||
sortableParamName,
|
||
sortDirection,
|
||
SORTABLE_COLUMN.AuthorId
|
||
)}`}
|
||
onClick={() =>
|
||
updateSortColumn(SORTABLE_COLUMN.AuthorId)
|
||
}
|
||
style={{
|
||
pointerEvents: isLoading ? "none" : "auto",
|
||
}}
|
||
>
|
||
{t(
|
||
getTranslationID("dictationPage.label.authorId")
|
||
)}
|
||
</a>
|
||
</th>
|
||
)}
|
||
{displayColumn.WorkType && (
|
||
<th className={styles.clm6}>
|
||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
|
||
<a
|
||
className={`${styles.hasSort} ${sortIconClass(
|
||
sortableParamName,
|
||
sortDirection,
|
||
SORTABLE_COLUMN.WorkType
|
||
)}`}
|
||
onClick={() =>
|
||
updateSortColumn(SORTABLE_COLUMN.WorkType)
|
||
}
|
||
style={{
|
||
pointerEvents: isLoading ? "none" : "auto",
|
||
}}
|
||
>
|
||
{t(
|
||
getTranslationID("dictationPage.label.workType")
|
||
)}
|
||
</a>
|
||
</th>
|
||
)}
|
||
{displayColumn.FileName && (
|
||
<th className={styles.clm7}>
|
||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
|
||
<a
|
||
className={`${styles.hasSort} ${sortIconClass(
|
||
sortableParamName,
|
||
sortDirection,
|
||
SORTABLE_COLUMN.FileName
|
||
)}`}
|
||
onClick={() =>
|
||
updateSortColumn(SORTABLE_COLUMN.FileName)
|
||
}
|
||
style={{
|
||
pointerEvents: isLoading ? "none" : "auto",
|
||
}}
|
||
>
|
||
{t(
|
||
getTranslationID("dictationPage.label.fileName")
|
||
)}
|
||
</a>
|
||
</th>
|
||
)}
|
||
{displayColumn.FileLength && (
|
||
<th className={styles.clm8}>
|
||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
|
||
<a
|
||
className={`${styles.hasSort} ${sortIconClass(
|
||
sortableParamName,
|
||
sortDirection,
|
||
SORTABLE_COLUMN.FileLength
|
||
)}`}
|
||
onClick={() =>
|
||
updateSortColumn(SORTABLE_COLUMN.FileLength)
|
||
}
|
||
style={{
|
||
pointerEvents: isLoading ? "none" : "auto",
|
||
}}
|
||
>
|
||
{t(
|
||
getTranslationID("dictationPage.label.fileLength")
|
||
)}
|
||
</a>
|
||
</th>
|
||
)}
|
||
{displayColumn.FileSize && (
|
||
<th className={styles.clm9}>
|
||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
|
||
<a
|
||
className={`${styles.hasSort} ${sortIconClass(
|
||
sortableParamName,
|
||
sortDirection,
|
||
SORTABLE_COLUMN.FileSize
|
||
)}`}
|
||
onClick={() =>
|
||
updateSortColumn(SORTABLE_COLUMN.FileSize)
|
||
}
|
||
style={{
|
||
pointerEvents: isLoading ? "none" : "auto",
|
||
}}
|
||
>
|
||
{t(
|
||
getTranslationID("dictationPage.label.fileSize")
|
||
)}
|
||
</a>
|
||
</th>
|
||
)}
|
||
{displayColumn.RecordingStartedDate && (
|
||
<th className={styles.clm10}>
|
||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
|
||
<a
|
||
className={`${styles.hasSort} ${sortIconClass(
|
||
sortableParamName,
|
||
sortDirection,
|
||
SORTABLE_COLUMN.RecordingStartedDate
|
||
)}`}
|
||
onClick={() =>
|
||
updateSortColumn(
|
||
SORTABLE_COLUMN.RecordingStartedDate
|
||
)
|
||
}
|
||
style={{
|
||
pointerEvents: isLoading ? "none" : "auto",
|
||
}}
|
||
>
|
||
{t(
|
||
getTranslationID(
|
||
"dictationPage.label.recordingStartedDate"
|
||
)
|
||
)}
|
||
</a>
|
||
</th>
|
||
)}
|
||
{displayColumn.RecordingFinishedDate && (
|
||
<th className={styles.clm11}>
|
||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
|
||
<a
|
||
className={`${styles.hasSort} ${sortIconClass(
|
||
sortableParamName,
|
||
sortDirection,
|
||
SORTABLE_COLUMN.RecordingFinishedDate
|
||
)}`}
|
||
onClick={() =>
|
||
updateSortColumn(
|
||
SORTABLE_COLUMN.RecordingFinishedDate
|
||
)
|
||
}
|
||
style={{
|
||
pointerEvents: isLoading ? "none" : "auto",
|
||
}}
|
||
>
|
||
{t(
|
||
getTranslationID(
|
||
"dictationPage.label.recordingFinishedDate"
|
||
)
|
||
)}
|
||
</a>
|
||
</th>
|
||
)}
|
||
{displayColumn.UploadDate && (
|
||
<th className={styles.clm12}>
|
||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
|
||
<a
|
||
className={`${styles.hasSort} ${sortIconClass(
|
||
sortableParamName,
|
||
sortDirection,
|
||
SORTABLE_COLUMN.UploadDate
|
||
)}`}
|
||
onClick={() =>
|
||
updateSortColumn(SORTABLE_COLUMN.UploadDate)
|
||
}
|
||
style={{
|
||
pointerEvents: isLoading ? "none" : "auto",
|
||
}}
|
||
>
|
||
{t(
|
||
getTranslationID("dictationPage.label.uploadDate")
|
||
)}
|
||
</a>
|
||
</th>
|
||
)}
|
||
{displayColumn.TranscriptionStartedDate && (
|
||
<th className={styles.clm13}>
|
||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
|
||
<a
|
||
className={`${styles.hasSort} ${sortIconClass(
|
||
sortableParamName,
|
||
sortDirection,
|
||
SORTABLE_COLUMN.TranscriptionStartedDate
|
||
)}`}
|
||
onClick={() =>
|
||
updateSortColumn(
|
||
SORTABLE_COLUMN.TranscriptionStartedDate
|
||
)
|
||
}
|
||
style={{
|
||
pointerEvents: isLoading ? "none" : "auto",
|
||
}}
|
||
>
|
||
{t(
|
||
getTranslationID(
|
||
"dictationPage.label.transcriptionStartedDate"
|
||
)
|
||
)}
|
||
</a>
|
||
</th>
|
||
)}
|
||
{displayColumn.TranscriptionFinishedDate && (
|
||
<th className={styles.clm14}>
|
||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
|
||
<a
|
||
className={`${styles.hasSort} ${sortIconClass(
|
||
sortableParamName,
|
||
sortDirection,
|
||
SORTABLE_COLUMN.TranscriptionFinishedDate
|
||
)}`}
|
||
onClick={() =>
|
||
updateSortColumn(
|
||
SORTABLE_COLUMN.TranscriptionFinishedDate
|
||
)
|
||
}
|
||
style={{
|
||
pointerEvents: isLoading ? "none" : "auto",
|
||
}}
|
||
>
|
||
{t(
|
||
getTranslationID(
|
||
"dictationPage.label.transcriptionFinishedDate"
|
||
)
|
||
)}
|
||
</a>
|
||
</th>
|
||
)}
|
||
{displayColumn.Transcriptionist && (
|
||
<th className={styles.clm15}>
|
||
{t(
|
||
getTranslationID(
|
||
"dictationPage.label.transcriptionist"
|
||
)
|
||
)}
|
||
</th>
|
||
)}
|
||
{displayColumn.Comment && (
|
||
<th className={styles.clm16}>
|
||
{t(getTranslationID("dictationPage.label.comment"))}
|
||
</th>
|
||
)}
|
||
{displayColumn.OptionItem1 && (
|
||
<th className={styles.op1}>
|
||
{t(
|
||
getTranslationID("dictationPage.label.optionItem1")
|
||
)}
|
||
</th>
|
||
)}
|
||
{displayColumn.OptionItem2 && (
|
||
<th className={styles.op2}>
|
||
{t(
|
||
getTranslationID("dictationPage.label.optionItem2")
|
||
)}
|
||
</th>
|
||
)}
|
||
{displayColumn.OptionItem3 && (
|
||
<th className={styles.op3}>
|
||
{t(
|
||
getTranslationID("dictationPage.label.optionItem3")
|
||
)}
|
||
</th>
|
||
)}
|
||
{displayColumn.OptionItem4 && (
|
||
<th className={styles.op4}>
|
||
{t(
|
||
getTranslationID("dictationPage.label.optionItem4")
|
||
)}
|
||
</th>
|
||
)}
|
||
{displayColumn.OptionItem5 && (
|
||
<th className={styles.op5}>
|
||
{t(
|
||
getTranslationID("dictationPage.label.optionItem5")
|
||
)}
|
||
</th>
|
||
)}
|
||
{displayColumn.OptionItem6 && (
|
||
<th className={styles.op6}>
|
||
{t(
|
||
getTranslationID("dictationPage.label.optionItem6")
|
||
)}
|
||
</th>
|
||
)}
|
||
{displayColumn.OptionItem7 && (
|
||
<th className={styles.op7}>
|
||
{t(
|
||
getTranslationID("dictationPage.label.optionItem7")
|
||
)}
|
||
</th>
|
||
)}
|
||
{displayColumn.OptionItem8 && (
|
||
<th className={styles.op8}>
|
||
{t(
|
||
getTranslationID("dictationPage.label.optionItem8")
|
||
)}
|
||
</th>
|
||
)}
|
||
{displayColumn.OptionItem9 && (
|
||
<th className={styles.op9}>
|
||
{t(
|
||
getTranslationID("dictationPage.label.optionItem9")
|
||
)}
|
||
</th>
|
||
)}
|
||
{displayColumn.OptionItem10 && (
|
||
<th className={styles.op10}>
|
||
{t(
|
||
getTranslationID("dictationPage.label.optionItem10")
|
||
)}
|
||
</th>
|
||
)}
|
||
</tr>
|
||
{(isChangeTranscriptionistPopupOpen || !isLoading) &&
|
||
tasks.length !== 0 &&
|
||
tasks.map((x) => (
|
||
<tr key={x.audioFileId}>
|
||
<td className={styles.clm0}>
|
||
<ul className={styles.menuInTable}>
|
||
<li>
|
||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
|
||
<a
|
||
className={isNone ? styles.isDisable : ""}
|
||
onClick={() => onPlayBack(x.audioFileId)}
|
||
>
|
||
{t(
|
||
getTranslationID(
|
||
"dictationPage.label.playback"
|
||
)
|
||
)}
|
||
</a>
|
||
</li>
|
||
<li>
|
||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
|
||
<a onClick={() => onClickFileProperty(x)}>
|
||
{t(
|
||
getTranslationID(
|
||
"dictationPage.label.fileProperty"
|
||
)
|
||
)}
|
||
</a>
|
||
</li>
|
||
<li>
|
||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
|
||
<a
|
||
className={
|
||
x.status !== STATUS.UPLOADED ||
|
||
!(isAdmin || isAuthor)
|
||
? styles.isDisable
|
||
: ""
|
||
}
|
||
onClick={() => {
|
||
onChangeTranscriptionistPopupOpen(x);
|
||
}}
|
||
>
|
||
{t(
|
||
getTranslationID(
|
||
"dictationPage.label.changeTranscriptionist"
|
||
)
|
||
)}
|
||
</a>
|
||
</li>
|
||
<li>
|
||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
|
||
<a
|
||
className={
|
||
(x.status === STATUS.INPROGRESS ||
|
||
x.status === STATUS.PENDING) &&
|
||
(isAdmin || isTypist)
|
||
? ""
|
||
: styles.isDisable
|
||
}
|
||
onClick={() => {
|
||
onCancel(x.audioFileId);
|
||
}}
|
||
>
|
||
{t(
|
||
getTranslationID(
|
||
"dictationPage.label.cancelDictation"
|
||
)
|
||
)}
|
||
</a>
|
||
</li>
|
||
<li>
|
||
{/* タスクのステータスがFinishedかつ、ログインユーザーがAdminかTypistの場合、Change status to Pendingボタンを活性化する */}
|
||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
|
||
<a
|
||
className={
|
||
x.status === STATUS.FINISHED &&
|
||
(isAdmin || isTypist)
|
||
? ""
|
||
: styles.isDisable
|
||
}
|
||
onClick={() => {
|
||
onReopen(x.audioFileId);
|
||
}}
|
||
>
|
||
{t(
|
||
getTranslationID(
|
||
"dictationPage.label.reopenDictation"
|
||
)
|
||
)}
|
||
</a>
|
||
</li>
|
||
<li>
|
||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
|
||
<a
|
||
// タスクのステータスがInprogressまたはPending以外の場合、削除ボタンを活性化する
|
||
className={
|
||
isDeletableRole &&
|
||
x.status !== STATUS.INPROGRESS &&
|
||
x.status !== STATUS.PENDING
|
||
? ""
|
||
: styles.isDisable
|
||
}
|
||
onClick={() => onDeleteTask(x.audioFileId)}
|
||
>
|
||
{t(
|
||
getTranslationID(
|
||
"dictationPage.label.deleteDictation"
|
||
)
|
||
)}
|
||
</a>
|
||
</li>
|
||
</ul>
|
||
</td>
|
||
{displayColumn.JobNumber && (
|
||
<td className={styles.clm1}>{x.jobNumber}</td>
|
||
)}
|
||
{displayColumn.Status && (
|
||
<td className={styles.clm2}>
|
||
{(() => {
|
||
switch (x.status) {
|
||
case STATUS.UPLOADED:
|
||
return (
|
||
<img src={uploaded} alt="Uploaded" />
|
||
);
|
||
case STATUS.PENDING:
|
||
return <img src={pending} alt="Pending" />;
|
||
case STATUS.FINISHED:
|
||
return (
|
||
<img src={finished} alt="Finished" />
|
||
);
|
||
case STATUS.INPROGRESS:
|
||
return (
|
||
<img src={inprogress} alt="InProgress" />
|
||
);
|
||
default:
|
||
return <img src={backup} alt="Backup" />;
|
||
}
|
||
})()}
|
||
{x.status}
|
||
</td>
|
||
)}
|
||
{displayColumn.Priority && (
|
||
<td
|
||
className={styles.clm3}
|
||
style={{
|
||
color: x.priority === "01" ? "red" : undefined,
|
||
}}
|
||
>
|
||
{x.priority === "01"
|
||
? PRIORITY.HIGH
|
||
: PRIORITY.NORMAL}
|
||
</td>
|
||
)}
|
||
{displayColumn.Encryption && (
|
||
<td className={styles.clm4}>
|
||
{x.isEncrypted ? (
|
||
<img src={lock} alt="encrypted" />
|
||
) : (
|
||
<>-</>
|
||
)}
|
||
</td>
|
||
)}
|
||
{displayColumn.AuthorId && (
|
||
<td className={styles.clm5}>{x.authorId}</td>
|
||
)}
|
||
{displayColumn.WorkType && (
|
||
<td className={styles.clm6}>{x.workType}</td>
|
||
)}
|
||
{displayColumn.FileName && (
|
||
<td className={styles.clm7}>{x.fileName}</td>
|
||
)}
|
||
{displayColumn.FileLength && (
|
||
<td className={styles.clm8}>{x.audioDuration}</td>
|
||
)}
|
||
{displayColumn.FileSize && (
|
||
<td className={styles.clm9}>{x.fileSize}</td>
|
||
)}
|
||
{displayColumn.RecordingStartedDate && (
|
||
<td className={styles.clm10}>
|
||
{x.audioCreatedDate}
|
||
</td>
|
||
)}
|
||
{displayColumn.RecordingFinishedDate && (
|
||
<td className={styles.clm11}>
|
||
{x.audioFinishedDate}
|
||
</td>
|
||
)}
|
||
{displayColumn.UploadDate && (
|
||
<td className={styles.clm12}>
|
||
{x.audioUploadedDate}
|
||
</td>
|
||
)}
|
||
{displayColumn.TranscriptionStartedDate && (
|
||
<td className={styles.clm13}>
|
||
{x.transcriptionStartedDate}
|
||
</td>
|
||
)}
|
||
{displayColumn.TranscriptionFinishedDate && (
|
||
<td className={styles.clm14}>
|
||
{x.transcriptionFinishedDate}
|
||
</td>
|
||
)}
|
||
{displayColumn.Transcriptionist && (
|
||
<td
|
||
className={`${styles.txWsline} ${styles.clm15}`}
|
||
>
|
||
{x.assignees.map((a, i) => (
|
||
<>
|
||
{a.typistName}
|
||
{i !== x.assignees.length - 1 && <br />}
|
||
</>
|
||
))}
|
||
</td>
|
||
)}
|
||
{displayColumn.Comment && (
|
||
<td className={styles.clm16}>{x.comment}</td>
|
||
)}
|
||
{displayColumn.OptionItem1 && (
|
||
<td className={styles.op1}>
|
||
{x.optionItemList[0].optionItemValue}
|
||
</td>
|
||
)}
|
||
|
||
{displayColumn.OptionItem2 && (
|
||
<td className={styles.op2}>
|
||
{x.optionItemList[1].optionItemValue}
|
||
</td>
|
||
)}
|
||
{displayColumn.OptionItem3 && (
|
||
<td className={styles.op3}>
|
||
{x.optionItemList[2].optionItemValue}
|
||
</td>
|
||
)}
|
||
{displayColumn.OptionItem4 && (
|
||
<td className={styles.op4}>
|
||
{x.optionItemList[3].optionItemValue}
|
||
</td>
|
||
)}
|
||
{displayColumn.OptionItem5 && (
|
||
<td className={styles.op5}>
|
||
{x.optionItemList[4].optionItemValue}
|
||
</td>
|
||
)}
|
||
{displayColumn.OptionItem6 && (
|
||
<td className={styles.op6}>
|
||
{x.optionItemList[5].optionItemValue}
|
||
</td>
|
||
)}
|
||
{displayColumn.OptionItem7 && (
|
||
<td className={styles.op7}>
|
||
{x.optionItemList[6].optionItemValue}
|
||
</td>
|
||
)}
|
||
{displayColumn.OptionItem8 && (
|
||
<td className={styles.op8}>
|
||
{x.optionItemList[7].optionItemValue}
|
||
</td>
|
||
)}
|
||
{displayColumn.OptionItem9 && (
|
||
<td className={styles.op9}>
|
||
{x.optionItemList[8].optionItemValue}
|
||
</td>
|
||
)}
|
||
{displayColumn.OptionItem10 && (
|
||
<td className={styles.op10}>
|
||
{x.optionItemList[9].optionItemValue}
|
||
</td>
|
||
)}
|
||
</tr>
|
||
))}
|
||
</table>
|
||
{(isChangeTranscriptionistPopupOpen || !isLoading) &&
|
||
tasks.length === 0 && (
|
||
<p style={{ margin: "10px", textAlign: "center" }}>
|
||
{t(getTranslationID("common.message.listEmpty"))}
|
||
</p>
|
||
)}
|
||
</div>
|
||
{isLoading && (
|
||
<img
|
||
style={{ position: "sticky" }}
|
||
src={progress_activit}
|
||
className={styles.icLoading}
|
||
alt="Loading"
|
||
/>
|
||
)}
|
||
{/** pagenation */}
|
||
<div className={styles.pagenation}>
|
||
<nav className={styles.pagenationNav}>
|
||
<span className={styles.pagenationTotal}>{`${total} ${t(
|
||
getTranslationID("dictationPage.label.title")
|
||
)}`}</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}
|
||
>
|
||
«
|
||
</a>
|
||
{/* 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={getPrevPage}
|
||
>
|
||
‹
|
||
</a>
|
||
{`${currentPage} of ${totalPage}`}
|
||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
|
||
<a
|
||
className={`${!isLoading && currentPage < totalPage
|
||
? styles.isActive
|
||
: ""
|
||
}`}
|
||
onClick={getNextPage}
|
||
>
|
||
›
|
||
</a>
|
||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
|
||
<a
|
||
className={`${!isLoading && currentPage < totalPage
|
||
? styles.isActive
|
||
: ""
|
||
}`}
|
||
onClick={getLastPage}
|
||
>
|
||
»
|
||
</a>
|
||
</nav>
|
||
</div>
|
||
<ul className={`${styles.menuAction} ${styles.alignRight}`}>
|
||
<li className={styles.alignLeft}>
|
||
<a
|
||
// TODO: 将来的に正式なURLに変更する
|
||
href="https://download.omsystem.com/pages/odms_download/odms_cloud_desktop/en/"
|
||
className={`${styles.menuLink} ${styles.isActive}`}
|
||
target="_blank"
|
||
rel="noreferrer"
|
||
>
|
||
{t(getTranslationID("dictationPage.label.applications"))}
|
||
<img
|
||
src={open_in_new}
|
||
alt=""
|
||
className={styles.menuIcon}
|
||
/>
|
||
</a>
|
||
</li>
|
||
<li>
|
||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
|
||
<a
|
||
onClick={onClickBackup}
|
||
className={`${styles.menuLink} ${isAdmin ? styles.isActive : ""
|
||
}`}
|
||
>
|
||
<img src={download} alt="" className={styles.menuIcon} />
|
||
{t(getTranslationID("dictationPage.label.fileBackup"))}
|
||
</a>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</section>
|
||
</div>
|
||
</main>
|
||
<Footer />
|
||
</div>
|
||
</>
|
||
);
|
||
};
|
||
|
||
export default DictationPage;
|