From 6d235fe65fcf6de8f97669a8aff546425b446080 Mon Sep 17 00:00:00 2001 From: sstefdev Date: Sun, 24 Nov 2024 19:13:08 +0100 Subject: [PATCH 1/6] feat: added new statuses, styles and logic --- .../src/lib/dashboard/invoice-view.svelte | 156 ++++++++++++++---- 1 file changed, 126 insertions(+), 30 deletions(-) diff --git a/packages/invoice-dashboard/src/lib/dashboard/invoice-view.svelte b/packages/invoice-dashboard/src/lib/dashboard/invoice-view.svelte index 76419657..c2ff472d 100644 --- a/packages/invoice-dashboard/src/lib/dashboard/invoice-view.svelte +++ b/packages/invoice-dashboard/src/lib/dashboard/invoice-view.svelte @@ -21,6 +21,7 @@ // Icons import Check from "@requestnetwork/shared-icons/check.svelte"; import Download from "@requestnetwork/shared-icons/download.svelte"; + import InfoCircle from "@requestnetwork/shared-icons/info-circle.svelte"; // Utils import { formatDate } from "@requestnetwork/shared-utils/formatDate"; import { calculateItemTotal } from "@requestnetwork/shared-utils/invoiceTotals"; @@ -53,7 +54,6 @@ let currency: CurrencyTypes.CurrencyDefinition | undefined = getCurrencyFromManager(request.currencyInfo, currencyManager); let paymentCurrencies: (CurrencyTypes.CurrencyDefinition | undefined)[] = []; - let statuses: any = []; let isPaid = false; let loading = false; let requestData: any = null; @@ -72,6 +72,23 @@ let paymentNetworkExtension: | Types.Extension.IPaymentNetworkState | undefined; + let statuses: any[] = [ + { + name: "SIGN_TRANSACTION", + message: "Sign Transaction", + done: false, + }, + { + name: "PAYMENT_DETECTED", + message: "Payment Detected", + done: false, + }, + { + name: "CORRECT_NETWORK", + message: "Correct Network", + done: false, + }, + ]; const generateDetailParagraphs = (info: any) => { const fullName = [info?.firstName, info?.lastName] @@ -124,6 +141,7 @@ onMount(() => { checkInvoice(); + updateStatuses(); }); $: request, checkInvoice(); @@ -193,7 +211,7 @@ unsupportedNetwork = true; } } finally { - loading = false; + // loading = false; } }; @@ -204,7 +222,7 @@ requestData?.requestId! ); - statuses = [...statuses, "Waiting for payment"]; + // statuses = [...statuses, "SIGN_TRANSACTION"]; let paymentSettings = undefined; if ( @@ -233,13 +251,14 @@ ); await paymentTx.wait(); - statuses = [...statuses, "Payment detected"]; + // statuses = [...statuses, "PAYMENT_DETECTED"]; + while (requestData.balance?.balance! < requestData.expectedAmount) { requestData = await _request?.refresh(); await new Promise((resolve) => setTimeout(resolve, 1000)); } - statuses = [...statuses, "Payment confirmed"]; + // statuses = [...statuses, "CORRECT_NETWORK"]; isPaid = true; loading = false; statuses = []; @@ -351,6 +370,28 @@ ? `${integerPart}.${decimalPart.substring(0, maxDecimalDigits)}` : value; } + + const currentStatusIndex = statuses.length - 1; + + const getStatusColor = (index: number) => { + if (statuses[index].done) return "green"; + return "blue"; + }; + + const updateStatuses = async () => { + statuses[0].done = true; + statuses = statuses; + + await new Promise((resolve) => setTimeout(resolve, 2000)); + + statuses[1].done = true; + statuses = statuses; + + await new Promise((resolve) => setTimeout(resolve, 2000)); + + statuses[2].done = true; + statuses = statuses; + };
{#if statuses.length > 0 && loading} - {#each statuses as status, index (index)} -
- {status || "-"} - {#if (index === 0 && statuses.length === 2) || (index === 1 && statuses.length === 3)} - - - - {/if} -
- {/each} +
+
    + {#each statuses as status, index} +
  1. + + {#if status.done} + + {:else} + + {/if} + + {status.message} + {#if index < 2} +
    + {/if} +
  2. + {/each} +
+
{/if}
- {#if loading} -
Loading...
- {:else if !correctChain && !isPayee} + {#if !correctChain && !isPayee}
From fe382b155d766dcd0526ea56c65d13fb9208199c Mon Sep 17 00:00:00 2001 From: sstefdev Date: Mon, 16 Dec 2024 20:21:59 +0100 Subject: [PATCH 5/6] feat: added dynamic button, added erc-20 approval and network statuses --- package-lock.json | 6 +- .../src/lib/dashboard/invoice-view.svelte | 306 ++++++++++++------ .../src/lib/view-requests.svelte | 43 +-- 3 files changed, 232 insertions(+), 123 deletions(-) diff --git a/package-lock.json b/package-lock.json index b0a36ab5..2b5b0f86 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11007,7 +11007,7 @@ }, "packages/create-invoice-form": { "name": "@requestnetwork/create-invoice-form", - "version": "0.11.8", + "version": "0.11.10", "license": "MIT", "dependencies": { "@requestnetwork/data-format": "0.19.4", @@ -11027,7 +11027,7 @@ }, "packages/invoice-dashboard": { "name": "@requestnetwork/invoice-dashboard", - "version": "0.11.5", + "version": "0.11.8", "license": "MIT", "dependencies": { "@requestnetwork/payment-detection": "0.48.0", @@ -11062,7 +11062,7 @@ }, "packages/payment-widget": { "name": "@requestnetwork/payment-widget", - "version": "0.3.5", + "version": "0.3.6", "license": "MIT", "dependencies": { "@requestnetwork/payment-processor": "0.51.0", diff --git a/packages/invoice-dashboard/src/lib/dashboard/invoice-view.svelte b/packages/invoice-dashboard/src/lib/dashboard/invoice-view.svelte index 101173f3..858634eb 100644 --- a/packages/invoice-dashboard/src/lib/dashboard/invoice-view.svelte +++ b/packages/invoice-dashboard/src/lib/dashboard/invoice-view.svelte @@ -20,9 +20,7 @@ import Button from "@requestnetwork/shared-components/button.svelte"; import Tooltip from "@requestnetwork/shared-components/tooltip.svelte"; // Icons - import Check from "@requestnetwork/shared-icons/check.svelte"; import Download from "@requestnetwork/shared-icons/download.svelte"; - import InfoCircle from "@requestnetwork/shared-icons/info-circle.svelte"; // Utils import { formatDate } from "@requestnetwork/shared-utils/formatDate"; import { checkStatus } from "@requestnetwork/shared-utils/checkStatus"; @@ -77,7 +75,7 @@ { name: "CORRECT_NETWORK", message: "Correct Network", - done: false, + done: correctChain, }, { name: "SIGN_TRANSACTION", @@ -93,6 +91,8 @@ let status = checkStatus(requestData || request); + let isSigningTransaction = false; + const generateDetailParagraphs = (info: any) => { const fullName = [info?.firstName, info?.lastName] .filter(Boolean) @@ -142,11 +142,14 @@ buyerInfo = generateDetailParagraphs(request?.contentData?.buyerInfo); } - onMount(() => { - checkInvoice(); - }); + let previousRequestId: string | null = null; - $: request, checkInvoice(); + $: { + if (request?.requestId !== previousRequestId) { + previousRequestId = request?.requestId; + checkInvoice(); + } + } $: { account = account; @@ -158,6 +161,7 @@ try { unsupportedNetwork = false; loading = true; + const singleRequest = await requestNetwork?.fromRequestId( request!.requestId ); @@ -167,6 +171,9 @@ requestData = singleRequest?.getData(); paymentNetworkExtension = getPaymentNetworkExtension(requestData); + isPaid = requestData?.balance?.balance >= requestData?.expectedAmount; + + // Handle payment currencies setup if ( paymentNetworkExtension?.id === Types.Extension.PAYMENT_NETWORK_ID.ANY_TO_ERC20_PROXY @@ -201,12 +208,49 @@ network = paymentCurrencies[0]?.network || "mainnet"; + // Check ERC20 approval if needed if (paymentCurrencies[0]?.type === Types.RequestLogic.CURRENCY.ERC20) { approved = await checkApproval(requestData, paymentCurrencies, signer); } else { approved = true; } + // Build status flow based on conditions + const baseStatuses = [ + { + name: "CORRECT_NETWORK", + message: "Correct Network", + done: correctChain, + }, + ]; + + // Add ERC20 approval status if needed + if ( + paymentCurrencies[0]?.type === Types.RequestLogic.CURRENCY.ERC20 && + !approved + ) { + baseStatuses.push({ + name: "APPROVE_ERC20", + message: "Approve ERC20", + done: false, + }); + } + + // Add transaction and payment detection statuses + baseStatuses.push( + { + name: "SIGN_TRANSACTION", + message: "Sign Transaction", + done: false, + }, + { + name: "PAYMENT_DETECTED", + message: "Payment Detected", + done: false, + } + ); + + statuses = baseStatuses; status = checkStatus(requestData || request); } catch (err: any) { console.error("Error while checking invoice: ", err); @@ -214,19 +258,25 @@ unsupportedNetwork = true; } } finally { - // loading = false; + loading = false; } }; const payTheRequest = async () => { try { loading = true; + isSigningTransaction = true; + + if (!requestNetwork || !requestData?.requestId) { + throw new Error("Request network or request data not available"); + } + const _request = await requestNetwork?.fromRequestId( - requestData?.requestId! + requestData.requestId ); - - const networkStatus = statuses.find((s) => s.name === "CORRECT_NETWORK"); - if (networkStatus) networkStatus.done = true; + if (!_request) { + throw new Error("Could not fetch request details"); + } let paymentSettings = undefined; if ( @@ -235,10 +285,14 @@ paymentNetworkExtension?.id === Types.Extension.PAYMENT_NETWORK_ID.ANY_TO_ETH_PROXY ) { + if (!currency || !paymentCurrencies[0]) { + throw new Error("Currency information not available"); + } + const { conversion } = await getConversionPaymentValues({ - baseAmount: requestData?.expectedAmount, - denominationCurrency: currency!, - selectedPaymentCurrency: paymentCurrencies[0]!, + baseAmount: requestData.expectedAmount, + denominationCurrency: currency, + selectedPaymentCurrency: paymentCurrencies[0], currencyManager, provider: signer, fromAddress: address, @@ -254,26 +308,56 @@ paymentSettings ); + // Update sign transaction status const signStatus = statuses.find((s) => s.name === "SIGN_TRANSACTION"); if (signStatus) signStatus.done = true; + statuses = [...statuses]; await paymentTx.wait(); + // Update payment detected status const paymentStatus = statuses.find((s) => s.name === "PAYMENT_DETECTED"); if (paymentStatus) paymentStatus.done = true; + statuses = [...statuses]; while (requestData.balance?.balance! < requestData.expectedAmount) { requestData = await _request?.refresh(); await new Promise((resolve) => setTimeout(resolve, 1000)); } + // Add a 2-second delay before completing + await new Promise((resolve) => setTimeout(resolve, 2000)); + + // Refresh the request data one final time + requestData = await _request?.refresh(); + request = requestData; // Update the parent request object too + isPaid = true; - loading = false; + status = checkStatus(requestData); isRequestPayed = true; } catch (err) { console.error("Something went wrong while paying : ", err); + + if ( + String(err).includes("ACTION_REJECTED") || + String(err).includes("User rejected") + ) { + toast.error("Transaction cancelled", { + description: "You rejected the transaction", + }); + } else { + toast.error("Payment failed", { + description: err instanceof Error ? err.message : String(err), + }); + } + + statuses = statuses.map((status) => ({ + ...status, + done: false, + })); + } finally { loading = false; - statuses = []; + isSigningTransaction = false; } }; @@ -306,12 +390,6 @@ try { loading = true; - statuses.push({ - name: "APPROVE_ERC20", - message: "Approve ERC20", - done: false, - }); - const approvers: { [key: string]: () => Promise } = { [Types.Extension.PAYMENT_NETWORK_ID.ERC20_FEE_PROXY_CONTRACT]: async () => { @@ -338,7 +416,9 @@ } const approveStatus = statuses.find((s) => s.name === "APPROVE_ERC20"); + if (approveStatus) approveStatus.done = true; + statuses = [...statuses]; } catch (err) { console.error("Something went wrong while approving ERC20: ", err); } finally { @@ -353,8 +433,14 @@ signer = await getEthersSigner(wagmiConfig); correctChain = true; + + // Update network switch status + const networkStatus = statuses.find((s) => s.name === "CORRECT_NETWORK"); + if (networkStatus) networkStatus.done = true; } catch (err) { console.error("Something went wrong while switching networks: ", err); + toast.error("Failed to switch network"); + throw err; } } @@ -387,20 +473,19 @@ : value; } - const currentStatusIndex = statuses.length - 1; - async function handlePayment() { try { - if (!correctChain) { - await switchNetworkIfNeeded(network || "mainnet"); - return; - } + await switchNetworkIfNeeded(network || "mainnet"); if ( !approved && paymentCurrencies[0]?.type === Types.RequestLogic.CURRENCY.ERC20 ) { await approve(); + + const approveStatus = statuses.find((s) => s.name === "APPROVE_ERC20"); + if (approveStatus) approveStatus.done = true; + return; } @@ -410,6 +495,11 @@ toast.error("Payment process failed", { description: String(err), }); + // Reset statuses on error make them all false + statuses = statuses.map((status) => ({ + ...status, + done: false, + })); } } @@ -628,81 +718,83 @@ {/each} {/if}
-
-
- {#if statuses[0].done} -
    - {#each statuses as status, index} -
  • - +
    + {#if statuses?.length > 0} +
      + {#each statuses as status, index} +
    • - {#if status.done} - - - - {:else} - - - - {/if} - - {status.message} -
      -
    • - {/each} -
    - {/if} + + {#if status.done} + + + + {:else} + + + + {/if} + + {status.message} +
    +
  • + {/each} +
+ {/if} +
+ {/if} + {#if !isPayee && !unsupportedNetwork && !isPaid && !isSigningTransaction} +