Add staff email client with WebSocket real-time updates
Implements a complete email client for platform staff members: Backend: - Add routing_mode field to PlatformEmailAddress (PLATFORM/STAFF) - Create staff_email app with models for folders, emails, attachments, labels - IMAP service for fetching emails with folder mapping - SMTP service for sending emails with attachment support - Celery tasks for periodic sync and full sync operations - WebSocket consumer for real-time notifications - Comprehensive API viewsets with filtering and actions Frontend: - Thunderbird-style three-pane email interface - Multi-account support with drag-and-drop ordering - Email composer with rich text editor - Email viewer with thread support - Real-time WebSocket updates for new emails and sync status - 94 unit tests covering models, serializers, views, services, and consumers 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -39,6 +39,7 @@ vi.mock('../../components/TopBar', () => ({
|
||||
TopBar - {user.name} - {isDarkMode ? 'Dark' : 'Light'}
|
||||
<button onClick={toggleTheme} data-testid="theme-toggle">Toggle Theme</button>
|
||||
<button onClick={onMenuClick} data-testid="menu-button">Menu</button>
|
||||
<div data-testid="help-button">Help</div>
|
||||
</div>
|
||||
),
|
||||
}));
|
||||
@@ -99,9 +100,7 @@ vi.mock('../../components/TicketModal', () => ({
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock('../../components/FloatingHelpButton', () => ({
|
||||
default: () => <div data-testid="floating-help-button">Help</div>,
|
||||
}));
|
||||
// HelpButton is now rendered inside TopBar, not as a separate component
|
||||
|
||||
// Mock hooks
|
||||
vi.mock('../../hooks/useAuth', () => ({
|
||||
@@ -224,7 +223,7 @@ describe('BusinessLayout', () => {
|
||||
expect(screen.getAllByTestId('sidebar').length).toBeGreaterThan(0);
|
||||
expect(screen.getByTestId('topbar')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('outlet')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('floating-help-button')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('help-button')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render children content via Outlet', () => {
|
||||
@@ -649,7 +648,7 @@ describe('BusinessLayout', () => {
|
||||
it('should render floating help button', () => {
|
||||
renderLayout();
|
||||
|
||||
expect(screen.getByTestId('floating-help-button')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('help-button')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -795,7 +794,7 @@ describe('BusinessLayout', () => {
|
||||
expect(screen.getAllByTestId('sidebar').length).toBeGreaterThan(0);
|
||||
expect(screen.getByTestId('topbar')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('outlet')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('floating-help-button')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('help-button')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user