/** * App context hook for accessing controllers and app-level functions. */ import React, { createContext, useContext, useState, useCallback, type ReactNode } from 'react'; import type { WalletController } from '../../controllers/wallet-controller.js'; import type { InvitationController } from '../../controllers/invitation-controller.js'; import type { AppContextType, DialogState } from '../types.js'; /** * App context. */ const AppContext = createContext(null); /** * Dialog context for managing modal dialogs. */ interface DialogContextType { dialog: DialogState | null; setDialog: (dialog: DialogState | null) => void; } const DialogContext = createContext(null); /** * Status context for managing status bar. */ interface StatusContextType { status: string; setStatus: (status: string) => void; } const StatusContext = createContext(null); /** * App provider props. */ interface AppProviderProps { children: ReactNode; walletController: WalletController; invitationController: InvitationController; onExit: () => void; } /** * App provider component. * Provides controllers, dialog management, and app-level functions to children. */ export function AppProvider({ children, walletController, invitationController, onExit, }: AppProviderProps): React.ReactElement { const [dialog, setDialog] = useState(null); const [status, setStatusState] = useState('Ready'); const [isWalletInitialized, setWalletInitialized] = useState(false); // Promise resolver for confirm dialogs const [confirmResolver, setConfirmResolver] = useState<((value: boolean) => void) | null>(null); /** * Show an error dialog. */ const showError = useCallback((message: string) => { setDialog({ visible: true, type: 'error', message, onCancel: () => setDialog(null), }); }, []); /** * Show an info dialog. */ const showInfo = useCallback((message: string) => { setDialog({ visible: true, type: 'info', message, onCancel: () => setDialog(null), }); }, []); /** * Show a confirmation dialog and wait for user response. */ const confirm = useCallback((message: string): Promise => { return new Promise((resolve) => { setConfirmResolver(() => resolve); setDialog({ visible: true, type: 'confirm', message, onConfirm: () => { setDialog(null); resolve(true); }, onCancel: () => { setDialog(null); resolve(false); }, }); }); }, []); /** * Update status bar message. */ const setStatus = useCallback((message: string) => { setStatusState(message); }, []); const appValue: AppContextType = { walletController, invitationController, showError, showInfo, confirm, exit: onExit, setStatus, isWalletInitialized, setWalletInitialized, }; const dialogValue: DialogContextType = { dialog, setDialog, }; const statusValue: StatusContextType = { status, setStatus, }; return ( {children} ); } /** * Hook to access app context. * @returns App context * @throws Error if used outside AppProvider */ export function useAppContext(): AppContextType { const context = useContext(AppContext); if (!context) { throw new Error('useAppContext must be used within an AppProvider'); } return context; } /** * Hook to access dialog context. * @returns Dialog context */ export function useDialog(): DialogContextType { const context = useContext(DialogContext); if (!context) { throw new Error('useDialog must be used within an AppProvider'); } return context; } /** * Hook to access status context. * @returns Status context */ export function useStatus(): StatusContextType { const context = useContext(StatusContext); if (!context) { throw new Error('useStatus must be used within an AppProvider'); } return context; }