Skip to content

Commit 837daab

Browse files
joaquim-vergesMananTank
authored andcommitted
[Dashboard] Fix asset page link and improve token claim UX (#7193)
1 parent 55e82a1 commit 837daab

File tree

11 files changed

+237
-144
lines changed

11 files changed

+237
-144
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { Input } from "./input";
2+
export function DecimalInput(props: {
3+
value: string;
4+
onChange: (value: string) => void;
5+
maxValue?: number;
6+
id?: string;
7+
className?: string;
8+
}) {
9+
return (
10+
<Input
11+
id={props.id}
12+
type="text"
13+
value={props.value}
14+
className={props.className}
15+
inputMode="decimal"
16+
onChange={(e) => {
17+
const number = Number(e.target.value);
18+
// ignore if string becomes invalid number
19+
if (Number.isNaN(number)) {
20+
return;
21+
}
22+
if (props.maxValue && number > props.maxValue) {
23+
return;
24+
}
25+
// replace leading multiple zeros with single zero
26+
let cleanedValue = e.target.value.replace(/^0+/, "0");
27+
// replace leading zero before decimal point
28+
if (!cleanedValue.includes(".")) {
29+
cleanedValue = cleanedValue.replace(/^0+/, "");
30+
}
31+
props.onChange(cleanedValue || "0");
32+
}}
33+
/>
34+
);
35+
}

apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/ContractOverviewPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ export const ContractOverviewPage: React.FC<ContractOverviewPageProps> = ({
5353
text: "View asset page",
5454
icon: <ExternalLinkIcon className="size-4" />,
5555
target: "_blank",
56-
link: `https://thirdweb.com/${chainSlug}/${contract.address}`,
56+
link: `/${chainSlug}/${contract.address}`,
5757
}}
5858
trackingCategory="erc20-contract"
5959
trackingLabel="view-asset-page"

apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/Analytics.tsx

Lines changed: 69 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,22 @@ import {
77
useContractTransactionAnalytics,
88
useContractUniqueWalletAnalytics,
99
} from "data/analytics/hooks";
10+
import { differenceInCalendarDays, formatDate } from "date-fns";
1011
import { useTrack } from "hooks/analytics/useTrack";
1112
import { ArrowRightIcon } from "lucide-react";
1213
import Link from "next/link";
1314
import { useMemo, useState } from "react";
1415
import type { ProjectMeta } from "../../../../../../team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types";
1516
import { buildContractPagePath } from "../../_utils/contract-page-path";
1617

17-
function getDayKey(date: Date) {
18-
return date.toISOString().split("T")[0];
18+
function getDateKey(date: Date, precision: "day" | "hour") {
19+
const dayKey = date.toISOString().split("T")[0];
20+
if (precision === "day") {
21+
return dayKey;
22+
}
23+
24+
const hourKey = date.getHours();
25+
return `${dayKey}-${hourKey}`;
1926
}
2027

2128
export function ContractAnalyticsOverviewCard(props: {
@@ -59,33 +66,59 @@ export function ContractAnalyticsOverviewCard(props: {
5966
const isPending =
6067
wallets.isPending || transactions.isPending || events.isPending;
6168

62-
const mergedData = useMemo(() => {
69+
const { data, precision } = useMemo(() => {
6370
if (isPending) {
64-
return undefined;
71+
return {
72+
data: undefined,
73+
precision: "day" as const,
74+
};
6575
}
6676

6777
const time = (wallets.data || transactions.data || events.data || []).map(
6878
(wallet) => wallet.time,
6979
);
7080

71-
return time.map((time) => {
72-
const wallet = wallets.data?.find(
73-
(wallet) => getDayKey(wallet.time) === getDayKey(time),
74-
);
75-
const transaction = transactions.data?.find(
76-
(transaction) => getDayKey(transaction.time) === getDayKey(time),
77-
);
78-
const event = events.data?.find((event) => {
79-
return getDayKey(event.time) === getDayKey(time);
80-
});
81+
// if the time difference between the first and last time is less than 3 days - use hour precision
82+
const firstTime = time[0];
83+
const lastTime = time[time.length - 1];
84+
const timeDiff =
85+
firstTime && lastTime
86+
? differenceInCalendarDays(lastTime, firstTime)
87+
: undefined;
8188

82-
return {
83-
time,
84-
wallets: wallet?.count || 0,
85-
transactions: transaction?.count || 0,
86-
events: event?.count || 0,
87-
};
88-
});
89+
const precision: "day" | "hour" = !timeDiff
90+
? "hour"
91+
: timeDiff < 3
92+
? "hour"
93+
: "day";
94+
95+
return {
96+
data: time.map((time) => {
97+
const wallet = wallets.data?.find(
98+
(wallet) =>
99+
getDateKey(wallet.time, precision) === getDateKey(time, precision),
100+
);
101+
const transaction = transactions.data?.find(
102+
(transaction) =>
103+
getDateKey(transaction.time, precision) ===
104+
getDateKey(time, precision),
105+
);
106+
107+
const event = events.data?.find((event) => {
108+
return (
109+
getDateKey(event.time, precision) === getDateKey(time, precision)
110+
);
111+
});
112+
113+
return {
114+
time,
115+
wallets: wallet?.count || 0,
116+
transactions: transaction?.count || 0,
117+
events: event?.count || 0,
118+
};
119+
}),
120+
precision,
121+
};
89122
}, [wallets.data, transactions.data, events.data, isPending]);
90123

91124
const analyticsPath = buildContractPagePath({
@@ -111,10 +144,11 @@ export function ContractAnalyticsOverviewCard(props: {
111144
color: "hsl(var(--chart-3))",
112145
},
113146
}}
114-
data={mergedData || []}
147+
data={data || []}
115148
isPending={isPending}
116149
showLegend
117150
chartClassName="aspect-[1.5] lg:aspect-[3]"
151+
toolTipLabelFormatter={toolTipLabelFormatterWithPrecision(precision)}
118152
customHeader={
119153
<div className="flex items-center justify-between gap-4 border-b p-6 py-4">
120154
<h2 className="font-semibold text-xl tracking-tight">Analytics</h2>
@@ -141,3 +175,16 @@ export function ContractAnalyticsOverviewCard(props: {
141175
/>
142176
);
143177
}
178+
179+
function toolTipLabelFormatterWithPrecision(precision: "day" | "hour") {
180+
return function toolTipLabelFormatter(_v: string, item: unknown) {
181+
if (Array.isArray(item)) {
182+
const time = item[0].payload.time as number;
183+
return formatDate(
184+
new Date(time),
185+
precision === "day" ? "MMM d, yyyy" : "MMM d, yyyy hh:mm a",
186+
);
187+
}
188+
return undefined;
189+
};
190+
}

apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/RecentTransfers.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
ChevronRightIcon,
1919
ExternalLinkIcon,
2020
} from "lucide-react";
21-
import { useState } from "react";
21+
import { useEffect, useState } from "react";
2222
import { type ThirdwebContract, toTokens } from "thirdweb";
2323
import type { ChainMetadata } from "thirdweb/chains";
2424
import {
@@ -199,6 +199,7 @@ export function RecentTransfers(props: {
199199
}) {
200200
const rowsPerPage = 10;
201201
const [page, setPage] = useState(0);
202+
const [hasFetchedOnce, setHasFetchedOnce] = useState(false);
202203

203204
const tokenQuery = useTokenTransfers({
204205
chainId: props.clientContract.chain.id,
@@ -207,11 +208,18 @@ export function RecentTransfers(props: {
207208
limit: rowsPerPage,
208209
});
209210

211+
// eslint-disable-next-line no-restricted-syntax
212+
useEffect(() => {
213+
if (!tokenQuery.isPending) {
214+
setHasFetchedOnce(true);
215+
}
216+
}, [tokenQuery.isPending]);
217+
210218
return (
211219
<div>
212220
<RecentTransfersUI
213221
data={tokenQuery.data ?? []}
214-
isPending={tokenQuery.isPending}
222+
isPending={tokenQuery.isPending && !hasFetchedOnce}
215223
rowsPerPage={rowsPerPage}
216224
tokenMetadata={{
217225
decimals: props.decimals,

0 commit comments

Comments
 (0)