Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: pending ocr list to reveal immediately after user uploads file, and transform the pending ocr to uploaded ocr after successful post response, yet wait for the backend modification #2076

Merged
merged 2 commits into from
Aug 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "iSunFA",
"version": "0.8.0+7",
"version": "0.8.0+8",
"private": false,
"scripts": {
"dev": "next dev",
Expand Down Expand Up @@ -53,7 +53,8 @@
"react-usestateref": "^1.0.8",
"sharp": "^0.33.3",
"tailwind-merge": "^2.2.2",
"ts-node": "^10.9.2"
"ts-node": "^10.9.2",
"uuid": "^10.0.0"
},
"devDependencies": {
"@babel/eslint-plugin": "^7.23.5",
Expand All @@ -67,6 +68,7 @@
"@types/nodemailer": "^6.4.15",
"@types/react": "^18",
"@types/react-dom": "^18",
"@types/uuid": "^10.0.0",
"@typescript-eslint/eslint-plugin": "^6.16.0",
"@typescript-eslint/parser": "^6.16.0",
"autoprefixer": "^10.4.16",
Expand Down
53 changes: 41 additions & 12 deletions src/components/journal_upload_area/journal_upload_area.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import { v4 as uuidv4 } from 'uuid';
import React, { useState, useEffect } from 'react';
import { useTranslation } from 'next-i18next';
import Image from 'next/image';
import APIHandler from '@/lib/utils/api_handler';
import { APIName } from '@/constants/api_connection';
import { IAccountResultStatus } from '@/interfaces/accounting_account';
// import { IAccountResultStatus } from '@/interfaces/accounting_account';
import { useUserCtx } from '@/contexts/user_context';
import { useGlobalCtx } from '@/contexts/global_context';
import { useAccountingCtx } from '@/contexts/accounting_context';
import { ProgressStatus } from '@/constants/account';
import { MessageType } from '@/interfaces/message_modal';
import { ToastType } from '@/interfaces/toastify';
import { getTimestampNow } from '@/lib/utils/common';
import { transformBytesToFileSizeString } from '@/lib/utils/common';
import { IOCR } from '@/interfaces/ocr';

interface FileInfo {
file: File;
Expand All @@ -21,15 +23,17 @@ interface FileInfo {
const JournalUploadArea = () => {
const { t } = useTranslation('common');
const { selectedCompany } = useUserCtx();
const { setInvoiceIdHandler, addOCRHandler } = useAccountingCtx();
const { setInvoiceIdHandler, addPendingOCRHandler, deletePendingOCRHandler, addOCRHandler } =
useAccountingCtx();
const { messageModalDataHandler, messageModalVisibilityHandler, toastHandler } = useGlobalCtx();

const {
trigger: uploadInvoice,
data: results,
success: uploadSuccess,
code: uploadCode,
} = APIHandler<IAccountResultStatus[]>(APIName.OCR_UPLOAD);
} = APIHandler<IOCR[]>(APIName.OCR_UPLOAD);
// IAccountResultStatus[]

// Info: (20240711 - Julian) 上傳的檔案
const [uploadFile, setUploadFile] = useState<FileInfo | null>(null);
Expand All @@ -44,10 +48,11 @@ const JournalUploadArea = () => {
const { files } = event.target;
if (files && files.length > 0) {
const file = files[0];
const fileSize = transformBytesToFileSizeString(file.size);
setUploadFile({
file,
name: file.name,
size: file.size.toString(),
size: fileSize,
});
}
};
Expand All @@ -65,10 +70,11 @@ const JournalUploadArea = () => {
event.preventDefault();
const droppedFile = event.dataTransfer.files[0];
if (droppedFile) {
const fileSize = transformBytesToFileSizeString(droppedFile.size);
setUploadFile({
file: droppedFile,
name: droppedFile.name,
size: droppedFile.size.toString(),
size: fileSize,
});
setIsDragOver(false);
}
Expand All @@ -77,11 +83,19 @@ const JournalUploadArea = () => {
useEffect(() => {
if (uploadFile && selectedCompany) {
const formData = new FormData();
const uuid = uuidv4();
formData.append('image', uploadFile.file);
// TODO: in dev (20240815 - Shirley) 加上 imageSize, imageName, uploadIdentifier
formData.append('imageSize', uploadFile.size);
formData.append('imageName', uploadFile.name);
formData.append('uploadIdentifier', uuid);
// eslint-disable-next-line no-console
// console.log('formData', formData);

// Info: (20240711 - Julian) 點擊上傳後才升起 flag
// setIsShowSuccessModal(true);
addOCRHandler(`${getTimestampNow()}`, uploadFile.name, uploadFile.size);
// addOCRHandler(`${getTimestampNow()}`, uploadFile.name, uploadFile.size, uuid);
addPendingOCRHandler(uploadFile.name, uploadFile.size, uuid);

uploadInvoice({ params: { companyId: selectedCompany.id }, body: formData });
}
Expand All @@ -90,7 +104,7 @@ const JournalUploadArea = () => {
useEffect(() => {
if (uploadSuccess && results) {
results.forEach((result) => {
const { resultId } = result;
// const { resultId } = result;
/* Info: (20240805 - Anna) 將狀態的翻譯key值存到變數 */
const translatedStatus = t(
`PROGRESS_STATUS.${result.status.toUpperCase().replace(/_/g, '_')}`
Expand All @@ -107,10 +121,25 @@ const JournalUploadArea = () => {
closeable: true,
type: ToastType.SUCCESS,
});
setInvoiceIdHandler(resultId);
// if (uploadFile) {
// addOCRHandler(resultId, uploadFile.name, uploadFile.size);
// }
setInvoiceIdHandler(result.aichResultId);
// setInvoiceIdHandler(resultId);
// TODO: in dev (20240815 - Shirley) 加上
// eslint-disable-next-line no-console
console.log('result in JournalUploadArea', result);
if (
result?.uploadIdentifier &&
result?.aichResultId &&
result?.imageName &&
result?.imageSize
) {
addOCRHandler(
result.aichResultId,
result.imageName,
result.imageSize,
result.uploadIdentifier
);
deletePendingOCRHandler(result?.uploadIdentifier);
}
// messageModalDataHandler({
// // title: 'Upload Successful',
// title: t('JOURNAL.UPLOAD_SUCCESSFUL'),
Expand Down
32 changes: 28 additions & 4 deletions src/components/step_one_tab/step_one_tab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,19 @@ const StepOneTab = () => {
const { t } = useTranslation('common');
const { cameraScannerVisibilityHandler, toastHandler } = useGlobalCtx();
const { selectedCompany } = useUserCtx();
const { OCRList, OCRListStatus, updateOCRListHandler, selectOCRHandler, deleteOCRHandler } =
useAccountingCtx();
const {
OCRList,
OCRListStatus,
updateOCRListHandler,
selectOCRHandler,
deleteOCRHandler,
pendingOCRList,
} = useAccountingCtx();
// Info: (20240809 - Shirley) disabled for now , 分頁功能在 alpha release 還沒實作
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [currentFilePage, setCurrentFilePage] = useState<number>(1);
const [fileList, setFileList] = useState<IOCR[]>(OCRList);
// const [pendingFileList, setPendingFileList] = useState<IOCR[]>(pendingOCRList);
// Info: (20240809 - Shirley) disabled for now , 分頁功能在 alpha release 還沒實作
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [totalPages, setTotalPages] = useState<number>(1);
Expand Down Expand Up @@ -83,6 +90,9 @@ const StepOneTab = () => {
}
};

// eslint-disable-next-line no-console
console.log('in StepOneTab, fileList', fileList, 'pendingOCRList', pendingOCRList);

useEffect(() => {
setTotalPages(Math.ceil(fileList.length / 5));
}, [fileList]);
Expand Down Expand Up @@ -154,6 +164,16 @@ const StepOneTab = () => {
};

const displayedFileList = fileList.map((data) => (
<UploadedFileItem
key={data.id}
itemData={data}
pauseHandler={fileItemPauseHandler}
deleteHandler={fileItemDeleteHandler}
clickHandler={handleOCRClick}
/>
));

const displayedPendingFileList = pendingOCRList.map((data) => (
<UploadedFileItem
key={data.id}
itemData={data}
Expand All @@ -165,7 +185,7 @@ const StepOneTab = () => {
));

const uploadedFileSection =
fileList.length > 0 ? (
fileList.length > 0 || pendingOCRList.length > 0 ? (
<>
<div className="my-5 flex items-center gap-4">
<hr className="block flex-1 border-lightGray4 md:hidden" />
Expand All @@ -182,7 +202,11 @@ const StepOneTab = () => {
</div>
{/* Info: (20240523 - Julian) Uploaded File List */}
<div className="mb-50px flex flex-col items-center gap-y-50px">
<div className="flex w-full flex-col items-center gap-y-12px">{displayedFileList}</div>
<div className="flex w-full flex-col items-center gap-y-12px">
{displayedFileList}
{displayedPendingFileList}
</div>

{/* Info: (20240523 - Julian) Pagination */}
{/* Info: (20240809 - Shirley) disabled for now , 分頁功能在 alpha release 還沒實作 */}
{/* {totalPages > 1 && (
Expand Down
14 changes: 10 additions & 4 deletions src/components/uploaded_file_item/uploaded_file_item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ const UploadedFileItem = ({
clickHandler(itemData);
};

// Info: (20240527 - Julian) 若檔名過長,則擷取前 3 個和後 4 個(副檔名)字元,中間以 ... 代替
// Info: (20240527 - Julian) 若檔名過長,則擷取前 5 個和後 4 個(副檔名)字元,中間以 ... 代替
const truncatedFileName =
imageName.length > 20 ? `${imageName.slice(0, 3)}...${imageName.slice(-4)}` : imageName;
imageName.length > 20 ? `${imageName.slice(0, 5)}...${imageName.slice(-4)}` : imageName;

const displayedPauseButton =
status === ProgressStatus.PAUSED ? <FiPlay size={20} /> : <FiPauseCircle size={20} />;
Expand All @@ -81,8 +81,14 @@ const UploadedFileItem = ({
<Skeleton width={56} height={56} /> {/* Info: 掃描動畫 (20240814 - Shirley) */}
<Skeleton width={64} height={64} /> {/* Info: 文件縮略圖 (20240814 - Shirley) */}
<div className="flex shrink grow flex-col items-start">
<Skeleton width={100} height={24} /> {/* Info: 文件名 (20240814 - Shirley) */}
<Skeleton width={50} height={16} /> {/* Info: 文件大小 (20240814 - Shirley) */}
<h3
className={`text-base font-semibold leading-normal tracking-tight text-file-uploading-text-primary`}
>
{truncatedFileName}
</h3>
<p className="text-xs font-normal leading-tight tracking-tight text-file-uploading-text-disable">
{imageSize}
</p>
</div>
<div className="absolute right-0 z-10 flex items-center gap-10px">
<Skeleton width={20} height={20} /> {/* Info: 狀態圖標 (20240814 - Shirley) */}
Expand Down
54 changes: 52 additions & 2 deletions src/contexts/accounting_context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,15 @@ interface IAccountingContext {
OCRList: IOCR[];
OCRListStatus: { listSuccess: boolean | undefined; listCode: string | undefined };
updateOCRListHandler: (companyId: number | undefined, update: boolean) => void;
addOCRHandler: (aichId: string, imageName: string, imageSize: string) => void;
addOCRHandler: (
aichId: string,
imageName: string,
imageSize: string,
uploadIdentifier: string
) => void;
deleteOCRHandler: (aichId: string) => void;
addPendingOCRHandler: (imageName: string, imageSize: string, uploadIdentifier: string) => void;
deletePendingOCRHandler: (uploadIdentifier: string) => void;
accountList: IAccount[];
getAccountListHandler: (
companyId: number,
Expand Down Expand Up @@ -114,6 +121,7 @@ interface IAccountingContext {
generateAccountTitle: (account: IAccount | null) => string;

deleteOwnAccountTitle: (companyId: number, id: number) => void;
pendingOCRList: IOCR[];
}

const initialAccountingContext: IAccountingContext = {
Expand All @@ -127,6 +135,8 @@ const initialAccountingContext: IAccountingContext = {
updateOCRListHandler: () => {},
addOCRHandler: () => {},
deleteOCRHandler: () => {},
addPendingOCRHandler: () => {},
deletePendingOCRHandler: () => {},
accountList: [],
getAccountListHandler: () => {},
getAIStatusHandler: () => {},
Expand Down Expand Up @@ -159,6 +169,7 @@ const initialAccountingContext: IAccountingContext = {
generateAccountTitle: () => 'Account Title',

deleteOwnAccountTitle: () => {},
pendingOCRList: [],
};

export const AccountingContext = createContext<IAccountingContext>(initialAccountingContext);
Expand Down Expand Up @@ -212,6 +223,9 @@ export const AccountingProvider = ({ children }: IAccountingProvider) => {
const [intervalId, setIntervalId] = useState<NodeJS.Timeout | null>(null);
const [inputDescription, setInputDescription] = useState<string>('');

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [pendingOCRList, setPendingOCRList] = useState<IOCR[]>([]);

const getAccountListHandler = (
companyId: number,
type?: string,
Expand Down Expand Up @@ -297,7 +311,12 @@ export const AccountingProvider = ({ children }: IAccountingProvider) => {
});
};

const addOCRHandler = (aichId: string, imageName: string, imageSize: string) => {
const addOCRHandler = (
aichId: string,
imageName: string,
imageSize: string,
uploadIdentifier: string
) => {
const now = getTimestampNow();
const pendingOCR: IOCR = {
id: now,
Expand All @@ -308,13 +327,39 @@ export const AccountingProvider = ({ children }: IAccountingProvider) => {
progress: 0,
status: ProgressStatus.WAITING_FOR_UPLOAD,
createdAt: 0,
uploadIdentifier,
};
setOCRList((prev) => {
const rs = [...prev, pendingOCR];
return rs;
});
};

const addPendingOCRHandler = (imageName: string, imageSize: string, uploadIdentifier: string) => {
const ocr: IOCR = {
id: getTimestampNow(),
aichResultId: getTimestampNow().toString(),
imageName,
imageUrl: '',
progress: 0,
status: ProgressStatus.WAITING_FOR_UPLOAD,
imageSize,
createdAt: 0,
uploadIdentifier,
};
setPendingOCRList((prev) => {
const rs = [...prev, ocr];
return rs;
});
};

const deletePendingOCRHandler = (uploadIdentifier: string) => {
setPendingOCRList((prev) => {
const rs = prev.filter((ocr) => ocr.uploadIdentifier !== uploadIdentifier);
return rs;
});
};

useEffect(() => {
if (accountSuccess && accountTitleList) {
setAccountList(accountTitleList.data);
Expand Down Expand Up @@ -598,6 +643,8 @@ export const AccountingProvider = ({ children }: IAccountingProvider) => {
updateOCRListHandler,
addOCRHandler,
deleteOCRHandler,
addPendingOCRHandler,
deletePendingOCRHandler,
accountList,
getAccountListHandler,
getAIStatusHandler,
Expand Down Expand Up @@ -628,6 +675,8 @@ export const AccountingProvider = ({ children }: IAccountingProvider) => {
deleteOwnAccountTitle,
inputDescription,
inputDescriptionHandler,

pendingOCRList,
}),
[
OCRList,
Expand All @@ -652,6 +701,7 @@ export const AccountingProvider = ({ children }: IAccountingProvider) => {
selectedJournal,
selectJournalHandler,
inputDescription,
pendingOCRList,
]
);

Expand Down
2 changes: 1 addition & 1 deletion src/interfaces/accounting_account.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { AccountType, EquityType, ProgressStatus } from '@/constants/account';
import { Account } from '@prisma/client';
import { ReportSheetType } from '@/constants/report';
import { IPaginatedData } from './pagination';
import { IPaginatedData } from '@/interfaces/pagination';

export interface IAccount {
id: number;
Expand Down
Loading