Skip to content

Commit af756f5

Browse files
committed
fix: empty states
1 parent 8adc5c9 commit af756f5

File tree

5 files changed

+72
-192
lines changed

5 files changed

+72
-192
lines changed

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

Lines changed: 20 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
'use client';
22

3-
import { FlaskIcon, PlusIcon } from '@phosphor-icons/react';
3+
import { FlaskIcon } from '@phosphor-icons/react';
44
import { memo } from 'react';
5-
import { Button } from '@/components/ui/button';
6-
import { Card, CardContent } from '@/components/ui/card';
5+
import { EmptyState } from '@/components/empty-state';
6+
import { Card } from '@/components/ui/card';
77
import type { Experiment } from '@/hooks/use-experiments';
88
import { ExperimentCard } from './experiment-card';
99

@@ -20,36 +20,6 @@ interface ExperimentsListProps {
2020
websiteId: string;
2121
}
2222

23-
const EmptyState = memo(function EmptyExperimentsState({
24-
onCreateExperiment,
25-
}: {
26-
onCreateExperiment: () => void;
27-
}) {
28-
return (
29-
<Card className="rounded border-border/50">
30-
<CardContent className="flex flex-col items-center justify-center py-16 text-center">
31-
<div className="mb-4 rounded border border-primary/20 bg-primary/10 p-4">
32-
<FlaskIcon
33-
className="h-8 w-8 text-primary"
34-
size={32}
35-
weight="duotone"
36-
/>
37-
</div>
38-
<h3 className="mb-2 font-semibold text-foreground text-lg">
39-
No experiments yet
40-
</h3>
41-
<p className="mb-6 max-w-md text-muted-foreground text-sm">
42-
Create your first A/B experiment to start testing different variants.
43-
</p>
44-
<Button onClick={onCreateExperiment}>
45-
<PlusIcon className="mr-2 h-4 w-4" size={16} />
46-
Create Experiment
47-
</Button>
48-
</CardContent>
49-
</Card>
50-
);
51-
});
52-
5323
const LoadingSkeleton = memo(function ExperimentsLoadingSkeleton() {
5424
return (
5525
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
@@ -94,7 +64,23 @@ export const ExperimentsList = memo(function ExperimentsListComponent({
9464
}
9565

9666
if (!experiments.length) {
97-
return <EmptyState onCreateExperiment={onCreateExperiment} />;
67+
return (
68+
<EmptyState
69+
action={{
70+
label: 'Create Experiment',
71+
onClick: onCreateExperiment,
72+
}}
73+
description="Create your first A/B experiment to start testing different variants."
74+
icon={
75+
<FlaskIcon
76+
className="h-8 w-8 text-primary"
77+
size={32}
78+
weight="duotone"
79+
/>
80+
}
81+
title="No experiments yet"
82+
/>
83+
);
9884
}
9985

10086
return (

apps/dashboard/app/(main)/websites/[id]/funnels/_components/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
export { DeleteFunnelDialog } from './delete-funnel-dialog';
22
export { EditFunnelDialog } from './edit-funnel-dialog';
3-
export { EmptyState } from './empty-state';
43
export { FunnelAnalytics } from './funnel-analytics';
54
export { FunnelCard } from './funnel-card';
65
export { FunnelFlow } from './funnel-flow';

apps/dashboard/app/(main)/websites/[id]/revenue/_components/empty-states.tsx

Lines changed: 0 additions & 88 deletions
This file was deleted.

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

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { useAtom } from 'jotai';
1010
import { useParams } from 'next/navigation';
1111
import { lazy, Suspense, useCallback, useState } from 'react';
1212
import { useRevenueConfig } from '@/app/(main)/revenue/hooks/use-revenue-config';
13+
import { EmptyState } from '@/components/empty-state';
1314
import { Skeleton } from '@/components/ui/skeleton';
1415
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
1516
import { useDateFilters } from '@/hooks/use-date-filters';
@@ -33,16 +34,6 @@ const RecentTransactions = lazy(() =>
3334
default: m.RecentTransactions,
3435
}))
3536
);
36-
const RevenueNotSetup = lazy(() =>
37-
import('./_components/empty-states').then((m) => ({
38-
default: m.RevenueNotSetup,
39-
}))
40-
);
41-
const NoRevenueData = lazy(() =>
42-
import('./_components/empty-states').then((m) => ({
43-
default: m.NoRevenueData,
44-
}))
45-
);
4637

4738
const PageHeaderSkeleton = () => (
4839
<div className="space-y-4">
@@ -164,9 +155,21 @@ export default function WebsiteRevenuePage() {
164155
websiteName={websiteData?.name || undefined}
165156
/>
166157

167-
<Suspense fallback={<Skeleton className="h-64 w-full" />}>
168-
<RevenueNotSetup websiteName={websiteData?.name || undefined} />
169-
</Suspense>
158+
<EmptyState
159+
action={{
160+
label: 'Configure Revenue Tracking',
161+
onClick: () => window.open('/revenue', '_self'),
162+
}}
163+
description={`Configure your Stripe webhook integration to start tracking revenue for ${websiteData?.name || 'this website'}.`}
164+
icon={
165+
<CreditCardIcon
166+
className="h-8 w-8 text-orange-500"
167+
size={32}
168+
weight="duotone"
169+
/>
170+
}
171+
title="Revenue Tracking Not Set Up"
172+
/>
170173
</div>
171174
);
172175
}
@@ -193,9 +196,26 @@ export default function WebsiteRevenuePage() {
193196
websiteName={websiteData?.name || undefined}
194197
/>
195198

196-
<Suspense fallback={<Skeleton className="h-64 w-full" />}>
197-
<NoRevenueData websiteName={websiteData?.name || undefined} />
198-
</Suspense>
199+
<EmptyState
200+
action={{
201+
label: 'View Integration Guide',
202+
onClick: () =>
203+
window.open(
204+
'https://www.databuddy.cc/docs/Integrations/stripe',
205+
'_blank',
206+
'noopener noreferrer'
207+
),
208+
}}
209+
description={`No revenue has been recorded for ${websiteData?.name || 'this website'} in the selected time period. Make sure your Stripe checkout includes the correct client_id and session_id.`}
210+
icon={
211+
<CreditCardIcon
212+
className="h-8 w-8 text-blue-500"
213+
size={32}
214+
weight="duotone"
215+
/>
216+
}
217+
title="No Revenue Data"
218+
/>
199219
</div>
200220
);
201221
}

apps/dashboard/app/(main)/websites/page.tsx

Lines changed: 16 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
TrendUpIcon,
88
} from '@phosphor-icons/react';
99
import { useState } from 'react';
10+
import { EmptyState } from '@/components/empty-state';
1011
import { Button } from '@/components/ui/button';
1112
import { Card, CardContent, CardHeader } from '@/components/ui/card';
1213
import { Skeleton } from '@/components/ui/skeleton';
@@ -51,58 +52,6 @@ function LoadingSkeleton() {
5152
);
5253
}
5354

