184 lines
4.2 KiB
TypeScript
184 lines
4.2 KiB
TypeScript
/**
|
|
* 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<AppContextType | null>(null);
|
|
|
|
/**
|
|
* Dialog context for managing modal dialogs.
|
|
*/
|
|
interface DialogContextType {
|
|
dialog: DialogState | null;
|
|
setDialog: (dialog: DialogState | null) => void;
|
|
}
|
|
|
|
const DialogContext = createContext<DialogContextType | null>(null);
|
|
|
|
/**
|
|
* Status context for managing status bar.
|
|
*/
|
|
interface StatusContextType {
|
|
status: string;
|
|
setStatus: (status: string) => void;
|
|
}
|
|
|
|
const StatusContext = createContext<StatusContextType | null>(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<DialogState | null>(null);
|
|
const [status, setStatusState] = useState<string>('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<boolean> => {
|
|
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 (
|
|
<AppContext.Provider value={appValue}>
|
|
<DialogContext.Provider value={dialogValue}>
|
|
<StatusContext.Provider value={statusValue}>
|
|
{children}
|
|
</StatusContext.Provider>
|
|
</DialogContext.Provider>
|
|
</AppContext.Provider>
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
}
|