Skip to content

Commit 9dd4b33

Browse files
committed
cleanup users
1 parent 4a983fa commit 9dd4b33

File tree

8 files changed

+186
-151
lines changed

8 files changed

+186
-151
lines changed

apps/dashboard/app/(main)/websites/[id]/_components/utils/technology-helpers.tsx

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,34 +16,33 @@ const MOBILE_PREFIX_REGEX = /^Mobile\s+/;
1616
const MOBILE_SUFFIX_REGEX = /\s+Mobile$/;
1717

1818
// Types
19-
export interface DeviceTypeEntry {
19+
export type DeviceTypeEntry = {
2020
device_type: string;
2121
device_brand?: string;
2222
device_model?: string;
2323
visitors: number;
2424
pageviews?: number;
25-
}
25+
};
2626

27-
export interface BrowserVersionEntry {
27+
export type BrowserVersionEntry = {
2828
browser: string;
2929
version?: string;
3030
visitors: number;
3131
pageviews?: number;
3232
count?: number;
33-
}
33+
};
3434

35-
export interface TechnologyTableEntry {
35+
export type TechnologyTableEntry = {
3636
name: string;
3737
visitors: number;
3838
percentage: number;
3939
icon?: string;
4040
iconComponent?: React.ReactNode;
4141
category?: string;
42-
}
42+
};
4343

