Skip to content

Commit 1146212

Browse files
feat: add fee breakdown tooltip to payment route component (#150)
1 parent c015b84 commit 1146212

File tree

7 files changed

+97
-141
lines changed

7 files changed

+97
-141
lines changed

package-lock.json

Lines changed: 16 additions & 120 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/app/globals.css

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
--foreground: 0 0% 3.9%;
88
--card: 0 0% 100%;
99
--card-foreground: 0 0% 3.9%;
10-
--popover: 0 0% 100%;
11-
--popover-foreground: 0 0% 3.9%;
10+
--popover: 0 0% 3.9%;
11+
--popover-foreground: 0 0% 98%;
1212
--primary: 0 0% 9%;
1313
--primary-foreground: 0 0% 98%;
1414
--secondary: 0 0% 96.1%;
@@ -34,8 +34,8 @@
3434
--foreground: 0 0% 98%;
3535
--card: 0 0% 3.9%;
3636
--card-foreground: 0 0% 98%;
37-
--popover: 0 0% 3.9%;
38-
--popover-foreground: 0 0% 98%;
37+
--popover: 0 0% 100%;
38+
--popover-foreground: 0 0% 3.9%;
3939
--primary: 0 0% 98%;
4040
--primary-foreground: 0 0% 9%;
4141
--secondary: 0 0% 14.9%;

src/app/i/[id]/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ import { Footer } from "@/components/footer";
33
import { Header } from "@/components/header";
44
import { InvoiceCreator } from "@/components/invoice-creator";
55
import { getInvoiceCount } from "@/lib/helpers/invoice";
6+
import { api } from "@/trpc/server";
67
import { ArrowLeft } from "lucide-react";
78
import type { Metadata } from "next";
89
import Link from "next/link";
910
import { notFound, redirect } from "next/navigation";
1011
import { getInvoiceMeLink } from "./helpers";
11-
import { api } from "@/trpc/server";
1212

1313
export const metadata: Metadata = {
1414
title: "Invoice Me | EasyInvoice",

src/components/dashboard/blocks/invoice-row.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,10 @@ export const InvoiceRow = ({ invoice, type, children }: InvoiceRowProps) => {
9595
{invoice?.recurrence?.startDate && (
9696
<span className="text-xs text-muted-foreground">
9797
from{" "}
98-
{format(new Date(invoice?.recurrence?.startDate), "do MMM yyyy")}
98+
{format(
99+
new Date(invoice?.recurrence?.startDate),
100+
"do MMM yyyy",
101+
)}
99102
</span>
100103
)}
101104
</div>

src/components/payment-route.tsx

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
import { Tooltip } from "@/components/ui/tooltip";
12
import type { PaymentRoute as PaymentRouteType } from "@/lib/types";
2-
import { ArrowRight, Globe, Zap } from "lucide-react";
3+
import { ArrowRight, Globe, Info, Zap } from "lucide-react";
34
import Image from "next/image";
45

56
interface RouteTypeInfo {
@@ -26,16 +27,13 @@ export function PaymentRoute({
2627
onClick,
2728
variant = "default",
2829
routeType,
29-
platformFee,
3030
}: PaymentRouteProps) {
3131
const isDirectPayment =
3232
routeType?.type === "direct" ||
3333
(route.id === "REQUEST_NETWORK_PAYMENT" && !route.isCryptoToFiat);
3434
const isGasFreePayment = routeType?.type === "same-chain-erc20";
3535
const isCryptoToFiat = routeType?.type === "crypto-to-fiat";
3636

37-
const nativeToken = route.chain === "POLYGON" ? "POL" : "ETH";
38-
3937
// Get the appropriate badge color and icon based on route type
4038
const getBadgeStyles = () => {
4139
if (isCryptoToFiat) {
@@ -71,6 +69,40 @@ export function PaymentRoute({
7169

7270
const { bgColor, textColor, icon } = getBadgeStyles();
7371

72+
// Format fee breakdown for tooltip
73+
const formatFeeBreakdown = () => {
74+
if (!route.feeBreakdown || route.feeBreakdown.length === 0) {
75+
return null;
76+
}
77+
78+
return (
79+
<div className="space-y-2 max-w-xs">
80+
<div className="font-medium text-popover-foreground">Fee Breakdown</div>
81+
{route.feeBreakdown.map((fee) => (
82+
<div
83+
key={`${fee.type}-${fee.provider}-${fee.stage}`}
84+
className="flex justify-between items-start text-xs"
85+
>
86+
<div className="flex-1">
87+
<div className="capitalize font-medium">
88+
{fee.type === "gas"
89+
? "Gas Fee"
90+
: fee.type === "crosschain"
91+
? "Crosschain Fee"
92+
: "Platform Fee"}
93+
</div>
94+
</div>
95+
<div className="text-right ml-2">
96+
<div className="font-medium">
97+
{Number(fee.amountInUSD).toFixed(6)} USD
98+
</div>
99+
</div>
100+
</div>
101+
))}
102+
</div>
103+
);
104+
};
105+
74106
return (
75107
<button
76108
type="button"
@@ -117,21 +149,31 @@ export function PaymentRoute({
117149
{route.fee === 0 ? (
118150
"No fee"
119151
) : (
120-
<span className="text-amber-700">
121-
{route.fee} {isDirectPayment ? nativeToken : route.token} fee
122-
</span>
152+
<div className="flex items-center gap-1 justify-end">
153+
<span className="text-amber-700">
154+
{Number(route?.feeInUSD)?.toFixed(6)} USD fee
155+
</span>
156+
{route.feeBreakdown && route.feeBreakdown.length > 0 && (
157+
<Tooltip
158+
tooltipTrigger={
159+
<button
160+
type="button"
161+
aria-label="Show fee breakdown"
162+
className="text-zinc-400 hover:text-zinc-600 transition-colors focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-zinc-400 rounded"
163+
onClick={(e) => e.stopPropagation()}
164+
>
165+
<Info className="w-3 h-3" aria-hidden="true" />
166+
</button>
167+
}
168+
tooltipContent={formatFeeBreakdown()}
169+
/>
170+
)}
171+
</div>
123172
)}
124173
</div>
125174
<div className="text-sm text-muted-foreground">
126175
{typeof route.speed === "number" ? `~${route.speed}s` : "Fast"}
127176
</div>
128-
{platformFee?.percentage && platformFee?.percentage > 0 && (
129-
<div className="text-sm text-muted-foreground mt-1">
130-
<span className="text-purple-600">
131-
{platformFee?.percentage}% {route.token} platform fee
132-
</span>
133-
</div>
134-
)}
135177
</div>
136178
</div>
137179
</button>

src/components/view-recurring-payments/view-recurring-payments.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,9 @@ export function ViewRecurringPayments({
147147

148148
<CardContent className="py-16">
149149
<div className="flex flex-col items-center justify-center space-y-4">
150-
<p className="text-muted-foreground">No recurring payouts found</p>
150+
<p className="text-muted-foreground">
151+
No recurring payouts found
152+
</p>
151153
<p className="text-muted-foreground text-sm">
152154
Your recurring payouts will appear here
153155
</p>

src/lib/types/index.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,25 @@ import type { inferRouterOutputs } from "@trpc/server";
55
export interface PaymentRoute {
66
id: string;
77
fee: number;
8+
feeInUSD: number;
89
speed: number | "FAST";
910
price_impact: number;
1011
chain: string;
1112
token: string;
1213
isCryptoToFiat?: boolean;
1314
platformFee?: number;
15+
feeBreakdown?: {
16+
type: "gas" | "crosschain" | "platform";
17+
stage: "sending" | "overall";
18+
provider: string;
19+
amount: string;
20+
amountInUSD: string;
21+
amountInGwei?: string | null;
22+
currency: string;
23+
network: string;
24+
rateProvider?: string;
25+
receiverAddress?: string;
26+
}[];
1427
}
1528

1629
export type SubscriptionWithDetails = RecurringPayment & {

0 commit comments

Comments
 (0)