2024-05-02 12:14:47 +00:00
|
|
|
import {
|
|
|
|
ArrowLeftOutlined,
|
|
|
|
ArrowRightOutlined,
|
|
|
|
CheckCircleOutlined,
|
|
|
|
ClockCircleFilled,
|
2024-05-03 02:52:15 +00:00
|
|
|
CopyOutlined,
|
2024-05-02 12:14:47 +00:00
|
|
|
FullscreenExitOutlined,
|
|
|
|
FullscreenOutlined,
|
|
|
|
} from '@ant-design/icons';
|
|
|
|
import { t } from '@lingui/macro';
|
|
|
|
import { Viewer } from '@react-pdf-viewer/core';
|
2024-05-31 09:55:02 +00:00
|
|
|
import '@react-pdf-viewer/core/lib/styles/index.css';
|
|
|
|
import { defaultLayoutPlugin } from '@react-pdf-viewer/default-layout';
|
|
|
|
import '@react-pdf-viewer/default-layout/lib/styles/index.css';
|
2024-05-02 12:14:47 +00:00
|
|
|
import {
|
|
|
|
Button,
|
|
|
|
DatePicker,
|
|
|
|
Form,
|
|
|
|
Input,
|
|
|
|
InputNumber,
|
|
|
|
message,
|
|
|
|
Modal,
|
|
|
|
notification,
|
|
|
|
Select,
|
|
|
|
Spin,
|
|
|
|
Tag,
|
|
|
|
} from 'antd';
|
2024-06-03 06:59:26 +00:00
|
|
|
import { isEmpty } from 'lodash-es';
|
2024-07-04 09:17:32 +00:00
|
|
|
import { useEffect, useMemo, useState } from 'react';
|
2024-05-02 12:14:47 +00:00
|
|
|
import Lightbox from 'react-awesome-lightbox';
|
|
|
|
import 'react-awesome-lightbox/build/style.css';
|
|
|
|
import { useHotkeys } from 'react-hotkeys-hook';
|
2024-06-03 06:59:26 +00:00
|
|
|
import { useSearchParams } from 'react-router-dom';
|
2024-05-24 05:59:34 +00:00
|
|
|
import { getErrorMessage } from 'utils/error-handler';
|
|
|
|
import {
|
2024-06-03 06:59:26 +00:00
|
|
|
addRecentRequest,
|
2024-06-28 04:29:05 +00:00
|
|
|
confirmRequest,
|
2024-05-24 05:59:34 +00:00
|
|
|
fetchAllRequests,
|
|
|
|
fetchRequest,
|
|
|
|
updateRevisedDataByFile,
|
|
|
|
} from './api';
|
2024-05-03 02:52:15 +00:00
|
|
|
import {
|
|
|
|
counter_measure_map,
|
2024-12-03 09:18:20 +00:00
|
|
|
DOCTYPE,
|
2024-05-23 11:48:21 +00:00
|
|
|
FEEDBACK_ACCURACY,
|
|
|
|
FEEDBACK_RESULT,
|
|
|
|
PREDICTED_RESULT,
|
2024-05-03 02:52:15 +00:00
|
|
|
REASON_BAD_QUALITY,
|
2024-05-23 11:48:21 +00:00
|
|
|
REVIEWED_RESULT,
|
2024-05-03 02:52:15 +00:00
|
|
|
SOLUTION_BAD_QUALITY,
|
2024-05-23 11:48:21 +00:00
|
|
|
SOURCE_KEYS,
|
|
|
|
SOURCE_OBJECT_NAMES,
|
2024-05-03 02:52:15 +00:00
|
|
|
SUBSIDIARIES,
|
|
|
|
} from './const';
|
2024-05-02 12:14:47 +00:00
|
|
|
import FileCard from './FileCard';
|
2024-06-03 06:59:26 +00:00
|
|
|
import RecentRequest from './RecentRequest';
|
2024-06-06 04:05:05 +00:00
|
|
|
import './style.css';
|
|
|
|
|
2024-05-02 12:14:47 +00:00
|
|
|
const ReviewPage = () => {
|
|
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
const [fullscreen, setFullscreen] = useState(false);
|
|
|
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
|
|
const [selectedFileId, setSelectedFileId] = useState(0);
|
|
|
|
const [selectedFileData, setSelectedFileData] = useState(null);
|
2024-05-23 11:48:21 +00:00
|
|
|
const [selectedFileDataSource, setSelectedFileDataSource] = useState({});
|
2024-05-02 12:14:47 +00:00
|
|
|
const [selectedFileName, setSelectedFileName] = useState(null);
|
2024-06-20 06:27:41 +00:00
|
|
|
const [isOpenConfirmRequest, setIsOpenConfirmRequest] = useState(false);
|
2024-05-02 12:14:47 +00:00
|
|
|
// Default date range: 1 month ago to today
|
|
|
|
const [filterDateRange, setFilterDateRange] = useState(['', '']);
|
|
|
|
|
|
|
|
const [filterSubsidiaries, setFilterSubsidiaries] = useState('SEAO');
|
|
|
|
const [filterAccuracy, setFilterAccuracy] = useState(100);
|
|
|
|
const [filterReviewState, setFilterReviewState] = useState('all');
|
|
|
|
const [filterIncludeTests, setFilterIncludesTests] = useState('true');
|
2024-12-03 09:18:20 +00:00
|
|
|
const [filterDoctype, setFilterDoctype] = useState(null);
|
|
|
|
const [filterFeedbackResult, setFilterFeedbackResult] = useState('');
|
|
|
|
const [filterPredictResult, setFilterPredictResult] = useState('');
|
|
|
|
const [filterReviewedResult, setFilterReviewedResult] = useState('');
|
2024-05-02 12:14:47 +00:00
|
|
|
// const [requests, setRequests] = useState([]);
|
|
|
|
const [currentRequest, setCurrentRequest] = useState(null);
|
|
|
|
const [currentRequestIndex, setCurrentRequestIndex] = useState(1);
|
|
|
|
const [hasNextRequest, setHasNextRequest] = useState(true);
|
|
|
|
const [totalRequests, setTotalPages] = useState(0);
|
|
|
|
|
|
|
|
const [pageIndexToGoto, setPageIndexToGoto] = useState(1);
|
|
|
|
|
|
|
|
const [reason, setReason] = useState('');
|
|
|
|
const [otherReason, setOtherReason] = useState('');
|
|
|
|
const [solution, setSolution] = useState('');
|
|
|
|
const [otherSolution, setOtherSolution] = useState('');
|
2024-05-09 09:12:14 +00:00
|
|
|
const [imageLoading, setImageLoading] = useState(false);
|
2024-05-31 09:55:02 +00:00
|
|
|
const defaultLayoutPluginInstance = defaultLayoutPlugin();
|
2024-06-03 06:59:26 +00:00
|
|
|
let [searchParams, setSearchParams] = useSearchParams();
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
const request_id = searchParams.get('request_id');
|
|
|
|
if (request_id) {
|
|
|
|
setLoading(true);
|
|
|
|
setTotalPages(1);
|
|
|
|
setHasNextRequest(false);
|
|
|
|
const requestData = fetchRequest(request_id);
|
|
|
|
requestData
|
|
|
|
.then(async (data) => {
|
|
|
|
if (data) setCurrentRequest(data);
|
|
|
|
setAndLoadSelectedFile(data, 0);
|
|
|
|
})
|
|
|
|
.finally(() => {
|
|
|
|
setLoading(false);
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
setCurrentRequestIndex(1);
|
|
|
|
fetchAllRequests(
|
|
|
|
filterDateRange,
|
|
|
|
filterSubsidiaries,
|
|
|
|
filterReviewState,
|
|
|
|
filterIncludeTests,
|
2024-12-03 09:18:20 +00:00
|
|
|
filterDoctype,
|
|
|
|
filterFeedbackResult,
|
|
|
|
filterPredictResult,
|
|
|
|
filterReviewedResult,
|
2024-06-03 06:59:26 +00:00
|
|
|
1,
|
|
|
|
1,
|
|
|
|
filterAccuracy,
|
|
|
|
).then((data) => {
|
|
|
|
setTotalPages(data?.page?.total_requests);
|
|
|
|
setHasNextRequest(1 < data?.page?.total_requests);
|
|
|
|
const firstRequest = fetchRequest(
|
|
|
|
data?.subscription_requests[0].RequestID,
|
|
|
|
);
|
|
|
|
firstRequest.then(async (data) => {
|
|
|
|
if (data) setCurrentRequest(data);
|
|
|
|
setAndLoadSelectedFile(data, 0);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}, []);
|
|
|
|
|
2024-06-06 06:56:05 +00:00
|
|
|
// useEffect(() => {
|
|
|
|
// if (reason) {
|
|
|
|
// setSolution(counter_measure_map[reason]);
|
|
|
|
// }
|
|
|
|
// }, [reason]);
|
2024-05-02 12:14:47 +00:00
|
|
|
|
2024-05-23 11:48:21 +00:00
|
|
|
const updateSelectedFileDataSource = (fileContent) => {
|
|
|
|
let tempData = {};
|
|
|
|
SOURCE_KEYS.forEach((k) => {
|
|
|
|
tempData[k] = {};
|
|
|
|
SOURCE_OBJECT_NAMES.forEach((name) => {
|
|
|
|
tempData[k][name] = fileContent[name][k];
|
|
|
|
});
|
2024-06-06 04:05:05 +00:00
|
|
|
if (!isEmpty(tempData[k][PREDICTED_RESULT])) {
|
|
|
|
let isEmptyResult = false;
|
|
|
|
if (isEmpty(tempData[k][REVIEWED_RESULT])) {
|
|
|
|
isEmptyResult = true;
|
|
|
|
}
|
2024-06-19 08:33:33 +00:00
|
|
|
if (
|
|
|
|
Array.isArray(tempData[k][REVIEWED_RESULT]) &&
|
|
|
|
tempData[k][REVIEWED_RESULT].length > 0
|
|
|
|
) {
|
2024-06-06 04:05:05 +00:00
|
|
|
isEmptyResult = tempData[k][REVIEWED_RESULT].every((r: any) =>
|
|
|
|
isEmpty(r),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if (isEmptyResult) {
|
|
|
|
tempData[k][REVIEWED_RESULT] = tempData[k][PREDICTED_RESULT];
|
|
|
|
}
|
2024-06-03 06:59:26 +00:00
|
|
|
}
|
2024-05-23 11:48:21 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
setSelectedFileDataSource(tempData);
|
|
|
|
};
|
|
|
|
|
2024-05-02 12:14:47 +00:00
|
|
|
const setAndLoadSelectedFile = async (requestData, index) => {
|
|
|
|
setSelectedFileId(index);
|
|
|
|
if (!requestData['Files'][index]) {
|
|
|
|
setSelectedFileData('FAILED_TO_LOAD_FILE');
|
2024-05-09 09:12:14 +00:00
|
|
|
setImageLoading(false);
|
2024-05-02 12:14:47 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
const fileName = requestData['Files'][index]['File Name'];
|
|
|
|
const fileURL = requestData['Files'][index]['File URL'];
|
2024-05-24 05:59:34 +00:00
|
|
|
let fileDataSource = requestData['Files'][index];
|
|
|
|
updateSelectedFileDataSource(fileDataSource);
|
|
|
|
let reason = fileDataSource.Reason;
|
|
|
|
let solution = fileDataSource['Counter Measures'];
|
|
|
|
|
|
|
|
if (!reason) {
|
|
|
|
setReason(null);
|
2024-06-06 06:56:05 +00:00
|
|
|
setOtherReason(null);
|
2024-05-24 05:59:34 +00:00
|
|
|
} else if (REASON_BAD_QUALITY.some((r) => r.value === reason)) {
|
|
|
|
setReason(reason);
|
2024-06-06 06:56:05 +00:00
|
|
|
setOtherReason(null);
|
2024-05-24 05:59:34 +00:00
|
|
|
} else {
|
|
|
|
setReason('other');
|
|
|
|
setOtherReason(reason);
|
|
|
|
}
|
|
|
|
if (!solution) {
|
|
|
|
setSolution(null);
|
2024-06-06 06:56:05 +00:00
|
|
|
setOtherSolution(null);
|
2024-05-24 05:59:34 +00:00
|
|
|
} else if (SOLUTION_BAD_QUALITY.some((r) => r.value === solution)) {
|
|
|
|
setSolution(solution);
|
2024-06-06 06:56:05 +00:00
|
|
|
setOtherSolution(null);
|
2024-05-24 05:59:34 +00:00
|
|
|
} else {
|
|
|
|
setSolution('other');
|
|
|
|
setOtherSolution(solution);
|
|
|
|
}
|
2024-05-23 11:48:21 +00:00
|
|
|
|
2024-05-24 05:59:34 +00:00
|
|
|
setSelectedFileName(fileName);
|
2024-06-19 08:33:33 +00:00
|
|
|
try {
|
|
|
|
const response = await fetch(fileURL);
|
|
|
|
if (response.status === 200) {
|
|
|
|
setSelectedFileData(fileURL);
|
|
|
|
} else {
|
|
|
|
setSelectedFileData('FAILED_TO_LOAD_FILE');
|
|
|
|
}
|
|
|
|
} catch (error) {
|
2024-05-02 12:14:47 +00:00
|
|
|
setSelectedFileData('FAILED_TO_LOAD_FILE');
|
|
|
|
}
|
2024-06-19 08:33:33 +00:00
|
|
|
setImageLoading(false);
|
2024-05-02 12:14:47 +00:00
|
|
|
};
|
|
|
|
const loadCurrentRequest = (requestIndex) => {
|
2024-06-28 04:29:05 +00:00
|
|
|
setCurrentRequestIndex(requestIndex);
|
2024-05-02 12:14:47 +00:00
|
|
|
setLoading(true);
|
2024-05-09 09:12:14 +00:00
|
|
|
setImageLoading(true);
|
2024-05-02 12:14:47 +00:00
|
|
|
fetchAllRequests(
|
|
|
|
filterDateRange,
|
|
|
|
filterSubsidiaries,
|
|
|
|
filterReviewState,
|
|
|
|
filterIncludeTests,
|
2024-12-03 09:18:20 +00:00
|
|
|
filterDoctype,
|
|
|
|
filterFeedbackResult,
|
|
|
|
filterPredictResult,
|
|
|
|
filterReviewedResult,
|
2024-05-02 12:14:47 +00:00
|
|
|
requestIndex,
|
|
|
|
1,
|
|
|
|
filterAccuracy,
|
|
|
|
)
|
|
|
|
.then((data) => {
|
|
|
|
setTotalPages(data?.page?.total_requests);
|
|
|
|
setHasNextRequest(requestIndex < data?.page?.total_requests);
|
2024-07-04 09:17:32 +00:00
|
|
|
|
2024-06-28 04:29:05 +00:00
|
|
|
fetchRequest(data?.subscription_requests[0].RequestID)
|
2024-05-02 12:14:47 +00:00
|
|
|
.then(async (data) => {
|
|
|
|
if (data) setCurrentRequest(data);
|
|
|
|
setAndLoadSelectedFile(data, 0);
|
|
|
|
})
|
2024-06-28 04:29:05 +00:00
|
|
|
.catch((error) => {
|
|
|
|
notification.error({ message: getErrorMessage(error) });
|
|
|
|
})
|
2024-05-02 12:14:47 +00:00
|
|
|
.finally(() => {
|
|
|
|
setLoading(false);
|
|
|
|
});
|
|
|
|
})
|
2024-06-28 04:29:05 +00:00
|
|
|
.catch((error) => {
|
|
|
|
notification.error({ message: getErrorMessage(error) });
|
|
|
|
})
|
2024-05-02 12:14:47 +00:00
|
|
|
.finally(() => {
|
|
|
|
setLoading(false);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
const gotoNextRequest = () => {
|
|
|
|
if (currentRequestIndex >= totalRequests) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const nextRequestIndex = currentRequestIndex + 1;
|
|
|
|
loadCurrentRequest(nextRequestIndex);
|
|
|
|
};
|
|
|
|
|
|
|
|
const gotoPreviousRequest = () => {
|
|
|
|
if (currentRequestIndex === 1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const previousRequestIndex = currentRequestIndex - 1;
|
|
|
|
loadCurrentRequest(previousRequestIndex);
|
|
|
|
};
|
|
|
|
|
|
|
|
const reloadFilters = () => {
|
|
|
|
setCurrentRequestIndex(1);
|
2024-06-03 06:59:26 +00:00
|
|
|
if (searchParams.has('request_id')) {
|
|
|
|
searchParams.delete('request_id');
|
|
|
|
setSearchParams(searchParams);
|
|
|
|
}
|
2024-05-02 12:14:47 +00:00
|
|
|
fetchAllRequests(
|
|
|
|
filterDateRange,
|
|
|
|
filterSubsidiaries,
|
|
|
|
filterReviewState,
|
|
|
|
filterIncludeTests,
|
2024-12-03 09:18:20 +00:00
|
|
|
filterDoctype,
|
|
|
|
filterFeedbackResult,
|
|
|
|
filterPredictResult,
|
|
|
|
filterReviewedResult,
|
2024-05-02 12:14:47 +00:00
|
|
|
1,
|
|
|
|
1,
|
|
|
|
filterAccuracy,
|
|
|
|
).then((data) => {
|
|
|
|
setTotalPages(data?.page?.total_requests);
|
|
|
|
setHasNextRequest(1 < data?.page?.total_requests);
|
|
|
|
const firstRequest = fetchRequest(
|
|
|
|
data?.subscription_requests[0].RequestID,
|
|
|
|
);
|
|
|
|
firstRequest.then(async (data) => {
|
|
|
|
if (data) setCurrentRequest(data);
|
|
|
|
setAndLoadSelectedFile(data, 0);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2024-06-28 04:29:05 +00:00
|
|
|
const handleConfirmRequest = async () => {
|
2024-06-20 06:27:41 +00:00
|
|
|
try {
|
2024-06-28 04:29:05 +00:00
|
|
|
const res = await confirmRequest(currentRequest?.RequestID);
|
|
|
|
if (res.status == 200) {
|
|
|
|
addRecentRequest(currentRequest?.RequestID, res, true);
|
|
|
|
notification.success({ message: 'Update file success' });
|
|
|
|
setCurrentRequest({
|
|
|
|
...currentRequest,
|
|
|
|
['Is Reviewed']: true,
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
throw new Error(await res.text());
|
|
|
|
}
|
2024-06-20 06:27:41 +00:00
|
|
|
} catch (error) {
|
2024-06-28 04:29:05 +00:00
|
|
|
addRecentRequest(currentRequest?.RequestID, error, false);
|
2024-06-20 06:27:41 +00:00
|
|
|
notification.error({
|
|
|
|
message: getErrorMessage(error),
|
|
|
|
});
|
2024-05-24 05:59:34 +00:00
|
|
|
}
|
2024-05-02 12:14:47 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const submitRevisedData = async () => {
|
2024-05-24 05:59:34 +00:00
|
|
|
const fileId = selectedFileName.split('.')[0];
|
|
|
|
|
|
|
|
let request_file_result = {};
|
|
|
|
SOURCE_KEYS.forEach((k) => {
|
|
|
|
request_file_result[k] = selectedFileDataSource[k][REVIEWED_RESULT];
|
2024-06-19 08:33:33 +00:00
|
|
|
if (Array.isArray(selectedFileDataSource[k][REVIEWED_RESULT])) {
|
|
|
|
request_file_result[k] =
|
|
|
|
selectedFileDataSource[k][REVIEWED_RESULT].toString();
|
|
|
|
} else {
|
2024-06-06 06:56:05 +00:00
|
|
|
request_file_result[k] = selectedFileDataSource[k][REVIEWED_RESULT];
|
|
|
|
}
|
2024-05-24 05:59:34 +00:00
|
|
|
});
|
|
|
|
let data = {
|
|
|
|
request_file_result,
|
2024-06-06 06:56:05 +00:00
|
|
|
reason: reason !== 'other' ? reason : otherReason,
|
|
|
|
solution: solution !== 'other' ? solution : otherSolution,
|
2024-05-24 05:59:34 +00:00
|
|
|
};
|
|
|
|
try {
|
2024-06-28 04:29:05 +00:00
|
|
|
let res = await updateRevisedDataByFile(
|
|
|
|
currentRequest?.RequestID,
|
|
|
|
fileId,
|
|
|
|
data,
|
|
|
|
);
|
|
|
|
if (res.status != 200) {
|
|
|
|
throw new Error('Could not update revised data');
|
|
|
|
}
|
2024-05-24 05:59:34 +00:00
|
|
|
let newData = currentRequest;
|
|
|
|
newData.Files[selectedFileId]['Is Reviewed'] = true;
|
2024-05-02 12:14:47 +00:00
|
|
|
setCurrentRequest({
|
2024-05-24 05:59:34 +00:00
|
|
|
...newData,
|
2024-05-02 12:14:47 +00:00
|
|
|
});
|
2024-05-24 05:59:34 +00:00
|
|
|
notification.success({ message: 'Update file success' });
|
|
|
|
|
2024-05-31 09:55:02 +00:00
|
|
|
const requestData = await fetchRequest(currentRequest?.RequestID);
|
|
|
|
setCurrentRequest(requestData);
|
2024-05-24 05:59:34 +00:00
|
|
|
} catch (error) {
|
|
|
|
notification.error({
|
|
|
|
message: getErrorMessage(error),
|
|
|
|
});
|
|
|
|
}
|
2024-05-02 12:14:47 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// use left/right keys to navigate
|
|
|
|
useHotkeys('left', gotoPreviousRequest);
|
|
|
|
useHotkeys('right', gotoNextRequest);
|
2024-06-06 04:05:05 +00:00
|
|
|
useHotkeys('u', submitRevisedData);
|
2024-06-28 04:29:05 +00:00
|
|
|
useHotkeys('c', handleConfirmRequest);
|
2024-05-02 12:14:47 +00:00
|
|
|
|
|
|
|
const fileExtension = selectedFileName
|
|
|
|
? selectedFileName.split('.').pop()
|
|
|
|
: '';
|
|
|
|
|
|
|
|
const [lightBox, setLightBox] = useState(false);
|
|
|
|
|
2024-06-06 06:56:05 +00:00
|
|
|
const updateRevisedByFeedback = (fieldName) => {
|
2024-05-23 11:48:21 +00:00
|
|
|
setSelectedFileDataSource((prevData) => {
|
|
|
|
prevData[fieldName][REVIEWED_RESULT] =
|
2024-06-19 08:33:33 +00:00
|
|
|
prevData[fieldName][FEEDBACK_RESULT];
|
2024-05-23 11:48:21 +00:00
|
|
|
return {
|
|
|
|
...prevData,
|
|
|
|
};
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2024-05-24 05:59:34 +00:00
|
|
|
const handleUpdateFileInField = (fieldName, fieldValue) => {
|
|
|
|
setSelectedFileDataSource((prevData) => {
|
|
|
|
prevData[fieldName][REVIEWED_RESULT] = fieldValue;
|
|
|
|
return {
|
|
|
|
...prevData,
|
|
|
|
};
|
|
|
|
});
|
|
|
|
};
|
2024-05-23 11:48:21 +00:00
|
|
|
|
2024-07-04 09:17:32 +00:00
|
|
|
const isSafeToConfirm = useMemo(() => {
|
|
|
|
let isSafe = true;
|
|
|
|
isSafe = !currentRequest?.Files.some((file) => {
|
|
|
|
const isRequired = file['Is Required'];
|
|
|
|
const isReviewed = file['Is Reviewed'];
|
|
|
|
return isRequired && !isReviewed;
|
|
|
|
});
|
|
|
|
return isSafe;
|
|
|
|
}, [currentRequest]);
|
|
|
|
|
2024-05-02 12:14:47 +00:00
|
|
|
return (
|
|
|
|
<div
|
|
|
|
style={
|
|
|
|
fullscreen
|
|
|
|
? {
|
|
|
|
position: 'fixed',
|
|
|
|
top: 0,
|
|
|
|
left: 0,
|
|
|
|
width: '100%',
|
|
|
|
height: '100%',
|
|
|
|
backgroundColor: '#fff',
|
|
|
|
zIndex: 1000,
|
|
|
|
}
|
|
|
|
: {
|
|
|
|
height: '100%',
|
|
|
|
position: 'relative',
|
|
|
|
}
|
|
|
|
}
|
|
|
|
>
|
|
|
|
<div
|
|
|
|
style={{
|
|
|
|
height: '100%',
|
|
|
|
position: 'absolute',
|
|
|
|
top: 0,
|
|
|
|
left: 0,
|
|
|
|
width: '100%',
|
|
|
|
background: '#00000033',
|
|
|
|
zIndex: 1000,
|
|
|
|
display: loading ? 'block' : 'none',
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<Spin
|
|
|
|
spinning={true}
|
|
|
|
style={{
|
|
|
|
position: 'absolute',
|
|
|
|
top: '50%',
|
|
|
|
left: '50%',
|
|
|
|
marginTop: -12,
|
|
|
|
marginLeft: -12,
|
|
|
|
width: 24,
|
|
|
|
height: 24,
|
|
|
|
borderRadius: '50%',
|
|
|
|
}}
|
|
|
|
size='large'
|
|
|
|
/>
|
|
|
|
</div>
|
2024-05-24 05:59:34 +00:00
|
|
|
|
2024-05-02 12:14:47 +00:00
|
|
|
<div
|
|
|
|
style={{
|
|
|
|
overflow: 'auto',
|
|
|
|
width: '100%',
|
2024-05-24 05:59:34 +00:00
|
|
|
height: fullscreen ? 'calc(100% - 32px)' : '100%',
|
2024-05-02 12:14:47 +00:00
|
|
|
maxWidth: '100%',
|
|
|
|
display: 'flex',
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<div
|
|
|
|
style={{
|
|
|
|
height: '100%',
|
2024-05-23 11:48:21 +00:00
|
|
|
flexGrow: 1,
|
2024-05-02 12:14:47 +00:00
|
|
|
display: 'flex',
|
2024-05-23 11:48:21 +00:00
|
|
|
flexDirection: 'column',
|
|
|
|
position: 'relative',
|
2024-05-02 12:14:47 +00:00
|
|
|
}}
|
|
|
|
>
|
2024-05-24 05:59:34 +00:00
|
|
|
<div
|
|
|
|
style={{
|
|
|
|
display: 'flex',
|
|
|
|
justifyContent: 'space-between',
|
|
|
|
alignItems: 'center',
|
|
|
|
margin: '0 0 4px 0',
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<Button
|
|
|
|
onClick={() => {
|
|
|
|
setFullscreen(!fullscreen);
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
{fullscreen ? <FullscreenExitOutlined /> : <FullscreenOutlined />}
|
|
|
|
</Button>
|
|
|
|
{totalRequests && (
|
|
|
|
<div
|
|
|
|
style={{
|
|
|
|
flexGrow: 1,
|
|
|
|
display: 'grid',
|
|
|
|
gridTemplateColumns: '1fr 1fr 1fr',
|
|
|
|
marginLeft: '16px',
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<div style={{ gridColumn: 'span 2 / span 2' }}>
|
|
|
|
<b>Request ID: </b>
|
|
|
|
{currentRequest?.RequestID}
|
|
|
|
</div>{' '}
|
|
|
|
<div>
|
|
|
|
<b>Created at: </b>
|
|
|
|
{currentRequest?.created_at}
|
|
|
|
</div>{' '}
|
|
|
|
<div>
|
|
|
|
<b>Request time: </b>
|
|
|
|
{currentRequest?.['Client Request Time (ms)']}
|
|
|
|
</div>{' '}
|
|
|
|
<div style={{ gridColumn: 'span 2 / span 2' }}>
|
|
|
|
<b>Redemption ID: </b>
|
|
|
|
{currentRequest?.RedemptionID}
|
|
|
|
</div>{' '}
|
|
|
|
<div>
|
|
|
|
<b>Raw accuracy: </b>
|
|
|
|
{currentRequest?.raw_accuracy}
|
|
|
|
</div>{' '}
|
|
|
|
<div style={{ gridColumn: 'span 2 / span 2' }}>
|
|
|
|
<b>Processing time: </b>
|
|
|
|
{currentRequest?.['Server Processing Time (ms)']}
|
|
|
|
</div>{' '}
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
</div>
|
2024-05-02 12:14:47 +00:00
|
|
|
{totalRequests > 0 && (
|
|
|
|
<div
|
|
|
|
style={{
|
|
|
|
display: 'flex',
|
2024-05-23 11:48:21 +00:00
|
|
|
flexDirection: 'row',
|
|
|
|
alignItems: 'center',
|
2024-05-02 12:14:47 +00:00
|
|
|
flexGrow: 0,
|
2024-05-24 05:59:34 +00:00
|
|
|
margin: '8px 0 0 0',
|
2024-05-02 12:14:47 +00:00
|
|
|
}}
|
|
|
|
>
|
2024-05-23 11:48:21 +00:00
|
|
|
<p
|
2024-05-02 12:14:47 +00:00
|
|
|
style={{
|
2024-05-23 11:48:21 +00:00
|
|
|
color: '#333',
|
|
|
|
fontWeight: 'bold',
|
|
|
|
margin: '0 16px 0 0',
|
2024-05-02 12:14:47 +00:00
|
|
|
}}
|
|
|
|
>
|
2024-05-23 11:48:21 +00:00
|
|
|
Files ({currentRequest?.Files?.length})
|
|
|
|
</p>
|
|
|
|
{currentRequest?.Files.map((file, index) => (
|
|
|
|
<FileCard
|
|
|
|
key={index}
|
|
|
|
file={file}
|
|
|
|
isSelected={index === selectedFileId}
|
|
|
|
onClick={() => {
|
|
|
|
setAndLoadSelectedFile(currentRequest, index);
|
|
|
|
setImageLoading(true);
|
2024-05-02 12:14:47 +00:00
|
|
|
}}
|
2024-05-23 11:48:21 +00:00
|
|
|
/>
|
|
|
|
))}
|
2024-05-02 12:14:47 +00:00
|
|
|
</div>
|
|
|
|
)}
|
2024-05-31 09:55:02 +00:00
|
|
|
{selectedFileData === 'FAILED_TO_LOAD_FILE' ? (
|
2024-06-19 08:33:33 +00:00
|
|
|
<div
|
|
|
|
style={{
|
|
|
|
flexGrow: 1,
|
|
|
|
overflow: 'auto',
|
|
|
|
display: 'flex',
|
|
|
|
justifyContent: 'center',
|
|
|
|
alignItems: 'center',
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<p style={{ color: '#333' }}>Failed to load file.</p>
|
|
|
|
</div>
|
2024-05-31 09:55:02 +00:00
|
|
|
) : fileExtension === 'pdf' ? (
|
|
|
|
<div
|
|
|
|
style={{
|
|
|
|
flexGrow: 1,
|
|
|
|
overflow: 'auto',
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<Viewer
|
|
|
|
plugins={[defaultLayoutPluginInstance]}
|
|
|
|
fileUrl={selectedFileData}
|
|
|
|
onDocumentLoad={() => setImageLoading(false)}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
) : (
|
|
|
|
<div
|
|
|
|
style={{
|
|
|
|
flexGrow: 1,
|
|
|
|
overflow: 'auto',
|
|
|
|
display: 'flex',
|
|
|
|
justifyContent: 'center',
|
|
|
|
alignItems: 'center',
|
|
|
|
overflowX: 'visible',
|
|
|
|
}}
|
|
|
|
>
|
2024-06-06 04:05:05 +00:00
|
|
|
<Spin spinning={imageLoading} wrapperClassName='image-spin'>
|
2024-06-03 06:59:26 +00:00
|
|
|
<img
|
|
|
|
style={{
|
2024-06-06 04:05:05 +00:00
|
|
|
height: '100%',
|
|
|
|
width: '100%',
|
|
|
|
objectFit: 'contain',
|
2024-06-03 06:59:26 +00:00
|
|
|
cursor: 'zoom-in',
|
|
|
|
}}
|
|
|
|
src={selectedFileData}
|
|
|
|
alt='file'
|
|
|
|
onClick={() => setLightBox(true)}
|
|
|
|
onLoad={() => {
|
|
|
|
setImageLoading(false);
|
|
|
|
}}
|
|
|
|
/>
|
2024-05-02 12:14:47 +00:00
|
|
|
|
2024-06-03 06:59:26 +00:00
|
|
|
{lightBox && (
|
|
|
|
<Lightbox
|
|
|
|
image={selectedFileData}
|
|
|
|
onClose={() => setLightBox(false)}
|
|
|
|
></Lightbox>
|
|
|
|
)}
|
|
|
|
</Spin>
|
2024-05-31 09:55:02 +00:00
|
|
|
</div>
|
|
|
|
)}
|
2024-05-02 12:14:47 +00:00
|
|
|
|
2024-05-03 02:52:15 +00:00
|
|
|
<div
|
|
|
|
style={{
|
|
|
|
flexGrow: 0,
|
|
|
|
display: 'flex',
|
|
|
|
justifyContent: 'space-between',
|
2024-05-09 09:12:14 +00:00
|
|
|
margin: '8px 0 0',
|
2024-05-03 02:52:15 +00:00
|
|
|
alignItems: 'center',
|
|
|
|
}}
|
|
|
|
>
|
2024-05-02 12:14:47 +00:00
|
|
|
<div
|
|
|
|
style={{
|
|
|
|
display: 'flex',
|
|
|
|
justifyContent: 'center',
|
|
|
|
alignItems: 'center',
|
|
|
|
}}
|
|
|
|
>
|
2024-06-03 06:59:26 +00:00
|
|
|
<RecentRequest />
|
2024-05-03 02:52:15 +00:00
|
|
|
<h3 style={{ margin: '0 8px ' }}>
|
2024-05-02 12:14:47 +00:00
|
|
|
{totalRequests
|
2024-05-03 02:52:15 +00:00
|
|
|
? 'No: ' + currentRequestIndex + '/' + totalRequests
|
2024-05-02 12:14:47 +00:00
|
|
|
: 'No Request. Adjust your search criteria to see more results.'}
|
2024-05-03 02:52:15 +00:00
|
|
|
</h3>
|
2024-05-02 12:14:47 +00:00
|
|
|
{currentRequest &&
|
|
|
|
(currentRequest['Is Reviewed'] ? (
|
|
|
|
<Tag
|
|
|
|
icon={<CheckCircleOutlined />}
|
|
|
|
color='success'
|
|
|
|
style={{ padding: '4px 16px' }}
|
|
|
|
>
|
|
|
|
Reviewed
|
|
|
|
</Tag>
|
|
|
|
) : (
|
|
|
|
<Tag
|
|
|
|
icon={<ClockCircleFilled />}
|
|
|
|
color='warning'
|
|
|
|
style={{ padding: '4px 16px' }}
|
|
|
|
>
|
|
|
|
Not Reviewed
|
|
|
|
</Tag>
|
|
|
|
))}
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
style={{
|
|
|
|
display: 'flex',
|
|
|
|
justifyContent: 'center',
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<div>
|
|
|
|
<Button
|
|
|
|
type='default'
|
|
|
|
style={{ height: 38 }}
|
|
|
|
disabled={currentRequestIndex === 1}
|
|
|
|
onClick={() => {
|
|
|
|
gotoPreviousRequest();
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<ArrowLeftOutlined />
|
2024-05-03 02:52:15 +00:00
|
|
|
Prev
|
2024-05-02 12:14:47 +00:00
|
|
|
</Button>
|
|
|
|
<Button
|
|
|
|
type='default'
|
|
|
|
style={{ height: 38 }}
|
|
|
|
disabled={!hasNextRequest}
|
|
|
|
onClick={() => {
|
|
|
|
if (!hasNextRequest) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
gotoNextRequest();
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
Next
|
|
|
|
<ArrowRightOutlined />
|
|
|
|
</Button>
|
|
|
|
<Input
|
|
|
|
size='middle'
|
|
|
|
addonBefore='To'
|
|
|
|
style={{ marginBottom: '4px', marginLeft: '4px', width: 180 }}
|
|
|
|
defaultValue={currentRequestIndex}
|
|
|
|
addonAfter={
|
|
|
|
<Button
|
|
|
|
type='default'
|
|
|
|
onClick={() => {
|
|
|
|
if (pageIndexToGoto > totalRequests) {
|
|
|
|
message.error('RequestID is out of range.');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (pageIndexToGoto < 1) {
|
|
|
|
message.error('RequestID is out of range.');
|
|
|
|
return;
|
|
|
|
}
|
2024-06-28 04:29:05 +00:00
|
|
|
|
2024-05-02 12:14:47 +00:00
|
|
|
loadCurrentRequest(pageIndexToGoto);
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
Go to
|
|
|
|
</Button>
|
|
|
|
}
|
|
|
|
value={pageIndexToGoto}
|
|
|
|
onChange={(e) => {
|
|
|
|
setPageIndexToGoto(parseInt(e.target.value));
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</div>
|
2024-05-23 11:48:21 +00:00
|
|
|
<Button
|
|
|
|
type='primary'
|
2024-05-24 05:59:34 +00:00
|
|
|
shape='default'
|
2024-05-23 11:48:21 +00:00
|
|
|
size='middle'
|
2024-05-31 09:55:02 +00:00
|
|
|
disabled={currentRequest && currentRequest['Is Reviewed']}
|
2024-06-03 06:59:26 +00:00
|
|
|
style={{ minWidth: '120px' }}
|
2024-06-20 06:27:41 +00:00
|
|
|
onClick={() => setIsOpenConfirmRequest(true)}
|
2024-05-23 11:48:21 +00:00
|
|
|
>
|
2024-06-19 08:33:33 +00:00
|
|
|
Confirm request
|
2024-05-23 11:48:21 +00:00
|
|
|
</Button>
|
2024-05-02 12:14:47 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
2024-05-09 09:12:14 +00:00
|
|
|
<div
|
|
|
|
style={{
|
|
|
|
flexBasis: 400,
|
|
|
|
flexShrink: 0,
|
|
|
|
display: 'flex',
|
|
|
|
flexDirection: 'column',
|
2024-05-24 05:59:34 +00:00
|
|
|
paddingLeft: '8px',
|
2024-05-09 09:12:14 +00:00
|
|
|
}}
|
|
|
|
>
|
2024-05-23 11:48:21 +00:00
|
|
|
<div
|
|
|
|
style={{
|
|
|
|
display: 'flex',
|
|
|
|
alignItems: 'center',
|
2024-05-24 05:59:34 +00:00
|
|
|
justifyContent: 'center',
|
|
|
|
marginBottom: '8px',
|
2024-05-23 11:48:21 +00:00
|
|
|
}}
|
|
|
|
>
|
|
|
|
<Input
|
|
|
|
size='middle'
|
|
|
|
value={`Sub: ${filterSubsidiaries}, Date:${
|
|
|
|
filterDateRange[0]
|
|
|
|
? filterDateRange[0] + ' to ' + filterDateRange[1]
|
|
|
|
: 'All'
|
|
|
|
}, Reviewed: ${filterReviewState}, Tests: ${filterIncludeTests}`}
|
|
|
|
readOnly
|
|
|
|
/>
|
|
|
|
<Button
|
|
|
|
type='primary'
|
|
|
|
size='middle'
|
2024-05-24 05:59:34 +00:00
|
|
|
style={{
|
|
|
|
height: '36px',
|
|
|
|
}}
|
2024-05-23 11:48:21 +00:00
|
|
|
onClick={() => {
|
|
|
|
setIsModalOpen(true);
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
Filters
|
|
|
|
</Button>
|
|
|
|
</div>
|
2024-05-24 05:59:34 +00:00
|
|
|
<div style={{ flexGrow: 1, overflowY: 'auto', overflowX: 'hidden' }}>
|
2024-05-23 11:48:21 +00:00
|
|
|
{SOURCE_KEYS?.map((data) => {
|
|
|
|
let shouldRevised = false;
|
|
|
|
try {
|
|
|
|
if (
|
|
|
|
selectedFileDataSource[data]?.[FEEDBACK_ACCURACY].length > 0
|
|
|
|
) {
|
|
|
|
shouldRevised =
|
|
|
|
selectedFileDataSource[data][FEEDBACK_ACCURACY][0] < 1;
|
|
|
|
}
|
|
|
|
} catch (error) {}
|
2024-05-02 12:14:47 +00:00
|
|
|
return (
|
2024-06-06 04:05:05 +00:00
|
|
|
<div style={{ margin: '0 0 8px' }} className='file-input-group'>
|
2024-05-09 09:12:14 +00:00
|
|
|
<div
|
|
|
|
style={{
|
|
|
|
display: 'flex',
|
|
|
|
justifyContent: 'space-between',
|
|
|
|
alignItems: 'center',
|
|
|
|
margin: '0 0 4px',
|
|
|
|
}}
|
|
|
|
>
|
2024-05-23 11:48:21 +00:00
|
|
|
<p style={{ fontWeight: 'bold', margin: 0 }}>{data}</p>
|
2024-05-03 02:52:15 +00:00
|
|
|
<Button
|
|
|
|
shape='round'
|
2024-05-09 09:12:14 +00:00
|
|
|
type='primary'
|
|
|
|
ghost
|
2024-05-03 02:52:15 +00:00
|
|
|
icon={<CopyOutlined />}
|
|
|
|
size='small'
|
2024-06-06 06:56:05 +00:00
|
|
|
onClick={() => updateRevisedByFeedback(data)}
|
2024-05-03 02:52:15 +00:00
|
|
|
/>
|
|
|
|
</div>
|
2024-05-02 12:14:47 +00:00
|
|
|
<Input
|
|
|
|
addonBefore='Feedback'
|
|
|
|
size='small'
|
|
|
|
readOnly
|
2024-05-23 11:48:21 +00:00
|
|
|
value={selectedFileDataSource[data]?.[FEEDBACK_RESULT]}
|
2024-05-02 12:14:47 +00:00
|
|
|
/>
|
|
|
|
<Input
|
|
|
|
addonBefore='Predicted'
|
|
|
|
readOnly
|
|
|
|
size='small'
|
2024-05-23 11:48:21 +00:00
|
|
|
value={selectedFileDataSource[data]?.[PREDICTED_RESULT]}
|
2024-05-02 12:14:47 +00:00
|
|
|
/>
|
|
|
|
<Input
|
2024-05-24 05:59:34 +00:00
|
|
|
addonBefore='Revised'
|
2024-05-23 11:48:21 +00:00
|
|
|
style={{ background: shouldRevised ? 'yellow' : '' }}
|
2024-05-02 12:14:47 +00:00
|
|
|
size='small'
|
2024-05-23 11:48:21 +00:00
|
|
|
value={selectedFileDataSource[data]?.[REVIEWED_RESULT]}
|
2024-05-31 09:55:02 +00:00
|
|
|
onChange={(e) =>
|
|
|
|
handleUpdateFileInField(data, e.target.value)
|
|
|
|
}
|
2024-05-02 12:14:47 +00:00
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
})}
|
2024-05-23 11:48:21 +00:00
|
|
|
<b>{t`Bad image reason:`}</b>
|
|
|
|
<div
|
|
|
|
style={{
|
|
|
|
display: 'flex',
|
|
|
|
margin: '8px 0px',
|
|
|
|
justifyContent: 'space-between',
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<Select
|
|
|
|
placeholder='Select a reason'
|
2024-05-24 05:59:34 +00:00
|
|
|
style={{ width: 170, flexBasis: '50%', height: '32px' }}
|
2024-05-23 11:48:21 +00:00
|
|
|
options={REASON_BAD_QUALITY}
|
2024-06-06 06:56:05 +00:00
|
|
|
onChange={(value) => {
|
|
|
|
let newReason = value;
|
|
|
|
setReason(newReason);
|
|
|
|
setSolution(counter_measure_map[newReason]);
|
|
|
|
}}
|
2024-05-23 11:48:21 +00:00
|
|
|
value={reason}
|
|
|
|
/>
|
|
|
|
{reason === 'other' && (
|
|
|
|
<Input
|
|
|
|
placeholder='Other reason'
|
|
|
|
value={otherReason}
|
2024-05-24 05:59:34 +00:00
|
|
|
style={{ width: 170, flexBasis: '50%', height: '32px' }}
|
2024-05-23 11:48:21 +00:00
|
|
|
onChange={(e) => {
|
|
|
|
setOtherReason(e.target.value);
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
<b>{t`Solution:`}</b>
|
|
|
|
<div
|
|
|
|
style={{
|
|
|
|
display: 'flex',
|
|
|
|
margin: '8px 0px',
|
|
|
|
justifyContent: 'space-between',
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<Select
|
|
|
|
placeholder='Select a solution'
|
2024-05-24 05:59:34 +00:00
|
|
|
style={{ width: 170, flexBasis: '50%', height: '32px' }}
|
2024-05-23 11:48:21 +00:00
|
|
|
options={SOLUTION_BAD_QUALITY}
|
|
|
|
onChange={setSolution}
|
|
|
|
value={solution}
|
|
|
|
// defaultValue={solution}
|
|
|
|
/>
|
|
|
|
{solution === 'other' && (
|
|
|
|
<Input
|
2024-05-24 05:59:34 +00:00
|
|
|
style={{ width: 170, flexBasis: '50%', height: '32px' }}
|
2024-05-23 11:48:21 +00:00
|
|
|
placeholder='Other solution'
|
|
|
|
value={otherSolution}
|
|
|
|
onChange={(e) => {
|
|
|
|
setOtherSolution(e.target.value);
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
</div>
|
2024-05-02 12:14:47 +00:00
|
|
|
</div>
|
2024-05-24 05:59:34 +00:00
|
|
|
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
|
|
|
|
<Button
|
|
|
|
type='primary'
|
|
|
|
color='success'
|
|
|
|
size='middle'
|
|
|
|
style={{
|
|
|
|
height: '36px',
|
|
|
|
}}
|
|
|
|
onClick={submitRevisedData}
|
|
|
|
>
|
2024-06-06 06:56:05 +00:00
|
|
|
Update File
|
2024-05-24 05:59:34 +00:00
|
|
|
</Button>
|
|
|
|
</div>
|
2024-05-02 12:14:47 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<Modal
|
|
|
|
title={t`Report Filters`}
|
|
|
|
open={isModalOpen}
|
|
|
|
width={700}
|
|
|
|
onOk={() => {
|
|
|
|
setIsModalOpen(false);
|
|
|
|
reloadFilters();
|
|
|
|
}}
|
|
|
|
onCancel={() => {
|
|
|
|
setIsModalOpen(false);
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<Form
|
|
|
|
style={{
|
|
|
|
marginTop: 30,
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<Form.Item
|
|
|
|
name='dateRange'
|
|
|
|
label={t`Date (GMT+8)`}
|
|
|
|
rules={[
|
|
|
|
{
|
|
|
|
required: true,
|
|
|
|
message: 'Please select a date range',
|
|
|
|
},
|
|
|
|
]}
|
|
|
|
style={{
|
|
|
|
marginBottom: 24,
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<DatePicker.RangePicker
|
|
|
|
onChange={(date, dateString) => {
|
|
|
|
setFilterDateRange(dateString);
|
|
|
|
}}
|
|
|
|
style={{ width: 200 }}
|
|
|
|
/>
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
<div
|
|
|
|
style={{
|
|
|
|
marginTop: 10,
|
|
|
|
display: 'flex',
|
|
|
|
justifyContent: 'space-between',
|
|
|
|
marginLeft: 0,
|
|
|
|
padding: 0,
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<Form.Item
|
|
|
|
name='subsidiary'
|
|
|
|
label={t`Subsidiary`}
|
|
|
|
rules={[
|
|
|
|
{
|
|
|
|
required: true,
|
|
|
|
message: 'Please select a subsidiary',
|
|
|
|
},
|
|
|
|
]}
|
|
|
|
>
|
|
|
|
<Select
|
|
|
|
placeholder='Select a subsidiary'
|
|
|
|
style={{ width: 200 }}
|
2024-05-03 02:52:15 +00:00
|
|
|
options={SUBSIDIARIES}
|
2024-05-02 12:14:47 +00:00
|
|
|
value={filterSubsidiaries}
|
|
|
|
defaultValue={filterSubsidiaries}
|
|
|
|
onChange={setFilterSubsidiaries}
|
|
|
|
/>
|
|
|
|
</Form.Item>
|
|
|
|
<Form.Item
|
|
|
|
name='max_accuracy'
|
|
|
|
label={t`max_accuracy` + ' (1-100)'}
|
|
|
|
rules={[
|
|
|
|
{
|
|
|
|
required: true,
|
|
|
|
message: 'Please select max accuracy',
|
|
|
|
},
|
|
|
|
]}
|
|
|
|
>
|
|
|
|
<InputNumber
|
|
|
|
min={1}
|
|
|
|
max={100}
|
|
|
|
defaultValue={filterAccuracy}
|
|
|
|
onChange={(value) => setFilterAccuracy(value)}
|
|
|
|
/>
|
|
|
|
</Form.Item>
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
style={{
|
|
|
|
marginTop: 10,
|
|
|
|
display: 'flex',
|
|
|
|
justifyContent: 'space-between',
|
|
|
|
marginLeft: 0,
|
|
|
|
padding: 0,
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<Form.Item
|
|
|
|
name='reviewed'
|
|
|
|
label={t`Reviewed`}
|
|
|
|
rules={[
|
|
|
|
{
|
|
|
|
required: true,
|
|
|
|
message: 'Please select review status',
|
|
|
|
},
|
|
|
|
]}
|
|
|
|
>
|
|
|
|
<Select
|
|
|
|
style={{ width: 200 }}
|
|
|
|
options={[
|
|
|
|
{ label: 'All', value: 'all' },
|
|
|
|
{ label: 'Reviewed', value: 'reviewed' },
|
|
|
|
{ label: 'Not Reviewed', value: 'not_reviewed' },
|
|
|
|
]}
|
|
|
|
value={filterReviewState}
|
|
|
|
defaultValue={filterReviewState}
|
|
|
|
onChange={setFilterReviewState}
|
|
|
|
/>
|
|
|
|
</Form.Item>
|
|
|
|
<Form.Item
|
|
|
|
name='is_test'
|
|
|
|
label={t`Is Test`}
|
|
|
|
rules={[
|
|
|
|
{
|
|
|
|
required: true,
|
|
|
|
message: 'Please select test status',
|
|
|
|
},
|
|
|
|
]}
|
|
|
|
style={{ marginLeft: 16 }}
|
|
|
|
>
|
|
|
|
<Select
|
|
|
|
style={{ width: 200 }}
|
|
|
|
options={[
|
|
|
|
{ label: 'Include tests', value: 'true' },
|
|
|
|
{ label: 'Exclude tests', value: 'false' },
|
|
|
|
]}
|
|
|
|
value={filterIncludeTests}
|
|
|
|
defaultValue={filterIncludeTests}
|
|
|
|
onChange={setFilterIncludesTests}
|
|
|
|
/>
|
|
|
|
</Form.Item>
|
|
|
|
</div>
|
2024-12-03 09:18:20 +00:00
|
|
|
{/* add 4 more filter fields */}
|
|
|
|
<div
|
|
|
|
style={{
|
|
|
|
marginTop: 10,
|
|
|
|
display: 'flex',
|
|
|
|
justifyContent: 'space-between',
|
|
|
|
marginLeft: 0,
|
|
|
|
padding: 0,
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<Form.Item
|
|
|
|
name='doc_type'
|
|
|
|
label={t`Only type`}
|
|
|
|
rules={[
|
|
|
|
{
|
|
|
|
required: true,
|
|
|
|
message: 'Please select a document type',
|
|
|
|
},
|
|
|
|
]}
|
|
|
|
>
|
|
|
|
<Select
|
|
|
|
placeholder='Select a document type'
|
|
|
|
style={{ width: 200 }}
|
|
|
|
options={DOCTYPE}
|
|
|
|
value={filterDoctype}
|
|
|
|
defaultValue={filterDoctype}
|
|
|
|
onChange={setFilterDoctype}
|
|
|
|
/>
|
|
|
|
</Form.Item>
|
|
|
|
<Form.Item
|
|
|
|
name='feedback_result'
|
|
|
|
label={t`Feedback includes`}
|
|
|
|
>
|
|
|
|
<Input
|
|
|
|
defaultValue={filterFeedbackResult}
|
|
|
|
onChange={(e) => setFilterFeedbackResult(e.target.value)}
|
|
|
|
/>
|
|
|
|
</Form.Item>
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
style={{
|
|
|
|
marginTop: 10,
|
|
|
|
display: 'flex',
|
|
|
|
justifyContent: 'space-between',
|
|
|
|
marginLeft: 0,
|
|
|
|
padding: 0,
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<Form.Item
|
|
|
|
name='predict_result'
|
|
|
|
label={t`Predict includes`}
|
|
|
|
>
|
|
|
|
<Input
|
|
|
|
defaultValue={filterPredictResult}
|
|
|
|
onChange={(e) => setFilterPredictResult(e.target.value)}
|
|
|
|
/>
|
|
|
|
</Form.Item>
|
|
|
|
<Form.Item
|
|
|
|
name='reviewed_result'
|
|
|
|
label={t`Review inculdes`}
|
|
|
|
>
|
|
|
|
<Input
|
|
|
|
defaultValue={filterReviewedResult}
|
|
|
|
onChange={(e) => setFilterReviewedResult(e.target.value)}
|
|
|
|
/>
|
|
|
|
</Form.Item>
|
|
|
|
</div>
|
2024-05-02 12:14:47 +00:00
|
|
|
</Form>
|
|
|
|
</Modal>
|
2024-06-20 06:27:41 +00:00
|
|
|
<Modal
|
|
|
|
title='Confirm this request?'
|
|
|
|
centered
|
|
|
|
open={isOpenConfirmRequest}
|
|
|
|
onOk={() => {
|
|
|
|
setIsOpenConfirmRequest(false);
|
2024-06-28 04:29:05 +00:00
|
|
|
handleConfirmRequest();
|
2024-06-20 06:27:41 +00:00
|
|
|
}}
|
|
|
|
onCancel={() => {
|
|
|
|
setIsOpenConfirmRequest(false);
|
|
|
|
}}
|
|
|
|
>
|
2024-07-04 09:17:32 +00:00
|
|
|
{!isSafeToConfirm && (
|
|
|
|
<p style={{ fontWeight: 'bold', color: 'red' }}>
|
|
|
|
There is still at least 1 photo need to be reviewed!{' '}
|
|
|
|
</p>
|
|
|
|
)}
|
2024-06-20 06:27:41 +00:00
|
|
|
<p>Are you sure you want to confirm this request is reviewed?</p>
|
|
|
|
</Modal>
|
2024-05-02 12:14:47 +00:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default ReviewPage;
|