11'use client' ;
22
33import { SpinnerIcon , UsersIcon } from '@phosphor-icons/react' ;
4- import { useAtom } from 'jotai' ;
54import dynamic from 'next/dynamic' ;
6- import { useCallback , useEffect , useMemo , useState } from 'react' ;
5+ import { useCallback , useEffect , useState } from 'react' ;
76import { Card , CardContent } from '@/components/ui/card' ;
87import { useProfilesData } from '@/hooks/use-dynamic-query' ;
9- import {
10- dynamicQueryFiltersAtom ,
11- formattedDateRangeAtom ,
12- timeGranularityAtom ,
13- } from '@/stores/jotai/filterAtoms' ;
148
159// Type adapter for the new profile data structure
1610type ProfileData = {
@@ -53,7 +47,8 @@ type ProfileData = {
5347 } > ;
5448} ;
5549
56-
50+ import { WebsitePageHeader } from '../../_components/website-page-header' ;
51+ import { getDefaultDateRange } from './profile-utils' ;
5752
5853const ProfileRow = dynamic (
5954 ( ) => import ( './profile-row' ) . then ( ( mod ) => ( { default : mod . ProfileRow } ) ) ,
@@ -71,20 +66,7 @@ interface ProfilesListProps {
7166}
7267
7368export function ProfilesList ( { websiteId } : ProfilesListProps ) {
74- // Use shared state atoms for consistency
75- const [ formattedDateRangeState ] = useAtom ( formattedDateRangeAtom ) ;
76- const [ currentGranularity ] = useAtom ( timeGranularityAtom ) ;
77- const [ filters ] = useAtom ( dynamicQueryFiltersAtom ) ;
78-
79- const dateRange = useMemo (
80- ( ) => ( {
81- start_date : formattedDateRangeState . startDate ,
82- end_date : formattedDateRangeState . endDate ,
83- granularity : currentGranularity ,
84- } ) ,
85- [ formattedDateRangeState , currentGranularity ]
86- ) ;
87-
69+ const [ dateRange ] = useState ( ( ) => getDefaultDateRange ( ) ) ;
8870 const [ expandedProfileId , setExpandedProfileId ] = useState < string | null > (
8971 null
9072 ) ;
@@ -98,17 +80,9 @@ export function ProfilesList({ websiteId }: ProfilesListProps) {
9880 websiteId ,
9981 dateRange ,
10082 25 ,
101- page ,
102- filters
83+ page
10384 ) ;
10485
105- // Reset page and profiles when dateRange or filters change
106- useEffect ( ( ) => {
107- setPage ( 1 ) ;
108- setAllProfiles ( [ ] ) ;
109- setIsInitialLoad ( true ) ;
110- } , [ dateRange . start_date , dateRange . end_date , dateRange . granularity , JSON . stringify ( filters ) ] ) ;
111-
11286 const toggleProfile = useCallback ( ( profileId : string ) => {
11387 setExpandedProfileId ( ( currentId ) =>
11488 currentId === profileId ? null : profileId
@@ -170,93 +144,121 @@ export function ProfilesList({ websiteId }: ProfilesListProps) {
170144
171145 if ( isLoading && isInitialLoad ) {
172146 return (
173- < Card >
174- < CardContent >
175- < div className = "space-y-3" >
176- { [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 ] . map ( ( i ) => (
177- < div
178- className = "h-16 animate-pulse rounded bg-muted/20"
179- key = { i }
180- />
181- ) ) }
182- </ div >
183- < div className = "flex items-center justify-center pt-4" >
184- < div className = "flex items-center gap-2 text-muted-foreground" >
185- < SpinnerIcon className = "h-4 w-4 animate-spin" />
186- < span className = "text-sm" > Loading profiles...</ span >
147+ < div className = "space-y-6" >
148+ < WebsitePageHeader
149+ description = "Visitor profiles with session data and behavior patterns"
150+ icon = { < UsersIcon className = "h-6 w-6 text-primary" /> }
151+ title = "Recent Profiles"
152+ variant = "minimal"
153+ websiteId = { websiteId }
154+ />
155+ < Card >
156+ < CardContent >
157+ < div className = "space-y-3" >
158+ { [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 ] . map ( ( i ) => (
159+ < div
160+ className = "h-16 animate-pulse rounded bg-muted/20"
161+ key = { i }
162+ />
163+ ) ) }
187164 </ div >
188- </ div >
189- </ CardContent >
190- </ Card >
165+ < div className = "flex items-center justify-center pt-4" >
166+ < div className = "flex items-center gap-2 text-muted-foreground" >
167+ < SpinnerIcon className = "h-4 w-4 animate-spin" />
168+ < span className = "text-sm" > Loading profiles...</ span >
169+ </ div >
170+ </ div >
171+ </ CardContent >
172+ </ Card >
173+ </ div >
191174 ) ;
192175 }
193176
194177 if ( isError ) {
195178 return (
196- < Card >
197- < CardContent >
198- < div className = "flex flex-col items-center py-12 text-center text-muted-foreground" >
199- < UsersIcon className = "mb-4 h-12 w-12 opacity-50" />
200- < p className = "mb-2 font-medium text-lg" > Failed to load profiles </ p >
201- < p className = "text-sm" >
202- { error ?. message || 'There was an error loading the profiles' }
203- </ p >
204- </ div >
205- </ CardContent >
206- </ Card >
179+ < div className = "space-y-6" >
180+ < WebsitePageHeader
181+ description = "Visitor profiles with session data and behavior patterns"
182+ errorMessage = { error ?. message || 'Failed to load profiles' }
183+ hasError = { true }
184+ icon = { < UsersIcon className = "h-6 w-6 text-primary" /> }
185+ title = "Recent Profiles"
186+ variant = "minimal"
187+ websiteId = { websiteId }
188+ / >
189+ </ div >
207190 ) ;
208191 }
209192
210193 if ( ! allProfiles || allProfiles . length === 0 ) {
211194 return (
212- < Card >
213- < CardContent >
214- < div className = "flex flex-col items-center py-12 text-center text-muted-foreground" >
215- < UsersIcon className = "mb-4 h-12 w-12 opacity-50" />
216- < p className = "mb-2 font-medium text-lg" > No profiles found</ p >
217- < p className = "text-sm" >
218- Visitor profiles will appear here once users visit your website
219- </ p >
220- </ div >
221- </ CardContent >
222- </ Card >
195+ < div className = "space-y-6" >
196+ < WebsitePageHeader
197+ description = "Visitor profiles with session data and behavior patterns"
198+ icon = { < UsersIcon className = "h-6 w-6 text-primary" /> }
199+ title = "Recent Profiles"
200+ variant = "minimal"
201+ websiteId = { websiteId }
202+ />
203+ < Card >
204+ < CardContent >
205+ < div className = "flex flex-col items-center py-12 text-center text-muted-foreground" >
206+ < UsersIcon className = "mb-4 h-12 w-12 opacity-50" />
207+ < p className = "mb-2 font-medium text-lg" > No profiles found</ p >
208+ < p className = "text-sm" >
209+ Visitor profiles will appear here once users visit your website
210+ </ p >
211+ </ div >
212+ </ CardContent >
213+ </ Card >
214+ </ div >
223215 ) ;
224216 }
225217
226218 return (
227- < Card >
228- < CardContent className = "p-0" >
229- < div className = "divide-y divide-border" >
230- { allProfiles . map ( ( profile , index ) => (
231- < ProfileRow
232- index = { index }
233- isExpanded = { expandedProfileId === profile . visitor_id }
234- key = { `${ profile . visitor_id } -${ index } ` }
235- onToggle = { ( ) => toggleProfile ( profile . visitor_id ) }
236- profile = { profile }
237- />
238- ) ) }
239- </ div >
219+ < div className = "space-y-6" >
220+ < WebsitePageHeader
221+ description = "Visitor profiles with session data and behavior patterns"
222+ icon = { < UsersIcon className = "h-6 w-6 text-primary" /> }
223+ subtitle = { `${ allProfiles . length } loaded` }
224+ title = "Recent Profiles"
225+ variant = "minimal"
226+ websiteId = { websiteId }
227+ />
228+ < Card >
229+ < CardContent className = "p-0" >
230+ < div className = "divide-y divide-border" >
231+ { allProfiles . map ( ( profile , index ) => (
232+ < ProfileRow
233+ index = { index }
234+ isExpanded = { expandedProfileId === profile . visitor_id }
235+ key = { `${ profile . visitor_id } -${ index } ` }
236+ onToggle = { ( ) => toggleProfile ( profile . visitor_id ) }
237+ profile = { profile }
238+ />
239+ ) ) }
240+ </ div >
240241
241- < div className = "border-t p-4" ref = { setLoadMoreRef } >
242- { pagination . hasNext ? (
243- < div className = "flex justify-center" >
244- { isLoading ? (
245- < div className = "flex items-center gap-2 text-muted-foreground" >
246- < SpinnerIcon className = "h-4 w-4 animate-spin" />
247- < span className = "text-sm" > Loading more profiles...</ span >
248- </ div >
249- ) : null }
250- </ div >
251- ) : (
252- < div className = "text-center text-muted-foreground text-sm" >
253- { allProfiles . length > 0
254- ? 'All profiles loaded'
255- : 'No more profiles' }
256- </ div >
257- ) }
258- </ div >
259- </ CardContent >
260- </ Card >
242+ < div className = "border-t p-4" ref = { setLoadMoreRef } >
243+ { pagination . hasNext ? (
244+ < div className = "flex justify-center" >
245+ { isLoading ? (
246+ < div className = "flex items-center gap-2 text-muted-foreground" >
247+ < SpinnerIcon className = "h-4 w-4 animate-spin" />
248+ < span className = "text-sm" > Loading more profiles...</ span >
249+ </ div >
250+ ) : null }
251+ </ div >
252+ ) : (
253+ < div className = "text-center text-muted-foreground text-sm" >
254+ { allProfiles . length > 0
255+ ? 'All profiles loaded'
256+ : 'No more profiles' }
257+ </ div >
258+ ) }
259+ </ div >
260+ </ CardContent >
261+ </ Card >
262+ </ div >
261263 ) ;
262264}
0 commit comments