Skip to content

Commit 6c62b14

Browse files
authored
Merge pull request #792 from olaayoade27-coder/main
#696 Visual regression for dashboard
2 parents 51ba994 + 4f7fbd8 commit 6c62b14

3 files changed

Lines changed: 79 additions & 6 deletions

File tree

frontend/package.json

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@
77
"build": "next build",
88
"start": "next start",
99
"lint": "eslint",
10-
"test:e2e": "playwright test"
10+
"test:e2e": "playwright test",
11+
"storybook": "storybook dev -p 6006",
12+
"build-storybook": "storybook build",
13+
"chromatic": "chromatic",
14+
"test": "vitest run"
1115
},
1216
"dependencies": {
1317
"@stellar/stellar-sdk": "^14.5.0",
@@ -19,28 +23,38 @@
1923
"recharts": "^3.7.0"
2024
},
2125
"devDependencies": {
26+
"@chromatic-com/storybook": "3.2.6",
2227
"@playwright/test": "^1.58.2",
28+
"@storybook/addon-essentials": "8.6.12",
29+
"@storybook/react": "^8.6.12",
30+
"@storybook/react-vite": "^8.6.12",
31+
"@storybook/test": "8.6.12",
2332
"@tailwindcss/postcss": "^4",
33+
"@testing-library/dom": "^10.4.1",
2434
"@testing-library/jest-dom": "^6.9.1",
2535
"@testing-library/react": "^16.3.2",
2636
"@types/node": "^20",
2737
"@types/react": "^19.2.14",
2838
"@types/react-dom": "^19.2.3",
39+
"@vitejs/plugin-react": "^4.4.1",
2940
"ajv": "^6.12.6",
3041
"axe-core": "^4.8.2",
42+
"chromatic": "11.28.1",
43+
"esbuild": "^0.25.3",
3144
"eslint": "^9",
3245
"eslint-config-next": "16.2.4",
3346
"eslint-plugin-jsx-a11y": "^6.7.1",
3447
"jsdom": "^29.0.1",
48+
"storybook": "8.6.12",
3549
"tailwindcss": "^4",
3650
"typescript": "5.9.3",
51+
"vite": "^6.3.5",
3752
"vitest": "^3.2.4"
3853
},
3954
"overrides": {
4055
"ajv": "^6.12.6",
4156
"minimatch": ">=10.2.5",
4257
"flatted": ">=3.4.2",
43-
"picomatch": ">=4.0.4",
44-
"vite": ">=7.3.2"
58+
"picomatch": ">=4.0.4"
4559
}
4660
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import type { Meta, StoryObj } from '@storybook/react';
2+
import { fn } from '@storybook/test';
3+
import { DashboardHome } from './DashboardHome';
4+
import type { DashboardData } from '@/lib/dashboard';
5+
6+
const meta: Meta<typeof DashboardHome> = {
7+
title: 'Dashboard/DashboardHome',
8+
component: DashboardHome,
9+
parameters: {
10+
// Prevent real network calls in Storybook/Chromatic
11+
mockData: [],
12+
chromatic: { viewports: [320, 768, 1024, 1440] },
13+
},
14+
};
15+
export default meta;
16+
type Story = StoryObj<typeof DashboardHome>;
17+
18+
const mockData: DashboardData = {
19+
metrics: {
20+
totalSubscribers: 1247,
21+
totalSubscribersChangePercent: 12.4,
22+
mrr: 3840,
23+
mrrChangePercent: 8.2,
24+
activeSubscriptions: 892,
25+
activeSubscriptionsChangePercent: -2.1,
26+
},
27+
recentActivity: [
28+
{ id: '1', type: 'subscription', title: 'New subscriber', description: '@alex_fan subscribed to Premium', timestamp: new Date('2026-04-23T14:00:00Z').toISOString(), metadata: '+$9.99' },
29+
{ id: '2', type: 'renewal', title: 'Renewal', description: '@jordan_art renewed Monthly', timestamp: new Date('2026-04-23T13:00:00Z').toISOString(), metadata: '$4.99' },
30+
{ id: '3', type: 'content', title: 'Content published', description: 'New post: "Behind the scenes"', timestamp: new Date('2026-04-23T12:00:00Z').toISOString() },
31+
{ id: '4', type: 'cancellation', title: 'Subscription cancelled', description: '@sam_user cancelled Premium', timestamp: new Date('2026-04-23T11:00:00Z').toISOString() },
32+
{ id: '5', type: 'payout', title: 'Payout sent', description: 'Weekly payout completed', timestamp: new Date('2026-04-23T10:00:00Z').toISOString(), metadata: '$420.00' },
33+
],
34+
};
35+
36+
export const Loaded: Story = {
37+
args: {
38+
onCreatePlan: fn(),
39+
onUploadContent: fn(),
40+
fetchDashboardData: () => Promise.resolve(mockData),
41+
},
42+
};
43+
44+
export const Loading: Story = {
45+
args: {
46+
onCreatePlan: fn(),
47+
onUploadContent: fn(),
48+
fetchDashboardData: () => new Promise(() => {}),
49+
},
50+
};
51+
52+
export const ErrorState: Story = {
53+
args: {
54+
onCreatePlan: fn(),
55+
onUploadContent: fn(),
56+
fetchDashboardData: () => Promise.reject(new Error('Network error')),
57+
},
58+
};

frontend/src/components/dashboard/DashboardHome.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,10 @@ const UploadIcon = () => (
2828
export interface DashboardHomeProps {
2929
onCreatePlan?: () => void;
3030
onUploadContent?: () => void;
31+
fetchDashboardData?: () => Promise<DashboardData>;
3132
}
3233

33-
export function DashboardHome({ onCreatePlan, onUploadContent }: DashboardHomeProps) {
34+
export function DashboardHome({ onCreatePlan, onUploadContent, fetchDashboardData: fetchFn = fetchDashboardData }: DashboardHomeProps) {
3435
const [state, setState] = useState<'loading' | 'success' | 'error'>('loading');
3536
const [data, setData] = useState<DashboardData | null>(null);
3637
const [errorMessage, setErrorMessage] = useState<string>('');
@@ -39,14 +40,14 @@ export function DashboardHome({ onCreatePlan, onUploadContent }: DashboardHomePr
3940
setState('loading');
4041
setErrorMessage('');
4142
try {
42-
const result = await fetchDashboardData();
43+
const result = await fetchFn();
4344
setData(result);
4445
setState('success');
4546
} catch (e) {
4647
setState('error');
4748
setErrorMessage(e instanceof Error ? e.message : 'Failed to load dashboard');
4849
}
49-
}, []);
50+
}, [fetchFn]);
5051

5152
useEffect(() => {
5253
// eslint-disable-next-line react-hooks/set-state-in-effect

0 commit comments

Comments
 (0)