--- description: Reusable React components organized by feature. icon: puzzle-piece --- # Components Reusable React components organized by feature. ## Component Structure ``` components/ ├── Route Guards │ ├── ProtectedRoute.tsx │ ├── PublicRoute.tsx │ └── DefaultRedirect.tsx │ ├── Authentication │ └── TelegramLoginButton.tsx │ ├── Connection Status │ ├── ConnectionIndicator.tsx │ ├── TelegramConnectionIndicator.tsx │ ├── TelegramConnectionModal.tsx │ └── GmailConnectionIndicator.tsx │ ├── Onboarding │ ├── ProgressIndicator.tsx │ └── LottieAnimation.tsx │ ├── Settings Modal (16 files) │ ├── SettingsModal.tsx │ ├── SettingsLayout.tsx │ ├── SettingsHome.tsx │ ├── panels/ │ ├── components/ │ └── hooks/ │ └── Development └── DesignSystemShowcase.tsx ``` ## Route Guard Components ### ProtectedRoute Requires authentication and optionally onboarding. ```typescript interface ProtectedRouteProps { requireOnboarded?: boolean; } // Usage in AppRoutes.tsx }> } /> }> } /> ``` ### PublicRoute Redirects authenticated users away. ```typescript // Usage in AppRoutes.tsx }> } /> } /> ``` ### DefaultRedirect Fallback that routes based on auth state. ```typescript // Redirects to: // - "/" if not authenticated // - "/onboarding" if authenticated but not onboarded // - "/home" if authenticated and onboarded ``` ## Authentication Components ### TelegramLoginButton OAuth login button for Telegram. ```typescript interface TelegramLoginButtonProps { onClick: () => void; disabled?: boolean; } // Usage openUrl(`${BACKEND_URL}/auth/telegram?platform=desktop`)} /> ``` ## Connection Status Components ### ConnectionIndicator Generic connection status badge. ```typescript interface ConnectionIndicatorProps { status: 'connected' | 'connecting' | 'disconnected' | 'error'; label?: string; } ``` ### TelegramConnectionIndicator Telegram-specific status display. ```typescript interface TelegramConnectionIndicatorProps { status: 'connected' | 'connecting' | 'disconnected' | 'error'; } // Usage with Redux state const telegramStatus = useAppSelector((state) => selectTelegramConnectionStatus(state, userId) ); ``` ### TelegramConnectionModal Modal for setting up Telegram connection. ```typescript interface TelegramConnectionModalProps { isOpen: boolean; onClose: () => void; } // Usage in onboarding/settings const [showModal, setShowModal] = useState(false); setShowModal(false)} /> ``` **Features:** - QR code login flow - Phone number login flow - Connection status display - Error handling ### GmailConnectionIndicator Gmail status badge (future integration). ```typescript ``` ## Onboarding Components ### ProgressIndicator Visual progress through onboarding steps. ```typescript interface ProgressIndicatorProps { current: number; total: number; } ``` ### LottieAnimation Lottie animation player for onboarding. ```typescript interface LottieAnimationProps { animationData: object; loop?: boolean; autoplay?: boolean; className?: string; } import welcomeAnimation from '../assets/animations/welcome.json'; ``` ## Settings Modal System Complete modal system with URL-based routing. ### File Structure ``` components/settings/ ├── SettingsModal.tsx # Route-based container ├── SettingsLayout.tsx # Portal + backdrop wrapper ├── SettingsHome.tsx # Main menu with profile ├── panels/ │ ├── ConnectionsPanel.tsx # Connection management │ ├── MessagingPanel.tsx # (Future) │ ├── PrivacyPanel.tsx # (Future) │ ├── ProfilePanel.tsx # (Future) │ ├── AdvancedPanel.tsx # (Future) │ └── BillingPanel.tsx # (Future) ├── components/ │ ├── SettingsHeader.tsx # User profile section │ ├── SettingsMenuItem.tsx # Menu item component │ ├── SettingsBackButton.tsx # Back navigation │ └── SettingsPanelLayout.tsx# Panel wrapper └── hooks/ ├── useSettingsNavigation.ts # URL routing └── useSettingsAnimation.ts # Animation state ``` ### SettingsModal Main container that renders based on URL. ```typescript export function SettingsModal() { const location = useLocation(); const isOpen = location.pathname.startsWith('/settings'); if (!isOpen) return null; return ( {/* Route to appropriate panel */} {location.pathname === '/settings' && } {location.pathname === '/settings/connections' && } {/* ... more panels */} ); } ``` ### SettingsLayout Portal-based modal wrapper. ```typescript export function SettingsLayout({ children }) { const { closeModal } = useSettingsNavigation(); return createPortal(
{/* Backdrop */}
{/* Modal */}
{children}
, document.body ); } ``` ### SettingsHome Main menu with user profile. ```typescript export function SettingsHome() { const { navigateTo, closeModal } = useSettingsNavigation(); const user = useAppSelector((state) => state.user.profile); const menuItems = [ { id: 'connections', label: 'Connections', icon: LinkIcon }, { id: 'messaging', label: 'Messaging', icon: MessageIcon }, { id: 'privacy', label: 'Privacy', icon: ShieldIcon }, // ... more items ]; return (
{menuItems.map((item) => ( navigateTo(item.id)} /> ))}
); } ``` ### ConnectionsPanel Connection management interface. ```typescript export function ConnectionsPanel() { const { navigateBack } = useSettingsNavigation(); const [telegramModalOpen, setTelegramModalOpen] = useState(false); const telegramStatus = useAppSelector((state) => selectTelegramConnectionStatus(state, userId) ); // Reuses connectOptions from onboarding const connections = connectOptions.map((opt) => ({ ...opt, status: opt.id === 'telegram' ? telegramStatus : 'coming-soon' })); return ( {connections.map((conn) => ( conn.id === 'telegram' && setTelegramModalOpen(true)} /> ))} setTelegramModalOpen(false)} /> ); } ``` ### Settings Hooks #### useSettingsNavigation URL-based navigation for settings modal. ```typescript interface UseSettingsNavigationReturn { currentRoute: string; navigateTo: (panel: string) => void; navigateBack: () => void; closeModal: () => void; } const { navigateTo, navigateBack, closeModal } = useSettingsNavigation(); // Navigate to panel navigateTo('connections'); // → /settings/connections // Go back navigateBack(); // → /settings // Close modal closeModal(); // → previous non-settings route ``` #### useSettingsAnimation Animation state management. ```typescript interface UseSettingsAnimationReturn { isEntering: boolean; isExiting: boolean; animationClass: string; } const { animationClass } = useSettingsAnimation();
{/* Content */}
``` ### Settings Components #### SettingsHeader User profile section at top of settings. ```typescript interface SettingsHeaderProps { user: User | null; onClose: () => void; } ``` #### SettingsMenuItem Individual menu item with icon and chevron. ```typescript interface SettingsMenuItemProps { label: string; icon: React.ComponentType; onClick: () => void; badge?: string; disabled?: boolean; } navigateTo('connections')} badge="2" /> ``` #### SettingsBackButton Back navigation button. ```typescript interface SettingsBackButtonProps { onClick: () => void; } ``` #### SettingsPanelLayout Wrapper for settings panels. ```typescript interface SettingsPanelLayoutProps { title: string; onBack: () => void; children: React.ReactNode; } {/* Panel content */} ``` ## Component Patterns ### Reusing Connection Options The `connectOptions` array is shared between onboarding and settings: ```typescript // Defined in ConnectStep.tsx, imported elsewhere export const connectOptions = [ { id: 'telegram', label: 'Telegram', icon: TelegramIcon, description: 'Connect your Telegram account', }, { id: 'gmail', label: 'Gmail', icon: GmailIcon, description: 'Connect your Gmail account', comingSoon: true, }, ]; ``` ### Modal via Portal Settings modal uses `createPortal` to render outside the component tree: ```typescript return createPortal(
{/* Modal content */}
, document.body ); ``` ### Controlled vs Uncontrolled Connection modals are controlled components: ```typescript // Parent controls open state const [isOpen, setIsOpen] = useState(false); setIsOpen(false)} /> ``` --- _Previous: [Pages & Routing](./05-pages-routing.md) | Next: [Providers](./07-providers.md)_