Merged PR 126: 画面実装(タスク一覧画面)

## 概要
[Task1834: 画面実装(タスク一覧画面)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/1834)

- タスク一覧画面を実装しました。
- 表示項目、フィルターを制御できるようにしています
- 表示項目はlocalStorageに保存するようにしています
- ソート順の取得、変更、更新をする処理を追加

## レビューポイント
- デザインの反映は適切か
- フィルター、表示の反映ロジックは適切か
- ソートの反映を追加したので適切か確認をお願いします。

## UIの変更
- [Task1834](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/Task1834?csf=1&web=1&e=zBcQ6i)

## 動作確認状況
- ローカルで確認
  - API呼び出しは未検証
This commit is contained in:
makabe.t 2023-06-08 08:04:34 +00:00
parent 942ac30d8f
commit 3dca5c604b
43 changed files with 4070 additions and 1043 deletions

View File

@ -14,6 +14,7 @@ import VerifyAlreadyExistPage from "pages/VerifyAlreadyExistPage";
import SignupCompletePage from "pages/SignupCompletePage";
import UserListPage from "pages/UserListPage";
import LicensePage from "pages/LicensePage";
import DictationPage from "pages/DictationPage";
const AppRouter: React.FC = () => (
<Routes>
@ -52,7 +53,7 @@ const AppRouter: React.FC = () => (
/>
<Route
path="/dictations"
element={<RouteAuthGuard component={<SamplePage />} />}
element={<RouteAuthGuard component={<DictationPage />} />}
/>
<Route
path="/workflow"

View File

@ -304,6 +304,32 @@ export interface ErrorResponse {
*/
'code': string;
}
/**
*
* @export
* @interface GetLicenseSummaryRequest
*/
export interface GetLicenseSummaryRequest {
/**
*
* @type {number}
* @memberof GetLicenseSummaryRequest
*/
'accountId': number;
}
/**
*
* @export
* @interface GetLicenseSummaryResponse
*/
export interface GetLicenseSummaryResponse {
/**
*
* @type {LicenseSummaryInfo}
* @memberof GetLicenseSummaryResponse
*/
'licenseSummaryInfo': LicenseSummaryInfo;
}
/**
*
* @export
@ -359,6 +385,25 @@ export interface GetRelationsResponse {
*/
'prompt': boolean;
}
/**
*
* @export
* @interface GetSortCriteriaResponse
*/
export interface GetSortCriteriaResponse {
/**
* ASC/DESC
* @type {string}
* @memberof GetSortCriteriaResponse
*/
'direction': string;
/**
* JOB_NUMBER/STATUS/ENCRYPTION/AUTHOR_ID/FILE_NAME/FILE_LENGTH/FILE_SIZE/RECORDING_STARTED_DATE/RECORDING_FINISHED_DATE/UPLOAD_DATE/TRANSCRIPTION_STARTED_DATE/TRANSCRIPTION_FINISHED_DATE
* @type {string}
* @memberof GetSortCriteriaResponse
*/
'paramName': string;
}
/**
*
* @export
@ -372,6 +417,79 @@ export interface GetUsersResponse {
*/
'users': Array<User>;
}
/**
*
* @export
* @interface LicenseSummaryInfo
*/
export interface LicenseSummaryInfo {
/**
*
* @type {number}
* @memberof LicenseSummaryInfo
*/
'totalLicense': number;
/**
*
* @type {number}
* @memberof LicenseSummaryInfo
*/
'allocatedLicense': number;
/**
*
* @type {number}
* @memberof LicenseSummaryInfo
*/
'reusableLicense': number;
/**
*
* @type {number}
* @memberof LicenseSummaryInfo
*/
'freeLicense': number;
/**
*
* @type {number}
* @memberof LicenseSummaryInfo
*/
'expiringWithin14daysLicense': number;
/**
*
* @type {number}
* @memberof LicenseSummaryInfo
*/
'issueRequesting': number;
/**
*
* @type {number}
* @memberof LicenseSummaryInfo
*/
'numberOfRequesting': number;
/**
*
* @type {number}
* @memberof LicenseSummaryInfo
*/
'shortage': number;
/**
*
* @type {number}
* @memberof LicenseSummaryInfo
*/
'storageSize': number;
/**
*
* @type {number}
* @memberof LicenseSummaryInfo
*/
'usedSize': number;
/**
*
* @type {boolean}
* @memberof LicenseSummaryInfo
*/
'isAccountLock': boolean;
}
/**
*
* @export
@ -416,6 +534,25 @@ export interface OptionItemList {
*/
'optionItemList': Array<OptionItem>;
}
/**
*
* @export
* @interface PostSortCriteriaRequest
*/
export interface PostSortCriteriaRequest {
/**
* ASC/DESC
* @type {string}
* @memberof PostSortCriteriaRequest
*/
'direction': string;
/**
* JOB_NUMBER/STATUS/ENCRYPTION/AUTHOR_ID/FILE_NAME/FILE_LENGTH/FILE_SIZE/RECORDING_STARTED_DATE/RECORDING_FINISHED_DATE/UPLOAD_DATE/TRANSCRIPTION_STARTED_DATE/TRANSCRIPTION_FINISHED_DATE
* @type {string}
* @memberof PostSortCriteriaRequest
*/
'paramName': string;
}
/**
*
* @export
@ -490,25 +627,6 @@ export interface SignupRequest {
*/
'notification': boolean;
}
/**
*
* @export
* @interface SortCriteriaRequest
*/
export interface SortCriteriaRequest {
/**
* ASC/DESC
* @type {string}
* @memberof SortCriteriaRequest
*/
'direction': string;
/**
* JOB_NUMBER/STATUS/ENCRYPTION/AUTHOR_ID/FILE_NAME/FILE_LENGTH/FILE_SIZE/RECORDING_STARTED_DATE/RECORDING_FINISHED_DATE/UPLOAD_DATE/TRANSCRIPTION_STARTED_DATE/TRANSCRIPTION_FINISHED_DATE
* @type {string}
* @memberof SortCriteriaRequest
*/
'paramName': string;
}
/**
*
* @export
@ -873,6 +991,46 @@ export const AccountsApiAxiosParamCreator = function (configuration?: Configurat
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
localVarRequestOptions.data = serializeDataIfNeeded(createAccountRequest, localVarRequestOptions, configuration)
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
*
* @summary
* @param {GetLicenseSummaryRequest} getLicenseSummaryRequest
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
getLicenseSummary: async (getLicenseSummaryRequest: GetLicenseSummaryRequest, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'getLicenseSummaryRequest' is not null or undefined
assertParamExists('getLicenseSummary', 'getLicenseSummaryRequest', getLicenseSummaryRequest)
const localVarPath = `/accounts/licenses/summary`;
// 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(getLicenseSummaryRequest, localVarRequestOptions, configuration)
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
@ -899,6 +1057,17 @@ export const AccountsApiFp = function(configuration?: Configuration) {
const localVarAxiosArgs = await localVarAxiosParamCreator.createAccount(createAccountRequest, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
*
* @summary
* @param {GetLicenseSummaryRequest} getLicenseSummaryRequest
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async getLicenseSummary(getLicenseSummaryRequest: GetLicenseSummaryRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<GetLicenseSummaryResponse>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.getLicenseSummary(getLicenseSummaryRequest, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
}
};
@ -919,6 +1088,16 @@ export const AccountsApiFactory = function (configuration?: Configuration, baseP
createAccount(createAccountRequest: CreateAccountRequest, options?: any): AxiosPromise<object> {
return localVarFp.createAccount(createAccountRequest, options).then((request) => request(axios, basePath));
},
/**
*
* @summary
* @param {GetLicenseSummaryRequest} getLicenseSummaryRequest
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
getLicenseSummary(getLicenseSummaryRequest: GetLicenseSummaryRequest, options?: any): AxiosPromise<GetLicenseSummaryResponse> {
return localVarFp.getLicenseSummary(getLicenseSummaryRequest, options).then((request) => request(axios, basePath));
},
};
};
@ -940,6 +1119,18 @@ export class AccountsApi extends BaseAPI {
public createAccount(createAccountRequest: CreateAccountRequest, options?: AxiosRequestConfig) {
return AccountsApiFp(this.configuration).createAccount(createAccountRequest, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary
* @param {GetLicenseSummaryRequest} getLicenseSummaryRequest
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof AccountsApi
*/
public getLicenseSummary(getLicenseSummaryRequest: GetLicenseSummaryRequest, options?: AxiosRequestConfig) {
return AccountsApiFp(this.configuration).getLicenseSummary(getLicenseSummaryRequest, options).then((request) => request(this.axios, this.basePath));
}
}
@ -1982,10 +2173,12 @@ export const TasksApiAxiosParamCreator = function (configuration?: Configuration
* @param {number} [limit]
* @param {number} [offset]  
* @param {string} [status] (,)許容するステータスの値は次の通り: Uploaded / Pending / InProgress / Finished / Backup
* @param {string} [direction] ASC/DESC
* @param {string} [paramName] JOB_NUMBER/STATUS/ENCRYPTION/AUTHOR_ID/FILE_NAME/FILE_LENGTH/FILE_SIZE/RECORDING_STARTED_DATE/RECORDING_FINISHED_DATE/UPLOAD_DATE/TRANSCRIPTION_STARTED_DATE/TRANSCRIPTION_FINISHED_DATE
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
getTasks: async (limit?: number, offset?: number, status?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
getTasks: async (limit?: number, offset?: number, status?: string, direction?: string, paramName?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/tasks`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
@ -2014,6 +2207,14 @@ export const TasksApiAxiosParamCreator = function (configuration?: Configuration
localVarQueryParameter['status'] = status;
}
if (direction !== undefined) {
localVarQueryParameter['direction'] = direction;
}
if (paramName !== undefined) {
localVarQueryParameter['paramName'] = paramName;
}
setSearchParams(localVarUrlObj, localVarQueryParameter);
@ -2172,11 +2373,13 @@ export const TasksApiFp = function(configuration?: Configuration) {
* @param {number} [limit]
* @param {number} [offset]  
* @param {string} [status] (,)許容するステータスの値は次の通り: Uploaded / Pending / InProgress / Finished / Backup
* @param {string} [direction] ASC/DESC
* @param {string} [paramName] JOB_NUMBER/STATUS/ENCRYPTION/AUTHOR_ID/FILE_NAME/FILE_LENGTH/FILE_SIZE/RECORDING_STARTED_DATE/RECORDING_FINISHED_DATE/UPLOAD_DATE/TRANSCRIPTION_STARTED_DATE/TRANSCRIPTION_FINISHED_DATE
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async getTasks(limit?: number, offset?: number, status?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<TasksResponse>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.getTasks(limit, offset, status, options);
async getTasks(limit?: number, offset?: number, status?: string, direction?: string, paramName?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<TasksResponse>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.getTasks(limit, offset, status, direction, paramName, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
@ -2267,11 +2470,13 @@ export const TasksApiFactory = function (configuration?: Configuration, basePath
* @param {number} [limit]
* @param {number} [offset]  
* @param {string} [status] (,)許容するステータスの値は次の通り: Uploaded / Pending / InProgress / Finished / Backup
* @param {string} [direction] ASC/DESC
* @param {string} [paramName] JOB_NUMBER/STATUS/ENCRYPTION/AUTHOR_ID/FILE_NAME/FILE_LENGTH/FILE_SIZE/RECORDING_STARTED_DATE/RECORDING_FINISHED_DATE/UPLOAD_DATE/TRANSCRIPTION_STARTED_DATE/TRANSCRIPTION_FINISHED_DATE
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
getTasks(limit?: number, offset?: number, status?: string, options?: any): AxiosPromise<TasksResponse> {
return localVarFp.getTasks(limit, offset, status, options).then((request) => request(axios, basePath));
getTasks(limit?: number, offset?: number, status?: string, direction?: string, paramName?: string, options?: any): AxiosPromise<TasksResponse> {
return localVarFp.getTasks(limit, offset, status, direction, paramName, options).then((request) => request(axios, basePath));
},
/**
* Pendingにします
@ -2369,12 +2574,14 @@ export class TasksApi extends BaseAPI {
* @param {number} [limit]
* @param {number} [offset]  
* @param {string} [status] (,)許容するステータスの値は次の通り: Uploaded / Pending / InProgress / Finished / Backup
* @param {string} [direction] ASC/DESC
* @param {string} [paramName] JOB_NUMBER/STATUS/ENCRYPTION/AUTHOR_ID/FILE_NAME/FILE_LENGTH/FILE_SIZE/RECORDING_STARTED_DATE/RECORDING_FINISHED_DATE/UPLOAD_DATE/TRANSCRIPTION_STARTED_DATE/TRANSCRIPTION_FINISHED_DATE
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof TasksApi
*/
public getTasks(limit?: number, offset?: number, status?: string, options?: AxiosRequestConfig) {
return TasksApiFp(this.configuration).getTasks(limit, offset, status, options).then((request) => request(this.axios, this.basePath));
public getTasks(limit?: number, offset?: number, status?: string, direction?: string, paramName?: string, options?: AxiosRequestConfig) {
return TasksApiFp(this.configuration).getTasks(limit, offset, status, direction, paramName, options).then((request) => request(this.axios, this.basePath));
}
/**
@ -2506,6 +2713,40 @@ export const UsersApiAxiosParamCreator = function (configuration?: Configuration
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
*
* @summary
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
getSortCcriteria: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/users/sort-criteria`;
// 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: 'GET', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication bearer required
// http bearer authentication required
await setBearerAuthToObject(localVarHeaderParameter, configuration)
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
@ -2592,13 +2833,13 @@ export const UsersApiAxiosParamCreator = function (configuration?: Configuration
/**
*
* @summary
* @param {SortCriteriaRequest} sortCriteriaRequest
* @param {PostSortCriteriaRequest} postSortCriteriaRequest
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
updateSortCcriteria: async (sortCriteriaRequest: SortCriteriaRequest, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'sortCriteriaRequest' is not null or undefined
assertParamExists('updateSortCcriteria', 'sortCriteriaRequest', sortCriteriaRequest)
updateSortCcriteria: async (postSortCriteriaRequest: PostSortCriteriaRequest, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'postSortCriteriaRequest' is not null or undefined
assertParamExists('updateSortCcriteria', 'postSortCriteriaRequest', postSortCriteriaRequest)
const localVarPath = `/users/sort-criteria`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
@ -2622,7 +2863,7 @@ export const UsersApiAxiosParamCreator = function (configuration?: Configuration
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
localVarRequestOptions.data = serializeDataIfNeeded(sortCriteriaRequest, localVarRequestOptions, configuration)
localVarRequestOptions.data = serializeDataIfNeeded(postSortCriteriaRequest, localVarRequestOptions, configuration)
return {
url: toPathString(localVarUrlObj),
@ -2671,6 +2912,16 @@ export const UsersApiFp = function(configuration?: Configuration) {
const localVarAxiosArgs = await localVarAxiosParamCreator.getRelations(options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
*
* @summary
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async getSortCcriteria(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<GetSortCriteriaResponse>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.getSortCcriteria(options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
*
* @summary
@ -2695,12 +2946,12 @@ export const UsersApiFp = function(configuration?: Configuration) {
/**
*
* @summary
* @param {SortCriteriaRequest} sortCriteriaRequest
* @param {PostSortCriteriaRequest} postSortCriteriaRequest
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async updateSortCcriteria(sortCriteriaRequest: SortCriteriaRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<object>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.updateSortCcriteria(sortCriteriaRequest, options);
async updateSortCcriteria(postSortCriteriaRequest: PostSortCriteriaRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<object>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.updateSortCcriteria(postSortCriteriaRequest, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
}
@ -2742,6 +2993,15 @@ export const UsersApiFactory = function (configuration?: Configuration, basePath
getRelations(options?: any): AxiosPromise<GetRelationsResponse> {
return localVarFp.getRelations(options).then((request) => request(axios, basePath));
},
/**
*
* @summary
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
getSortCcriteria(options?: any): AxiosPromise<GetSortCriteriaResponse> {
return localVarFp.getSortCcriteria(options).then((request) => request(axios, basePath));
},
/**
*
* @summary
@ -2764,12 +3024,12 @@ export const UsersApiFactory = function (configuration?: Configuration, basePath
/**
*
* @summary
* @param {SortCriteriaRequest} sortCriteriaRequest
* @param {PostSortCriteriaRequest} postSortCriteriaRequest
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
updateSortCcriteria(sortCriteriaRequest: SortCriteriaRequest, options?: any): AxiosPromise<object> {
return localVarFp.updateSortCcriteria(sortCriteriaRequest, options).then((request) => request(axios, basePath));
updateSortCcriteria(postSortCriteriaRequest: PostSortCriteriaRequest, options?: any): AxiosPromise<object> {
return localVarFp.updateSortCcriteria(postSortCriteriaRequest, options).then((request) => request(axios, basePath));
},
};
};
@ -2816,6 +3076,17 @@ export class UsersApi extends BaseAPI {
return UsersApiFp(this.configuration).getRelations(options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof UsersApi
*/
public getSortCcriteria(options?: AxiosRequestConfig) {
return UsersApiFp(this.configuration).getSortCcriteria(options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary
@ -2842,13 +3113,13 @@ export class UsersApi extends BaseAPI {
/**
*
* @summary
* @param {SortCriteriaRequest} sortCriteriaRequest
* @param {PostSortCriteriaRequest} postSortCriteriaRequest
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof UsersApi
*/
public updateSortCcriteria(sortCriteriaRequest: SortCriteriaRequest, options?: AxiosRequestConfig) {
return UsersApiFp(this.configuration).updateSortCcriteria(sortCriteriaRequest, options).then((request) => request(this.axios, this.basePath));
public updateSortCcriteria(postSortCriteriaRequest: PostSortCriteriaRequest, options?: AxiosRequestConfig) {
return UsersApiFp(this.configuration).updateSortCcriteria(postSortCriteriaRequest, options).then((request) => request(this.axios, this.basePath));
}
}

View File

@ -6,6 +6,7 @@ import verify from "features/verify/verifySlice";
import ui from "features/ui/uiSlice";
import user from "features/user/userSlice";
import license from "features/license/licenseSlice";
import dictation from "features/dictation/dictationSlice";
export const store = configureStore({
reducer: {
@ -16,6 +17,7 @@ export const store = configureStore({
ui,
user,
license,
dictation,
},
});

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 27.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="レイヤー_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" viewBox="0 0 48 48" style="enable-background:new 0 0 48 48;" xml:space="preserve">
<style type="text/css">
.st0{fill:#282828;}
</style>
<path class="st0" d="M24,31.3l2.1-2.1l-3.7-3.7h9.1v-3h-9.1l3.7-3.7L24,16.7L16.7,24L24,31.3z M24,44c-2.7,0-5.3-0.5-7.8-1.6
c-2.4-1-4.6-2.5-6.4-4.3s-3.2-3.9-4.3-6.4C4.5,29.3,4,26.7,4,24c0-2.8,0.5-5.4,1.6-7.8s2.5-4.6,4.3-6.4s3.9-3.2,6.4-4.3S21.3,4,24,4
c2.8,0,5.4,0.5,7.8,1.6s4.6,2.5,6.4,4.3s3.2,3.9,4.3,6.4c1.1,2.4,1.6,5,1.6,7.8c0,2.7-0.5,5.3-1.6,7.8c-1,2.4-2.5,4.6-4.3,6.4
s-3.9,3.2-6.4,4.3C29.4,43.5,26.8,44,24,44z M24,41c4.7,0,8.8-1.7,12-5c3.3-3.3,5-7.3,5-12c0-4.7-1.6-8.7-5-12c-3.3-3.3-7.3-5-12-5
c-4.7,0-8.7,1.7-12,5s-5,7.3-5,12c0,4.7,1.7,8.7,5,12S19.3,41,24,41z"/>
</svg>

After

Width:  |  Height:  |  Size: 999 B

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 27.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="レイヤー_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" viewBox="0 0 48 48" style="enable-background:new 0 0 48 48;" xml:space="preserve">
<style type="text/css">
.st0{fill:#282828;}
</style>
<path class="st0" d="M24,31.3l7.3-7.3L24,16.7l-2.1,2.1l3.7,3.7h-9.1v3h9.1l-3.7,3.7L24,31.3z M24,44c-2.7,0-5.3-0.5-7.8-1.6
c-2.4-1-4.6-2.5-6.4-4.3s-3.2-3.9-4.3-6.4C4.5,29.3,4,26.7,4,24c0-2.8,0.5-5.4,1.6-7.8s2.5-4.6,4.3-6.4s3.9-3.2,6.4-4.3S21.3,4,24,4
c2.8,0,5.4,0.5,7.8,1.6s4.6,2.5,6.4,4.3s3.2,3.9,4.3,6.4c1.1,2.4,1.6,5,1.6,7.8c0,2.7-0.5,5.3-1.6,7.8c-1,2.4-2.5,4.6-4.3,6.4
s-3.9,3.2-6.4,4.3C29.4,43.5,26.8,44,24,44z M24,41c4.7,0,8.8-1.7,12-5c3.3-3.3,5-7.3,5-12c0-4.7-1.6-8.7-5-12c-3.3-3.3-7.3-5-12-5
c-4.7,0-8.7,1.7-12,5s-5,7.3-5,12c0,4.7,1.7,8.7,5,12S19.3,41,24,41z"/>
</svg>

After

Width:  |  Height:  |  Size: 999 B

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 27.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="レイヤー_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" viewBox="0 0 48 48" style="enable-background:new 0 0 48 48;" xml:space="preserve">
<style type="text/css">
.st0{fill:#A5A5A5;}
</style>
<path class="st0" d="M22.9,26.5h9c0.8,0,1.5-0.3,2.1-0.8c0.6-0.6,0.8-1.2,0.8-2s-0.3-1.5-0.8-2.1c-0.6-0.6-1.2-0.9-2.1-0.9h-0.6
l-0.1-0.5c-0.1-1-0.6-1.9-1.4-2.6s-1.7-1.1-2.8-1.1c-0.9,0-1.7,0.2-2.4,0.7c-0.7,0.4-1.2,1-1.5,1.8L23,19.3h-0.4
c-1,0-1.8,0.4-2.4,1.1c-0.7,0.7-1,1.6-1,2.5c0,1,0.4,1.8,1.1,2.5C21,26.1,21.9,26.5,22.9,26.5z M5,42c-0.8,0-1.5-0.3-2.1-0.9
C2.3,40.5,2,39.8,2,39V10.5h3V39h36.5v3H5z M11,36c-0.8,0-1.5-0.3-2.1-0.9C8.3,34.5,8,33.8,8,33V7c0-0.8,0.3-1.5,0.9-2.1
C9.5,4.3,10.2,4,11,4h13l3,3h16c0.8,0,1.5,0.3,2.1,0.9C45.7,8.5,46,9.2,46,10v23c0,0.8-0.3,1.5-0.9,2.1C44.5,35.7,43.8,36,43,36H11z
M11,33h32V10H25.8l-3-3H11V33z M11,33V7V33z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 27.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!-- Generator: Adobe Illustrator 27.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="レイヤー_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" viewBox="0 0 48 48" style="enable-background:new 0 0 48 48;" xml:space="preserve">
<style type="text/css">
.st0{fill:#00B4AA;}
.st0{fill:#282828;}
</style>
<path class="st0" d="M21,33.1L35.2,19l-2.3-2.2L21.1,28.6l-6-6l-2.2,2.2L21,33.1z M24,44c-2.7,0-5.3-0.5-7.8-1.6
c-2.4-1-4.6-2.5-6.4-4.3s-3.2-3.9-4.3-6.4S4,26.7,4,24c0-2.8,0.5-5.4,1.6-7.8s2.5-4.5,4.3-6.4s3.9-3.2,6.4-4.3S21.3,4,24,4
c2.8,0,5.4,0.5,7.8,1.6s4.6,2.5,6.3,4.3c1.8,1.8,3.2,3.9,4.3,6.4c1.1,2.4,1.6,5,1.6,7.8c0,2.7-0.5,5.3-1.6,7.8
c-1,2.4-2.5,4.6-4.3,6.4c-1.8,1.8-3.9,3.2-6.4,4.3C29.4,43.5,26.8,44,24,44z"/>
<path class="st0" d="M21.1,33.1l14.1-14.2l-2.3-2.2L21.1,28.5l-6-6l-2.2,2.2L21.1,33.1z M24,44c-2.7,0-5.3-0.5-7.8-1.6
c-2.4-1-4.6-2.5-6.4-4.3s-3.2-3.9-4.3-6.4C4.5,29.3,4,26.7,4,24c0-2.8,0.5-5.4,1.6-7.8s2.5-4.6,4.3-6.4s3.9-3.2,6.4-4.3S21.3,4,24,4
c2.8,0,5.4,0.5,7.8,1.6s4.6,2.5,6.4,4.3s3.2,3.9,4.3,6.4c1.1,2.4,1.6,5,1.6,7.8c0,2.7-0.5,5.3-1.6,7.8c-1,2.4-2.5,4.6-4.3,6.4
s-3.9,3.2-6.4,4.3C29.4,43.5,26.8,44,24,44z"/>
</svg>

Before

Width:  |  Height:  |  Size: 841 B

After

Width:  |  Height:  |  Size: 840 B

View File

@ -1,10 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 27.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!-- Generator: Adobe Illustrator 27.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="レイヤー_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" viewBox="0 0 40 40" style="enable-background:new 0 0 40 40;" xml:space="preserve">
y="0px" viewBox="0 0 48 48" style="enable-background:new 0 0 48 48;" xml:space="preserve">
<style type="text/css">
.st0{fill:#282828;}
</style>
<path class="st0" d="M11.1,35c-0.8,0-1.4-0.3-1.9-0.8c-0.5-0.6-0.8-1.2-0.8-2v-23H6.7V6.4h8V5h10.7v1.4h8v2.8h-1.7v23
c0,0.8-0.3,1.4-0.8,2c-0.5,0.6-1.2,0.8-1.9,0.8H11.1z M15.2,28.7H18V12.6h-2.8V28.7z M22,28.7h2.8V12.6H22V28.7z"/>
<path class="st0" d="M13.1,42c-0.8,0-1.5-0.3-2.1-0.9c-0.6-0.6-0.9-1.3-0.9-2.1V10.5H8v-3h9.4V6h13.2v1.5H40v3h-2V39
c0,0.8-0.3,1.5-0.9,2.1C36.5,41.7,35.8,42,35,42H13.1z M35,10.5H13.1V39H35V10.5z M18.4,34.7h3v-20h-3V34.7z M26.6,34.7h3v-20h-3
V34.7z M13.1,10.5V39V10.5z"/>
</svg>

Before

Width:  |  Height:  |  Size: 651 B

After

Width:  |  Height:  |  Size: 695 B

View File

@ -1,10 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 27.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!-- Generator: Adobe Illustrator 27.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="レイヤー_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" viewBox="0 0 48 48" style="enable-background:new 0 0 48 48;" xml:space="preserve">
<style type="text/css">
.st0{fill:#282828;}
</style>
<path class="st0" d="M39.7,14.7l-6.4-6.4l2.1-2.1c0.6-0.6,1.3-0.8,2.1-0.8c0.8,0,1.6,0.3,2.1,0.9l2.1,2.1c0.6,0.6,0.9,1.3,0.9,2.1
s-0.3,1.5-0.9,2.1L39.7,14.7z M37.6,16.8L12.4,42H6v-6.4l25.2-25.2L37.6,16.8z"/>
<path class="st0" d="M9,39h2.2l22.2-22.1l-2.2-2.2L9,36.8V39z M39.7,14.7l-6.4-6.4l2.1-2.1c0.6-0.6,1.3-0.9,2.1-0.9
c0.8,0,1.5,0.3,2.1,0.9l2.2,2.2c0.6,0.6,0.9,1.3,0.9,2.1c0,0.8-0.3,1.5-0.9,2.1L39.7,14.7z M37.6,16.8L12.4,42H6v-6.4l25.2-25.2
L37.6,16.8z M32.2,15.7l-1.1-1.1l2.2,2.2L32.2,15.7z"/>
</svg>

Before

Width:  |  Height:  |  Size: 630 B

After

Width:  |  Height:  |  Size: 717 B

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 27.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="レイヤー_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" viewBox="0 0 48 48" style="enable-background:new 0 0 48 48;" xml:space="preserve">
<style type="text/css">
.st0{fill:#00B4AA;}
</style>
<path class="st0" d="M24,44c-2.8,0-5.5-0.5-7.9-1.5s-4.6-2.4-6.4-4.2S6.5,34.4,5.5,32S4,26.8,4,24s0.5-5.4,1.5-7.8S8,11.6,9.8,9.8
s3.9-3.2,6.4-4.2S21.2,4,24,4c2.5,0,4.8,0.4,7,1.2s4.1,1.9,5.9,3.3l-2.2,2.1c-1.5-1.2-3.1-2.1-4.9-2.7C28,7.3,26.1,7,24,7
c-4.8,0-8.9,1.6-12.1,4.9S7,19.2,7,24s1.6,8.9,4.9,12.1S19.2,41,24,41s8.9-1.6,12.1-4.9S41,28.8,41,24c0-1-0.1-2-0.2-2.9
c-0.2-1-0.4-1.9-0.7-2.8l2.3-2.3c0.5,1.2,0.9,2.5,1.2,3.8s0.4,2.7,0.4,4.1c0,2.8-0.5,5.5-1.5,7.9s-2.5,4.5-4.2,6.3s-3.9,3.2-6.4,4.2
C29.4,43.5,26.8,44,24,44z M21.1,33.1l-8.3-8.3l2.2-2.2l6,6L41.8,7.8l2.3,2.2L21.1,33.1z"/>
</svg>

After

Width:  |  Height:  |  Size: 1009 B

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 27.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="レイヤー_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" viewBox="0 0 48 48" style="enable-background:new 0 0 48 48;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FF5A33;}
</style>
<path class="st0" d="M26.4,44v-3c1.2-0.2,2.3-0.5,3.5-1c1.1-0.5,2.2-1.1,3.3-1.9l2.1,2.2c-1.3,1-2.8,1.8-4.2,2.4
C29.5,43.3,28,43.8,26.4,44z M21.9,44c-4.6-0.7-8.3-2.7-11.3-6.1s-4.5-7.4-4.5-12.1c0-2.5,0.5-4.8,1.4-7s2.2-4.1,3.9-5.7
c1.6-1.6,3.5-2.9,5.7-3.8s4.5-1.4,7-1.4h1l-4-3.9l2.2-2.2L31,9.3L23.4,17l-2.2-2.2l4-4h-1c-4.2,0-7.8,1.4-10.7,4.3
s-4.3,6.4-4.3,10.7c0,3.9,1.2,7.2,3.6,10s5.5,4.5,9.1,5.2V44z M38.4,37.2L36.2,35c0.8-1,1.4-2.1,1.8-3.2s0.8-2.4,0.9-3.7h3
c-0.2,1.7-0.7,3.3-1.3,4.9C40.1,34.5,39.3,35.9,38.4,37.2z M42,23.6h-3c-0.2-1.2-0.5-2.3-0.9-3.5s-1.1-2.3-1.8-3.4l2.2-2.1
c1,1.3,1.8,2.8,2.3,4.3C41.4,20.3,41.8,21.9,42,23.6z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 27.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="レイヤー_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" viewBox="0 0 48 48" style="enable-background:new 0 0 48 48;" xml:space="preserve">
<style type="text/css">
.st0{fill:#282828;}
</style>
<path class="st0" d="M19.7,23.6c-2.3,0-4.3-0.7-5.8-2.2s-2.2-3.4-2.2-5.8s0.7-4.3,2.2-5.8s3.4-2.2,5.8-2.2s4.3,0.7,5.8,2.2
s2.2,3.4,2.2,5.8s-0.7,4.3-2.2,5.8S22.1,23.6,19.7,23.6z M2.7,40.7v-5c0-1.2,0.3-2.4,0.9-3.4s1.5-1.8,2.7-2.3c2.6-1.1,4.9-2,7.1-2.5
s4.3-0.7,6.3-0.7H21c-0.2,0.5-0.4,1-0.5,1.5s-0.2,1.1-0.3,1.7h-0.5c-2.1,0-4.1,0.2-6,0.7s-4,1.2-6.1,2.2c-0.6,0.3-1,0.7-1.3,1.2
c-0.3,0.5-0.4,1-0.4,1.6v1.8h14.3c0.2,0.6,0.4,1.2,0.6,1.7c0.2,0.5,0.6,1,0.9,1.5H2.7z M34,43.1l-0.5-3.5c-0.6-0.2-1.2-0.4-1.8-0.8
s-1.1-0.7-1.6-1.1l-2.9,0.6l-1.3-2.2l2.5-2.3c-0.1-0.3-0.1-0.8-0.1-1.3s0-1,0.1-1.3l-2.5-2.3l1.3-2.2l2.9,0.6c0.4-0.4,1-0.8,1.6-1.1
c0.6-0.3,1.2-0.6,1.8-0.8l0.5-3.5h2.9l0.5,3.5c0.6,0.2,1.2,0.4,1.8,0.8c0.6,0.3,1.1,0.7,1.6,1.1l2.9-0.6l1.3,2.2L42.6,31
c0.1,0.3,0.1,0.8,0.1,1.3s0,1-0.1,1.3l2.5,2.3l-1.3,2.2l-2.9-0.6c-0.4,0.4-1,0.8-1.6,1.1c-0.6,0.3-1.2,0.6-1.8,0.8l-0.5,3.5H34z
M35.4,36.6c1.3,0,2.3-0.4,3.1-1.2s1.2-1.8,1.2-3.1c0-1.3-0.4-2.3-1.2-3.1c-0.8-0.8-1.8-1.2-3.1-1.2c-1.3,0-2.3,0.4-3.1,1.2
c-0.8,0.8-1.2,1.8-1.2,3.1c0,1.3,0.4,2.3,1.2,3.1C33.1,36.3,34.1,36.6,35.4,36.6z M19.7,20.4c1.4,0,2.5-0.5,3.4-1.4s1.4-2.1,1.4-3.4
s-0.5-2.5-1.4-3.4c-0.9-0.9-2.1-1.4-3.4-1.4s-2.5,0.5-3.4,1.4c-0.9,0.9-1.4,2.1-1.4,3.4s0.5,2.5,1.4,3.4
C17.2,20,18.4,20.4,19.7,20.4z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 27.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="レイヤー_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" viewBox="0 0 48 48" style="enable-background:new 0 0 48 48;" xml:space="preserve">
<style type="text/css">
.st0{fill:#282828;}
</style>
<path class="st0" d="M30.1,39.4h1.9v-7h-1.9V39.4z M31,30.6c0.2,0,0.5-0.1,0.7-0.3c0.2-0.2,0.3-0.4,0.3-0.7s-0.1-0.5-0.3-0.7
c-0.2-0.2-0.4-0.3-0.7-0.3c-0.3,0-0.5,0.1-0.7,0.3c-0.2,0.2-0.3,0.4-0.3,0.7c0,0.3,0.1,0.5,0.3,0.7C30.5,30.5,30.7,30.6,31,30.6z
M10,8.1v13.8v-0.2v18.2V8.1v8.7V8.1z M14.6,26.8h7.8c0.4-0.5,0.8-1,1.3-1.5c0.5-0.5,1-0.9,1.5-1.3H14.6V26.8z M14.6,34.7h5.7
c-0.1-0.4-0.1-0.9-0.1-1.4c0-0.5,0.1-1,0.1-1.4h-5.8V34.7z M10,42.7c-0.7,0-1.4-0.3-2-0.8s-0.8-1.2-0.8-2V8.1c0-0.7,0.3-1.4,0.8-2
s1.2-0.8,2-0.8h16.8l10.2,10.2v7.2c-0.4-0.2-0.9-0.4-1.4-0.5c-0.5-0.2-0.9-0.3-1.4-0.4v-5.1h-8.8V8.1H10v31.7h12.1
c0.3,0.5,0.7,1,1.1,1.5c0.4,0.5,0.9,0.9,1.4,1.3H10z M32.2,24.5c2.5,0,4.6,0.9,6.4,2.6c1.8,1.8,2.6,3.9,2.6,6.4s-0.9,4.6-2.6,6.4
c-1.8,1.8-3.9,2.6-6.4,2.6s-4.6-0.9-6.4-2.6c-1.8-1.8-2.6-3.9-2.6-6.4s0.9-4.6,2.6-6.4C27.5,25.4,29.7,24.5,32.2,24.5z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 27.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="レイヤー_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" viewBox="0 0 48 48" style="enable-background:new 0 0 48 48;" xml:space="preserve">
<style type="text/css">
.st0{fill:#282828;}
</style>
<path class="st0" d="M19.1,32.5L32.5,24l-13.4-8.5V32.5z M24,44c-2.7,0-5.3-0.5-7.8-1.6c-2.4-1-4.6-2.5-6.4-4.3s-3.2-3.9-4.3-6.4
C4.5,29.3,4,26.7,4,24c0-2.8,0.5-5.4,1.6-7.8s2.5-4.6,4.3-6.4s3.9-3.2,6.4-4.3S21.3,4,24,4c2.8,0,5.4,0.5,7.8,1.6s4.6,2.5,6.4,4.3
s3.2,3.9,4.3,6.4c1.1,2.4,1.6,5,1.6,7.8c0,2.7-0.5,5.3-1.6,7.8c-1,2.4-2.5,4.6-4.3,6.4s-3.9,3.2-6.4,4.3C29.4,43.5,26.8,44,24,44z
M24,41c4.7,0,8.8-1.7,12-5c3.3-3.3,5-7.3,5-12c0-4.7-1.6-8.7-5-12c-3.3-3.3-7.3-5-12-5c-4.7,0-8.7,1.7-12,5s-5,7.3-5,12
c0,4.7,1.7,8.7,5,12S19.3,41,24,41z"/>
</svg>

After

Width:  |  Height:  |  Size: 963 B

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 27.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="レイヤー_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" viewBox="0 0 48 48" style="enable-background:new 0 0 48 48;" xml:space="preserve">
<style type="text/css">
.st0{fill:#A5A5A5;}
</style>
<path class="st0" d="M13.3,26.5c0.7,0,1.3-0.2,1.8-0.7s0.7-1.1,0.7-1.8c0-0.7-0.2-1.3-0.7-1.8s-1.1-0.7-1.8-0.7s-1.3,0.2-1.8,0.7
s-0.7,1.1-0.7,1.8c0,0.7,0.2,1.3,0.7,1.8S12.6,26.5,13.3,26.5z M24,26.5c0.7,0,1.3-0.2,1.8-0.7s0.7-1.1,0.7-1.8
c0-0.7-0.2-1.3-0.7-1.8s-1.1-0.7-1.8-0.7c-0.7,0-1.3,0.2-1.8,0.7s-0.7,1.1-0.7,1.8c0,0.7,0.2,1.3,0.7,1.8S23.3,26.5,24,26.5z
M34.7,26.5c0.7,0,1.3-0.2,1.8-0.7s0.7-1.1,0.7-1.8c0-0.7-0.2-1.3-0.7-1.8s-1.1-0.7-1.8-0.7s-1.3,0.2-1.8,0.7s-0.7,1.1-0.7,1.8
c0,0.7,0.2,1.3,0.7,1.8S34,26.5,34.7,26.5z M24,44c-2.8,0-5.3-0.5-7.8-1.6c-2.4-1-4.5-2.5-6.4-4.3s-3.2-3.9-4.3-6.4
c-1-2.4-1.5-5-1.5-7.7s0.5-5.4,1.6-7.8c1-2.4,2.5-4.5,4.3-6.3s3.9-3.2,6.4-4.3C18.7,4.5,21.3,4,24,4s5.4,0.5,7.8,1.6
c2.4,1,4.5,2.5,6.3,4.3s3.2,3.9,4.3,6.4c1.1,2.4,1.6,5,1.6,7.8s-0.5,5.3-1.6,7.8c-1,2.4-2.5,4.5-4.3,6.4c-1.8,1.8-3.9,3.2-6.4,4.3
C29.4,43.5,26.8,44,24,44z M24,41c4.7,0,8.7-1.7,12-5s5-7.3,5-12.1s-1.6-8.7-4.9-12C32.8,8.6,28.7,7,24,7s-8.7,1.6-12,4.9
S7,19.3,7,24s1.7,8.7,5,12S19.3,41,24,41z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -1,12 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 27.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!-- Generator: Adobe Illustrator 27.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="レイヤー_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" viewBox="0 0 40 40" style="enable-background:new 0 0 40 40;" xml:space="preserve">
y="0px" viewBox="0 0 48 48" style="enable-background:new 0 0 48 48;" xml:space="preserve">
<style type="text/css">
.st0{fill:#282828;}
</style>
<path class="st0" d="M30.3,23.3V18H25v-2.8h5.3V10H33v5.3h5.3V18H33v5.3H30.3z M15,20c-1.8,0-3.4-0.6-4.6-1.8
c-1.2-1.2-1.8-2.7-1.8-4.6s0.6-3.4,1.8-4.6c1.2-1.2,2.7-1.8,4.6-1.8s3.4,0.6,4.6,1.8c1.2,1.2,1.8,2.7,1.8,4.6s-0.6,3.4-1.8,4.6
C18.4,19.4,16.8,20,15,20z M1.7,33.3v-4.2c0-1,0.2-1.9,0.7-2.6c0.5-0.8,1.2-1.4,2.1-1.8c1.9-0.9,3.8-1.5,5.4-1.9
c1.7-0.4,3.4-0.6,5.1-0.6s3.4,0.2,5.1,0.6c1.7,0.4,3.5,1,5.5,1.9c0.9,0.4,1.5,1,2,1.8c0.5,0.8,0.8,1.7,0.8,2.6v4.2H1.7z"/>
<path class="st0" d="M36.5,28v-6.5H30v-3h6.5V12h3v6.5H46v3h-6.5V28H36.5z M18,23.9c-2.2,0-4-0.7-5.4-2.1s-2.1-3.2-2.1-5.4
s0.7-4,2.1-5.4s3.2-2.1,5.4-2.1s4,0.7,5.4,2.1c1.4,1.4,2.1,3.2,2.1,5.4s-0.7,4-2.1,5.4C22,23.2,20.2,23.9,18,23.9z M2,40v-4.7
c0-1.2,0.3-2.2,0.9-3.2c0.6-0.9,1.4-1.7,2.5-2.1c2.5-1.1,4.7-1.9,6.7-2.3C14,27.2,16,27,18,27c2,0,4,0.2,5.9,0.7
c1.9,0.4,4.2,1.2,6.7,2.3c1.1,0.5,1.9,1.2,2.6,2.2c0.6,0.9,0.9,2,0.9,3.1V40H2z M5,37h26v-1.7c0-0.5-0.1-1-0.4-1.5
c-0.3-0.5-0.7-0.8-1.2-1.1c-2.4-1.1-4.4-1.8-6-2.2C21.7,30.2,19.9,30,18,30s-3.7,0.2-5.4,0.5c-1.6,0.3-3.7,1.1-6,2.2
c-0.5,0.2-0.9,0.6-1.2,1.1S5,34.8,5,35.3V37z M18,20.9c1.3,0,2.4-0.4,3.2-1.3s1.3-1.9,1.3-3.2s-0.4-2.4-1.3-3.2
c-0.9-0.8-1.9-1.3-3.2-1.3c-1.3,0-2.4,0.4-3.2,1.3c-0.9,0.9-1.3,1.9-1.3,3.2s0.4,2.4,1.3,3.2C15.6,20.5,16.7,20.9,18,20.9z"/>
</svg>

Before

Width:  |  Height:  |  Size: 886 B

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 27.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="レイヤー_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" viewBox="0 0 48 48" style="enable-background:new 0 0 48 48;" xml:space="preserve">
<style type="text/css">
.st0{fill:#282828;}
</style>
<path class="st0" d="M17.5,37H41v-6.8H17.5V37z M7,17.8h7.5V11H7V17.8z M7,27.2h7.5v-6.4H7V27.2z M7,37h7.5v-6.8H7V37z M17.5,27.2
H41v-6.4H17.5V27.2z M17.5,17.8H41V11H17.5V17.8z M7,40c-0.8,0-1.5-0.3-2.1-0.9C4.3,38.5,4,37.8,4,37V11c0-0.8,0.3-1.5,0.9-2.1
S6.2,8,7,8h34c0.8,0,1.5,0.3,2.1,0.9C43.7,9.5,44,10.2,44,11v26c0,0.8-0.3,1.5-0.9,2.1C42.5,39.7,41.8,40,41,40H7z"/>
</svg>

After

Width:  |  Height:  |  Size: 790 B

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 27.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="レイヤー_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" viewBox="0 0 48 48" style="enable-background:new 0 0 48 48;" xml:space="preserve">
<style type="text/css">
.st0{fill:#0084B2;}
</style>
<path class="st0" d="M16.9,31.3H32c1.6,0,2.9-0.5,4-1.5s1.7-2.2,1.7-3.7s-0.6-2.7-1.7-3.7S33.5,21,32,21c-0.2-2.1-1-3.8-2.4-5.3
s-3.1-2.2-5.2-2.2c-1.7,0-3.3,0.5-4.7,1.4c-1.4,0.9-2.4,2.3-2.8,3.9c-1.8,0-3.3,0.6-4.6,1.8s-1.9,2.7-1.9,4.5s0.6,3.2,1.9,4.5
C13.5,30.7,15.1,31.3,16.9,31.3z M24,44c-2.7,0-5.3-0.5-7.8-1.6c-2.4-1-4.6-2.5-6.4-4.3s-3.2-3.9-4.3-6.4c-1-2.4-1.5-5-1.5-7.7
c0-2.8,0.5-5.4,1.6-7.8s2.5-4.6,4.3-6.4s3.9-3.2,6.4-4.3S21.3,4,24,4c2.8,0,5.4,0.5,7.8,1.6s4.6,2.5,6.4,4.3s3.2,3.9,4.3,6.4
c1.1,2.4,1.6,5,1.6,7.8c0,2.7-0.5,5.3-1.6,7.8c-1,2.4-2.5,4.6-4.3,6.4s-3.9,3.2-6.4,4.3C29.4,43.5,26.8,44,24,44z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1,97 @@
export const STATUS = {
UPLOADED: "Uploaded",
PENDING: "Pending",
INPROGRESS: "InProgress",
FINISHED: "Finished",
BACKUP: "Backup",
} as const;
export type StatusType = typeof STATUS[keyof typeof STATUS];
export const LIMIT_TASK_NUM = 20;
export const SORTABLE_COLUMN = {
JobNumber: "JOB_NUMBER",
Status: "STATUS",
Encryption: "ENCRYPTION",
AuthorId: "AUTHOR_ID",
WorkType: "WORK_TYPE",
FileName: "FILE_NAME",
FileLength: "FILE_LENGTH",
FileSize: "FILE_SIZE",
RecordingStartedDate: "RECORDING_STARTED_DATE",
RecordingFinishedDate: "RECORDING_FINISHED_DATE",
UploadDate: "UPLOAD_DATE",
TranscriptionStartedDate: "TRANSCRIPTION_STARTED_DATE",
TranscriptionFinishedDate: "TRANSCRIPTION_FINISHED_DATE",
} as const;
export type SortableColumnType =
typeof SORTABLE_COLUMN[keyof typeof SORTABLE_COLUMN];
export type SortableColumnList =
typeof SORTABLE_COLUMN[keyof typeof SORTABLE_COLUMN];
export const DIRECTION = {
ASC: "ASC",
DESC: "DESC",
} as const;
export type DirectionType = typeof DIRECTION[keyof typeof DIRECTION];
export interface DisplayInfoType {
JobNumber: boolean;
Status: boolean;
Priority: boolean;
Encryption: boolean;
AuthorId: boolean;
WorkType: boolean;
FileName: boolean;
FileLength: boolean;
FileSize: boolean;
RecordingStartedDate: boolean;
RecordingFinishedDate: boolean;
UploadDate: boolean;
TranscriptionStartedDate: boolean;
TranscriptionFinishedDate: boolean;
Transcriptionist: boolean;
Comment: boolean;
OptionItem1: boolean;
OptionItem2: boolean;
OptionItem3: boolean;
OptionItem4: boolean;
OptionItem5: boolean;
OptionItem6: boolean;
OptionItem7: boolean;
OptionItem8: boolean;
OptionItem9: boolean;
OptionItem10: boolean;
}
export const INIT_DISPLAY_INFO: DisplayInfoType = {
JobNumber: true,
Status: true,
Priority: false,
Encryption: true,
AuthorId: true,
WorkType: true,
FileName: true,
FileLength: true,
FileSize: false,
RecordingStartedDate: true,
RecordingFinishedDate: true,
UploadDate: false,
TranscriptionStartedDate: true,
TranscriptionFinishedDate: true,
Transcriptionist: true,
Comment: true,
OptionItem1: false,
OptionItem2: false,
OptionItem3: false,
OptionItem4: false,
OptionItem5: false,
OptionItem6: false,
OptionItem7: false,
OptionItem8: false,
OptionItem9: false,
OptionItem10: false,
} as const;

View File

@ -0,0 +1,71 @@
import { PayloadAction, createSlice } from "@reduxjs/toolkit";
import { DictationState } from "./state";
import { getSortColumnAsync, listTasksAsync } from "./operations";
import {
SORTABLE_COLUMN,
DIRECTION,
DisplayInfoType,
INIT_DISPLAY_INFO,
LIMIT_TASK_NUM,
DirectionType,
SortableColumnType,
} from "./constants";
const initialState: DictationState = {
domain: {
limit: LIMIT_TASK_NUM,
offset: 0,
total: 0,
tasks: [],
},
apps: {
displayInfo: INIT_DISPLAY_INFO,
direction: DIRECTION.ASC,
paramName: SORTABLE_COLUMN.JobNumber,
},
};
export const dictationSlice = createSlice({
name: "dictation",
initialState,
reducers: {
changeDisplayInfo: (
state,
action: PayloadAction<{ column: DisplayInfoType }>
) => {
const { column } = action.payload;
state.apps.displayInfo = column;
},
changeDirection: (
state,
action: PayloadAction<{ direction: DirectionType }>
) => {
const { direction } = action.payload;
state.apps.direction = direction;
},
changeParamName: (
state,
action: PayloadAction<{ paramName: SortableColumnType }>
) => {
const { paramName } = action.payload;
state.apps.paramName = paramName;
},
},
extraReducers: (builder) => {
builder.addCase(listTasksAsync.fulfilled, (state, action) => {
state.domain.limit = action.payload.limit;
state.domain.offset = action.payload.offset;
state.domain.total = action.payload.total;
state.domain.tasks = action.payload.tasks;
});
builder.addCase(getSortColumnAsync.fulfilled, (state, action) => {
state.apps.direction = action.payload.direction;
state.apps.paramName = action.payload.paramName;
});
},
});
export const { changeDisplayInfo, changeDirection, changeParamName } =
dictationSlice.actions;
export default dictationSlice.reducer;

View File

@ -0,0 +1,5 @@
export * from "./state";
export * from "./constants";
export * from "./selectors";
export * from "./dictationSlice";
export * from "./operations";

View File

@ -0,0 +1,164 @@
import { createAsyncThunk } from "@reduxjs/toolkit";
import type { RootState } from "app/store";
import { getTranslationID } from "translation";
import { openSnackbar } from "features/ui/uiSlice";
import { TasksResponse, TasksApi, UsersApi } from "../../api/api";
import { Configuration } from "../../api/configuration";
import { ErrorObject, createErrorObject } from "../../common/errors";
import {
DIRECTION,
DirectionType,
SORTABLE_COLUMN,
SortableColumnType,
} from "./constants";
export const listTasksAsync = createAsyncThunk<
TasksResponse,
{
// パラメータ
limit: number;
offset: number;
filter: string;
direction: DirectionType;
paramName: SortableColumnType;
},
{
// rejectした時の返却値の型
rejectValue: {
error: ErrorObject;
};
}
>("dictations/listTasksAsync", async (args, thunkApi) => {
const { limit, offset, filter, direction, paramName } = args;
// apiのConfigurationを取得する
const { getState } = thunkApi;
const state = getState() as RootState;
const { configuration, accessToken } = state.auth;
const config = new Configuration(configuration);
const tasksApi = new TasksApi(config);
try {
const res = await tasksApi.getTasks(
limit,
offset,
filter,
direction,
paramName,
{
headers: { authorization: `Bearer ${accessToken}` },
}
);
return res.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 getSortColumnAsync = createAsyncThunk<
{
direction: DirectionType;
paramName: SortableColumnType;
},
void,
{
// rejectした時の返却値の型
rejectValue: {
error: ErrorObject;
};
}
>("dictations/getSortColumnAsync", async (args, thunkApi) => {
// apiのConfigurationを取得する
const { getState } = thunkApi;
const state = getState() as RootState;
const { configuration, accessToken } = state.auth;
const config = new Configuration(configuration);
const usersApi = new UsersApi(config);
try {
const sort = await usersApi.getSortCcriteria({
headers: { authorization: `Bearer ${accessToken}` },
});
const { direction, paramName } = sort.data;
if (
Object.values<string>(DIRECTION).includes(direction) &&
Object.values<string>(SORTABLE_COLUMN).includes(paramName)
) {
return {
direction: direction as DirectionType,
paramName: paramName as SortableColumnType,
};
}
throw new Error(
`invalid param. direction=${direction}, paramName=${paramName}`
);
} catch (e) {
// e ⇒ errorObjectに変換"
const error = createErrorObject(e);
thunkApi.dispatch(
openSnackbar({
level: "error",
message: getTranslationID("common.message.internalServerError"),
})
);
return thunkApi.rejectWithValue({ error });
}
});
export const updateSortColumnAsync = createAsyncThunk<
{
/** empty */
},
{
// パラメータ
direction: DirectionType;
paramName: SortableColumnType;
},
{
// rejectした時の返却値の型
rejectValue: {
error: ErrorObject;
};
}
>("dictations/updateSortColumnAsync", async (args, thunkApi) => {
const { direction, paramName } = args;
// apiのConfigurationを取得する
const { getState } = thunkApi;
const state = getState() as RootState;
const { configuration, accessToken } = state.auth;
const config = new Configuration(configuration);
const usersApi = new UsersApi(config);
try {
await usersApi.updateSortCcriteria(
{ direction, paramName },
{
headers: { authorization: `Bearer ${accessToken}` },
}
);
return {};
} catch (e) {
// e ⇒ errorObjectに変換"
const error = createErrorObject(e);
thunkApi.dispatch(
openSnackbar({
level: "error",
message: getTranslationID("common.message.internalServerError"),
})
);
return thunkApi.rejectWithValue({ error });
}
});

View File

@ -0,0 +1,31 @@
import { RootState } from "app/store";
import { ceil, floor } from "lodash";
export const selectTasks = (state: RootState) => state.dictation.domain.tasks;
export const selectTotal = (state: RootState) => state.dictation.domain.total;
export const seletctLimit = (state: RootState) => state.dictation.domain.limit;
export const selectOffset = (state: RootState) => state.dictation.domain.offset;
export const selectTotalPage = (state: RootState) => {
const { limit, total } = state.dictation.domain;
const page = ceil(total / limit);
return page;
};
export const selectCurrentPage = (state: RootState) => {
const { limit, offset } = state.dictation.domain;
const page = floor(offset / limit) + 1;
return page;
};
export const selectDisplayInfo = (state: RootState) =>
state.dictation.apps.displayInfo;
export const selectDirection = (state: RootState) =>
state.dictation.apps.direction;
export const selectParamName = (state: RootState) =>
state.dictation.apps.paramName;

View File

@ -0,0 +1,24 @@
import { Task } from "../../api/api";
import {
DirectionType,
DisplayInfoType,
SortableColumnType,
} from "./constants";
export interface DictationState {
domain: Domain;
apps: Apps;
}
export interface Domain {
limit: number;
offset: number;
total: number;
tasks: Task[];
}
export interface Apps {
displayInfo: DisplayInfoType;
direction: DirectionType;
paramName: SortableColumnType;
}

View File

@ -0,0 +1,575 @@
import React, { 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 {
DisplayInfoType,
selectDisplayInfo,
changeDisplayInfo,
} from "features/dictation";
import { getTranslationID } from "translation";
import table from "../../assets/images/table.svg";
export const DisPlayInfo: React.FC = (): JSX.Element => {
const dispatch: AppDispatch = useDispatch();
const [t] = useTranslation();
const [openDisplayInfo, setOpenDisplayInfo] = useState(false);
// 各カラムの表示/非表示
const displayColumn = useSelector(selectDisplayInfo);
const updateDisplayInfo = (column: DisplayInfoType) => {
localStorage.setItem("displayInfo", JSON.stringify(column));
};
return (
<>
<ul className={`${styles.menuAction} ${styles.alignRight}`}>
<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={() => {
setOpenDisplayInfo(!openDisplayInfo);
}}
>
<img src={table} alt="" className={`${styles.menuIcon}`} />
{t(getTranslationID("dictationPage.label.displayInfomation"))}
</a>
</li>
</ul>
<ul
className={`${styles.displayOptions} ${styles.form} ${
openDisplayInfo ? styles.isShow : ""
}`}
>
<li>
<label htmlFor="jobNumber">
<input
id="jobNumber"
type="checkbox"
value="clm1"
className={styles.formCheck}
checked={displayColumn.JobNumber}
onChange={(e) => {
const column: DisplayInfoType = {
...displayColumn,
JobNumber: e.target.checked,
};
updateDisplayInfo(column);
dispatch(changeDisplayInfo({ column }));
dispatch(changeDisplayInfo({ column }));
}}
/>
{t(getTranslationID("dictationPage.label.jobNumber"))}
</label>
</li>
<li>
<label htmlFor="status">
<input
id="status"
type="checkbox"
value="clm2"
className={styles.formCheck}
checked={displayColumn.Status}
onChange={(e) => {
const column: DisplayInfoType = {
...displayColumn,
Status: e.target.checked,
};
updateDisplayInfo(column);
dispatch(changeDisplayInfo({ column }));
}}
/>
{t(getTranslationID("dictationPage.label.status"))}
</label>
</li>
<li>
<label htmlFor="priority">
<input
id="priority"
type="checkbox"
value="clm3"
className={styles.formCheck}
checked={displayColumn.Priority}
onChange={(e) => {
const column: DisplayInfoType = {
...displayColumn,
Priority: e.target.checked,
};
updateDisplayInfo(column);
dispatch(changeDisplayInfo({ column }));
}}
/>
{t(getTranslationID("dictationPage.label.priority"))}
</label>
</li>
<li>
<label htmlFor="encryption">
<input
id="encryption"
type="checkbox"
value="clm4"
className={styles.formCheck}
checked={displayColumn.Encryption}
onChange={(e) => {
const column: DisplayInfoType = {
...displayColumn,
Encryption: e.target.checked,
};
updateDisplayInfo(column);
dispatch(changeDisplayInfo({ column }));
}}
/>
{t(getTranslationID("dictationPage.label.encryption"))}
</label>
</li>
<li>
<label htmlFor="authorId">
<input
id="authorId"
type="checkbox"
value="clm5"
className={styles.formCheck}
checked={displayColumn.AuthorId}
onChange={(e) => {
const column: DisplayInfoType = {
...displayColumn,
AuthorId: e.target.checked,
};
updateDisplayInfo(column);
dispatch(changeDisplayInfo({ column }));
}}
/>
{t(getTranslationID("dictationPage.label.authorId"))}
</label>
</li>
<li>
<label htmlFor="workType">
<input
id="workType"
type="checkbox"
value="clm6"
className={styles.formCheck}
checked={displayColumn.WorkType}
onChange={(e) => {
const column: DisplayInfoType = {
...displayColumn,
WorkType: e.target.checked,
};
updateDisplayInfo(column);
dispatch(changeDisplayInfo({ column }));
}}
/>
{t(getTranslationID("dictationPage.label.workType"))}
</label>
</li>
<li>
<label htmlFor="fileName">
<input
id="fileName"
type="checkbox"
value="clm7"
className={styles.formCheck}
checked={displayColumn.FileName}
onChange={(e) => {
const column: DisplayInfoType = {
...displayColumn,
FileName: e.target.checked,
};
updateDisplayInfo(column);
dispatch(changeDisplayInfo({ column }));
}}
/>
{t(getTranslationID("dictationPage.label.fileName"))}
</label>
</li>
<li>
<label htmlFor="fileLength">
<input
id="fileLength"
type="checkbox"
value="clm8"
className={styles.formCheck}
checked={displayColumn.FileLength}
onChange={(e) => {
const column: DisplayInfoType = {
...displayColumn,
FileLength: e.target.checked,
};
updateDisplayInfo(column);
dispatch(changeDisplayInfo({ column }));
}}
/>
{t(getTranslationID("dictationPage.label.fileLength"))}
</label>
</li>
<li>
<label htmlFor="fileSize">
<input
id="fileSize"
type="checkbox"
value="clm9"
className={styles.formCheck}
checked={displayColumn.FileSize}
onChange={(e) => {
const column: DisplayInfoType = {
...displayColumn,
FileSize: e.target.checked,
};
updateDisplayInfo(column);
dispatch(changeDisplayInfo({ column }));
}}
/>
{t(getTranslationID("dictationPage.label.fileSize"))}
</label>
</li>
<li>
<label htmlFor="recordingStartedDate">
<input
id="recordingStartedDate"
type="checkbox"
value="clm10"
className={styles.formCheck}
checked={displayColumn.RecordingStartedDate}
onChange={(e) => {
const column: DisplayInfoType = {
...displayColumn,
RecordingStartedDate: e.target.checked,
};
updateDisplayInfo(column);
dispatch(changeDisplayInfo({ column }));
}}
/>
{t(getTranslationID("dictationPage.label.recordingStartedDate"))}
</label>
</li>
<li>
<label htmlFor="recordingFinishedDate">
<input
id="recordingFinishedDate"
type="checkbox"
value="clm11"
className={styles.formCheck}
checked={displayColumn.RecordingFinishedDate}
onChange={(e) => {
const column: DisplayInfoType = {
...displayColumn,
RecordingFinishedDate: e.target.checked,
};
updateDisplayInfo(column);
dispatch(changeDisplayInfo({ column }));
}}
/>
{t(getTranslationID("dictationPage.label.recordingFinishedDate"))}
</label>
</li>
<li>
<label htmlFor="uploadDate">
<input
id="uploadDate"
type="checkbox"
value="clm12"
className={styles.formCheck}
checked={displayColumn.UploadDate}
onChange={(e) => {
const column: DisplayInfoType = {
...displayColumn,
UploadDate: e.target.checked,
};
updateDisplayInfo(column);
dispatch(changeDisplayInfo({ column }));
}}
/>
{t(getTranslationID("dictationPage.label.uploadDate"))}
</label>
</li>
<li>
<label htmlFor="transcriptionStartDate">
<input
id="transcriptionStartDate"
type="checkbox"
value="clm13"
className={styles.formCheck}
checked={displayColumn.TranscriptionStartedDate}
onChange={(e) => {
const column: DisplayInfoType = {
...displayColumn,
TranscriptionStartedDate: e.target.checked,
};
updateDisplayInfo(column);
dispatch(changeDisplayInfo({ column }));
}}
/>
{t(
getTranslationID("dictationPage.label.transcriptionStartedDate")
)}
</label>
</li>
<li>
<label htmlFor="transcriptionFinishedDate">
<input
id="transcriptionFinishedDate"
type="checkbox"
value="clm14"
className={styles.formCheck}
checked={displayColumn.TranscriptionFinishedDate}
onChange={(e) => {
const column: DisplayInfoType = {
...displayColumn,
TranscriptionFinishedDate: e.target.checked,
};
updateDisplayInfo(column);
dispatch(changeDisplayInfo({ column }));
}}
/>
{t(
getTranslationID("dictationPage.label.transcriptionFinishedDate")
)}
</label>
</li>
<li>
<label htmlFor="transcriptionist">
<input
id="transcriptionist"
type="checkbox"
value="clm15"
className={styles.formCheck}
checked={displayColumn.Transcriptionist}
onChange={(e) => {
const column: DisplayInfoType = {
...displayColumn,
Transcriptionist: e.target.checked,
};
updateDisplayInfo(column);
dispatch(changeDisplayInfo({ column }));
}}
/>
{t(getTranslationID("dictationPage.label.transcriptionist"))}
</label>
</li>
<li>
<label htmlFor="comment">
<input
type="checkbox"
value="clm16"
className={styles.formCheck}
checked={displayColumn.Comment}
onChange={(e) => {
const column: DisplayInfoType = {
...displayColumn,
Comment: e.target.checked,
};
updateDisplayInfo(column);
dispatch(changeDisplayInfo({ column }));
}}
/>
{t(getTranslationID("dictationPage.label.comment"))}
</label>
</li>
<li>
<label htmlFor="optionItem1">
<input
id="optionItem1"
type="checkbox"
value="op1"
className={styles.formCheck}
checked={displayColumn.OptionItem1}
onChange={(e) => {
const column: DisplayInfoType = {
...displayColumn,
OptionItem1: e.target.checked,
};
updateDisplayInfo(column);
dispatch(changeDisplayInfo({ column }));
}}
/>
{t(getTranslationID("dictationPage.label.optionItem1"))}
</label>
</li>
<li>
<label htmlFor="optionItem2">
<input
id="optionItem2"
type="checkbox"
value="op2"
className={styles.formCheck}
checked={displayColumn.OptionItem2}
onChange={(e) => {
const column: DisplayInfoType = {
...displayColumn,
OptionItem2: e.target.checked,
};
updateDisplayInfo(column);
dispatch(changeDisplayInfo({ column }));
}}
/>
{t(getTranslationID("dictationPage.label.optionItem2"))}
</label>
</li>
<li>
<label htmlFor="optionItem3">
<input
id="optionItem3"
type="checkbox"
value="op3"
className={styles.formCheck}
checked={displayColumn.OptionItem3}
onChange={(e) => {
const column: DisplayInfoType = {
...displayColumn,
OptionItem3: e.target.checked,
};
updateDisplayInfo(column);
dispatch(changeDisplayInfo({ column }));
}}
/>
{t(getTranslationID("dictationPage.label.optionItem3"))}
</label>
</li>
<li>
<label htmlFor="optionItem4">
<input
id="optionItem4"
type="checkbox"
value="op4"
className={styles.formCheck}
checked={displayColumn.OptionItem4}
onChange={(e) => {
const column: DisplayInfoType = {
...displayColumn,
OptionItem4: e.target.checked,
};
updateDisplayInfo(column);
dispatch(changeDisplayInfo({ column }));
}}
/>
{t(getTranslationID("dictationPage.label.optionItem4"))}
</label>
</li>
<li>
<label htmlFor="optionItem5">
<input
id="optionItem5"
type="checkbox"
value="op5"
className={styles.formCheck}
checked={displayColumn.OptionItem5}
onChange={(e) => {
const column: DisplayInfoType = {
...displayColumn,
OptionItem5: e.target.checked,
};
updateDisplayInfo(column);
dispatch(changeDisplayInfo({ column }));
}}
/>
{t(getTranslationID("dictationPage.label.optionItem5"))}
</label>
</li>
<li>
<label htmlFor="optionItem6">
<input
id="optionItem6"
type="checkbox"
value="op6"
className={styles.formCheck}
checked={displayColumn.OptionItem6}
onChange={(e) => {
const column: DisplayInfoType = {
...displayColumn,
OptionItem6: e.target.checked,
};
updateDisplayInfo(column);
dispatch(changeDisplayInfo({ column }));
}}
/>
{t(getTranslationID("dictationPage.label.optionItem6"))}
</label>
</li>
<li>
<label htmlFor="optionItem7">
<input
id="optionItem7"
type="checkbox"
value="op7"
className={styles.formCheck}
checked={displayColumn.OptionItem7}
onChange={(e) => {
const column: DisplayInfoType = {
...displayColumn,
OptionItem7: e.target.checked,
};
updateDisplayInfo(column);
dispatch(changeDisplayInfo({ column }));
}}
/>
{t(getTranslationID("dictationPage.label.optionItem7"))}
</label>
</li>
<li>
<label htmlFor="optionItem8">
<input
id="optionItem8"
type="checkbox"
value="op8"
className={styles.formCheck}
checked={displayColumn.OptionItem8}
onChange={(e) => {
const column: DisplayInfoType = {
...displayColumn,
OptionItem8: e.target.checked,
};
updateDisplayInfo(column);
dispatch(changeDisplayInfo({ column }));
}}
/>
{t(getTranslationID("dictationPage.label.optionItem8"))}
</label>
</li>
<li>
<label htmlFor="optionItem9">
<input
id="optionItem9"
type="checkbox"
value="op9"
className={styles.formCheck}
checked={displayColumn.OptionItem9}
onChange={(e) => {
const column: DisplayInfoType = {
...displayColumn,
OptionItem9: e.target.checked,
};
updateDisplayInfo(column);
dispatch(changeDisplayInfo({ column }));
}}
/>
{t(getTranslationID("dictationPage.label.optionItem9"))}
</label>
</li>
<li>
<label htmlFor="optionItem10">
<input
id="optionItem10"
type="checkbox"
value="op10"
className={styles.formCheck}
checked={displayColumn.OptionItem10}
onChange={(e) => {
const column: DisplayInfoType = {
...displayColumn,
OptionItem10: e.target.checked,
};
updateDisplayInfo(column);
dispatch(changeDisplayInfo({ column }));
}}
/>
{t(getTranslationID("dictationPage.label.optionItem10"))}
</label>
</li>
</ul>
</>
);
};

View File

@ -0,0 +1,966 @@
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,
updateSortColumnAsync,
SortableColumnType,
} from "features/dictation";
import { getTranslationID } from "translation";
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 { DisPlayInfo } from "./displayInfo";
const DictationPage: React.FC = (): JSX.Element => {
const dispatch: AppDispatch = useDispatch();
const [t] = useTranslation();
// 各カラムの表示/非表示
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 sortableParamName = useSelector(selectParamName);
const sortDirection = useSelector(selectDirection);
const tasks = useSelector(selectTasks);
const total = useSelector(selectTotal);
const totalPage = useSelector(selectTotalPage);
const currentPage = useSelector(selectCurrentPage);
// ページネーションのボタンクリック時のアクション
const getFirstPage = useCallback(() => {
const filter = getFilter(
filterUploaded,
filterInProgress,
filterPending,
filterFinished,
filterBackup
);
dispatch(
listTasksAsync({
limit: LIMIT_TASK_NUM,
offset: 0,
filter,
direction: sortDirection,
paramName: sortableParamName,
})
);
}, [
dispatch,
filterUploaded,
filterInProgress,
filterPending,
filterFinished,
filterBackup,
sortDirection,
sortableParamName,
]);
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,
})
);
}, [
dispatch,
totalPage,
filterUploaded,
filterInProgress,
filterPending,
filterFinished,
filterBackup,
sortDirection,
sortableParamName,
]);
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,
})
);
}, [
dispatch,
currentPage,
filterUploaded,
filterInProgress,
filterPending,
filterFinished,
filterBackup,
sortDirection,
sortableParamName,
]);
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,
})
);
}, [
dispatch,
currentPage,
filterUploaded,
filterInProgress,
filterPending,
filterFinished,
filterBackup,
sortDirection,
sortableParamName,
]);
const updateSortColumn = useCallback(
(paramName: SortableColumnType) => {
const currentDirection =
sortableParamName === paramName && sortDirection === DIRECTION.ASC
? DIRECTION.DESC
: DIRECTION.ASC;
dispatch(changeDirection({ direction: currentDirection }));
dispatch(changeParamName({ paramName }));
const filter = getFilter(
filterUploaded,
filterInProgress,
filterPending,
filterFinished,
filterBackup
);
dispatch(
listTasksAsync({
limit: LIMIT_TASK_NUM,
offset: 0,
filter,
direction: currentDirection,
paramName,
})
);
},
[
dispatch,
sortableParamName,
sortDirection,
filterUploaded,
filterInProgress,
filterPending,
filterFinished,
filterBackup,
]
);
const getFilter = (
hasUploaded: boolean,
hasInProgress: boolean,
hasPending: boolean,
hasFinished: boolean,
hasBackup: boolean
) => {
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);
}
return filterStatus.join(",");
};
// ステータスフィルターの変更時アクション
const updateFilter = useCallback(
(
hasUploaded: boolean,
hasInProgress: boolean,
hasPending: boolean,
hasFinished: boolean,
hasBackup: boolean
) => {
const filter = getFilter(
hasUploaded,
hasInProgress,
hasPending,
hasFinished,
hasBackup
);
dispatch(
listTasksAsync({
limit: LIMIT_TASK_NUM,
offset: 0,
filter,
direction: sortDirection,
paramName: sortableParamName,
})
);
},
[dispatch, sortDirection, sortableParamName]
);
const onPlayBack = useCallback(() => {
dispatch(
updateSortColumnAsync({
direction: sortDirection,
paramName: sortableParamName,
})
);
}, [dispatch, sortDirection, sortableParamName]);
// 初回読み込み処理
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 filter = getFilter(true, true, true, true, false);
const { meta, payload } = await dispatch(getSortColumnAsync());
if (
meta.requestStatus === "fulfilled" &&
payload &&
!("error" in payload)
) {
const { direction, paramName } = payload;
dispatch(
listTasksAsync({
limit: LIMIT_TASK_NUM,
offset: 0,
filter,
direction,
paramName,
})
);
}
})();
}, [dispatch]);
return (
<div className={styles.wrap}>
<Header userName="XXXXXX" />
<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.tableFilter}>
<li>{t(getTranslationID("dictationPage.label.filter"))}:</li>
<li>
<label htmlFor="uploaded">
<input
id="uploaded"
type="checkbox"
value="flUploaded"
className={styles.formCheck}
checked={filterUploaded}
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}
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}
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}
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}
onChange={(e) => {
setFilterBackup(e.target.checked);
updateFilter(
filterUploaded,
filterInProgress,
filterPending,
filterFinished,
e.target.checked
);
}}
/>
{t(getTranslationID("dictationPage.label.backup"))}
</label>
</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}
onClick={() =>
updateSortColumn(SORTABLE_COLUMN.JobNumber)
}
>
{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}
onClick={() =>
updateSortColumn(SORTABLE_COLUMN.Status)
}
>
{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}
onClick={() =>
updateSortColumn(SORTABLE_COLUMN.Encryption)
}
>
{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}
onClick={() =>
updateSortColumn(SORTABLE_COLUMN.AuthorId)
}
>
{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}
onClick={() =>
updateSortColumn(SORTABLE_COLUMN.WorkType)
}
>
{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}
onClick={() =>
updateSortColumn(SORTABLE_COLUMN.FileName)
}
>
{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}
onClick={() =>
updateSortColumn(SORTABLE_COLUMN.FileLength)
}
>
{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}
onClick={() =>
updateSortColumn(SORTABLE_COLUMN.FileSize)
}
>
{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}
onClick={() =>
updateSortColumn(
SORTABLE_COLUMN.RecordingStartedDate
)
}
>
{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}
onClick={() =>
updateSortColumn(
SORTABLE_COLUMN.RecordingFinishedDate
)
}
>
{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}
onClick={() =>
updateSortColumn(SORTABLE_COLUMN.UploadDate)
}
>
{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}
onClick={() =>
updateSortColumn(
SORTABLE_COLUMN.TranscriptionStartedDate
)
}
>
{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}
onClick={() =>
updateSortColumn(
SORTABLE_COLUMN.TranscriptionFinishedDate
)
}
>
{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>
{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 onClick={onPlayBack}>
{t(
getTranslationID(
"dictationPage.label.playback"
)
)}
</a>
</li>
<li>
<a>
{t(
getTranslationID(
"dictationPage.label.fileProperty"
)
)}
</a>
</li>
<li>
<a>
{" "}
{t(
getTranslationID(
"dictationPage.label.changeTranscriptionist"
)
)}
</a>
</li>
<li>
<a>
{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}>
{x.priority === "01" ? "High" : "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>
{tasks.length === 0 && (
<p style={{ margin: "10px", textAlign: "center" }}>
{t(getTranslationID("common.message.listEmpty"))}
</p>
)}
</div>
{/** 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={`${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={`${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={`${
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={`${
currentPage !== totalPage ? styles.isActive : ""
}`}
onClick={getLastPage}
>
»
</a>
</nav>
</div>
</div>
</section>
</div>
</main>
<Footer />
</div>
);
};
export default DictationPage;

View File

@ -17,18 +17,18 @@
z-index: 4;
}
.headerLogo {
margin: 1.2rem 2rem 1rem;
margin: 1.2rem 2rem 1.5rem;
font-size: 1.71rem;
line-height: 2rem;
letter-spacing: 0.07rem;
font-weight: normal;
}
.headerLogo img {
width: 198px;
width: 280px;
}
.headerSub {
margin: 1.4rem 2rem 1rem;
font-size: 1.2rem;
font-size: 1.8rem;
line-height: 2rem;
letter-spacing: 0.07rem;
font-weight: normal;
@ -44,7 +44,7 @@
padding: 0 2rem;
}
.headerMenu ul li {
font-size: 1rem;
font-size: 1.3rem;
line-height: 2rem;
letter-spacing: 0.07rem;
font-weight: normal;
@ -52,7 +52,7 @@
}
.headerMenu ul li a {
display: block;
padding: 0 2rem;
padding: 0.2rem 2.5rem 0.2rem;
color: #333333;
text-decoration: none;
-moz-transition: all 0.3s ease-out;
@ -61,7 +61,7 @@
transition: all 0.3s ease-out;
}
.headerMenu ul li a:hover {
background: #fafafa;
background: #f5f5f5;
text-decoration: underline;
}
.headerMenu ul li a.isActive {
@ -71,9 +71,9 @@
}
.headerMenu ul li a.isActive::after {
content: "";
border-right: 0.6rem transparent solid;
border-bottom: 0.6rem #282828 solid;
border-left: 0.6rem transparent solid;
border-right: 0.7rem transparent solid;
border-bottom: 0.7rem #282828 solid;
border-left: 0.7rem transparent solid;
position: absolute;
bottom: -4px;
left: 50%;
@ -600,7 +600,7 @@ h3 .brCrumb .tlIcon {
}
.pageHeader {
padding: 0.5rem 2.5rem 0.4rem;
padding: 0.3rem 2.5rem 0.2rem;
background: #282828;
color: #ffffff;
margin-bottom: 2rem;
@ -608,8 +608,8 @@ h3 .brCrumb .tlIcon {
.pageTitle {
display: inline-block;
padding-right: 1rem;
font-size: 1.8rem;
line-height: 2.5rem;
font-size: 1.4rem;
line-height: 1.4rem;
letter-spacing: 0.07rem;
font-weight: 500;
}
@ -978,6 +978,9 @@ _:-ms-lang(x)::-ms-backdrop,
.menuAction.inTable .colorLink.isActive:hover {
background: rgba(0, 94, 184, 0.7);
}
.menuAction.alignRight {
margin-top: -1rem;
}
.menuMore {
text-align: center;
}
@ -1205,7 +1208,7 @@ _:-ms-lang(x)::-ms-backdrop,
border-left: 0.6rem transparent solid;
position: absolute;
top: -0.5rem;
left: 1rem;
right: 3rem;
}
.dictation .table {
margin-bottom: 0;
@ -1307,6 +1310,13 @@ _:-ms-lang(x)::-ms-backdrop,
.dictation .table.dictation tr.isSelected:hover {
color: #ffffff;
}
.dictation .table.dictation tr.isSelected img[alt="Uploaded"],
.dictation .table.dictation tr.isSelected img[alt="Finished"],
.dictation .table.dictation tr.isSelected img[alt="InProgress"],
.dictation .table.dictation tr.isSelected img[alt="encrypted"] {
filter: brightness(0) saturate(100%) invert(100%) sepia(100%) saturate(2%)
hue-rotate(110deg) brightness(110%) contrast(101%);
}
.dictation .table.dictation td {
padding-bottom: 2rem;
vertical-align: top;
@ -1467,9 +1477,11 @@ _:-ms-lang(x)::-ms-backdrop,
margin-right: 0.5rem;
padding-right: 0.5rem;
}
.menuInTable li:not(:last-child) {
border-right: 1px #999999 solid;
}
.menuInTable li a {
display: block;
padding-left: 1.2rem;
font-size: 12px;
line-height: 1.4;
letter-spacing: 0.02rem;
@ -1484,26 +1496,7 @@ _:-ms-lang(x)::-ms-backdrop,
color: #999999;
pointer-events: none;
}
.menuInTable li a.mnPlay {
background: url(../assets/images/mn_play.svg) no-repeat left center;
background-size: 1.2rem;
}
.menuInTable li a.mnFile {
background: url(../assets/images/mn_file.svg) no-repeat left center;
background-size: 1.2rem;
}
.menuInTable li a.mnChange {
background: url(../assets/images/mn_change.svg) no-repeat left center;
background-size: 1.2rem;
}
.menuInTable li a.mnDelete {
background: url(../assets/images/delete.svg) no-repeat left center;
background-size: 1.2rem;
}
tr.isSelected .menuInTable li a {
color: #333333;
}
tr.isSelected .menuInTable li a:hover {
color: #ffffff;
}

View File

@ -78,6 +78,7 @@ declare const classNames: {
readonly inTable: "inTable";
readonly menuLink: "menuLink";
readonly colorLink: "colorLink";
readonly alignRight: "alignRight";
readonly menuMore: "menuMore";
readonly menuIcon: "menuIcon";
readonly icCheckCircle: "icCheckCircle";
@ -155,17 +156,12 @@ declare const classNames: {
readonly op9: "op9";
readonly hideO10: "hideO10";
readonly op10: "op10";
readonly mnPlay: "mnPlay";
readonly mnFile: "mnFile";
readonly mnChange: "mnChange";
readonly mnDelete: "mnDelete";
readonly formChange: "formChange";
readonly chooseMember: "chooseMember";
readonly holdMember: "holdMember";
readonly changeTitle: "changeTitle";
readonly alignCenter: "alignCenter";
readonly alignLeft: "alignLeft";
readonly alignRight: "alignRight";
readonly linkTx: "linkTx";
readonly borderTop: "borderTop";
readonly borderBottom: "borderBottom";

View File

@ -4,7 +4,8 @@
"inputEmptyError": "(de)Error Message",
"passwordIncorrectError": "(de)Error Message",
"emailIncorrectError": "(de)Error Message",
"internalServerError": "(de)処理に失敗しました。時間をおいて再実行しても解決しない場合はシステム管理者にお問い合わせください。"
"internalServerError": "(de)処理に失敗しました。時間をおいて再実行しても解決しない場合はシステム管理者にお問い合わせください。",
"listEmpty": "(de)検索結果が0件です。"
},
"label": {
"cancel": "(de)Cancel",
@ -154,5 +155,47 @@
"orderButton": "(de)Order",
"licenseTypeText": "(de)One year"
}
},
"dictationPage": {
"label": {
"title": "(de)Dictations",
"displayInfomation": "(de)Display Information",
"jobNumber": "(de)Job Number",
"status": "(de)Status",
"priority": "(de)Priority",
"encryption": "(de)Encryption",
"authorId": "(de)Author ID",
"workType": "(de)WorkType",
"fileName": "(de)File Name",
"fileLength": "(de)File Length",
"fileSize": "(de)File size",
"recordingStartedDate": "(de)Recording started date",
"recordingFinishedDate": "(de)Recording finished date",
"uploadDate": "(de)Upload date",
"transcriptionStartedDate": "(de)Transcription start date",
"transcriptionFinishedDate": "(de)Transcription finished date",
"transcriptionist": "(de)Transcriptionist",
"comment": "(de)Comment",
"optionItem1": "(de)OptionItem1",
"optionItem2": "(de)OptionItem2",
"optionItem3": "(de)OptionItem3",
"optionItem4": "(de)OptionItem4",
"optionItem5": "(de)OptionItem5",
"optionItem6": "(de)OptionItem6",
"optionItem7": "(de)OptionItem7",
"optionItem8": "(de)OptionItem8",
"optionItem9": "(de)OptionItem9",
"optionItem10": "(de)OptionItem10",
"filter": "(de)Filter",
"uploaded": "(de)Uploaded",
"inProgress": "(de)InProgress",
"finished": "(de)Finished",
"pending": "(de)Pending",
"backup": "(de)Backup",
"playback": "(de)Playback",
"fileProperty": "(de)File Property",
"changeTranscriptionist": "(de)Change Transcriptionist",
"deleteDictation": "(de)Delete Dictation"
}
}
}

View File

@ -4,7 +4,8 @@
"inputEmptyError": "Error Message",
"passwordIncorrectError": "Error Message",
"emailIncorrectError": "Error Message",
"internalServerError": "処理に失敗しました。時間をおいて再実行しても解決しない場合はシステム管理者にお問い合わせください。"
"internalServerError": "処理に失敗しました。時間をおいて再実行しても解決しない場合はシステム管理者にお問い合わせください。",
"listEmpty": "検索結果が0件です。"
},
"label": {
"cancel": "Cancel",
@ -154,5 +155,47 @@
"orderButton": "Order",
"licenseTypeText": "One year"
}
},
"dictationPage": {
"label": {
"title": "Dictations",
"displayInfomation": "Display Information",
"jobNumber": "Job Number",
"status": "Status",
"priority": "Priority",
"encryption": "Encryption",
"authorId": "Author ID",
"workType": "WorkType",
"fileName": "File Name",
"fileLength": "File Length",
"fileSize": "File size",
"recordingStartedDate": "Recording started date",
"recordingFinishedDate": "Recording finished date",
"uploadDate": "Upload date",
"transcriptionStartedDate": "Transcription start date",
"transcriptionFinishedDate": "Transcription finished date",
"transcriptionist": "Transcriptionist",
"comment": "Comment",
"optionItem1": "OptionItem1",
"optionItem2": "OptionItem2",
"optionItem3": "OptionItem3",
"optionItem4": "OptionItem4",
"optionItem5": "OptionItem5",
"optionItem6": "OptionItem6",
"optionItem7": "OptionItem7",
"optionItem8": "OptionItem8",
"optionItem9": "OptionItem9",
"optionItem10": "OptionItem10",
"filter": "Filter",
"uploaded": "Uploaded",
"inProgress": "InProgress",
"finished": "Finished",
"pending": "Pending",
"backup": "Backup",
"playback": "Playback",
"fileProperty": "File Property",
"changeTranscriptionist": "Change Transcriptionist",
"deleteDictation": "Delete Dictation"
}
}
}

View File

@ -4,7 +4,8 @@
"inputEmptyError": "(es)Error Message",
"passwordIncorrectError": "(es)Error Message",
"emailIncorrectError": "(es)Error Message",
"internalServerError": "(es)処理に失敗しました。時間をおいて再実行しても解決しない場合はシステム管理者にお問い合わせください。"
"internalServerError": "(es)処理に失敗しました。時間をおいて再実行しても解決しない場合はシステム管理者にお問い合わせください。",
"listEmpty": "(es)検索結果が0件です。"
},
"label": {
"cancel": "(es)Cancel",
@ -154,5 +155,47 @@
"orderButton": "(es)Order",
"licenseTypeText": "(es)One year"
}
},
"dictationPage": {
"label": {
"title": "(es)Dictations",
"displayInfomation": "(es)Display Information",
"jobNumber": "(es)Job Number",
"status": "(es)Status",
"priority": "(es)Priority",
"encryption": "(es)Encryption",
"authorId": "(es)Author ID",
"workType": "(es)WorkType",
"fileName": "(es)File Name",
"fileLength": "(es)File Length",
"fileSize": "(es)File size",
"recordingStartedDate": "(es)Recording started date",
"recordingFinishedDate": "(es)Recording finished date",
"uploadDate": "(es)Upload date",
"transcriptionStartedDate": "(es)Transcription start date",
"transcriptionFinishedDate": "(es)Transcription finished date",
"transcriptionist": "(es)Transcriptionist",
"comment": "(es)Comment",
"optionItem1": "(es)OptionItem1",
"optionItem2": "(es)OptionItem2",
"optionItem3": "(es)OptionItem3",
"optionItem4": "(es)OptionItem4",
"optionItem5": "(es)OptionItem5",
"optionItem6": "(es)OptionItem6",
"optionItem7": "(es)OptionItem7",
"optionItem8": "(es)OptionItem8",
"optionItem9": "(es)OptionItem9",
"optionItem10": "(es)OptionItem10",
"filter": "(es)Filter",
"uploaded": "(es)Uploaded",
"inProgress": "(es)InProgress",
"finished": "(es)Finished",
"pending": "(es)Pending",
"backup": "(es)Backup",
"playback": "(es)Playback",
"fileProperty": "(es)File Property",
"changeTranscriptionist": "(es)Change Transcriptionist",
"deleteDictation": "(es)Delete Dictation"
}
}
}

View File

@ -4,7 +4,8 @@
"inputEmptyError": "(fr)Error Message",
"passwordIncorrectError": "(fr)Error Message",
"emailIncorrectError": "(fr)Error Message",
"internalServerError": "(fr)処理に失敗しました。時間をおいて再実行しても解決しない場合はシステム管理者にお問い合わせください。"
"internalServerError": "(fr)処理に失敗しました。時間をおいて再実行しても解決しない場合はシステム管理者にお問い合わせください。",
"listEmpty": "(fr)検索結果が0件です。"
},
"label": {
"cancel": "(fr)Cancel",
@ -154,5 +155,47 @@
"orderButton": "(fr)Order",
"licenseTypeText": "(fr)One year"
}
},
"dictationPage": {
"label": {
"title": "(fr)Dictations",
"displayInfomation": "(fr)Display Information",
"jobNumber": "(fr)Job Number",
"status": "(fr)Status",
"priority": "(fr)Priority",
"encryption": "(fr)Encryption",
"authorId": "(fr)Author ID",
"workType": "(fr)WorkType",
"fileName": "(fr)File Name",
"fileLength": "(fr)File Length",
"fileSize": "(fr)File size",
"recordingStartedDate": "(fr)Recording started date",
"recordingFinishedDate": "(fr)Recording finished date",
"uploadDate": "(fr)Upload date",
"transcriptionStartedDate": "(fr)Transcription start date",
"transcriptionFinishedDate": "(fr)Transcription finished date",
"transcriptionist": "(fr)Transcriptionist",
"comment": "(fr)Comment",
"optionItem1": "(fr)OptionItem1",
"optionItem2": "(fr)OptionItem2",
"optionItem3": "(fr)OptionItem3",
"optionItem4": "(fr)OptionItem4",
"optionItem5": "(fr)OptionItem5",
"optionItem6": "(fr)OptionItem6",
"optionItem7": "(fr)OptionItem7",
"optionItem8": "(fr)OptionItem8",
"optionItem9": "(fr)OptionItem9",
"optionItem10": "(fr)OptionItem10",
"filter": "(fr)Filter",
"uploaded": "(fr)Uploaded",
"inProgress": "(fr)InProgress",
"finished": "(fr)Finished",
"pending": "(fr)Pending",
"backup": "(fr)Backup",
"playback": "(fr)Playback",
"fileProperty": "(fr)File Property",
"changeTranscriptionist": "(fr)Change Transcriptionist",
"deleteDictation": "(fr)Delete Dictation"
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -139,6 +139,7 @@ export const TASK_LIST_SORTABLE_ATTRIBUTES = [
'STATUS',
'ENCRYPTION',
'AUTHOR_ID',
'WORK_TYPE',
'FILE_NAME',
'FILE_LENGTH',
'FILE_SIZE',