54-
function EmptyState({ onAddWebsite }: { onAddWebsite: () => void }) {
55-
return (
56-
<Card className="fade-in-50 animate-in rounded border-2 border-dashed bg-gradient-to-br from-background to-muted/20 duration-700">
57-
<CardContent className="flex flex-col items-center justify-center px-8 py-16">
58-
<div className="group relative mb-8">
59-
<div className="rounded-full border-2 border-primary/20 bg-primary/10 p-6">
60-
<GlobeIcon
61-
aria-hidden="true"
62-
className="h-16 w-16 text-primary"
63-
size={16}
64-
weight="duotone"
65-
/>
66-
</div>
67-
<div className="-top-2 -right-2 absolute animate-pulse rounded-full border-2 border-primary/20 bg-background p-2 shadow-sm">
68-
<PlusIcon className="h-6 w-6 text-primary" size={16} />
69-
</div>
70-
</div>
71-
<div className="max-w-md space-y-4 text-center">
72-
<h3 className="font-semibold text-2xl text-foreground">
73-
No websites yet
74-
</h3>
75-
<p className="text-muted-foreground leading-relaxed">
76-
Start tracking your website analytics by adding your first website.
77-
Get insights into visitors, pageviews, and performance.
78-
</p>
79-
<div className="pt-2">
80-
<Button
81-
className={cn(
82-
'gap-2 rounded-lg px-8 py-4 font-medium text-base',
83-
'bg-gradient-to-r from-primary to-primary/90 hover:from-primary/90 hover:to-primary',
84-
'group relative overflow-hidden transition-all duration-300'
85-
)}
86-
data-button-type="primary-cta"
87-
data-section="empty-state"
88-
data-track="websites-add-first-website"
89-
onClick={onAddWebsite}
90-
size="lg"
91-
>
92-
<div className="absolute inset-0 translate-x-[-100%] bg-gradient-to-r from-white/0 via-white/20 to-white/0 transition-transform duration-700 group-hover:translate-x-[100%]" />
93-
<PlusIcon
94-
className="relative z-10 h-5 w-5 transition-transform duration-300 group-hover:rotate-90"
95-
size={16}
96-
/>
97-
<span className="relative z-10">Create Your First Website</span>
98-
</Button>
99-
</div>
100-
</div>
101-
</CardContent>
102-
</Card>
103-
);
104-
}
105-
10655
function ErrorState({ onRetry }: { onRetry: () => void }) {
10756
return (
10857
<div className="flex select-none flex-col items-center justify-center px-4 py-16 text-center">
@@ -234,7 +183,21 @@ export default function WebsitesPage() {
234183

235184
{/* Show empty state */}
236185
{!(isLoading || isError) && websites && websites.length === 0 && (
237-
<EmptyState onAddWebsite={() => setDialogOpen(true)} />
186+
<EmptyState
187+
action={{
188+
label: 'Create Your First Website',
189+
onClick: () => setDialogOpen(true),
190+
}}
191+
description="Start tracking your website analytics by adding your first website. Get insights into visitors, pageviews, and performance."
192+
icon={
193+
<GlobeIcon
194+
className="h-16 w-16 text-primary"
195+
size={16}
196+
weight="duotone"
197+
/>
198+
}
199+
title="No websites yet"
200+
/>
238201
)}
239202

240203
{/* Show website grid */}

0 commit comments

Comments
 (0)