@@ -7,15 +7,22 @@ import {
77 useContractTransactionAnalytics ,
88 useContractUniqueWalletAnalytics ,
99} from "data/analytics/hooks" ;
10+ import { differenceInCalendarDays , formatDate } from "date-fns" ;
1011import { useTrack } from "hooks/analytics/useTrack" ;
1112import { ArrowRightIcon } from "lucide-react" ;
1213import Link from "next/link" ;
1314import { useMemo , useState } from "react" ;
1415import type { ProjectMeta } from "../../../../../../team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types" ;
1516import { 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
2128export function ContractAnalyticsOverviewCard ( props : {
@@ -34,60 +41,13 @@ export function ContractAnalyticsOverviewCard(props: {
3441 } ) ( ) ,
3542 ) ;
3643 const [ endDate ] = useState ( new Date ( ) ) ;
37-
38- const wallets = useContractUniqueWalletAnalytics ( {
39- chainId : props . chainId ,
40- contractAddress : props . contractAddress ,
41- startDate,
42- endDate,
43- } ) ;
44-
45- const transactions = useContractTransactionAnalytics ( {
44+ const { data, precision, isPending } = useContractAnalyticsOverview ( {
4645 chainId : props . chainId ,
4746 contractAddress : props . contractAddress ,
4847 startDate,
4948 endDate,
5049 } ) ;
5150
52- const events = useContractEventAnalytics ( {
53- chainId : props . chainId ,
54- contractAddress : props . contractAddress ,
55- startDate,
56- endDate,
57- } ) ;
58-
59- const isPending =
60- wallets . isPending || transactions . isPending || events . isPending ;
61-
62- const mergedData = useMemo ( ( ) => {
63- if ( isPending ) {
64- return undefined ;
65- }
66-
67- const time = ( wallets . data || transactions . data || events . data || [ ] ) . map (
68- ( wallet ) => wallet . time ,
69- ) ;
70-
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-
82- return {
83- time,
84- wallets : wallet ?. count || 0 ,
85- transactions : transaction ?. count || 0 ,
86- events : event ?. count || 0 ,
87- } ;
88- } ) ;
89- } , [ wallets . data , transactions . data , events . data , isPending ] ) ;
90-
9151 const analyticsPath = buildContractPagePath ( {
9252 projectMeta : props . projectMeta ,
9353 chainIdOrSlug : props . chainSlug ,
@@ -111,10 +71,11 @@ export function ContractAnalyticsOverviewCard(props: {
11171 color : "hsl(var(--chart-3))" ,
11272 } ,
11373 } }
114- data = { mergedData || [ ] }
74+ data = { data || [ ] }
11575 isPending = { isPending }
11676 showLegend
11777 chartClassName = "aspect-[1.5] lg:aspect-[3]"
78+ toolTipLabelFormatter = { toolTipLabelFormatterWithPrecision ( precision ) }
11879 customHeader = {
11980 < div className = "flex items-center justify-between gap-4 border-b p-6 py-4" >
12081 < h2 className = "font-semibold text-xl tracking-tight" > Analytics</ h2 >
@@ -141,3 +102,109 @@ export function ContractAnalyticsOverviewCard(props: {
141102 />
142103 ) ;
143104}
105+
106+ export function useContractAnalyticsOverview ( props : {
107+ chainId : number ;
108+ contractAddress : string ;
109+ startDate : Date ;
110+ endDate : Date ;
111+ } ) {
112+ const { chainId, contractAddress, startDate, endDate } = props ;
113+ const wallets = useContractUniqueWalletAnalytics ( {
114+ chainId : chainId ,
115+ contractAddress : contractAddress ,
116+ startDate,
117+ endDate,
118+ } ) ;
119+
120+ const transactions = useContractTransactionAnalytics ( {
121+ chainId : chainId ,
122+ contractAddress : contractAddress ,
123+ startDate,
124+ endDate,
125+ } ) ;
126+
127+ const events = useContractEventAnalytics ( {
128+ chainId : chainId ,
129+ contractAddress : contractAddress ,
130+ startDate,
131+ endDate,
132+ } ) ;
133+
134+ const isPending =
135+ wallets . isPending || transactions . isPending || events . isPending ;
136+
137+ const { data, precision } = useMemo ( ( ) => {
138+ if ( isPending ) {
139+ return {
140+ data : undefined ,
141+ precision : "day" as const ,
142+ } ;
143+ }
144+
145+ const time = ( wallets . data || transactions . data || events . data || [ ] ) . map (
146+ ( wallet ) => wallet . time ,
147+ ) ;
148+
149+ // if the time difference between the first and last time is less than 3 days - use hour precision
150+ const firstTime = time [ 0 ] ;
151+ const lastTime = time [ time . length - 1 ] ;
152+ const timeDiff =
153+ firstTime && lastTime
154+ ? differenceInCalendarDays ( lastTime , firstTime )
155+ : undefined ;
156+
157+ const precision : "day" | "hour" = ! timeDiff
158+ ? "hour"
159+ : timeDiff < 3
160+ ? "hour"
161+ : "day" ;
162+
163+ return {
164+ data : time . map ( ( time ) => {
165+ const wallet = wallets . data ?. find (
166+ ( wallet ) =>
167+ getDateKey ( wallet . time , precision ) === getDateKey ( time , precision ) ,
168+ ) ;
169+ const transaction = transactions . data ?. find (
170+ ( transaction ) =>
171+ getDateKey ( transaction . time , precision ) ===
172+ getDateKey ( time , precision ) ,
173+ ) ;
174+
175+ const event = events . data ?. find ( ( event ) => {
176+ return (
177+ getDateKey ( event . time , precision ) === getDateKey ( time , precision )
178+ ) ;
179+ } ) ;
180+
181+ return {
182+ time,
183+ wallets : wallet ?. count || 0 ,
184+ transactions : transaction ?. count || 0 ,
185+ events : event ?. count || 0 ,
186+ } ;
187+ } ) ,
188+ precision,
189+ } ;
190+ } , [ wallets . data , transactions . data , events . data , isPending ] ) ;
191+
192+ return {
193+ data,
194+ precision,
195+ isPending,
196+ } ;
197+ }
198+
199+ export function toolTipLabelFormatterWithPrecision ( precision : "day" | "hour" ) {
200+ return function toolTipLabelFormatter ( _v : string , item : unknown ) {
201+ if ( Array . isArray ( item ) ) {
202+ const time = item [ 0 ] . payload . time as number ;
203+ return formatDate (
204+ new Date ( time ) ,
205+ precision === "day" ? "MMM d, yyyy" : "MMM d, yyyy hh:mm a" ,
206+ ) ;
207+ }
208+ return undefined ;
209+ } ;
210+ }
0 commit comments