From ae17be1163d1f530d8075987ac6fb8ae2686de5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cec=C3=ADlia=20Rom=C3=A3o?= Date: Wed, 14 Feb 2024 10:09:37 -0300 Subject: [PATCH 1/9] feat: future balance detail --- src/components/DisbursementDetails/index.tsx | 12 +++++++++++- src/pages/DisbursementDraftDetails.tsx | 13 +++++++++++++ src/pages/DisbursementsNew.tsx | 19 ++++++++++++++++++- 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/components/DisbursementDetails/index.tsx b/src/components/DisbursementDetails/index.tsx index bba2c0f..29651ed 100644 --- a/src/components/DisbursementDetails/index.tsx +++ b/src/components/DisbursementDetails/index.tsx @@ -25,6 +25,7 @@ import "./styles.scss"; interface DisbursementDetailsProps { variant: DisbursementStep; + assetBalance?: string; details?: Disbursement; csvFile?: File; onChange?: (state: Disbursement) => void; @@ -50,12 +51,14 @@ const initDetails: Disbursement = { createdAt: "", status: "DRAFT", statusHistory: [], - smsRegistrationMessageTemplate: "" + smsRegistrationMessageTemplate: "", + stats: undefined, }; export const DisbursementDetails: React.FC = ({ variant, details = initDetails, + assetBalance, csvFile, onChange, onValidate, @@ -244,6 +247,13 @@ export const DisbursementDetails: React.FC = ({ +
+ +
+ {Number(assetBalance) - Number(details.stats?.totalAmount)} +
+
+ {variant === "confirmation" ? (
diff --git a/src/pages/DisbursementDraftDetails.tsx b/src/pages/DisbursementDraftDetails.tsx index c919ccf..87d5563 100644 --- a/src/pages/DisbursementDraftDetails.tsx +++ b/src/pages/DisbursementDraftDetails.tsx @@ -57,6 +57,9 @@ export const DisbursementDraftDetails = () => { const [isDraftInProgress, setIsDraftInProgress] = useState(false); const [isResponseSuccess, setIsResponseSuccess] = useState(false); + const allBalances = organization.data.assetBalances?.[0].balances; + + console.log(organization.data.assetBalances); const dispatch: AppDispatch = useDispatch(); const navigate = useNavigate(); const { isLoading: csvDownloadIsLoading } = useDownloadCsvFile( @@ -286,6 +289,11 @@ export const DisbursementDraftDetails = () => { a.assetCode === draftDetails?.details.asset.code, + )?.balance + } csvFile={csvFile} /> { a.assetCode === draftDetails?.details.asset.code, + )?.balance + } /> { "organization", ); const { assetBalances, distributionAccountPublicKey } = organization.data; + const allBalances = assetBalances?.[0].balances; const [draftDetails, setDraftDetails] = useState(); const [customMessage, setCustomMessage] = useState(""); @@ -198,7 +199,14 @@ export const DisbursementsNew = () => { if (currentStep === "preview") { return (
- + a.assetCode === draftDetails?.asset.code) + ?.balance + } + /> { a.assetCode === draftDetails?.asset.code, + )?.balance + } csvFile={csvFile} /> { a.assetCode === draftDetails?.asset.code) + ?.balance + } onChange={(updatedState) => { if (apiError) { dispatch(clearDisbursementDraftsErrorAction()); From 59d244670b96a84a1d7eb82d5d3fc1b78c8afe4c Mon Sep 17 00:00:00 2001 From: Caio Teixeira Date: Fri, 16 Feb 2024 18:21:02 -0300 Subject: [PATCH 2/9] fix: useOrgAccount info to update organization balance state --- src/pages/DisbursementDraftDetails.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pages/DisbursementDraftDetails.tsx b/src/pages/DisbursementDraftDetails.tsx index 87d5563..d63e1f6 100644 --- a/src/pages/DisbursementDraftDetails.tsx +++ b/src/pages/DisbursementDraftDetails.tsx @@ -3,6 +3,7 @@ import { useNavigate, useParams } from "react-router-dom"; import { Badge, Heading, Link, Notification } from "@stellar/design-system"; import { useDispatch } from "react-redux"; import { useRedux } from "hooks/useRedux"; +import { useOrgAccountInfo } from "hooks/useOrgAccountInfo"; import { useDownloadCsvFile } from "hooks/useDownloadCsvFile"; import { AppDispatch } from "store"; @@ -59,7 +60,6 @@ export const DisbursementDraftDetails = () => { const allBalances = organization.data.assetBalances?.[0].balances; - console.log(organization.data.assetBalances); const dispatch: AppDispatch = useDispatch(); const navigate = useNavigate(); const { isLoading: csvDownloadIsLoading } = useDownloadCsvFile( @@ -110,6 +110,8 @@ export const DisbursementDraftDetails = () => { disbursementDetails.status, ]); + useOrgAccountInfo(organization.data.distributionAccountPublicKey); + useEffect(() => { setDraftDetails(disbursementDetails); dispatch(setDraftIdAction(disbursementDetails.details.id)); From 38899cd68e31a5503500e12ec11ef4553740b246 Mon Sep 17 00:00:00 2001 From: Caio Teixeira Date: Fri, 16 Feb 2024 18:21:57 -0300 Subject: [PATCH 3/9] fix: calculate total amount from file when disbursement is not saved yet --- src/pages/DisbursementsNew.tsx | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/pages/DisbursementsNew.tsx b/src/pages/DisbursementsNew.tsx index 415075d..db3c19b 100644 --- a/src/pages/DisbursementsNew.tsx +++ b/src/pages/DisbursementsNew.tsx @@ -156,9 +156,37 @@ export const DisbursementsNew = () => { if (apiError) { dispatch(clearDisbursementDraftsErrorAction()); } + calculateDisbursementTotalAmountFromFile(file); setCsvFile(file); }; + const calculateDisbursementTotalAmountFromFile = (file?: File) => { + if (file) { + const reader = new FileReader(); + reader.readAsText(file); + const handleLoadFile = () => { + const totalAmount = reader.result + ?.toString() + .split("\n") + .slice(1) + .reduce( + (accumulator, line) => + !line ? accumulator : accumulator + Number(line.split(",")[2]), + 0, + ); + + setDraftDetails({ + ...draftDetails, + stats: { + ...draftDetails?.stats, + totalAmount: totalAmount?.toString() ?? "0", + }, + } as Disbursement); + }; + reader.addEventListener("load", handleLoadFile, false); + } + }; + const handleViewDetails = () => { navigate(`${Routes.DISBURSEMENTS}/${disbursementDrafts.newDraftId}`); resetState(); From bf5c0c1b6046b8a3257f0939b8d3ee1167c38a3d Mon Sep 17 00:00:00 2001 From: Caio Teixeira Date: Mon, 19 Feb 2024 15:46:32 -0300 Subject: [PATCH 4/9] refactor: add negative balances in red and block disbursement confirmation --- src/components/DisbursementDetails/index.tsx | 14 ++++++---- .../DisbursementDetails/styles.scss | 4 +++ src/pages/DisbursementDraftDetails.tsx | 23 ++++++++-------- src/pages/DisbursementsNew.tsx | 27 +++++++++---------- 4 files changed, 38 insertions(+), 30 deletions(-) diff --git a/src/components/DisbursementDetails/index.tsx b/src/components/DisbursementDetails/index.tsx index 29651ed..3bb30cf 100644 --- a/src/components/DisbursementDetails/index.tsx +++ b/src/components/DisbursementDetails/index.tsx @@ -25,8 +25,8 @@ import "./styles.scss"; interface DisbursementDetailsProps { variant: DisbursementStep; - assetBalance?: string; details?: Disbursement; + futureBalance?: number; csvFile?: File; onChange?: (state: Disbursement) => void; onValidate?: (isValid: boolean) => void; @@ -58,7 +58,7 @@ const initDetails: Disbursement = { export const DisbursementDetails: React.FC = ({ variant, details = initDetails, - assetBalance, + futureBalance = 0, csvFile, onChange, onValidate, @@ -248,9 +248,13 @@ export const DisbursementDetails: React.FC = ({
- -
- {Number(assetBalance) - Number(details.stats?.totalAmount)} + +
= 0 ? "" : "DisbursementDetailsFields__negative" + }`} + > + {futureBalance}
diff --git a/src/components/DisbursementDetails/styles.scss b/src/components/DisbursementDetails/styles.scss index f186abb..98e95b7 100644 --- a/src/components/DisbursementDetails/styles.scss +++ b/src/components/DisbursementDetails/styles.scss @@ -19,4 +19,8 @@ font-weight: var(--font-weight-medium); margin-top: pxToRem(4px); } + + &__negative { + color: var(--color-red-60); + } } diff --git a/src/pages/DisbursementDraftDetails.tsx b/src/pages/DisbursementDraftDetails.tsx index d63e1f6..42a6da6 100644 --- a/src/pages/DisbursementDraftDetails.tsx +++ b/src/pages/DisbursementDraftDetails.tsx @@ -181,6 +181,14 @@ export const DisbursementDraftDetails = () => { resetState(); }; + const handleCalculateFutureBalance = (): number => { + const assetBalance = Number( + allBalances?.find((a) => a.assetCode === draftDetails?.details.asset.code) + ?.balance, + ); + return assetBalance - Number(draftDetails?.details.stats?.totalAmount); + }; + const handleSubmitDisbursement = ( event: React.FormEvent, ) => { @@ -236,7 +244,8 @@ export const DisbursementDraftDetails = () => { }} isDraftDisabled={!isCsvFileUpdated} isSubmitDisabled={ - !(Boolean(draftDetails) && Boolean(csvFile) && canUserSubmit) + !(Boolean(draftDetails) && Boolean(csvFile) && canUserSubmit) || + handleCalculateFutureBalance() < 0 } isDraftPending={disbursementDrafts.status === "PENDING"} actionType={disbursementDrafts.actionType} @@ -291,11 +300,7 @@ export const DisbursementDraftDetails = () => { a.assetCode === draftDetails?.details.asset.code, - )?.balance - } + futureBalance={handleCalculateFutureBalance()} csvFile={csvFile} /> { a.assetCode === draftDetails?.details.asset.code, - )?.balance - } + futureBalance={handleCalculateFutureBalance()} /> { const [customMessage, setCustomMessage] = useState(""); const [isDetailsValid, setIsDetailsValid] = useState(false); const [csvFile, setCsvFile] = useState(); + const [futureBalance, setFutureBalance] = useState(0); const [currentStep, setCurrentStep] = useState("edit"); const [isDraftInProgress, setIsDraftInProgress] = useState(false); @@ -182,6 +183,12 @@ export const DisbursementsNew = () => { totalAmount: totalAmount?.toString() ?? "0", }, } as Disbursement); + + // update future balance + const assetBalance = allBalances?.find( + (a) => a.assetCode === draftDetails?.asset.code, + )?.balance; + setFutureBalance(Number(assetBalance) - totalAmount!); }; reader.addEventListener("load", handleLoadFile, false); } @@ -208,7 +215,9 @@ export const DisbursementsNew = () => { Boolean(disbursementDrafts.newDraftId && currentStep === "preview") } isSubmitDisabled={ - organization.data.isApprovalRequired || !(draftDetails && csvFile) + organization.data.isApprovalRequired || + !(draftDetails && csvFile) || + futureBalance < 0 } isReviewDisabled={!isReviewEnabled} isDraftPending={disbursementDrafts.status === "PENDING"} @@ -230,10 +239,7 @@ export const DisbursementsNew = () => { a.assetCode === draftDetails?.asset.code) - ?.balance - } + futureBalance={futureBalance} /> { a.assetCode === draftDetails?.asset.code, - )?.balance - } + futureBalance={futureBalance} csvFile={csvFile} /> { a.assetCode === draftDetails?.asset.code) - ?.balance - } + futureBalance={futureBalance} onChange={(updatedState) => { if (apiError) { dispatch(clearDisbursementDraftsErrorAction()); From b2d0f15e8a2f57eccd171b7caa0f303f86af996a Mon Sep 17 00:00:00 2001 From: Caio Teixeira Date: Tue, 20 Feb 2024 14:24:46 -0300 Subject: [PATCH 5/9] refactor: address PR comments --- src/pages/DisbursementDraftDetails.tsx | 10 ++++++---- src/pages/DisbursementsNew.tsx | 5 ++++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/pages/DisbursementDraftDetails.tsx b/src/pages/DisbursementDraftDetails.tsx index 42a6da6..ed5e0c6 100644 --- a/src/pages/DisbursementDraftDetails.tsx +++ b/src/pages/DisbursementDraftDetails.tsx @@ -186,9 +186,11 @@ export const DisbursementDraftDetails = () => { allBalances?.find((a) => a.assetCode === draftDetails?.details.asset.code) ?.balance, ); - return assetBalance - Number(draftDetails?.details.stats?.totalAmount); + return assetBalance - Number(draftDetails?.details.stats?.totalAmount || 0); }; + const futureBalance = handleCalculateFutureBalance(); + const handleSubmitDisbursement = ( event: React.FormEvent, ) => { @@ -245,7 +247,7 @@ export const DisbursementDraftDetails = () => { isDraftDisabled={!isCsvFileUpdated} isSubmitDisabled={ !(Boolean(draftDetails) && Boolean(csvFile) && canUserSubmit) || - handleCalculateFutureBalance() < 0 + futureBalance < 0 } isDraftPending={disbursementDrafts.status === "PENDING"} actionType={disbursementDrafts.actionType} @@ -300,7 +302,7 @@ export const DisbursementDraftDetails = () => { { { const assetBalance = allBalances?.find( (a) => a.assetCode === draftDetails?.asset.code, )?.balance; - setFutureBalance(Number(assetBalance) - totalAmount!); + + if (totalAmount) { + setFutureBalance(Number(assetBalance) - totalAmount); + } }; reader.addEventListener("load", handleLoadFile, false); } From 9d871ed7709096acc5835d4a5db72ef99d8db523 Mon Sep 17 00:00:00 2001 From: Caio Teixeira Date: Fri, 23 Feb 2024 12:15:24 -0300 Subject: [PATCH 6/9] refactor: use BigNumber.js to avoid overflow --- src/components/DisbursementDetails/index.tsx | 5 ++++- src/pages/DisbursementDraftDetails.tsx | 9 ++++++--- src/pages/DisbursementsNew.tsx | 9 +++++++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/components/DisbursementDetails/index.tsx b/src/components/DisbursementDetails/index.tsx index 3bb30cf..5851da7 100644 --- a/src/components/DisbursementDetails/index.tsx +++ b/src/components/DisbursementDetails/index.tsx @@ -22,6 +22,7 @@ import { } from "types"; import "./styles.scss"; +import BigNumber from "bignumber.js"; interface DisbursementDetailsProps { variant: DisbursementStep; @@ -251,7 +252,9 @@ export const DisbursementDetails: React.FC = ({
= 0 ? "" : "DisbursementDetailsFields__negative" + BigNumber(futureBalance).gte(0) + ? "" + : "DisbursementDetailsFields__negative" }`} > {futureBalance} diff --git a/src/pages/DisbursementDraftDetails.tsx b/src/pages/DisbursementDraftDetails.tsx index ed5e0c6..acb1d16 100644 --- a/src/pages/DisbursementDraftDetails.tsx +++ b/src/pages/DisbursementDraftDetails.tsx @@ -31,6 +31,7 @@ import { DisbursementButtons } from "components/DisbursementButtons"; import { ErrorWithExtras } from "components/ErrorWithExtras"; import { DisbursementDraft, DisbursementStep } from "types"; +import BigNumber from "bignumber.js"; export const DisbursementDraftDetails = () => { const { id: draftId } = useParams(); @@ -182,11 +183,13 @@ export const DisbursementDraftDetails = () => { }; const handleCalculateFutureBalance = (): number => { - const assetBalance = Number( + const assetBalance = BigNumber( allBalances?.find((a) => a.assetCode === draftDetails?.details.asset.code) - ?.balance, + ?.balance || 0, ); - return assetBalance - Number(draftDetails?.details.stats?.totalAmount || 0); + return assetBalance + .minus(BigNumber(draftDetails?.details.stats?.totalAmount || 0)) + .toNumber(); }; const futureBalance = handleCalculateFutureBalance(); diff --git a/src/pages/DisbursementsNew.tsx b/src/pages/DisbursementsNew.tsx index 76593ea..24260a0 100644 --- a/src/pages/DisbursementsNew.tsx +++ b/src/pages/DisbursementsNew.tsx @@ -33,6 +33,7 @@ import { AccountBalances } from "components/AccountBalances"; import { ErrorWithExtras } from "components/ErrorWithExtras"; import { Disbursement, DisbursementStep } from "types"; +import BigNumber from "bignumber.js"; export const DisbursementsNew = () => { const { disbursementDrafts, organization } = useRedux( @@ -172,7 +173,11 @@ export const DisbursementsNew = () => { .slice(1) .reduce( (accumulator, line) => - !line ? accumulator : accumulator + Number(line.split(",")[2]), + !line + ? accumulator + : BigNumber(accumulator) + .plus(BigNumber(line.split(",")[2])) + .toNumber(), 0, ); @@ -220,7 +225,7 @@ export const DisbursementsNew = () => { isSubmitDisabled={ organization.data.isApprovalRequired || !(draftDetails && csvFile) || - futureBalance < 0 + BigNumber(futureBalance).lt(0) } isReviewDisabled={!isReviewEnabled} isDraftPending={disbursementDrafts.status === "PENDING"} From e0af409b9018b9a95327b157ebe0d29b848bb444 Mon Sep 17 00:00:00 2001 From: Caio Teixeira Date: Fri, 23 Feb 2024 12:20:22 -0300 Subject: [PATCH 7/9] fix: format asset amount --- src/components/DisbursementDetails/index.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/DisbursementDetails/index.tsx b/src/components/DisbursementDetails/index.tsx index 5851da7..8914478 100644 --- a/src/components/DisbursementDetails/index.tsx +++ b/src/components/DisbursementDetails/index.tsx @@ -23,6 +23,7 @@ import { import "./styles.scss"; import BigNumber from "bignumber.js"; +import { AssetAmount } from "components/AssetAmount"; interface DisbursementDetailsProps { variant: DisbursementStep; @@ -257,7 +258,10 @@ export const DisbursementDetails: React.FC = ({ : "DisbursementDetailsFields__negative" }`} > - {futureBalance} +
From 1cd28e0ec097a35e14b7774ba0322b5fe78a9dea Mon Sep 17 00:00:00 2001 From: Caio Teixeira Date: Fri, 23 Feb 2024 17:03:11 -0300 Subject: [PATCH 8/9] lint: fix import order --- src/components/DisbursementDetails/index.tsx | 4 ++-- src/pages/DisbursementDraftDetails.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/DisbursementDetails/index.tsx b/src/components/DisbursementDetails/index.tsx index 8914478..ef54ea7 100644 --- a/src/components/DisbursementDetails/index.tsx +++ b/src/components/DisbursementDetails/index.tsx @@ -5,11 +5,13 @@ import { Title, Notification, } from "@stellar/design-system"; +import BigNumber from "bignumber.js"; import { useWallets } from "apiQueries/useWallets"; import { useAssetsByWallet } from "apiQueries/useAssetsByWallet"; import { useCountries } from "apiQueries/useCountries"; import { useVerificationTypes } from "apiQueries/useVerificationTypes"; +import { AssetAmount } from "components/AssetAmount"; import { InfoTooltip } from "components/InfoTooltip"; import { formatUploadedFileDisplayName } from "helpers/formatUploadedFileDisplayName"; import { @@ -22,8 +24,6 @@ import { } from "types"; import "./styles.scss"; -import BigNumber from "bignumber.js"; -import { AssetAmount } from "components/AssetAmount"; interface DisbursementDetailsProps { variant: DisbursementStep; diff --git a/src/pages/DisbursementDraftDetails.tsx b/src/pages/DisbursementDraftDetails.tsx index acb1d16..7d1075c 100644 --- a/src/pages/DisbursementDraftDetails.tsx +++ b/src/pages/DisbursementDraftDetails.tsx @@ -5,6 +5,7 @@ import { useDispatch } from "react-redux"; import { useRedux } from "hooks/useRedux"; import { useOrgAccountInfo } from "hooks/useOrgAccountInfo"; import { useDownloadCsvFile } from "hooks/useDownloadCsvFile"; +import BigNumber from "bignumber.js"; import { AppDispatch } from "store"; import { @@ -31,7 +32,6 @@ import { DisbursementButtons } from "components/DisbursementButtons"; import { ErrorWithExtras } from "components/ErrorWithExtras"; import { DisbursementDraft, DisbursementStep } from "types"; -import BigNumber from "bignumber.js"; export const DisbursementDraftDetails = () => { const { id: draftId } = useParams(); From 57695d811ed455d924af664067dd8ce79183d09e Mon Sep 17 00:00:00 2001 From: Caio Teixeira Date: Fri, 23 Feb 2024 17:07:57 -0300 Subject: [PATCH 9/9] lint: fix import order --- src/pages/DisbursementsNew.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/DisbursementsNew.tsx b/src/pages/DisbursementsNew.tsx index 24260a0..3b22278 100644 --- a/src/pages/DisbursementsNew.tsx +++ b/src/pages/DisbursementsNew.tsx @@ -8,6 +8,7 @@ import { } from "@stellar/design-system"; import { useDispatch } from "react-redux"; import { useNavigate } from "react-router-dom"; +import BigNumber from "bignumber.js"; import { AppDispatch } from "store"; import { @@ -33,7 +34,6 @@ import { AccountBalances } from "components/AccountBalances"; import { ErrorWithExtras } from "components/ErrorWithExtras"; import { Disbursement, DisbursementStep } from "types"; -import BigNumber from "bignumber.js"; export const DisbursementsNew = () => { const { disbursementDrafts, organization } = useRedux(