33import { WalletAddress } from "@/components/blocks/wallet-address" ;
44import { PaginationButtons } from "@/components/pagination-buttons" ;
55import { Button } from "@/components/ui/button" ;
6- import { Switch } from "@/components/ui/switch" ;
76import {
8- type EmbeddedWalletUser ,
9- useEmbeddedWallets ,
10- } from "@3rdweb-sdk/react/hooks/useEmbeddedWallets" ;
7+ Tooltip ,
8+ TooltipContent ,
9+ TooltipProvider ,
10+ TooltipTrigger ,
11+ } from "@/components/ui/tooltip" ;
12+ import { useEmbeddedWallets } from "@3rdweb-sdk/react/hooks/useEmbeddedWallets" ;
1113import { createColumnHelper } from "@tanstack/react-table" ;
1214import { TWTable } from "components/shared/TWTable" ;
1315import { format } from "date-fns/format" ;
1416import Papa from "papaparse" ;
15- import { useCallback , useMemo , useState } from "react" ;
16- import { withinDays } from "utils/date-utils " ;
17+ import { useCallback , useState } from "react" ;
18+ import type { WalletUser } from "thirdweb/wallets " ;
1719
1820const ACTIVE_THRESHOLD_DAYS = 30 ;
21+ const getUserIdentifier = ( accounts : WalletUser [ "linkedAccounts" ] ) => {
22+ const mainDetail = accounts [ 0 ] ?. details ;
23+ return (
24+ mainDetail ?. email ??
25+ mainDetail ?. phone ??
26+ mainDetail ?. address ??
27+ mainDetail ?. id
28+ ) ;
29+ } ;
1930
20- const columnHelper = createColumnHelper < EmbeddedWalletUser > ( ) ;
21-
31+ const columnHelper = createColumnHelper < WalletUser > ( ) ;
2232const columns = [
23- columnHelper . accessor ( "ews_authed_user " , {
24- header : "Email " ,
33+ columnHelper . accessor ( "linkedAccounts " , {
34+ header : "User Identifier " ,
2535 enableColumnFilter : true ,
26- cell : ( cell ) => (
27- < span className = "text-sm" > { cell . getValue ( ) ?. [ 0 ] ?. email } </ span >
28- ) ,
36+ cell : ( cell ) => {
37+ const identifier = getUserIdentifier ( cell . getValue ( ) ) ;
38+ return < span className = "text-sm" > { identifier } </ span > ;
39+ } ,
40+ id : "user_identifier" ,
2941 } ) ,
30- columnHelper . accessor ( "embedded_wallet " , {
42+ columnHelper . accessor ( "wallets " , {
3143 header : "Address" ,
3244 cell : ( cell ) => {
33- const address = cell . getValue ( ) ?. [ 0 ] ?. address ;
45+ const address = cell . getValue ( ) [ 0 ] ?. address ;
3446 return address ? < WalletAddress address = { address } /> : null ;
3547 } ,
48+ id : "address" ,
3649 } ) ,
37- columnHelper . accessor ( "created_at " , {
50+ columnHelper . accessor ( "wallets " , {
3851 header : "Created" ,
3952 cell : ( cell ) => {
40- const value = cell . getValue ( ) ;
53+ const value = cell . getValue ( ) [ 0 ] ?. createdAt ;
4154
4255 if ( ! value ) {
4356 return ;
@@ -48,59 +61,64 @@ const columns = [
4861 </ span >
4962 ) ;
5063 } ,
64+ id : "created_at" ,
5165 } ) ,
52- columnHelper . accessor ( "last_accessed_at " , {
53- header : "Last login " ,
66+ columnHelper . accessor ( "linkedAccounts " , {
67+ header : "Login Methods " ,
5468 cell : ( cell ) => {
5569 const value = cell . getValue ( ) ;
56-
57- if ( ! value ) {
58- return ;
59- }
70+ const loginMethodsDisplay = value . reduce ( ( acc , curr ) => {
71+ if ( acc . length === 2 ) {
72+ acc . push ( "..." ) ;
73+ }
74+ if ( acc . length < 2 ) {
75+ acc . push ( curr . type ) ;
76+ }
77+ return acc ;
78+ } , [ ] as string [ ] ) ;
79+ const loginMethods = value . map ( ( v ) => v . type ) . join ( ", " ) ;
6080 return (
61- < span className = "text-sm" >
62- { format ( new Date ( value ) , "MMM dd, yyyy" ) }
63- </ span >
81+ < TooltipProvider >
82+ < Tooltip >
83+ < TooltipTrigger className = "text-sm" >
84+ { loginMethodsDisplay . join ( ", " ) }
85+ </ TooltipTrigger >
86+ < TooltipContent >
87+ < span className = "text-sm" > { loginMethods } </ span >
88+ </ TooltipContent >
89+ </ Tooltip >
90+ </ TooltipProvider >
6491 ) ;
6592 } ,
93+ id : "login_methods" ,
6694 } ) ,
6795] ;
6896
6997export const InAppWalletUsersPageContent = ( props : {
7098 clientId : string ;
7199 trackingCategory : string ;
72100} ) => {
73- const [ onlyActive , setOnlyActive ] = useState ( true ) ;
74- const walletsQuery = useEmbeddedWallets ( props . clientId ) ;
75- const wallets = walletsQuery ?. data || [ ] ;
76-
77- const activeWallets = useMemo ( ( ) => {
78- if ( ! wallets ) {
79- return [ ] ;
80- }
81-
82- return wallets . filter ( ( w ) => {
83- const lastAccessedAt = w . last_accessed_at ;
84- return (
85- lastAccessedAt && withinDays ( lastAccessedAt , ACTIVE_THRESHOLD_DAYS )
86- ) ;
87- } ) ;
88- } , [ wallets ] ) ;
89-
90- const theWalletsWeWant = useMemo ( ( ) => {
91- return ( onlyActive ? activeWallets : wallets ) ?? [ ] ;
92- } , [ activeWallets , onlyActive , wallets ] ) ;
101+ const [ activePage , setActivePage ] = useState ( 1 ) ;
102+ const walletsQuery = useEmbeddedWallets ( props . clientId , activePage ) ;
103+ const { users : wallets , totalPages } = walletsQuery ?. data || {
104+ users : [ ] ,
105+ totalPages : 1 ,
106+ } ;
93107
108+ // TODO: Make the download CSV grab all data instead of merely what's on the current page
94109 const downloadCSV = useCallback ( ( ) => {
95- if ( theWalletsWeWant . length === 0 ) {
110+ if ( wallets . length === 0 ) {
96111 return ;
97112 }
98113 const csv = Papa . unparse (
99- theWalletsWeWant . map ( ( row ) => ( {
100- email : row . ews_authed_user [ 0 ] ?. email ,
101- address : row . embedded_wallet ?. [ 0 ] ?. address || "" ,
102- created : format ( new Date ( row . created_at ) , "MMM dd, yyyy" ) ,
103- last_login : format ( new Date ( row . last_accessed_at ) , "MMM dd, yyyy" ) ,
114+ wallets . map ( ( row ) => ( {
115+ user_identifier : getUserIdentifier ( row . linkedAccounts ) ,
116+ address : row . wallets [ 0 ] ?. address || "" ,
117+ created : format (
118+ new Date ( row . wallets [ 0 ] ?. createdAt ?? "" ) ,
119+ "MMM dd, yyyy" ,
120+ ) ,
121+ login_methods : row . linkedAccounts . map ( ( acc ) => acc . type ) . join ( ", " ) ,
104122 } ) ) ,
105123 ) ;
106124 const csvUrl = URL . createObjectURL (
@@ -110,50 +128,33 @@ export const InAppWalletUsersPageContent = (props: {
110128 tempLink . href = csvUrl ;
111129 tempLink . setAttribute ( "download" , "download.csv" ) ;
112130 tempLink . click ( ) ;
113- } , [ theWalletsWeWant ] ) ;
114-
115- const [ activePage , setActivePage ] = useState ( 1 ) ;
116- const itemsPerPage = 20 ;
117- const totalPages =
118- theWalletsWeWant . length <= itemsPerPage
119- ? 1
120- : Math . ceil ( theWalletsWeWant . length / itemsPerPage ) ;
121-
122- const itemsToShow = useMemo ( ( ) => {
123- const startIndex = ( activePage - 1 ) * itemsPerPage ;
124- const endIndex = startIndex + itemsPerPage ;
125- return theWalletsWeWant . slice ( startIndex , endIndex ) ;
126- } , [ activePage , theWalletsWeWant ] ) ;
131+ } , [ wallets ] ) ;
127132
128133 return (
129134 < div >
130135 < div className = "flex flex-col gap-6" >
131136 { /* Top section */ }
132137 < div className = "flex items-center justify-between" >
133138 < Button
134- disabled = { theWalletsWeWant . length === 0 }
139+ disabled = { wallets . length === 0 }
135140 variant = "outline"
136141 onClick = { downloadCSV }
137142 size = "sm"
138143 >
139144 Download as .csv
140145 </ Button >
141146
142- < div className = "flex items-center justify-end gap-2" >
147+ { /* <div className="flex items-center justify-end gap-2">
143148 <p className="text-muted-foreground text-sm">
144149 Active last {ACTIVE_THRESHOLD_DAYS} days
145150 </p>
146- < Switch
147- checked = { onlyActive }
148- onCheckedChange = { ( v ) => setOnlyActive ( v ) }
149- disabled = { wallets . length === 0 }
150- />
151- </ div >
151+ <Switch checked={true} disabled={wallets.length === 0} />
152+ </div> */ }
152153 </ div >
153154
154155 < TWTable
155156 title = "active in-app wallets"
156- data = { itemsToShow }
157+ data = { wallets }
157158 columns = { columns }
158159 isPending = { walletsQuery . isPending }
159160 isFetched = { walletsQuery . isFetched }
0 commit comments