- Standardized import statements and removed unnecessary line breaks for better readability in various components. - Enhanced error handling and logging in the useElectronPrinter hook. - Updated sample data formatting in AgGridShowcase for improved clarity. - Refactored JSX elements for consistent indentation and structure in LandingSample, AuthPage, and EventsPage components. - Consolidated and simplified conditional rendering logic in several components. These changes aim to enhance code maintainability and readability throughout the project.
134 lines
4.0 KiB
TypeScript
134 lines
4.0 KiB
TypeScript
import { useState, useEffect, useCallback } from 'react';
|
||
import { useIsElectron } from './use-is-electron';
|
||
|
||
// ─── Types ──────────────────────────────────────────────────────
|
||
|
||
export type UpdateStatus = 'idle' | 'checking' | 'available' | 'not-available' | 'downloading' | 'ready' | 'error';
|
||
|
||
export interface UseElectronUpdaterReturn {
|
||
/** Current status of the auto-updater lifecycle */
|
||
status: UpdateStatus;
|
||
/** Download progress percentage (0–100) */
|
||
progress: number;
|
||
/** Download speed in bytes per second */
|
||
bytesPerSecond: number;
|
||
/** Information about the available/downloaded update */
|
||
updateInfo: ElectronUpdateInfo | null;
|
||
/** Error message if the updater encountered an issue */
|
||
errorMessage: string | null;
|
||
/** Whether the app is running inside Electron */
|
||
isElectron: boolean;
|
||
/** Trigger a manual update check */
|
||
checkForUpdates: () => void;
|
||
/** Quit the app and install the downloaded update */
|
||
installUpdate: () => void;
|
||
}
|
||
|
||
/**
|
||
* React hook for the Electron auto-updater.
|
||
*
|
||
* Subscribes to all update lifecycle events via `window.electronAPI`
|
||
* and provides reactive state for building an update notification UI.
|
||
*
|
||
* Safe to use in both Electron and browser environments — all
|
||
* Electron-specific calls are gated behind `window.electronAPI` checks.
|
||
*
|
||
* @example
|
||
* ```tsx
|
||
* function UpdateBanner() {
|
||
* const { status, progress, updateInfo, checkForUpdates, installUpdate } = useElectronUpdater();
|
||
*
|
||
* if (status === 'available') {
|
||
* return <div>Update {updateInfo?.version} available! Downloading...</div>;
|
||
* }
|
||
* if (status === 'downloading') {
|
||
* return <div>Downloading... {progress.toFixed(0)}%</div>;
|
||
* }
|
||
* if (status === 'ready') {
|
||
* return <button onClick={installUpdate}>Restart to update</button>;
|
||
* }
|
||
* return <button onClick={checkForUpdates}>Check for updates</button>;
|
||
* }
|
||
* ```
|
||
*/
|
||
export function useElectronUpdater(): UseElectronUpdaterReturn {
|
||
const [status, setStatus] = useState<UpdateStatus>('idle');
|
||
const [progress, setProgress] = useState(0);
|
||
const [bytesPerSecond, setBytesPerSecond] = useState(0);
|
||
const [updateInfo, setUpdateInfo] = useState<ElectronUpdateInfo | null>(null);
|
||
const [errorMessage, setErrorMessage] = useState<string | null>(null);
|
||
|
||
const isElectron = useIsElectron();
|
||
|
||
useEffect(() => {
|
||
if (!window.electronAPI) return;
|
||
|
||
const api = window.electronAPI;
|
||
|
||
const unsubChecking = api.onUpdateChecking(() => {
|
||
setStatus('checking');
|
||
setErrorMessage(null);
|
||
});
|
||
|
||
const unsubAvailable = api.onUpdateAvailable((info) => {
|
||
setStatus('available');
|
||
setUpdateInfo(info);
|
||
});
|
||
|
||
const unsubNotAvailable = api.onUpdateNotAvailable((info) => {
|
||
setStatus('not-available');
|
||
setUpdateInfo(info);
|
||
});
|
||
|
||
const unsubProgress = api.onDownloadProgress((progressInfo) => {
|
||
setStatus('downloading');
|
||
setProgress(progressInfo.percent);
|
||
setBytesPerSecond(progressInfo.bytesPerSecond);
|
||
});
|
||
|
||
const unsubDownloaded = api.onUpdateDownloaded((info) => {
|
||
setStatus('ready');
|
||
setProgress(100);
|
||
setUpdateInfo(info);
|
||
});
|
||
|
||
const unsubError = api.onUpdateError((error) => {
|
||
setStatus('error');
|
||
setErrorMessage(error);
|
||
});
|
||
|
||
// Cleanup all listeners on unmount
|
||
return () => {
|
||
unsubChecking();
|
||
unsubAvailable();
|
||
unsubNotAvailable();
|
||
unsubProgress();
|
||
unsubDownloaded();
|
||
unsubError();
|
||
};
|
||
}, []);
|
||
|
||
const checkForUpdates = useCallback(() => {
|
||
if (!window.electronAPI) return;
|
||
setStatus('checking');
|
||
setErrorMessage(null);
|
||
window.electronAPI.checkForUpdates();
|
||
}, []);
|
||
|
||
const installUpdate = useCallback(() => {
|
||
if (!window.electronAPI) return;
|
||
window.electronAPI.installUpdate();
|
||
}, []);
|
||
|
||
return {
|
||
status,
|
||
progress,
|
||
bytesPerSecond,
|
||
updateInfo,
|
||
errorMessage,
|
||
isElectron,
|
||
checkForUpdates,
|
||
installUpdate,
|
||
};
|
||
}
|