Skip to content

Commit f4a55d5

Browse files
committed
fix, clean up, and refactor profiles / sessions
1 parent ddf0d8d commit f4a55d5

File tree

2 files changed

+89
-59
lines changed

2 files changed

+89
-59
lines changed

apps/dashboard/app/(main)/websites/[id]/profiles/_components/profiles-list.tsx

Lines changed: 46 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import { Loader2Icon, UserRound } from 'lucide-react';
44
import { useCallback, useEffect, useState } from 'react';
5-
import { Button } from '@/components/ui/button';
65
import { Card, CardContent } from '@/components/ui/card';
76
import { useProfilesData } from '@/hooks/use-dynamic-query';
87

@@ -20,7 +19,31 @@ type ProfileData = {
2019
os: string;
2120
country: string;
2221
region: string;
23-
sessions: any[];
22+
sessions: Array<{
23+
session_id: string;
24+
session_name: string;
25+
first_visit: string;
26+
last_visit: string;
27+
duration: number;
28+
duration_formatted: string;
29+
page_views: number;
30+
unique_pages: number;
31+
device: string;
32+
browser: string;
33+
os: string;
34+
country: string;
35+
region: string;
36+
referrer: string;
37+
events: Array<{
38+
event_id: string;
39+
time: string;
40+
event_name: string;
41+
path: string;
42+
error_message?: string;
43+
error_type?: string;
44+
properties: Record<string, unknown>;
45+
}>;
46+
}>;
2447
};
2548

