import { lazy, Suspense } from 'preact/compat';
import { useEffect } from 'preact/hooks';
import { Link, Route, Switch } from 'wouter';
import { ArrowUpDown, Cloud, LogOut, Settings as SettingsIcon, Shield, ShieldUser } from 'lucide-preact';
import type { ImportAttachmentFile, ImportResultSummary } from '@/components/ImportPage';
import type { AdminBackupImportResponse, AdminBackupRunResponse, AdminBackupSettings, RemoteBackupBrowserResponse } from '@/lib/api/backup';
import type { CiphersImportPayload } from '@/lib/api/vault';
import { t } from '@/lib/i18n';
import type { AdminInvite, AdminUser, AuthorizedDevice, Cipher, Folder as VaultFolder, Profile, Send, SendDraft, SessionState, VaultDraft } from '@/lib/types';
import type { ExportRequest } from '@/lib/export-formats';
const SendsPage = lazy(() => import('@/components/SendsPage'));
const TotpCodesPage = lazy(() => import('@/components/TotpCodesPage'));
const VaultPage = lazy(() => import('@/components/VaultPage'));
const SettingsPage = lazy(() => import('@/components/SettingsPage'));
const SecurityDevicesPage = lazy(() => import('@/components/SecurityDevicesPage'));
const AdminPage = lazy(() => import('@/components/AdminPage'));
const BackupCenterPage = lazy(() => import('@/components/BackupCenterPage'));
const ImportPage = lazy(() => import('@/components/ImportPage'));
function RouteContentFallback() {
return
{t('txt_loading_nodewarden')}
;
}
function LegacyBackupRedirect(props: { onNavigate: (path: string) => void }) {
useEffect(() => {
props.onNavigate('/backup');
}, [props]);
return null;
}
export interface AppMainRoutesProps {
profile: Profile | null;
session: SessionState | null;
mobileLayout: boolean;
mobileSidebarToggleKey: number;
importRoute: string;
settingsHomeRoute: string;
settingsAccountRoute: string;
decryptedCiphers: Cipher[];
decryptedFolders: VaultFolder[];
decryptedSends: Send[];
ciphersLoading: boolean;
foldersLoading: boolean;
sendsLoading: boolean;
users: AdminUser[];
invites: AdminInvite[];
totpEnabled: boolean;
lockTimeoutMinutes: 0 | 1 | 5 | 15 | 30;
authorizedDevices: AuthorizedDevice[];
authorizedDevicesLoading: boolean;
onNavigate: (path: string) => void;
onLogout: () => void;
onNotify: (type: 'success' | 'error' | 'warning', text: string) => void;
onImport: (
payload: CiphersImportPayload,
options: { folderMode: 'original' | 'none' | 'target'; targetFolderId: string | null },
attachments?: ImportAttachmentFile[]
) => Promise;
onImportEncryptedRaw: (
payload: CiphersImportPayload,
options: { folderMode: 'original' | 'none' | 'target'; targetFolderId: string | null },
attachments?: ImportAttachmentFile[]
) => Promise;
onExport: (request: ExportRequest) => Promise;
onCreateVaultItem: (draft: VaultDraft, attachments?: File[]) => Promise;
onUpdateVaultItem: (cipher: Cipher, draft: VaultDraft, options?: { addFiles?: File[]; removeAttachmentIds?: string[] }) => Promise;
onDeleteVaultItem: (cipher: Cipher) => Promise;
onArchiveVaultItem: (cipher: Cipher) => Promise;
onUnarchiveVaultItem: (cipher: Cipher) => Promise;
onBulkDeleteVaultItems: (ids: string[]) => Promise;
onBulkPermanentDeleteVaultItems: (ids: string[]) => Promise;
onBulkRestoreVaultItems: (ids: string[]) => Promise;
onBulkArchiveVaultItems: (ids: string[]) => Promise;
onBulkUnarchiveVaultItems: (ids: string[]) => Promise;
onBulkMoveVaultItems: (ids: string[], folderId: string | null) => Promise;
onVerifyMasterPassword: (email: string, password: string) => Promise;
onCreateFolder: (name: string) => Promise;
onRenameFolder: (folderId: string, name: string) => Promise;
onDeleteFolder: (folderId: string) => Promise;
onBulkDeleteFolders: (folderIds: string[]) => Promise;
onDownloadVaultAttachment: (cipher: Cipher, attachmentId: string) => Promise;
downloadingAttachmentKey: string;
attachmentDownloadPercent: number | null;
uploadingAttachmentName: string;
attachmentUploadPercent: number | null;
onRefreshVault: () => Promise;
onCreateSend: (draft: SendDraft, autoCopyLink: boolean) => Promise;
onUpdateSend: (send: Send, draft: SendDraft, autoCopyLink: boolean) => Promise;
onDeleteSend: (send: Send) => Promise;
onBulkDeleteSends: (ids: string[]) => Promise;
uploadingSendFileName: string;
sendUploadPercent: number | null;
onChangePassword: (currentPassword: string, nextPassword: string, nextPassword2: string) => Promise;
onSavePasswordHint: (masterPasswordHint: string) => Promise;
onEnableTotp: (secret: string, token: string) => Promise;
onOpenDisableTotp: () => void;
onGetRecoveryCode: (masterPassword: string) => Promise;
onGetApiKey: (masterPassword: string) => Promise;
onRotateApiKey: (masterPassword: string) => Promise;
onLockTimeoutChange: (minutes: 0 | 1 | 5 | 15 | 30) => void;
onRefreshAuthorizedDevices: () => Promise;
onRenameAuthorizedDevice: (device: AuthorizedDevice, name: string) => Promise;
onRevokeDeviceTrust: (device: AuthorizedDevice) => void;
onRemoveDevice: (device: AuthorizedDevice) => void;
onRevokeAllDeviceTrust: () => void;
onRemoveAllDevices: () => void;
onCreateInvite: (hours: number) => Promise;
onRefreshAdmin: () => void;
onDeleteAllInvites: () => Promise;
onToggleUserStatus: (userId: string, status: 'active' | 'banned') => Promise;
onDeleteUser: (userId: string) => Promise;
onRevokeInvite: (code: string) => Promise;
onExportBackup: (includeAttachments?: boolean) => Promise;
onImportBackup: (file: File, replaceExisting?: boolean) => Promise;
onImportBackupAllowingChecksumMismatch: (file: File, replaceExisting?: boolean) => Promise;
onLoadBackupSettings: () => Promise;
onSaveBackupSettings: (settings: AdminBackupSettings) => Promise;
onRunRemoteBackup: (destinationId?: string | null) => Promise;
onListRemoteBackups: (destinationId: string, path: string) => Promise;
onDownloadRemoteBackup: (destinationId: string, path: string, onProgress?: (percent: number | null) => void) => Promise;
onInspectRemoteBackup: (destinationId: string, path: string) => Promise<{ object: 'backup-remote-integrity'; destinationId: string; path: string; fileName: string; integrity: { hasChecksumPrefix: boolean; expectedPrefix: string | null; actualPrefix: string; matches: boolean } }>;
onDeleteRemoteBackup: (destinationId: string, path: string) => Promise;
onRestoreRemoteBackup: (destinationId: string, path: string, replaceExisting?: boolean) => Promise;
onRestoreRemoteBackupAllowingChecksumMismatch: (destinationId: string, path: string, replaceExisting?: boolean) => Promise;
}
export default function AppMainRoutes(props: AppMainRoutesProps) {
const importRoutePaths = [props.importRoute, '/tools/import', '/tools/import-export', '/tools/import-data', '/import', '/import-export'] as const;
const importPageContent = (
}>
);
const renderImportPageRoute = () => (
{props.mobileLayout && (
)}
{importPageContent}
);
return (
}>
}>
}>
{props.profile && (
{props.mobileLayout && (
)}
}>
)}
{props.profile && (
{t('nav_account_settings')}
{t('nav_device_management')}
{t('nav_import_export')}
{props.profile.role === 'admin' && (
{t('nav_admin_panel')}
)}
{props.profile.role === 'admin' && (
{t('nav_backup_strategy')}
)}
)}
{props.mobileLayout && (
)}
}>
void props.onRefreshAuthorizedDevices()}
onRenameDevice={props.onRenameAuthorizedDevice}
onRevokeTrust={props.onRevokeDeviceTrust}
onRemoveDevice={props.onRemoveDevice}
onRevokeAll={props.onRevokeAllDeviceTrust}
onRemoveAll={props.onRemoveAllDevices}
/>
{props.mobileLayout && (
)}
}>
{importRoutePaths.map((path) => (
{renderImportPageRoute()}
))}
{props.profile?.role === 'admin' ? (
{props.mobileLayout && (
)}
}>
) : null}
);
}