From e0d0d6d5bb23346704912fb27787d9aa86e7547f Mon Sep 17 00:00:00 2001 From: julian Date: Tue, 8 Oct 2024 14:47:33 +0800 Subject: [PATCH 1/4] Feat: fix style --- package.json | 2 +- src/components/certificate/certificate_selection.tsx | 2 +- src/components/voucher/new_voucher_form.tsx | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index c4a624902..c08ce1cb9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "iSunFA", - "version": "0.8.2+34", + "version": "0.8.2+35", "private": false, "scripts": { "dev": "next dev", diff --git a/src/components/certificate/certificate_selection.tsx b/src/components/certificate/certificate_selection.tsx index 62aec19f7..b710c8ed2 100644 --- a/src/components/certificate/certificate_selection.tsx +++ b/src/components/certificate/certificate_selection.tsx @@ -91,7 +91,7 @@ const CertificateSelection: React.FC = ({ return (
{
{t('journal:VOUCHER.DEBIT')}
-
+
{t('journal:VOUCHER.CREDIT')}
-
{/* Info: (20240927 - Julian) Table Body */} {voucherLines} From 24732b67bf3aee00d0b30907c72fec141bc9846f Mon Sep 17 00:00:00 2001 From: julian Date: Tue, 8 Oct 2024 14:55:16 +0800 Subject: [PATCH 2/4] Feat: Add React.FC --- package.json | 2 +- src/components/voucher/ap_and_ar_item.tsx | 2 +- src/components/voucher/ap_and_ar_list.tsx | 2 +- .../voucher/ap_and_ar_page_body.tsx | 2 +- src/components/voucher/new_voucher_form.tsx | 2 +- src/components/voucher/sorting_button.tsx | 11 ++++---- src/components/voucher/voucher_item.tsx | 2 +- src/components/voucher/voucher_line_item.tsx | 26 ++++++++++--------- src/components/voucher/voucher_list.tsx | 2 +- .../voucher/voucher_list_page_body.tsx | 2 +- .../users/accounting/add_new_voucher.tsx | 2 +- .../accounting/payable_receivable_list.tsx | 3 ++- src/pages/users/accounting/voucher_list.tsx | 2 +- 13 files changed, 31 insertions(+), 29 deletions(-) diff --git a/package.json b/package.json index c08ce1cb9..af633640f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "iSunFA", - "version": "0.8.2+35", + "version": "0.8.2+36", "private": false, "scripts": { "dev": "next dev", diff --git a/src/components/voucher/ap_and_ar_item.tsx b/src/components/voucher/ap_and_ar_item.tsx index 0487d4f4c..16e89b973 100644 --- a/src/components/voucher/ap_and_ar_item.tsx +++ b/src/components/voucher/ap_and_ar_item.tsx @@ -5,7 +5,7 @@ import { FaDownload, FaUpload } from 'react-icons/fa'; import { VoucherType } from '@/constants/account'; import { FiRepeat } from 'react-icons/fi'; -const APandARItem = () => { +const APandARItem: React.FC = () => { // ToDo: (20240924 - Julian) dummy data const date: number = new Date().getTime() / 1000; const voucherType: VoucherType = VoucherType.EXPENSE; diff --git a/src/components/voucher/ap_and_ar_list.tsx b/src/components/voucher/ap_and_ar_list.tsx index b2cd6b5fd..c67021b04 100644 --- a/src/components/voucher/ap_and_ar_list.tsx +++ b/src/components/voucher/ap_and_ar_list.tsx @@ -10,7 +10,7 @@ enum ListType { PAYABLE = 'Payable', } -const APandARList = () => { +const APandARList: React.FC = () => { const { t } = useTranslation('common'); // ToDo: (20240924 - Julian) tabs 切換 diff --git a/src/components/voucher/ap_and_ar_page_body.tsx b/src/components/voucher/ap_and_ar_page_body.tsx index 6bdc2391f..7013c558a 100644 --- a/src/components/voucher/ap_and_ar_page_body.tsx +++ b/src/components/voucher/ap_and_ar_page_body.tsx @@ -2,7 +2,7 @@ import React, { useState } from 'react'; import APandARList from '@/components/voucher/ap_and_ar_list'; import Tabs from '@/components/tabs/tabs'; -const APandARPageBody = () => { +const APandARPageBody: React.FC = () => { const [activeTab, setActiveTab] = useState(0); return ( diff --git a/src/components/voucher/new_voucher_form.tsx b/src/components/voucher/new_voucher_form.tsx index db4f3e55d..7979e0f5c 100644 --- a/src/components/voucher/new_voucher_form.tsx +++ b/src/components/voucher/new_voucher_form.tsx @@ -37,7 +37,7 @@ enum RecurringUnit { WEEK = 'week', } -const NewVoucherForm = () => { +const NewVoucherForm: React.FC = () => { const { t } = useTranslation('common'); const router = useRouter(); diff --git a/src/components/voucher/sorting_button.tsx b/src/components/voucher/sorting_button.tsx index 1993c38ca..35333f400 100644 --- a/src/components/voucher/sorting_button.tsx +++ b/src/components/voucher/sorting_button.tsx @@ -1,17 +1,16 @@ // Info: (20240924 - tzuhan) To Julian, this component is seperated from your VourchList // Info: (20240920 - Julian) 排序按鈕 +import React from 'react'; import { SortOrder } from '@/constants/sort'; import { BsFillTriangleFill } from 'react-icons/bs'; -const SortingButton = ({ - string, - sortOrder, - setSortOrder, -}: { +interface ISortingButtonProps { string: string; sortOrder: null | SortOrder; setSortOrder: (sortOrder: null | SortOrder) => void; -}) => { +} + +const SortingButton: React.FC = ({ string, sortOrder, setSortOrder }) => { // Info: (20240920 - Julian) 初始無排序 -> 點擊後變成 ASC -> 再點擊變成 DESC -> 再點擊變回無排序 const clickHandler = () => { switch (sortOrder) { diff --git a/src/components/voucher/voucher_item.tsx b/src/components/voucher/voucher_item.tsx index 45c5eed54..4144de827 100644 --- a/src/components/voucher/voucher_item.tsx +++ b/src/components/voucher/voucher_item.tsx @@ -13,7 +13,7 @@ interface IVoucherItemProps { isCheckBoxOpen: boolean; } -const VoucherItem = ({ voucher, isCheckBoxOpen }: IVoucherItemProps) => { +const VoucherItem: React.FC = ({ voucher, isCheckBoxOpen }) => { const { date, voucherNo, diff --git a/src/components/voucher/voucher_line_item.tsx b/src/components/voucher/voucher_line_item.tsx index 916da100d..b49126225 100644 --- a/src/components/voucher/voucher_line_item.tsx +++ b/src/components/voucher/voucher_line_item.tsx @@ -8,18 +8,7 @@ import { useAccountingCtx } from '@/contexts/accounting_context'; import { IAccount } from '@/interfaces/accounting_account'; import { numberWithCommas } from '@/lib/utils/common'; -const VoucherLineItem = ({ - flagOfClear, - flagOfSubmit, - accountIsNull, - amountNotEqual, - amountIsZero, - deleteHandler, - accountTitleHandler, - particularsChangeHandler, - debitChangeHandler, - creditChangeHandler, -}: { +interface IVoucherLineItemProps { flagOfClear: boolean; flagOfSubmit: boolean; accountIsNull: boolean; @@ -30,6 +19,19 @@ const VoucherLineItem = ({ particularsChangeHandler: (particulars: string) => void; debitChangeHandler: (debit: number) => void; creditChangeHandler: (credit: number) => void; +} + +const VoucherLineItem: React.FC = ({ + flagOfClear, + flagOfSubmit, + accountIsNull, + amountNotEqual, + amountIsZero, + deleteHandler, + accountTitleHandler, + particularsChangeHandler, + debitChangeHandler, + creditChangeHandler, }) => { const { t } = useTranslation('common'); const { accountList } = useAccountingCtx(); diff --git a/src/components/voucher/voucher_list.tsx b/src/components/voucher/voucher_list.tsx index 29ab6052b..63d656954 100644 --- a/src/components/voucher/voucher_list.tsx +++ b/src/components/voucher/voucher_list.tsx @@ -11,7 +11,7 @@ import { SortOrder } from '@/constants/sort'; import { useGlobalCtx } from '@/contexts/global_context'; import { IVoucherBeta, dummyVoucherList } from '@/interfaces/voucher'; -const VoucherList = () => { +const VoucherList: React.FC = () => { const { t } = useTranslation('common'); const { exportVoucherModalVisibilityHandler } = useGlobalCtx(); diff --git a/src/components/voucher/voucher_list_page_body.tsx b/src/components/voucher/voucher_list_page_body.tsx index 25ed3135b..78d24edf8 100644 --- a/src/components/voucher/voucher_list_page_body.tsx +++ b/src/components/voucher/voucher_list_page_body.tsx @@ -5,7 +5,7 @@ import { Button } from '@/components/button/button'; import VoucherList from '@/components/voucher/voucher_list'; import Tabs from '@/components/tabs/tabs'; -const VoucherListPageBody = () => { +const VoucherListPageBody: React.FC = () => { const { t } = useTranslation('common'); const [activeTab, setActiveTab] = useState(0); diff --git a/src/pages/users/accounting/add_new_voucher.tsx b/src/pages/users/accounting/add_new_voucher.tsx index 6a6838410..36dcb6a8e 100644 --- a/src/pages/users/accounting/add_new_voucher.tsx +++ b/src/pages/users/accounting/add_new_voucher.tsx @@ -5,7 +5,7 @@ import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; import { ILocale } from '@/interfaces/locale'; import NewVoucherForm from '@/components/voucher/new_voucher_form'; -const AddNewVoucherPage = () => { +const AddNewVoucherPage: React.FC = () => { const { t } = useTranslation('common'); const [isSidebarOpen, setIsSidebarOpen] = useState(true); diff --git a/src/pages/users/accounting/payable_receivable_list.tsx b/src/pages/users/accounting/payable_receivable_list.tsx index db3582bbf..e50b9c70d 100644 --- a/src/pages/users/accounting/payable_receivable_list.tsx +++ b/src/pages/users/accounting/payable_receivable_list.tsx @@ -1,10 +1,11 @@ +import React from 'react'; import Head from 'next/head'; import { useTranslation } from 'next-i18next'; import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; import { ILocale } from '@/interfaces/locale'; import APandARPageBody from '@/components/voucher/ap_and_ar_page_body'; -const APandARListPage = () => { +const APandARListPage: React.FC = () => { const { t } = useTranslation('common'); return ( diff --git a/src/pages/users/accounting/voucher_list.tsx b/src/pages/users/accounting/voucher_list.tsx index 246afa63b..4a088b21d 100644 --- a/src/pages/users/accounting/voucher_list.tsx +++ b/src/pages/users/accounting/voucher_list.tsx @@ -5,7 +5,7 @@ import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; import { ILocale } from '@/interfaces/locale'; import VoucherListPageBody from '@/components/voucher/voucher_list_page_body'; -const VoucherListPage = () => { +const VoucherListPage: React.FC = () => { const { t } = useTranslation('common'); const [isSidebarOpen, setIsSidebarOpen] = useState(true); From ed779390e8ca42a034095e5298d4f923f2d63150 Mon Sep 17 00:00:00 2001 From: julian Date: Tue, 8 Oct 2024 16:22:06 +0800 Subject: [PATCH 3/4] Feat: fix style --- package.json | 2 +- src/components/voucher/new_voucher_form.tsx | 2 +- src/components/voucher/voucher_line_item.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index af633640f..47ed8048f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "iSunFA", - "version": "0.8.2+36", + "version": "0.8.2+37", "private": false, "scripts": { "dev": "next dev", diff --git a/src/components/voucher/new_voucher_form.tsx b/src/components/voucher/new_voucher_form.tsx index 7979e0f5c..e2de672af 100644 --- a/src/components/voucher/new_voucher_form.tsx +++ b/src/components/voucher/new_voucher_form.tsx @@ -703,7 +703,7 @@ const NewVoucherForm: React.FC = () => {
{displayedCounterparty}
diff --git a/src/components/voucher/voucher_line_item.tsx b/src/components/voucher/voucher_line_item.tsx index b49126225..4130156f8 100644 --- a/src/components/voucher/voucher_line_item.tsx +++ b/src/components/voucher/voucher_line_item.tsx @@ -262,7 +262,7 @@ const VoucherLineItem: React.FC = ({
{isEditAccounting}
From 6eee2adb12e4957b003ed4267bf9ec116626ed04 Mon Sep 17 00:00:00 2001 From: julian Date: Tue, 8 Oct 2024 17:37:39 +0800 Subject: [PATCH 4/4] Feat: voucher detail interface for fontend --- package.json | 2 +- src/constants/api_connection.ts | 5 + src/interfaces/api_connection.ts | 3 +- src/pages/voucher_detail.tsx | 331 +++++++++++++++++++++++++++++-- 4 files changed, 319 insertions(+), 22 deletions(-) diff --git a/package.json b/package.json index 47ed8048f..038ad00ab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "iSunFA", - "version": "0.8.2+37", + "version": "0.8.2+38", "private": false, "scripts": { "dev": "next dev", diff --git a/src/constants/api_connection.ts b/src/constants/api_connection.ts index 7c1e323e1..9fc3e476b 100644 --- a/src/constants/api_connection.ts +++ b/src/constants/api_connection.ts @@ -522,4 +522,9 @@ export const APIConfig: Record = { method: HttpMethod.GET, path: APIPath.CERTIFICATE_LIST, }), + [APIName.VOUCHER_GET_BY_ID_V2]: createConfig({ + name: APIName.VOUCHER_GET_BY_ID_V2, + method: HttpMethod.GET, + path: APIPath.VOUCHER_GET_BY_ID_V2, + }), }; diff --git a/src/interfaces/api_connection.ts b/src/interfaces/api_connection.ts index ae36fdae9..d999fd94e 100644 --- a/src/interfaces/api_connection.ts +++ b/src/interfaces/api_connection.ts @@ -64,7 +64,8 @@ export type IAPIName = | 'GET_PROJECT_BY_ID' | 'UPDATE_PROJECT_BY_ID' | 'PUBLIC_KEY_GET' - | 'CERTIFICATE_LIST'; + | 'CERTIFICATE_LIST' + | 'VOUCHER_GET_BY_ID_V2'; export type IHttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD'; diff --git a/src/pages/voucher_detail.tsx b/src/pages/voucher_detail.tsx index ed286fc63..678f7783d 100644 --- a/src/pages/voucher_detail.tsx +++ b/src/pages/voucher_detail.tsx @@ -1,16 +1,154 @@ import React from 'react'; +import Head from 'next/head'; import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; +import { FiTrash2, FiEdit, FiBookOpen } from 'react-icons/fi'; +import { MdOutlineFileDownload } from 'react-icons/md'; import { ILocale } from '@/interfaces/locale'; -import Head from 'next/head'; import SideMenu from '@/components/upload_certificate/side_menu'; import Header from '@/components/upload_certificate/header'; import { generateRandomCertificates, ICertificateUI, OPERATIONS } from '@/interfaces/certificate'; import CertificateSelection from '@/components/certificate/certificate_selection'; import { Button } from '@/components/button/button'; -import Image from 'next/image'; +import { timestampToString, numberWithCommas } from '@/lib/utils/common'; +import { ILineItem } from '@/interfaces/line_item'; +import { IDatePeriod } from '@/interfaces/date_period'; +import { useModalContext } from '@/contexts/modal_context'; +import { MessageType } from '@/interfaces/message_modal'; +import { APIName } from '@/constants/api_connection'; +import APIHandler from '@/lib/utils/api_handler'; +import Skeleton from '@/components/skeleton/skeleton'; + +interface IVoucherDetailForFrontend { + id: number; + voucherDate: number; + type: string; + note: string; + counterParty: { + id: number; + companyId: number; + name: string; + }; + recurringInfo: { + type: string; + startDate: number; + endDate: number; + daysOfWeek: number[]; + dayOfMonth: number[]; + daysOfYear: { + month: number; + day: number; + }[]; + }; +} -const AddVoucherPage: React.FC = () => { - const selectedCertificates: ICertificateUI[] = generateRandomCertificates(0).map( +const defaultVoucherDetail: IVoucherDetailForFrontend = { + id: 0, + voucherDate: 0, + type: '', + note: '', + counterParty: { + id: 0, + companyId: 0, + name: '', + }, + recurringInfo: { + type: '', + startDate: 0, + endDate: 0, + daysOfWeek: [], + dayOfMonth: [], + daysOfYear: [], + }, +}; + +const VoucherDetailPage: React.FC = () => { + const recurringStr: string = 'Every month'; + const recurringPeriod: IDatePeriod = { + startTimeStamp: 1643567783, + endTimeStamp: 1801578367, + }; + const payableAmount: number = 1300; + const paidAmount: number = 1000; + const remainAmount: number = 300; + const reverseVouchers: string[] = ['20241008-002', '20241008-003']; + // ToDo: (20241008 - Julian) Asset + // const assetIds = ['A00000001', 'A00000002', 'A00000003']; + const voucherLineItems: ILineItem[] = [ + { + lineItemIndex: '0', + accountId: 320, + account: 'Cash', + description: 'Buy a printer', + debit: true, + amount: 1000, + }, + { + lineItemIndex: '1', + accountId: 503, + account: 'Accounts Payable', + description: '', + debit: false, + amount: 1300, + }, + { + lineItemIndex: '3', + accountId: 673, + account: 'Miscellaneous Expense', + description: '', + debit: true, + amount: 300, + }, + ]; + + const { data: voucherData, isLoading } = APIHandler( + APIName.VOUCHER_GET_BY_ID_V2, + { + params: { + companyId: '111', + voucherId: '123', + }, + }, + true + ); + + const { + id: voucherId, + voucherDate, + type, + note, + counterParty, + } = voucherData || defaultVoucherDetail; + const { messageModalVisibilityHandler, messageModalDataHandler } = useModalContext(); + + const pageTitle = `Voucher ${voucherId}`; + const totalDebit = voucherLineItems.reduce((acc, cur) => (cur.debit ? acc + cur.amount : acc), 0); + const totalCredit = voucherLineItems.reduce( + (acc, cur) => (!cur.debit ? acc + cur.amount : acc), + 0 + ); + + const recurringPeriodStr = `From ${timestampToString(recurringPeriod.startTimeStamp).date} to ${timestampToString(recurringPeriod.endTimeStamp).date}`; + + // ToDo: (20241008 - Julian) Call API to delete voucher + const deleteVoucher = async () => { + // eslint-disable-next-line no-console + console.log('Voucher deleted'); + }; + + const deleteClickHandler = () => { + messageModalDataHandler({ + messageType: MessageType.WARNING, + title: 'Do you really want to delete this Voucher?', + content: 'All the assets that are connected to this voucher will be deleted too.', + submitBtnStr: 'Yes, delete the voucher.', + submitBtnFunction: deleteVoucher, + backBtnStr: 'Cancel', + backBtnFunction: messageModalVisibilityHandler, + }); + messageModalVisibilityHandler(); + }; + + const selectedCertificates: ICertificateUI[] = generateRandomCertificates(3).map( (certificate) => { const actions = [OPERATIONS.DOWNLOAD, OPERATIONS.REMOVE]; return { @@ -21,40 +159,107 @@ const AddVoucherPage: React.FC = () => { } ); + const reverseVoucherList = reverseVouchers.map((reverseVoucher) => ( +

+ {reverseVoucher} +

+ )); + + // ToDo: (20241008 - Julian) Display asset + // const displayAssetIds = assetIds.map((assetId) => ( + //

+ // {assetId} + //

+ // )); + + const voucherLineBlock = voucherLineItems.map((lineItem) => ( + <> +
+

+ {lineItem.accountId} - {lineItem.account} +

+
+ +
+
+
+ {lineItem.description} +
+
+ {lineItem.debit ? ( + numberWithCommas(lineItem.amount) + ) : ( +

0

+ )} +
+
+ {lineItem.debit ? ( +

0

+ ) : ( + numberWithCommas(lineItem.amount) + )} +
+ + )); + + const isDisplayDate = !isLoading ? ( +

{timestampToString(voucherDate).date}

+ ) : ( + + ); + + const isDisplayType = !isLoading ? ( +

{type}

+ ) : ( + + ); + + const isDisplayNote = !isLoading ? ( +

{note}

+ ) : ( + + ); + + const isDisplayCounterParty = !isLoading ? ( +

{counterParty.name}

+ ) : ( + + ); + return ( <> - Upload Certificate - iSunFA + {pageTitle} - iSunFA
{/* Info: (20240919 - tzuhan) Side Menu */} {/* Info: (20240919 - tzuhan) Main Content Area */} -
+
{/* Info: (20240919 - tzuhan) Header */}
{/* Info: (20240919 - tzuhan) Main Content */} -
+
- - -
{/* Info: (20240926 - tzuhan) CertificateSelection */} @@ -63,6 +268,92 @@ const AddVoucherPage: React.FC = () => { isSelectable={false} isDeletable /> + + {/* Info: (20241008 - Julian) Voucher Detail */} +
+ {/* Info: (20241007 - Julian) Voucher date */} +
+

Voucher Date

+ {isDisplayDate} +
+ {/* Info: (20241007 - Julian) Voucher type */} +
+

Voucher Type

+ {isDisplayType} +
+ {/* Info: (20241007 - Julian) Note */} +
+

Note

+ {isDisplayNote} +
+ {/* Info: (20241007 - Julian) Counterparty */} +
+

Counterparty

+ {isDisplayCounterParty} +
+ {/* Info: (20241007 - Julian) Recurring Entry */} +
+

Recurring Entry

+
+

{recurringStr}

+

{recurringPeriodStr}

+
+
+ {/* Info: (20241007 - Julian) Payable Amount */} +
+

Payable Amount

+

+ {numberWithCommas(payableAmount)} + TWD +

+
+ {/* Info: (20241007 - Julian) Paid Amount */} +
+

Paid Amount

+

+ {numberWithCommas(paidAmount)} + TWD +

+
+ {/* Info: (20241007 - Julian) Remain Amount */} +
+

Remain Amount

+

+ {numberWithCommas(remainAmount)} + TWD +

+
+ {/* Info: (20241007 - Julian) Reverse Vouchers */} +
+

Reverse Vouchers

+
{reverseVoucherList}
+
+ {/* Info: (20241007 - Julian) Asset */} + {/*
+

Asset

+
{displayAssetIds}
+
*/} +
+ + {/* Info: (20241008 - Julian) Voucher Line Block */} +
+ {/* Info: (20241008 - Julian) Voucher Line Header */} +
+

Accounting

+

Particulars

+

Debit

+

Credit

+
+ {/* Info: (20241008 - Julian) Voucher Line Items */} +
+ {voucherLineBlock} +
+ {/* Info: (20241008 - Julian) Voucher Line Total */} +
+
{numberWithCommas(totalDebit)}
+
{numberWithCommas(totalCredit)}
+
+
@@ -87,4 +378,4 @@ const getStaticPropsFunction = async ({ locale }: ILocale) => ({ export const getStaticProps = getStaticPropsFunction; -export default AddVoucherPage; +export default VoucherDetailPage;