Skip to content
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
4 changes: 2 additions & 2 deletions packages/create-invoice-form/src/lib/invoice/form-view.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@
}

.invoice-table-body-row th {
padding: 8px 0px 8px 8px;
padding: 12px 16px;
font-weight: 500;
white-space: nowrap;
}
Expand All @@ -469,7 +469,7 @@
}

.invoice-table-body td {
padding: 8px 0px;
padding: 12px 16px;
}

.invoice-summary {
Expand Down
18 changes: 13 additions & 5 deletions packages/create-invoice-form/src/lib/invoice/form.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,16 @@
return invoiceCurrency.hash === currency.hash;
});
}
$: if (!formData.issuedOn) {
formData.issuedOn = inputDateFormat(new Date());
}
$: if (!formData.dueDate) {
formData.dueDate = inputDateFormat(
new Date(new Date(formData.issuedOn).getTime() + 24 * 60 * 60 * 1000)
);
}
</script>

<form class="invoice-form">
Expand Down Expand Up @@ -585,17 +595,15 @@
<Input
id="issuedOn"
type="date"
value={inputDateFormat(new Date())}
value={formData.issuedOn}
label="Issued Date"
{handleInput}
/>
<Input
id="dueDate"
type="date"
min={inputDateFormat(formData.issuedOn)}
value={inputDateFormat(
new Date(new Date(formData.issuedOn).getTime() + 24 * 60 * 60 * 1000)
)}
min={formData.issuedOn}
value={formData.dueDate}
label="Due Date"
{handleInput}
/>
Expand Down
2 changes: 1 addition & 1 deletion packages/create-invoice-form/src/lib/utils/resetForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export function getInitialFormData() {
payerAddress: "",
payeeAddress: "",
dueDate: "",
issuedOn: new Date().toISOString(),
issuedOn: "",
miscellaneous: {
labels: [],
builderId: "",
Expand Down
115 changes: 100 additions & 15 deletions packages/invoice-dashboard/src/lib/dashboard/invoice-view.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script lang="ts">
import { toast } from "svelte-sonner";
import { getBalance } from "@wagmi/core";
import type { GetAccountReturnType } from "@wagmi/core";
import {
approveErc20,
Expand Down Expand Up @@ -90,6 +91,8 @@
];
let status = checkStatus(requestData || request);
let hasEnoughBalance = false;
let userBalance = "0";
let isSigningTransaction = false;
Expand Down Expand Up @@ -151,6 +154,12 @@
}
}
$: {
if (account && network) {
checkBalance();
}
}
$: {
account = account;
network = request?.currencyInfo?.network || "mainnet";
Expand Down Expand Up @@ -252,6 +261,7 @@
statuses = baseStatuses;
status = checkStatus(requestData || request);
await checkBalance();
} catch (err: any) {
console.error("Error while checking invoice: ", err);
if (String(err).includes("Unsupported payment")) {
Expand Down Expand Up @@ -469,6 +479,58 @@
: value;
}
function formatBalance(value: number, maxDecimals: number = 4): string {
return Number.isInteger(value)
? value.toString()
: value.toFixed(maxDecimals);
}
async function checkBalance() {
try {
if (!address || !paymentCurrencies[0] || !network) {
console.log("Missing required parameters for balance check:", {
address,
paymentCurrency: paymentCurrencies[0],
network,
});
return;
}
const invoiceNetworkId = Number(getNetworkIdFromNetworkName(network));
if (account.chainId !== invoiceNetworkId) {
hasEnoughBalance = false;
console.log("Wrong network - balance check skipped");
return;
}
if (paymentCurrencies[0]?.type === Types.RequestLogic.CURRENCY.ERC20) {
const balance = await getBalance(wagmiConfig, {
address,
token: paymentCurrencies[0].address as `0x${string}`,
chainId: invoiceNetworkId,
});
const balanceNum = BigInt(balance.formatted);
userBalance = formatBalance(balanceNum);
hasEnoughBalance = balance.value >= BigInt(request.expectedAmount);
} else {
const balance = await getBalance(wagmiConfig, {
address,
chainId: invoiceNetworkId,
});
const balanceNum = BigInt(balance.formatted);
userBalance = formatBalance(balanceNum);
hasEnoughBalance = balance.value >= BigInt(request.expectedAmount);
}
} catch (err) {
console.error("Error checking balance:", err);
hasEnoughBalance = false;
userBalance = "0";
}
}
const currentStatusIndex = statuses.length - 1;
async function handlePayment() {
try {
await switchNetworkIfNeeded(network || "mainnet");
Expand Down Expand Up @@ -776,20 +838,28 @@
</div>
</div>
{/if}
{#if !isPayee && !unsupportedNetwork && !isPaid && !isSigningTransaction}
<Button
className="pay-button"
type="button"
text={!correctChain
? "Switch Network"
: !approved &&
paymentCurrencies[0]?.type === Types.RequestLogic.CURRENCY.ERC20
? "Approve"
: "Pay Now"}
padding="px-[12px] py-[6px]"
onClick={handlePayment}
/>
{/if}
<div class="invoice-view-actions">
{#if !isPayee && !unsupportedNetwork && !isPaid && !isRequestPayed && !isSigningTransaction}
{#if !hasEnoughBalance}
<div class="balance-warning">
Insufficient funds: {userBalance}
{paymentCurrencies[0]?.symbol || "-"}
</div>
{/if}
<Button
type="button"
text={!correctChain
? "Switch Network"
: !approved &&
paymentCurrencies[0]?.type === Types.RequestLogic.CURRENCY.ERC20
? "Approve"
: "Pay Now"}
padding="px-[12px] py-[6px]"
onClick={handlePayment}
disabled={!hasEnoughBalance}
/>
{/if}
</div>

{#if unsupportedNetwork}
<div class="unsupported-network">Unsupported payment network!</div>
Expand Down Expand Up @@ -995,7 +1065,6 @@
flex-direction: column;
gap: 10px;
width: 100%;
margin-bottom: 32px;
}
.status {
Expand Down Expand Up @@ -1091,6 +1160,7 @@
display: flex;
align-items: center;
gap: 0.25rem;
justify-content: end;
}
:global(.invoice-view-actions button) {
Expand Down Expand Up @@ -1158,6 +1228,21 @@
text-decoration: underline;
}
.balance-warning {
color: #ef4444;
font-size: 0.875rem;
padding: 0.5rem;
border-radius: 0.375rem;
background-color: #fee2e2;
margin-right: 0.5rem;
}
:global(.invoice-view-actions button[disabled]) {
opacity: 0.5;
cursor: not-allowed;
background-color: #71717a !important;
}
:global(.pay-button) {
padding: 8px 12px !important;
width: fit-content;
Expand Down
2 changes: 1 addition & 1 deletion packages/invoice-dashboard/src/lib/view-requests.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -868,7 +868,7 @@
}

.tabs ul li {
width: 100px;
width: 110px;
display: inline-flex;
align-items: center;
justify-content: center;
Expand Down
5 changes: 4 additions & 1 deletion shared/components/status-label.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,15 @@

<style>
.status-indicator {
text-align: center;
display: inline-flex;
align-items: center;
padding: 6px 12px;
text-align: center;
width: fit-content;
border-radius: 8px;
font-weight: 500;
white-space: nowrap;
font-size: 14px;
}

.status-paid {
Expand Down
4 changes: 1 addition & 3 deletions shared/utils/formatAddress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ export const formatAddress = (
first: number = 6,
last: number = 4
): string => {
if (!checkAddress(address)) {
console.error("Invalid address!");
}
if (!address) return "";

return `${address.slice(0, first)}...${address.slice(-last)}`;
};
33 changes: 24 additions & 9 deletions shared/utils/initCurrencyManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,22 +62,30 @@ const defaultCurrencyIds = [
];

import { Types } from "@requestnetwork/request-client.js";
import { formattedCurrencyConversionPairs } from './currencyConversionPairs'
import { formattedCurrencyConversionPairs } from "./currencyConversionPairs";

export function initializeCurrencyManager(
customCurrencies: CurrencyTypes.CurrencyInput[] = []
): CurrencyManager {
// If customCurrencies is provided, use only those
if (customCurrencies?.length > 0) {
return new CurrencyManager(customCurrencies, {}, formattedCurrencyConversionPairs);
return new CurrencyManager(
customCurrencies,
{},
formattedCurrencyConversionPairs
);
}

// Otherwise, use default currencies
const defaultCurrencies = CurrencyManager.getDefaultList().filter(
(currency) => defaultCurrencyIds.includes(currency.id)
);

return new CurrencyManager(defaultCurrencies, {}, formattedCurrencyConversionPairs);
return new CurrencyManager(
defaultCurrencies,
{},
formattedCurrencyConversionPairs
);
}

export function initializeCurrencyManagerWithCurrencyIDS(
Expand All @@ -88,13 +96,20 @@ export function initializeCurrencyManagerWithCurrencyIDS(
});

return {
currencyManager: new CurrencyManager(currencies, {}, formattedCurrencyConversionPairs),
currencyManager: new CurrencyManager(
currencies,
{},
formattedCurrencyConversionPairs
),
currencies,
};
}

export const getCurrencySupportedNetworksForConversion = (currencyHash: string, currencyManager: any) : (string | undefined)[] => {
return Object.keys(currencyManager.conversionPairs).filter((network) =>
currencyManager.conversionPairs[network][currencyHash]
);
}
export const getCurrencySupportedNetworksForConversion = (
currencyHash: string,
currencyManager: any
): (string | undefined)[] => {
return Object.keys(currencyManager.conversionPairs).filter(
(network) => currencyManager.conversionPairs[network][currencyHash]
);
};
Loading