Files
ERitors-Scribe-Desktop/app/main.tsx
natreex 19c8d0057c Remove unused assets, refactor migration handling, and add crash reporting
- Deleted obsolete icons, layout files, and SVG assets.
- Added `useAutoUpdate` hook for streamlined update logic.
- Introduced `auto_migrate_electron` and migration commands for Electron-to-Tauri data migration.
- Implemented `init_panic_hook` for improved crash reporting.
- Updated `.gitignore` for Tauri build output and IDE-specific files.
2026-04-07 16:43:54 -04:00

138 lines
5.0 KiB
TypeScript

import React, {useEffect, useState} from 'react';
import ReactDOM from 'react-dom/client';
import {BrowserRouter, Routes, Route, Outlet} from 'react-router-dom';
import '@/app/globals.css';
import '@/lib/i18n';
import {listen} from '@tauri-apps/api/event';
import * as tauri from '@/lib/tauri';
import PulseLoader from '@/components/ui/PulseLoader';
import {useTranslations} from '@/lib/i18n';
listen('auth-success', () => window.location.reload()).then();
type MigrationState = 'pending' | 'error' | 'done';
function AppInitializer({children}: { children: React.ReactNode }) {
const t = useTranslations();
const [state, setState] = useState<MigrationState>('pending');
const [retryCount, setRetryCount] = useState<number>(0);
useEffect(function (): void {
setState('pending');
tauri.autoMigrateElectron().then(function (result): void {
if (result.migrated) {
window.location.reload();
} else if (result.error) {
setState('error');
} else {
setState('done');
}
}).catch(function (): void {
setState('error');
});
}, [retryCount]);
if (state === 'pending') {
return (
<div className="bg-background text-text-primary h-screen flex flex-col items-center justify-center gap-4 font-['Lora']">
<PulseLoader text={t('migration.autoMigrating')}/>
</div>
);
}
if (state === 'error') {
return (
<div className="bg-background text-text-primary h-screen flex flex-col items-center justify-center gap-6 font-['Lora'] p-8">
<div className="flex flex-col items-center gap-3 max-w-md text-center">
<p className="text-lg font-semibold">{t('migration.autoErrorTitle')}</p>
<p className="text-sm text-text-secondary">{t('migration.autoErrorText')}</p>
</div>
<div className="flex flex-col items-center gap-3">
<button
className="px-6 py-2 bg-primary text-white rounded-lg hover:opacity-90 transition-opacity"
onClick={function (): void { setRetryCount(function (n): number { return n + 1; }); }}
>
{t('migration.autoErrorRetry')}
</button>
<div className="flex flex-col items-center gap-1">
<button
className="px-6 py-2 text-sm text-text-secondary hover:text-text-primary underline transition-colors"
onClick={function (): void { setState('done'); }}
>
{t('migration.autoErrorContinue')}
</button>
<p className="text-xs text-text-secondary opacity-70">{t('migration.autoErrorContinueWarning')}</p>
</div>
</div>
</div>
);
}
return <>{children}</>;
}
import ScribeShell from '@/components/layout/ScribeShell';
import LoginWrapper from '@/app/login/LoginWrapper';
import HomePage from '@/app/HomePage';
import BookPage from '@/app/book/BookPage';
import ChapterPage from '@/app/book/ChapterPage';
import BookLayout from '@/app/book/BookLayout';
import LoginPage from '@/app/login/login/page';
import RegisterPage from '@/app/login/register/page';
import ResetPasswordPage from '@/app/login/reset-password/page';
import OfflineLoginPage from '@/app/login/offline/page';
function LoginShell() {
return (
<LoginWrapper>
<Outlet/>
</LoginWrapper>
);
}
function MainShell() {
return (
<ScribeShell>
<Outlet/>
</ScribeShell>
);
}
function BookShell() {
return (
<BookLayout>
<Outlet/>
</BookLayout>
);
}
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<AppInitializer>
<BrowserRouter>
<Routes>
{/* Login routes — dedicated window, no ScribeShell */}
<Route element={<LoginShell/>}>
<Route path="/login" element={<LoginPage/>}/>
<Route path="/login/login" element={<LoginPage/>}/>
<Route path="/login/register" element={<RegisterPage/>}/>
<Route path="/login/reset-password" element={<ResetPasswordPage/>}/>
<Route path="/login/offline" element={<OfflineLoginPage/>}/>
</Route>
{/* Main app routes — with ScribeShell */}
<Route element={<MainShell/>}>
<Route path="/" element={<HomePage/>}/>
<Route element={<BookShell/>}>
<Route path="/book/:bookId" element={<BookPage/>}/>
<Route path="/book/:bookId/chapter/:chapterId" element={<ChapterPage/>}/>
</Route>
</Route>
</Routes>
</BrowserRouter>
</AppInitializer>
</React.StrictMode>
);