@@ -7,15 +7,22 @@ import {
7
7
useContractTransactionAnalytics ,
8
8
useContractUniqueWalletAnalytics ,
9
9
} from "data/analytics/hooks" ;
10
+ import { differenceInCalendarDays , formatDate } from "date-fns" ;
10
11
import { useTrack } from "hooks/analytics/useTrack" ;
11
12
import { ArrowRightIcon } from "lucide-react" ;
12
13
import Link from "next/link" ;
13
14
import { useMemo , useState } from "react" ;
14
15
import type { ProjectMeta } from "../../../../../../team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types" ;
15
16
import { buildContractPagePath } from "../../_utils/contract-page-path" ;
16
17
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 } ` ;
19
26
}
20
27
21
28
export function ContractAnalyticsOverviewCard ( props : {
@@ -34,60 +41,13 @@ export function ContractAnalyticsOverviewCard(props: {
34
41
} ) ( ) ,
35
42
) ;
36
43
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 ( {
46
45
chainId : props . chainId ,
47
46
contractAddress : props . contractAddress ,
48
47
startDate,
49
48
endDate,
50
49
} ) ;
51
50
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
-
91
51
const analyticsPath = buildContractPagePath ( {
92
52
projectMeta : props . projectMeta ,
93
53
chainIdOrSlug : props . chainSlug ,
@@ -111,10 +71,11 @@ export function ContractAnalyticsOverviewCard(props: {
111
71
color : "hsl(var(--chart-3))" ,
112
72
} ,
113
73
} }
114
- data = { mergedData || [ ] }
74
+ data = { data || [ ] }
115
75
isPending = { isPending }
116
76
showLegend
117
77
chartClassName = "aspect-[1.5] lg:aspect-[3]"
78
+ toolTipLabelFormatter = { toolTipLabelFormatterWithPrecision ( precision ) }
118
79
customHeader = {
119
80
< div className = "flex items-center justify-between gap-4 border-b p-6 py-4" >
120
81
< h2 className = "font-semibold text-xl tracking-tight" > Analytics</ h2 >
@@ -141,3 +102,109 @@ export function ContractAnalyticsOverviewCard(props: {
141
102
/>
142
103
) ;
143
104
}
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