2649
import { WebsitePageHeader } from '../../_components/website-page-header';
@@ -39,9 +62,8 @@ export function ProfilesList({ websiteId }: ProfilesListProps) {
3962
const [page, setPage] = useState(1);
4063
const [allProfiles, setAllProfiles] = useState<ProfileData[]>([]);
4164
const [loadMoreRef, setLoadMoreRef] = useState<HTMLDivElement | null>(null);
42-
const [showLoadMore, setShowLoadMore] = useState(false);
65+
4366
const [isInitialLoad, setIsInitialLoad] = useState(true);
44-
const [hasIntersected, setHasIntersected] = useState(false);
4567

4668
const { profiles, pagination, isLoading, isError, error } = useProfilesData(
4769
websiteId,
@@ -60,15 +82,16 @@ export function ProfilesList({ websiteId }: ProfilesListProps) {
6082
(entries: IntersectionObserverEntry[]) => {
6183
const [entry] = entries;
6284
if (entry.isIntersecting && pagination.hasNext && !isLoading) {
63-
setHasIntersected(true);
6485
setPage((prev) => prev + 1);
6586
}
6687
},
6788
[pagination.hasNext, isLoading]
6889
);
6990

7091
useEffect(() => {
71-
if (!loadMoreRef) return;
92+
if (!loadMoreRef) {
93+
return;
94+
}
7295

7396
const observer = new IntersectionObserver(handleIntersection, {
7497
threshold: 0.1,
@@ -86,34 +109,29 @@ export function ProfilesList({ websiteId }: ProfilesListProps) {
86109
if (profiles?.length) {
87110
setAllProfiles((prev) => {
88111
const existingProfiles = new Map(prev.map((p) => [p.visitor_id, p]));
112+
let hasNewProfiles = false;
113+
89114
for (const profile of profiles) {
90115
if (!existingProfiles.has(profile.visitor_id)) {
91-
existingProfiles.set(profile.visitor_id, profile);
116+
existingProfiles.set(
117+
profile.visitor_id,
118+
profile as unknown as ProfileData
119+
);
120+
hasNewProfiles = true;
92121
}
93122
}
94-
return Array.from(existingProfiles.values());
123+
124+
if (hasNewProfiles) {
125+
return Array.from(existingProfiles.values());
126+
}
127+
128+
return prev;
95129
});
96130
setIsInitialLoad(false);
97131
}
98132
}, [profiles]);
99133

100-
useEffect(() => {
101-
if (pagination.hasNext && !isLoading && !isInitialLoad && !hasIntersected) {
102-
const timer = setTimeout(() => {
103-
setShowLoadMore(true);
104-
}, 3000);
105-
return () => clearTimeout(timer);
106-
}
107-
setShowLoadMore(false);
108-
}, [pagination.hasNext, isLoading, isInitialLoad, hasIntersected]);
109-
110-
useEffect(() => {
111-
if (isLoading) {
112-
setHasIntersected(false);
113-
}
114-
}, [isLoading]);
115-
116-
if (isLoading) {
134+
if (isLoading && isInitialLoad) {
117135
return (
118136
<div className="space-y-6">
119137
<WebsitePageHeader
@@ -218,19 +236,13 @@ export function ProfilesList({ websiteId }: ProfilesListProps) {
218236
<Loader2Icon className="h-4 w-4 animate-spin" />
219237
<span className="text-sm">Loading more profiles...</span>
220238
</div>
221-
) : showLoadMore ? (
222-
<Button
223-
className="w-full"
224-
onClick={() => setPage((prev) => prev + 1)}
225-
variant="outline"
226-
>
227-
Load More Profiles
228-
</Button>
229239
) : null}
230240
</div>
231241
) : (
232242
<div className="text-center text-muted-foreground text-sm">
233-
All profiles loaded
243+
{allProfiles.length > 0
244+
? 'All profiles loaded'
245+
: 'No more profiles'}
234246
</div>
235247
)}
236248
</div>

apps/dashboard/app/(main)/websites/[id]/sessions/_components/sessions-list.tsx

Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,42 @@ interface SessionsListProps {
1313
websiteId: string;
1414
}
1515

16+
// Type for the transformed session data structure
17+
type SessionData = {
18+
session_id: string;
19+
session_name: string;
20+
first_visit: string;
21+
last_visit: string;
22+
duration: number;
23+
duration_formatted: string;
24+
page_views: number;
25+
unique_pages: number;
26+
device: string;
27+
browser: string;
28+
os: string;
29+
country: string;
30+
region: string;
31+
referrer: string;
32+
events: Array<{
33+
event_id: string;
34+
time: string;
35+
event_name: string;
36+
path: string;
37+
error_message?: string;
38+
error_type?: string;
39+
properties: Record<string, unknown>;
40+
}>;
41+
};
42+
1643
export function SessionsList({ websiteId }: SessionsListProps) {
1744
const [dateRange] = useState(() => getDefaultDateRange());
1845
const [expandedSessionId, setExpandedSessionId] = useState<string | null>(
1946
null
2047
);
2148
const [page, setPage] = useState(1);
22-
const [allSessions, setAllSessions] = useState<any[]>([]);
49+
const [allSessions, setAllSessions] = useState<SessionData[]>([]);
2350
const [loadMoreRef, setLoadMoreRef] = useState<HTMLDivElement | null>(null);
24-
const [showLoadMore, setShowLoadMore] = useState(false);
2551
const [isInitialLoad, setIsInitialLoad] = useState(true);
26-
const [hasIntersected, setHasIntersected] = useState(false);
2752

2853
const { sessions, pagination, isLoading, isError, error } = useSessionsData(
2954
websiteId,
@@ -42,15 +67,16 @@ export function SessionsList({ websiteId }: SessionsListProps) {
4267
(entries: IntersectionObserverEntry[]) => {
4368
const [entry] = entries;
4469
if (entry.isIntersecting && pagination.hasNext && !isLoading) {
45-
setHasIntersected(true);
4670
setPage((prev) => prev + 1);
4771
}
4872
},
4973
[pagination.hasNext, isLoading]
5074
);
5175

5276
useEffect(() => {
53-
if (!loadMoreRef) return;
77+
if (!loadMoreRef) {
78+
return;
79+
}
5480

5581
const observer = new IntersectionObserver(handleIntersection, {
5682
threshold: 0.1,
@@ -68,33 +94,25 @@ export function SessionsList({ websiteId }: SessionsListProps) {
6894
if (sessions?.length) {
6995
setAllSessions((prev) => {
7096
const existingSessions = new Map(prev.map((s) => [s.session_id, s]));
97+
let hasNewSessions = false;
98+
7199
for (const session of sessions) {
72100
if (!existingSessions.has(session.session_id)) {
73101
existingSessions.set(session.session_id, session);
102+
hasNewSessions = true;
74103
}
75104
}
76-
return Array.from(existingSessions.values());
105+
106+
if (hasNewSessions) {
107+
return Array.from(existingSessions.values());
108+
}
109+
110+
return prev;
77111
});
78112
setIsInitialLoad(false);
79113
}
80114
}, [sessions]);
81115

82-
useEffect(() => {
83-
if (pagination.hasNext && !isLoading && !isInitialLoad && !hasIntersected) {
84-
const timer = setTimeout(() => {
85-
setShowLoadMore(true);
86-
}, 3000);
87-
return () => clearTimeout(timer);
88-
}
89-
setShowLoadMore(false);
90-
}, [pagination.hasNext, isLoading, isInitialLoad, hasIntersected]);
91-
92-
useEffect(() => {
93-
if (isLoading) {
94-
setHasIntersected(false);
95-
}
96-
}, [isLoading]);
97-
98116
if (isLoading && isInitialLoad) {
99117
return (
100118
<div className="space-y-6">
@@ -181,7 +199,7 @@ export function SessionsList({ websiteId }: SessionsListProps) {
181199
<Card>
182200
<CardContent className="p-0">
183201
<div className="divide-y divide-border">
184-
{allSessions.map((session: any, index: number) => (
202+
{allSessions.map((session: SessionData, index: number) => (
185203
<SessionRow
186204
index={index}
187205
isExpanded={expandedSessionId === session.session_id}
@@ -200,15 +218,15 @@ export function SessionsList({ websiteId }: SessionsListProps) {
200218
<Loader2Icon className="h-4 w-4 animate-spin" />
201219
<span className="text-sm">Loading more sessions...</span>
202220
</div>
203-
) : showLoadMore ? (
221+
) : (
204222
<Button
205223
className="w-full"
206224
onClick={() => setPage((prev) => prev + 1)}
207225
variant="outline"
208226
>
209227
Load More Sessions
210228
</Button>
211-
) : null}
229+
)}
212230
</div>
213231
) : (
214232
<div className="text-center text-muted-foreground text-sm">

0 commit comments

Comments
 (0)