Files
AppFlowy-Web/.storybook/mocks.ts
Nathan 67bf9ea607 refactor(storybook): consolidate configuration and eliminate code duplication
## Summary
Reviewed and refactored all Storybook stories to use shared utilities,
eliminating ~200 lines of duplicate code while ensuring stories use
current theme, config, and styles consistently.

## Changes

### New Shared Utilities (.storybook/)
- **argTypes.ts**: Shared argTypes definitions (hostname, subscription, etc.)
- **decorators.tsx**: Reusable decorators (context providers, hostname mocking)
- **mocks.ts**: Shared mock context values (AFConfig, AppContext)

### Refactored Story Files
- HomePageSetting.stories.tsx: Now uses shared utilities
- UpgradeBanner.stories.tsx: Reduced from ~195 to ~80 lines
- UpgradePlan.stories.tsx: Reduced from ~180 to ~95 lines
- TextColor.stories.tsx: Uses shared argTypes
- RecordNotFound.stories.tsx: Reduced from ~235 to ~170 lines

### Configuration Updates
- **main.ts**: Added MUI optimizeDeps for proper theme support, removed deprecated buildStoriesJson
- **GUIDE.md**: Comprehensive documentation with examples and best practices
- **tsconfig.web.json**: Explicitly exclude .storybook/ from production builds

### Lint Fixes & Improvements
- **ApproveRequestPage.tsx**: Added missing blank line (lint fix)
- **subscription.ts**: Fixed type casting to avoid @typescript-eslint/no-explicit-any
- **AppTheme.tsx**: Changed to named imports (better practice)

## Benefits
-  Zero code duplication across stories
-  Consistent theme, config, and styles across all stories
-  Better maintainability (change once, apply everywhere)
-  Improved type safety with shared utilities
-  Comprehensive documentation for future story development
-  Storybook files guaranteed excluded from production builds

## Testing
- All linting passes (pnpm run lint)
- Storybook configuration verified to not be included in production builds
- Multiple layers of protection ensure isolation from main application

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-16 14:48:48 +08:00

118 lines
2.8 KiB
TypeScript

/**
* Shared mock values for Storybook stories
*
* This file contains common mock context values to avoid duplication across story files.
* Import and use these mocks in your stories instead of creating new ones.
*/
import { SubscriptionInterval, SubscriptionPlan } from '@/application/types';
/**
* Mock AFConfig context value
* Used by components that need authentication and service configuration
*/
export const mockAFConfigValue = {
service: {
getSubscriptionLink: async () => 'https://example.com/subscribe',
},
isAuthenticated: true,
currentUser: {
email: 'storybook@example.com',
name: 'Storybook User',
uid: 'storybook-uid',
avatar: null,
uuid: 'storybook-uuid',
latestWorkspaceId: 'storybook-workspace-id',
},
updateCurrentUser: async () => {
// Mock implementation
},
openLoginModal: () => {
// Mock implementation
},
};
/**
* Minimal mock AFConfig without service
* Use this for components that don't need service functionality
*/
export const mockAFConfigValueMinimal = {
service: undefined,
isAuthenticated: true,
currentUser: {
email: 'storybook@example.com',
name: 'Storybook User',
uid: 'storybook-uid',
avatar: null,
uuid: 'storybook-uuid',
latestWorkspaceId: 'storybook-workspace-id',
},
updateCurrentUser: async () => {
// Mock implementation
},
openLoginModal: () => {
// Mock implementation
},
};
/**
* Mock App context value
* Used by components that need workspace and app state
*/
export const mockAppContextValue = {
userWorkspaceInfo: {
selectedWorkspace: {
id: 'storybook-workspace-id',
name: 'Storybook Workspace',
owner: {
uid: 'storybook-uid',
},
},
workspaces: [
{
id: 'storybook-workspace-id',
name: 'Storybook Workspace',
owner: {
uid: 'storybook-uid',
},
},
],
},
currentWorkspaceId: 'storybook-workspace-id',
outline: [],
rendered: true,
toView: async () => {},
loadViewMeta: async () => {
throw new Error('Not implemented in story');
},
loadView: async () => {
throw new Error('Not implemented in story');
},
createRowDoc: async () => {
throw new Error('Not implemented in story');
},
appendBreadcrumb: () => {},
onRendered: () => {},
updatePage: async () => {},
addPage: async () => 'test-page-id',
deletePage: async () => {},
openPageModal: () => {},
loadViews: async () => [],
setWordCount: () => {},
uploadFile: async () => {
throw new Error('Not implemented in story');
},
eventEmitter: undefined,
awarenessMap: {},
getSubscriptions: async () => {
return [
{
plan: SubscriptionPlan.Free,
currency: 'USD',
recurring_interval: SubscriptionInterval.Month,
price_cents: 0,
},
];
},
};