44-
// Enhanced device type icons with better styling
4544
export const getDeviceTypeIcon = (
46-
deviceType: string,
45+
deviceType: string | null | undefined,
4746
size: "sm" | "md" | "lg" = "md"
4847
) => {
4948
const sizeClasses = {
@@ -52,6 +51,12 @@ export const getDeviceTypeIcon = (
5251
lg: "size-5",
5352
};
5453

54+
if (!deviceType) {
55+
return (
56+
<HelpCircle className={`${sizeClasses[size]} text-muted-foreground`} />
57+
);
58+
}
59+
5560
const typeLower = deviceType.toLowerCase();
5661
const className = `${sizeClasses[size]}`;
5762

apps/dashboard/app/(main)/websites/[id]/users/[userId]/_components/session-row.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ function SessionRowInternal({
131131

132132
{/* Location */}
133133
<div className="flex items-center gap-1.5 overflow-hidden">
134-
<CountryFlag country={session.country_code} size="sm" />
134+
<CountryFlag country={session.country_code || ""} size="sm" />
135135
<span className="truncate">
136136
{session.country_name || session.country || "Unknown"}
137137
</span>
@@ -140,8 +140,8 @@ function SessionRowInternal({
140140
{/* Device Stack */}
141141
<div className="flex items-center gap-1">
142142
{getDeviceIcon(session.device_type)}
143-
<BrowserIcon name={session.browser_name} size="sm" />
144-
<OSIcon name={session.os_name} size="sm" />
143+
<BrowserIcon name={session.browser_name || "Unknown"} size="sm" />
144+
<OSIcon name={session.os_name || "Unknown"} size="sm" />
145145
</div>
146146

147147
{/* Referrer */}
@@ -160,7 +160,7 @@ function SessionRowInternal({
160160

161161
{/* Pages */}
162162
<span className="text-right font-medium tabular-nums">
163-
{session.page_views}
163+
{session.page_views ?? 0}
164164
</span>
165165

166166
{/* Events */}

apps/dashboard/app/(main)/websites/[id]/users/[userId]/page.tsx

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -220,9 +220,11 @@ function Header({
220220
</div>
221221
</div>
222222
<Badge
223-
variant={userProfile.total_sessions > 1 ? "default" : "secondary"}
223+
variant={
224+
(userProfile.total_sessions ?? 0) > 1 ? "default" : "secondary"
225+
}
224226
>
225-
{userProfile.total_sessions > 1 ? "Return" : "New"}
227+
{(userProfile.total_sessions ?? 0) > 1 ? "Return" : "New"}
226228
</Badge>
227229
</div>
228230
) : (
@@ -267,23 +269,23 @@ export default function UserDetailPage() {
267269
const transformSession = useCallback(
268270
(session: {
269271
session_id: string;
270-
first_visit: string;
271-
last_visit: string;
272-
page_views: number;
273-
country?: string;
274-
referrer?: string;
275-
device?: string;
276-
browser?: string;
277-
os?: string;
278-
events?: unknown[];
279-
session_name?: string;
272+
first_visit?: string | null;
273+
last_visit?: string | null;
274+
page_views?: number | null;
275+
country?: string | null;
276+
referrer?: string | null;
277+
device?: string | null;
278+
browser?: string | null;
279+
os?: string | null;
280+
events?: unknown[] | null;
281+
session_name?: string | null;
280282
}): Session => {
281283
const countryCode = getCountryCode(session.country || "");
282284
return {
283285
session_id: session.session_id,
284-
first_visit: session.first_visit,
285-
last_visit: session.last_visit,
286-
page_views: session.page_views,
286+
first_visit: session.first_visit || "",
287+
last_visit: session.last_visit || "",
288+
page_views: session.page_views ?? 0,
287289
visitor_id: userId as string,
288290
country: countryCode,
289291
country_name: session.country || "",
@@ -293,7 +295,7 @@ export default function UserDetailPage() {
293295
browser_name: session.browser || "",
294296
os_name: session.os || "",
295297
events: session.events || [],
296-
session_name: session.session_name,
298+
session_name: session.session_name || undefined,
297299
} as Session;
298300
},
299301
[userId]
@@ -321,16 +323,15 @@ export default function UserDetailPage() {
321323
(acc: number, s: { events?: unknown[] }) =>
322324
acc + (Array.isArray(s.events) ? s.events.length : 0),
323325
0
324-
) || 0;
326+
) ?? 0;
325327
const totalPages =
326328
userProfile.sessions?.reduce(
327329
(acc: number, s: { page_views?: number }) =>
328330
acc + (Number(s.page_views) || 0),
329331
0
330-
) || 0;
331-
const avgPagesPerSession = userProfile.total_sessions
332-
? totalPages / userProfile.total_sessions
333-
: 0;
332+
) ?? 0;
333+
const totalSessions = userProfile.total_sessions ?? 0;
334+
const avgPagesPerSession = totalSessions > 0 ? totalPages / totalSessions : 0;
334335

335336
return (
336337
<div className="flex h-full flex-col">
@@ -345,14 +346,14 @@ export default function UserDetailPage() {
345346
<StatItem
346347
icon={ChartLineIcon}
347348
label="Sessions"
348-
value={userProfile.total_sessions}
349+
value={userProfile.total_sessions ?? 0}
349350
/>
350351
</div>
351352
<div className="bg-sidebar p-4">
352353
<StatItem
353354
icon={EyeIcon}
354355
label="Pageviews"
355-
value={userProfile.total_pageviews}
356+
value={userProfile.total_pageviews ?? 0}
356357
/>
357358
</div>
358359
<div className="bg-sidebar p-4">
@@ -418,12 +419,17 @@ export default function UserDetailPage() {
418419
value={userProfile.device || "Unknown"}
419420
/>
420421
<TechItem
421-
icon={<BrowserIcon name={userProfile.browser} size="md" />}
422+
icon={
423+
<BrowserIcon
424+
name={userProfile.browser || "Unknown"}
425+
size="md"
426+
/>
427+
}
422428
label="Browser"
423429
value={userProfile.browser || "Unknown"}
424430
/>
425431
<TechItem
426-
icon={<OSIcon name={userProfile.os} size="md" />}
432+
icon={<OSIcon name={userProfile.os || "Unknown"} size="md" />}
427433
label="Operating System"
428434
value={userProfile.os || "Unknown"}
429435
/>
@@ -487,13 +493,13 @@ export default function UserDetailPage() {
487493
<div className="grid grid-cols-2 gap-px border-b bg-border sm:grid-cols-4 lg:hidden">
488494
<div className="bg-background p-3">
489495
<p className="font-bold text-foreground text-xl tabular-nums">
490-
{userProfile.total_sessions}
496+
{userProfile.total_sessions ?? 0}
491497
</p>
492498
<p className="text-muted-foreground text-xs">Sessions</p>
493499
</div>
494500
<div className="bg-background p-3">
495501
<p className="font-bold text-foreground text-xl tabular-nums">
496-
{userProfile.total_pageviews}
502+
{userProfile.total_pageviews ?? 0}
497503
</p>
498504
<p className="text-muted-foreground text-xs">Pageviews</p>
499505
</div>

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

Lines changed: 39 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -51,42 +51,42 @@ const wwwRegex = /^www\./;
5151

5252
function SkeletonRow() {
5353
return (
54-
<TableRow>
55-
<TableCell>
56-
<div className="flex items-center gap-2">
57-
<Skeleton className="size-6 rounded-full" />
54+
<TableRow className="h-[49px]">
55+
<TableCell className="h-[49px] py-2">
56+
<div className="flex items-center gap-2.5">
57+
<Skeleton className="size-6 shrink-0 rounded-full" />
5858
<Skeleton className="h-4 w-24" />
5959
</div>
6060
</TableCell>
61-
<TableCell>
61+
<TableCell className="h-[49px] py-2">
6262
<div className="flex items-center gap-2">
63-
<Skeleton className="size-5 rounded" />
63+
<Skeleton className="size-4 shrink-0 rounded" />
6464
<Skeleton className="h-4 w-16" />
6565
</div>
6666
</TableCell>
67-
<TableCell>
68-
<div className="flex gap-1">
69-
<Skeleton className="size-4 rounded" />
70-
<Skeleton className="size-4 rounded" />
71-
<Skeleton className="size-4 rounded" />
67+
<TableCell className="h-[49px] py-2">
68+
<div className="flex items-center gap-1">
69+
<Skeleton className="size-4 shrink-0 rounded" />
70+
<Skeleton className="size-4 shrink-0 rounded" />
71+
<Skeleton className="size-4 shrink-0 rounded" />
7272
</div>
7373
</TableCell>
74-
<TableCell>
74+
<TableCell className="h-[49px] py-2">
7575
<div className="flex items-center gap-1.5">
76-
<Skeleton className="size-3.5 rounded" />
76+
<Skeleton className="size-3.5 shrink-0 rounded" />
7777
<Skeleton className="h-4 w-16" />
7878
</div>
7979
</TableCell>
80-
<TableCell>
80+
<TableCell className="h-[49px] py-2">
8181
<Skeleton className="h-4 w-6" />
8282
</TableCell>
83-
<TableCell>
83+
<TableCell className="h-[49px] py-2">
8484
<Skeleton className="h-4 w-6" />
8585
</TableCell>
86-
<TableCell>
86+
<TableCell className="h-[49px] py-2">
8787
<Skeleton className="h-5 w-12 rounded-full" />
8888
</TableCell>
89-
<TableCell>
89+
<TableCell className="h-[49px] py-2">
9090
<Skeleton className="h-4 w-14" />
9191
</TableCell>
9292
</TableRow>
@@ -195,7 +195,8 @@ export function UsersList({ websiteId }: UsersListProps) {
195195
id: "location",
196196
header: "Location",
197197
cell: ({ row }) => {
198-
const countryCode = getCountryCode(row.original.country);
198+
const country = row.original.country || "";
199+
const countryCode = getCountryCode(country);
199200
const countryName = getCountryName(countryCode);
200201
const isUnknown = !countryCode || countryCode === "Unknown";
201202

@@ -217,16 +218,20 @@ export function UsersList({ websiteId }: UsersListProps) {
217218
{
218219
id: "device",
219220
header: "Device",
220-
cell: ({ row }) => (
221-
<div
222-
className="flex items-center gap-1"
223-
title={`${row.original.browser_name} on ${row.original.os_name}`}
224-
>
225-
{getDeviceIcon(row.original.device_type)}
226-
<BrowserIcon name={row.original.browser_name} size="sm" />
227-
<OSIcon name={row.original.os_name} size="sm" />
228-
</div>
229-
),
221+
cell: ({ row }) => {
222+
const browserName = row.original.browser_name || "Unknown";
223+
const osName = row.original.os_name || "Unknown";
224+
return (
225+
<div
226+
className="flex items-center gap-1"
227+
title={`${browserName} on ${osName}`}
228+
>
229+
{getDeviceIcon(row.original.device_type)}
230+
<BrowserIcon name={browserName} size="sm" />
231+
<OSIcon name={osName} size="sm" />
232+
</div>
233+
);
234+
},
230235
size: 80,
231236
},
232237
{
@@ -270,7 +275,7 @@ export function UsersList({ websiteId }: UsersListProps) {
270275
header: "Sessions",
271276
cell: ({ row }) => (
272277
<span className="font-medium tabular-nums">
273-
{row.original.session_count}
278+
{row.original.session_count ?? 0}
274279
</span>
275280
),
276281
size: 70,
@@ -280,7 +285,7 @@ export function UsersList({ websiteId }: UsersListProps) {
280285
header: "Pages",
281286
cell: ({ row }) => (
282287
<span className="font-medium tabular-nums">
283-
{row.original.total_events}
288+
{row.original.total_events ?? 0}
284289
</span>
285290
),
286291
size: 60,
@@ -289,7 +294,8 @@ export function UsersList({ websiteId }: UsersListProps) {
289294
id: "type",
290295
header: "Type",
291296
cell: ({ row }) => {
292-
const isReturning = row.original.session_count > 1;
297+
const sessionCount = row.original.session_count ?? 0;
298+
const isReturning = sessionCount > 1;
293299
return (
294300
<Badge variant={isReturning ? "default" : "secondary"}>
295301
{isReturning ? "Return" : "New"}
@@ -442,7 +448,7 @@ export function UsersList({ websiteId }: UsersListProps) {
442448
<TableBody>
443449
{table.getRowModel().rows.map((row) => (
444450
<TableRow
445-
className="cursor-pointer"
451+
className="h-[49px] cursor-pointer"
446452
key={row.id}
447453
onClick={() => {
448454
router.push(
@@ -452,6 +458,7 @@ export function UsersList({ websiteId }: UsersListProps) {
452458
>
453459
{row.getVisibleCells().map((cell) => (
454460
<TableCell
461+
className="h-[49px] py-2"
455462
key={cell.id}
456463
style={{
457464
width: cell.column.getSize(),

0 commit comments

Comments
 (0)