import { ArrowLeftOutlined, ArrowRightOutlined, CheckCircleOutlined, ClockCircleFilled, FullscreenExitOutlined, FullscreenOutlined, } from '@ant-design/icons'; import { t } from '@lingui/macro'; import { Viewer } from '@react-pdf-viewer/core'; import type { GetRef } from 'antd'; import { Button, DatePicker, Form, Input, InputNumber, message, Modal, notification, Select, Spin, Table, Tag, } from 'antd'; import React, { useContext, useEffect, useRef, useState } from 'react'; import Lightbox from 'react-awesome-lightbox'; import 'react-awesome-lightbox/build/style.css'; import { useHotkeys } from 'react-hotkeys-hook'; import { baseURL } from 'request/api'; import styled from 'styled-components'; // Import the styles import '@react-pdf-viewer/core/lib/styles/index.css'; import { badQualityReasonSubmit } from 'request'; import { normalizeData } from 'utils/field-value-process'; import { fetchAllRequests, fetchRequest } from './api'; import { counter_measure_map } from './consts'; import FileCard from './FileCard'; const siderStyle: React.CSSProperties = { backgroundColor: '#fafafa', padding: 10, flexBasis: 400, flexShrink: 0, }; const StyledTable = styled(Table)` & .sbt-table-cell { padding: 4px !important; } `; type InputRef = GetRef; type FormInstance = GetRef>; const EditableContext = React.createContext | null>(null); interface Item { key: string; accuracy: number; submitted: string; revised: string; action: string; } interface EditableRowProps { index: number; } const EditableRow: React.FC = ({ index, ...props }) => { const [form] = Form.useForm(); return (
); }; interface EditableCellProps { title: React.ReactNode; editable: boolean; children: React.ReactNode; dataIndex: keyof Item; record: Item; handleSave: (record: Item) => void; } const EditableCell: React.FC = ({ title, editable, children, dataIndex, record, handleSave, ...restProps }) => { const [editing, setEditing] = useState(false); const inputRef = useRef(null); const form = useContext(EditableContext)!; useEffect(() => { if (editing) { inputRef.current!.focus(); } }, [editing]); const toggleEdit = () => { setEditing(!editing); form.setFieldsValue({ [dataIndex]: record[dataIndex] }); }; const save = async () => { try { const values = await form.validateFields(); toggleEdit(); handleSave({ ...record, ...values }); } catch (errInfo) { console.log('Save failed:', errInfo); } }; let childNode = children; if (editable) { childNode = editing ? ( ) : (
{children}
); } return {childNode}; }; // type EditableTableProps = Parameters[0]; const ReviewPage = () => { const [loading, setLoading] = useState(false); const [fullscreen, setFullscreen] = useState(false); const [isModalOpen, setIsModalOpen] = useState(false); const [isReasonModalOpen, setIsReasonModalOpen] = useState(false); const [selectedFileId, setSelectedFileId] = useState(0); const [selectedFileData, setSelectedFileData] = useState(null); const [selectedFileName, setSelectedFileName] = useState(null); // 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'); // 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 [dataSource, setDataSource] = useState([]); const [pageIndexToGoto, setPageIndexToGoto] = useState(1); const [reason, setReason] = useState(''); const [otherReason, setOtherReason] = useState(''); const [solution, setSolution] = useState(''); const [otherSolution, setOtherSolution] = useState(''); useEffect(() => { if (reason) { setSolution(counter_measure_map[reason]); } }, [reason]); const setAndLoadSelectedFile = async (requestData, index) => { setSelectedFileId(index); if (!requestData['Files'][index]) { setSelectedFileData('FAILED_TO_LOAD_FILE'); return; } const fileName = requestData['Files'][index]['File Name']; const fileURL = requestData['Files'][index]['File URL']; const response = await fetch(fileURL); if (response.status === 200) { setSelectedFileName(fileName); setSelectedFileData(fileURL); console.log('Loading file: ' + fileName); console.log('URL: ' + fileURL); } else { setSelectedFileData('FAILED_TO_LOAD_FILE'); } }; console.log(dataSource); const loadCurrentRequest = (requestIndex) => { setLoading(true); fetchAllRequests( filterDateRange, filterSubsidiaries, filterReviewState, filterIncludeTests, requestIndex, 1, filterAccuracy, ) .then((data) => { // setRequests(data?.subscription_requests); // setHasNextRequest(data?.subscription_requests.length > 1); setTotalPages(data?.page?.total_requests); setHasNextRequest(requestIndex < data?.page?.total_requests); const requestData = fetchRequest( data?.subscription_requests[0].RequestID, ); requestData .then(async (data) => { console.log('🚀 ~ .then ~ data:', data); if (data) setCurrentRequest(data); const predicted = data && data['Predicted Result'] ? data['Predicted Result'] : {}; const submitted = data && data['Feedback Result'] ? data['Feedback Result'] : {}; const revised = data && data['Reviewed Result'] ? data['Reviewed Result'] : {}; const keys = Object.keys(predicted); const tableRows = []; for (let i = 0; i < keys.length; i++) { let instance = {}; instance['key'] = keys[i]; instance['predicted'] = predicted[keys[i]]; instance['submitted'] = submitted[keys[i]]; instance['revised'] = revised[keys[i]]; tableRows.push(instance); } setDataSource(tableRows); setLoading(false); setAndLoadSelectedFile(data, 0); }) .finally(() => { setLoading(false); }); }) .finally(() => { setLoading(false); }); }; const gotoNextRequest = () => { if (currentRequestIndex >= totalRequests) { return; } const nextRequestIndex = currentRequestIndex + 1; setCurrentRequestIndex(nextRequestIndex); loadCurrentRequest(nextRequestIndex); }; const gotoPreviousRequest = () => { if (currentRequestIndex === 1) { return; } const previousRequestIndex = currentRequestIndex - 1; setCurrentRequestIndex(previousRequestIndex); loadCurrentRequest(previousRequestIndex); }; const reloadFilters = () => { setCurrentRequestIndex(1); fetchAllRequests( filterDateRange, filterSubsidiaries, filterReviewState, filterIncludeTests, 1, 1, filterAccuracy, ).then((data) => { setTotalPages(data?.page?.total_requests); // setRequests(data?.subscription_requests); // setHasNextRequest(data?.subscription_requests.length > 1); 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); setTimeout(() => { loadCurrentRequest(1); }, 500); }); }); }; useEffect(() => { setCurrentRequestIndex(1); fetchAllRequests( filterDateRange, filterSubsidiaries, filterReviewState, filterIncludeTests, 1, 1, filterAccuracy, ).then((data) => { setTotalPages(data?.page?.total_requests); // setRequests(data?.subscription_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); }); }); }, []); const components = { body: { row: EditableRow, cell: EditableCell, }, }; // "Key", "Accuracy", "Submitted", "Revised" interface DataType { key: string; accuracy: number; submitted: string; revised: string; } const updateRevisedData = async (newRevisedData: any) => { const requestID = currentRequest.RequestID; const token = localStorage.getItem('sbt-token') || ''; const result = await fetch(`${baseURL}/ctel/request/${requestID}/`, { method: 'POST', headers: { Authorization: `${JSON.parse(token)}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ reviewed_result: newRevisedData, }), }).catch((error) => { console.log(error); throw error; }); if (result.status != 200) { throw new Error('Could not update revised data'); } }; const handleSave = (row: DataType) => { const newData = [...dataSource]; const index = newData.findIndex((item) => row.key === item.key); const item = newData[index]; newData.splice(index, 1, { ...item, ...row, }); const newRevisedData = {}; for (let i = 0; i < newData.length; i++) { newData[i].revised = normalizeData(newData[i].key, newData[i].revised); newRevisedData[newData[i].key] = newData[i].revised; } updateRevisedData(newRevisedData) .then(() => { // "[Is Reviewed]" => true setCurrentRequest({ ...currentRequest, ['Is Reviewed']: true, }); }) .then(() => { setDataSource(newData); }) .catch((error) => { message.error( 'Could not update revised data. Please check the format.', ); }); }; const submitRevisedData = async () => { const newData = [...dataSource]; const newRevisedData = {}; for (let i = 0; i < newData.length; i++) { newData[i].revised = normalizeData(newData[i].key, newData[i].revised); newRevisedData[newData[i].key] = newData[i].revised; } updateRevisedData(newRevisedData).then(() => { // "[Is Reviewed]" => true setCurrentRequest({ ...currentRequest, ['Is Reviewed']: true, }); }); }; const defaultColumns = [ { title: 'Key', dataIndex: 'key', key: 'key', width: 200, }, { title: 'Predicted', dataIndex: 'predicted', key: 'predicted', render: (text) => { if (!text) return {''}; const displayedContent = text; if (typeof displayedContent === 'string') { return {displayedContent}; } else if (typeof displayedContent === 'object') { if (displayedContent.length === 0) { return {''}; } // Set all empty values to "" for (const key in displayedContent) { if (!displayedContent[key]) { displayedContent[key] = ''; } } return ( {displayedContent.join(', ')} ); } return {displayedContent}; }, }, { title: 'Submitted', dataIndex: 'submitted', key: 'submitted', render: (text) => { if (!text) return {''}; const displayedContent = text; if (typeof displayedContent === 'string') { return {displayedContent}; } else if (typeof displayedContent === 'object') { if (displayedContent.length === 0) { return {''}; } // Set all empty values to "" for (const key in displayedContent) { if (!displayedContent[key]) { displayedContent[key] = ''; } } return ( {displayedContent.join(', ')} ); } return {displayedContent}; }, }, { title: (
Revised  
), dataIndex: 'revised', key: 'revised', editable: true, render: (text) => { if (!text) return {''}; const displayedContent = text; if (typeof displayedContent === 'string') { return {displayedContent}; } else if (typeof displayedContent === 'object') { if (displayedContent.length === 0) { return {''}; } // Set all empty values to "" for (const key in displayedContent) { if (!displayedContent[key]) { displayedContent[key] = ''; } } return ( {displayedContent.join(', ')} ); } return {displayedContent}; }, }, ]; const columns = defaultColumns.map((col) => { if (!col.editable) { return col; } return { ...col, onCell: (record: DataType) => ({ record, editable: col.key != 'request_id' && col.editable, dataIndex: col.dataIndex, title: col.title, handleSave, }), }; }); // use left/right keys to navigate useHotkeys('left', gotoPreviousRequest); useHotkeys('right', gotoNextRequest); const fileExtension = selectedFileName ? selectedFileName.split('.').pop() : ''; const [lightBox, setLightBox] = useState(false); return (
{totalRequests ? ( <>    Request ID: {currentRequest?.RequestID} ) : ( '' )}
{totalRequests > 0 && (

Files ({currentRequest?.Files?.length})

{currentRequest?.Files.map((file, index) => ( { setAndLoadSelectedFile(currentRequest, index); }} setIsReasonModalOpen={setIsReasonModalOpen} /> ))}
{totalRequests > 0 && (
Request ID Redemption Uploaded date Request time Processing time Raw accuracy
)}
)}
{selectedFileData === 'FAILED_TO_LOAD_FILE' ? (

Failed to load file.

) : fileExtension === 'pdf' ? ( ) : ( <> file setLightBox(true)} /> {lightBox && ( setLightBox(false)} > )} )}

