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
49 changes: 37 additions & 12 deletions src/app/request/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,25 @@ import { fetchRequestPayments } from '@/lib/queries/request-payments';
import {
calculateLongPaymentReference,
calculateShortPaymentReference,
capitalize,
commonQueryOptions,
formatTimestamp,
getAmountWithCurrencySymbol,
getBalance,
getContentDataFromCreateTransaction,
getPaymentDataFromCreateTransaction,
getTransactionCreateParameters,
renderAddress,
} from '@/lib/utils';
import { ActorInfo } from '@requestnetwork/data-format';
import { useQuery } from '@tanstack/react-query';
import { Copy, File } from 'lucide-react';
import { Copy, File, Loader2 } from 'lucide-react';
import Link from 'next/link';
import { redirect } from 'next/navigation';
import TimeAgo from 'timeago-react';
import { JsonEditor } from 'json-edit-react';
import useExportPDF from '@/lib/hooks/use-export-pdf';
import { useState } from 'react';

interface RequestPageProps {
params: {
Expand Down Expand Up @@ -107,6 +110,7 @@ const ActorInfoSection = ({ actorInfo }: { actorInfo?: ActorInfo }) => {

export default function RequestPage({ params: { id } }: RequestPageProps) {
const { exportPDF } = useExportPDF();
const [isDownloading, setIsDownloading] = useState(false);

const { data: request, isLoading: isLoadingRequest } = useQuery({
queryKey: ['request', id],
Expand Down Expand Up @@ -151,6 +155,13 @@ export default function RequestPage({ params: { id } }: RequestPageProps) {

const createParameters = getTransactionCreateParameters(firstTransaction);
const contentData = getContentDataFromCreateTransaction(createParameters);
const paymentData = getPaymentDataFromCreateTransaction(createParameters);

const balanceCurrency =
paymentData?.acceptedTokens?.length > 0
? paymentData.acceptedTokens[0]
: '';

const buyerData = contentData?.buyerInfo;
const sellerData = contentData?.sellerInfo;

Expand All @@ -166,15 +177,23 @@ export default function RequestPage({ params: { id } }: RequestPageProps) {
? requestPayments[requestPayments?.length - 1]?.timestamp
: lastTransaction?.blockTimestamp;

const handleExportPDF = () => {
exportPDF({
...contentData,
currency: createParameters.currency,
currencyInfo: createParameters.currency,
payer: createParameters.payer,
payee: createParameters.payee,
expectedAmount: createParameters.expectedAmount,
});
const handleExportPDF = async () => {
setIsDownloading(true);
try {
await exportPDF({
...contentData,
currency: createParameters.currency,
currencyInfo: createParameters.currency,
payer: createParameters.payer,
payee: createParameters.payee,
expectedAmount: createParameters.expectedAmount,
paymentData,
});
} catch (error) {
console.error('Error exporting PDF:', error);
} finally {
Comment thread
rodrigopavezi marked this conversation as resolved.
setIsDownloading(false);
}
};

return (
Expand All @@ -201,7 +220,11 @@ export default function RequestPage({ params: { id } }: RequestPageProps) {
size="sm"
className="h-8 gap-1"
onClick={handleExportPDF}
disabled={isDownloading}
>
{isDownloading && (
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
)}
Comment thread
rodrigopavezi marked this conversation as resolved.
<File className="h-3.5 w-3.5" />
<span className="sr-only sm:not-sr-only sm:whitespace-nowrap">
Export PDF
Expand Down Expand Up @@ -263,7 +286,7 @@ export default function RequestPage({ params: { id } }: RequestPageProps) {
<td className="pl-16">
{getAmountWithCurrencySymbol(
BigInt(balance),
createParameters.currency.value,
balanceCurrency || '',
)}
</td>
</tr>
Expand Down Expand Up @@ -294,7 +317,9 @@ export default function RequestPage({ params: { id } }: RequestPageProps) {
<tr>
<td className="text-muted-foreground">Blockchain:</td>
<td className="pl-16">
{createParameters.currency?.network}
{paymentData?.network
? capitalize(paymentData?.network)
: ''}
</td>
</tr>
<tr>
Expand Down
18 changes: 16 additions & 2 deletions src/lib/hooks/use-export-pdf.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@
import { Invoice, InvoiceItem } from '@requestnetwork/data-format';
import { formatUnits, isAddress } from 'viem';
import { currencyManager } from '../currency-manager';
import { renderAddress } from '../utils';
import { capitalize, renderAddress } from '../utils';
import { PaymentData } from '../types'

declare global {
interface Window {
html2pdf: any;
}
}
const RENDER_DELAY_MS = 3000; // Define this at the top of the file or in a config

const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));

export default function useExportPDF() {
const loadScript = (src: string): Promise<void> => {
Expand Down Expand Up @@ -60,11 +64,17 @@ export default function useExportPDF() {
payer: any;
payee: any;
expectedAmount: any;
paymentData: PaymentData;
},
) => {
await ensureHtml2PdfLoaded();

const currencyDetails = getCurrencyDetails(invoice.currencyInfo?.value);
const paymentCurrencyDetails = getCurrencyDetails(
invoice.paymentData?.acceptedTokens?.length > 0
? invoice.paymentData.acceptedTokens[0]
: undefined
);

const content = `
<html>
Expand Down Expand Up @@ -102,8 +112,9 @@ export default function useExportPDF() {
</div>

<div style="margin-bottom: 20px;">
<strong>Payment Chain:</strong> ${invoice.currencyInfo?.network || '-'}<br>
<strong>Payment Chain:</strong> ${invoice?.paymentData?.network ? capitalize(invoice?.paymentData?.network) : '-'}<br>
<strong>Invoice Currency:</strong> ${currencyDetails?.symbol || '-'}<br>
<strong>Settlement Currency:</strong> ${paymentCurrencyDetails?.symbol || "-"}<br>
Comment thread
rodrigopavezi marked this conversation as resolved.
<strong>Invoice Type:</strong> Regular Invoice
</div>

Expand Down Expand Up @@ -202,6 +213,9 @@ export default function useExportPDF() {
element.innerHTML = content;
document.body.appendChild(element);

// add a delay to ensure the content is rendered before exporting
await sleep(RENDER_DELAY_MS);

Comment thread
rodrigopavezi marked this conversation as resolved.
await window.html2pdf().from(element).set(opt).save();

document.body.removeChild(element);
Expand Down
4 changes: 4 additions & 0 deletions src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,7 @@ export interface Channel {
topics: string[];
transactions: Transaction[];
}
export interface PaymentData {
acceptedTokens: string[];
network: string;
}
Comment thread
rodrigopavezi marked this conversation as resolved.
9 changes: 9 additions & 0 deletions src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,13 @@ export const getContentDataFromCreateTransaction = (
return contentData;
};

export const getPaymentDataFromCreateTransaction = (
createParameters: RequestLogicTypes.ICreateParameters,
) => {
const extensionData = createParameters?.extensionsData!;
return extensionData[0]?.parameters;
};
Comment thread
rodrigopavezi marked this conversation as resolved.

export const getBalance = (payments: Payment[] | undefined) => {
return payments
? payments
Expand All @@ -181,3 +188,5 @@ export const renderAddress = (info: ActorInfo | undefined) => {

export const safeTruncateEthAddress = (address: string) =>
truncateEthAddress(address || '');

export const capitalize = (str: string) => (str && str[0].toUpperCase() + str.slice(1)) || ""