{totalRequests ? 'Request: ' + currentRequestIndex + '/' + totalRequests : 'No Request. Adjust your search criteria to see more results.'}

{currentRequest && (currentRequest['Is Reviewed'] ? ( } color='success' style={{ padding: '4px 16px' }} > Reviewed ) : ( } color='warning' style={{ padding: '4px 16px' }} > Not Reviewed ))}
{ if (pageIndexToGoto > totalRequests) { message.error('RequestID is out of range.'); return; } if (pageIndexToGoto < 1) { message.error('RequestID is out of range.'); return; } setCurrentRequestIndex(pageIndexToGoto); loadCurrentRequest(pageIndexToGoto); }} > Go to } value={pageIndexToGoto} onChange={(e) => { setPageIndexToGoto(parseInt(e.target.value)); }} />
{/* */} {/*

{totalRequests ? 'Request: ' + currentRequestIndex + '/' + totalRequests : 'No Request. Adjust your search criteria to see more results.'}

{currentRequest && (currentRequest['Is Reviewed'] ? ( } color='success' style={{ padding: '4px 16px' }} > Reviewed ) : ( } color='warning' style={{ padding: '4px 16px' }} > Not Reviewed ))}
{ if (pageIndexToGoto > totalRequests) { message.error('RequestID is out of range.'); return; } if (pageIndexToGoto < 1) { message.error('RequestID is out of range.'); return; } setCurrentRequestIndex(pageIndexToGoto); loadCurrentRequest(pageIndexToGoto); }} > Go to } value={pageIndexToGoto} onChange={(e) => { setPageIndexToGoto(parseInt(e.target.value)); }} />
*/}
{dataSource?.map((data) => { return (

{' '} {data.key}

); })}
{ setIsModalOpen(false); reloadFilters(); }} onCancel={() => { setIsModalOpen(false); }} >
{ setFilterDateRange(dateString); }} style={{ width: 200 }} />
{reason === 'other' && ( { setOtherReason(e.target.value); }} style={{ width: 200, marginTop: 30, marginBottom: 24, marginLeft: 10, }} /> )}
{counter_measure_map[reason]} { setOtherSolution(e.target.value); }} style={{ width: 200, marginBottom: 24, marginLeft: 10, }} /> )}
{/* {totalRequests > 0 && (
'editable-row'} bordered dataSource={dataSource} columns={columns} />
)} */}
); }; export default ReviewPage;