mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 22:41:09 +02:00
♻️ refactor: centralize global error handler in shared-ui
Extract setupGlobalErrorHandler() utility from contacts app and add to @manacore/shared-ui. Migrate 7 apps to use the shared implementation: calendar, chat, clock, contacts, matrix, picture, storage. Features: - Catches unhandled promise rejections with error classification - Handles offline/online network status changes - Built-in i18n (DE + EN) with customizable translations - Optional onAuthError callback for redirect handling - Returns cleanup function for proper unmounting
This commit is contained in:
parent
aca66b2014
commit
cdac341882
11 changed files with 307 additions and 119 deletions
|
|
@ -3,7 +3,7 @@
|
|||
import '$lib/i18n';
|
||||
import { theme } from '$lib/stores/theme';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
import { ToastContainer } from '@manacore/shared-ui';
|
||||
import { ToastContainer, setupGlobalErrorHandler } from '@manacore/shared-ui';
|
||||
import { AppLoadingSkeleton } from '$lib/components/skeletons';
|
||||
import { isLoading as i18nLoading } from 'svelte-i18n';
|
||||
import { onMount } from 'svelte';
|
||||
|
|
@ -13,10 +13,16 @@
|
|||
let loading = $state(true);
|
||||
let appReady = $derived(!loading && !$i18nLoading);
|
||||
|
||||
onMount(async () => {
|
||||
onMount(() => {
|
||||
// Setup global error handling
|
||||
const cleanupErrorHandler = setupGlobalErrorHandler();
|
||||
|
||||
theme.initialize();
|
||||
await authStore.initialize();
|
||||
loading = false;
|
||||
authStore.initialize().then(() => {
|
||||
loading = false;
|
||||
});
|
||||
|
||||
return cleanupErrorHandler;
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -2,13 +2,18 @@
|
|||
import '../app.css';
|
||||
import { onMount } from 'svelte';
|
||||
import { theme } from '$lib/stores/theme';
|
||||
import { ToastContainer } from '@manacore/shared-ui';
|
||||
import { ToastContainer, setupGlobalErrorHandler } from '@manacore/shared-ui';
|
||||
|
||||
let { children } = $props();
|
||||
|
||||
onMount(() => {
|
||||
const cleanup = theme.initialize();
|
||||
return cleanup;
|
||||
const cleanupErrorHandler = setupGlobalErrorHandler();
|
||||
const cleanupTheme = theme.initialize();
|
||||
|
||||
return () => {
|
||||
cleanupErrorHandler();
|
||||
cleanupTheme();
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -5,24 +5,34 @@
|
|||
import { theme } from '$lib/stores/theme.svelte';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
import { waitLocale } from '$lib/i18n';
|
||||
import { ToastContainer } from '@manacore/shared-ui';
|
||||
import { ToastContainer, setupGlobalErrorHandler } from '@manacore/shared-ui';
|
||||
import { AppLoadingSkeleton } from '$lib/components/skeletons';
|
||||
|
||||
let { children } = $props();
|
||||
|
||||
let loading = $state(true);
|
||||
|
||||
onMount(async () => {
|
||||
// Wait for locale to be loaded
|
||||
await waitLocale();
|
||||
onMount(() => {
|
||||
// Setup global error handling
|
||||
const cleanupErrorHandler = setupGlobalErrorHandler();
|
||||
|
||||
// Initialize theme
|
||||
theme.initialize();
|
||||
// Initialize async operations
|
||||
const init = async () => {
|
||||
// Wait for locale to be loaded
|
||||
await waitLocale();
|
||||
|
||||
// Initialize auth
|
||||
await authStore.initialize();
|
||||
// Initialize theme
|
||||
theme.initialize();
|
||||
|
||||
loading = false;
|
||||
// Initialize auth
|
||||
await authStore.initialize();
|
||||
|
||||
loading = false;
|
||||
};
|
||||
|
||||
init();
|
||||
|
||||
return cleanupErrorHandler;
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -2,11 +2,10 @@
|
|||
import '../app.css';
|
||||
import '$lib/i18n'; // Initialize i18n early
|
||||
import { onMount } from 'svelte';
|
||||
import { browser } from '$app/environment';
|
||||
import { isLoading as i18nLoading } from 'svelte-i18n';
|
||||
import { theme } from '$lib/stores/theme';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
import { toastStore, ToastContainer } from '@manacore/shared-ui';
|
||||
import { ToastContainer, setupGlobalErrorHandler } from '@manacore/shared-ui';
|
||||
import { AppLoadingSkeleton } from '$lib/components/skeletons';
|
||||
|
||||
let { children } = $props();
|
||||
|
|
@ -16,73 +15,19 @@
|
|||
// Derived state: app is ready when auth is initialized AND i18n is loaded
|
||||
let appReady = $derived(!loading && !$i18nLoading);
|
||||
|
||||
/**
|
||||
* Global error handler for unhandled promise rejections and API errors
|
||||
*/
|
||||
function setupGlobalErrorHandling() {
|
||||
if (!browser) return;
|
||||
|
||||
// Handle unhandled promise rejections (e.g., failed API calls)
|
||||
window.addEventListener('unhandledrejection', (event) => {
|
||||
const error = event.reason;
|
||||
|
||||
// Extract error message
|
||||
let message = 'Ein unerwarteter Fehler ist aufgetreten';
|
||||
|
||||
if (error instanceof Error) {
|
||||
// Network errors
|
||||
if (error.message === 'Failed to fetch' || error.name === 'TypeError') {
|
||||
message = 'Netzwerkfehler: Server nicht erreichbar';
|
||||
}
|
||||
// Auth errors
|
||||
else if (
|
||||
error.message.includes('401') ||
|
||||
error.message.toLowerCase().includes('unauthorized')
|
||||
) {
|
||||
message = 'Sitzung abgelaufen. Bitte erneut anmelden.';
|
||||
}
|
||||
// Other API errors
|
||||
else if (error.message) {
|
||||
message = error.message;
|
||||
}
|
||||
}
|
||||
|
||||
// Show toast notification
|
||||
toastStore.error(message);
|
||||
|
||||
// Prevent default browser error handling
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
// Handle general JavaScript errors
|
||||
window.addEventListener('error', (event) => {
|
||||
// Only handle non-script errors (network failures for resources, etc.)
|
||||
if (event.message && !event.filename) {
|
||||
toastStore.error('Ein Fehler ist aufgetreten');
|
||||
}
|
||||
});
|
||||
|
||||
// Handle offline/online status
|
||||
window.addEventListener('offline', () => {
|
||||
toastStore.warning('Keine Internetverbindung', 10000);
|
||||
});
|
||||
|
||||
window.addEventListener('online', () => {
|
||||
toastStore.success('Verbindung wiederhergestellt');
|
||||
});
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
// Setup global error handling
|
||||
setupGlobalErrorHandling();
|
||||
onMount(() => {
|
||||
// Setup global error handling (German translations by default)
|
||||
const cleanupErrorHandler = setupGlobalErrorHandler();
|
||||
|
||||
// Initialize theme
|
||||
theme.initialize();
|
||||
|
||||
// Initialize auth
|
||||
await authStore.initialize();
|
||||
authStore.initialize().then(() => {
|
||||
loading = false;
|
||||
});
|
||||
|
||||
loading = false;
|
||||
return cleanupErrorHandler;
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
import type { Snippet } from 'svelte';
|
||||
import { isLoading as i18nLoading, _ as t } from 'svelte-i18n';
|
||||
import { theme } from '$lib/stores/theme';
|
||||
import { ToastContainer } from '@manacore/shared-ui';
|
||||
import { ToastContainer, setupGlobalErrorHandler } from '@manacore/shared-ui';
|
||||
|
||||
interface Props {
|
||||
children: Snippet;
|
||||
|
|
@ -14,8 +14,13 @@
|
|||
let { children }: Props = $props();
|
||||
|
||||
onMount(() => {
|
||||
const cleanup = theme.initialize();
|
||||
return cleanup;
|
||||
const cleanupErrorHandler = setupGlobalErrorHandler();
|
||||
const cleanupTheme = theme.initialize();
|
||||
|
||||
return () => {
|
||||
cleanupErrorHandler();
|
||||
cleanupTheme();
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import '../app.css';
|
||||
import favicon from '$lib/assets/favicon.svg';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
import { ToastContainer } from '@manacore/shared-ui';
|
||||
import { ToastContainer, setupGlobalErrorHandler } from '@manacore/shared-ui';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
// Import and initialize theme
|
||||
|
|
@ -14,6 +14,9 @@
|
|||
let { children, data } = $props();
|
||||
|
||||
onMount(() => {
|
||||
// Setup global error handling
|
||||
const cleanupErrorHandler = setupGlobalErrorHandler();
|
||||
|
||||
// Initialize theme (applies CSS variables and loads from localStorage)
|
||||
const cleanupTheme = theme.initialize();
|
||||
|
||||
|
|
@ -21,6 +24,7 @@
|
|||
authStore.initialize();
|
||||
|
||||
return () => {
|
||||
cleanupErrorHandler();
|
||||
cleanupTheme();
|
||||
};
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
import { page } from '$app/stores';
|
||||
import { onMount } from 'svelte';
|
||||
import { locale } from 'svelte-i18n';
|
||||
import { PillNavigation } from '@manacore/shared-ui';
|
||||
import { PillNavigation, setupGlobalErrorHandler } from '@manacore/shared-ui';
|
||||
import type { PillNavItem, PillDropdownItem } from '@manacore/shared-ui';
|
||||
import { theme } from '$lib/stores/theme.svelte';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
|
|
@ -140,31 +140,41 @@
|
|||
goto('/login');
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
// Initialize theme
|
||||
theme.initialize();
|
||||
onMount(() => {
|
||||
// Setup global error handling
|
||||
const cleanupErrorHandler = setupGlobalErrorHandler();
|
||||
|
||||
// Initialize auth
|
||||
await authStore.initialize();
|
||||
// Initialize async operations
|
||||
const init = async () => {
|
||||
// Initialize theme
|
||||
theme.initialize();
|
||||
|
||||
// Load user settings
|
||||
await userSettings.load();
|
||||
// Initialize auth
|
||||
await authStore.initialize();
|
||||
|
||||
// Initialize sidebar mode from localStorage
|
||||
const savedSidebar = localStorage.getItem('storage-nav-sidebar');
|
||||
if (savedSidebar === 'true') {
|
||||
isSidebarMode = true;
|
||||
sidebarModeStore.set(true);
|
||||
}
|
||||
// Load user settings
|
||||
await userSettings.load();
|
||||
|
||||
// Initialize collapsed state from localStorage
|
||||
const savedCollapsed = localStorage.getItem('storage-nav-collapsed');
|
||||
if (savedCollapsed === 'true') {
|
||||
isCollapsed = true;
|
||||
collapsedStore.set(true);
|
||||
}
|
||||
// Initialize sidebar mode from localStorage
|
||||
const savedSidebar = localStorage.getItem('storage-nav-sidebar');
|
||||
if (savedSidebar === 'true') {
|
||||
isSidebarMode = true;
|
||||
sidebarModeStore.set(true);
|
||||
}
|
||||
|
||||
loading = false;
|
||||
// Initialize collapsed state from localStorage
|
||||
const savedCollapsed = localStorage.getItem('storage-nav-collapsed');
|
||||
if (savedCollapsed === 'true') {
|
||||
isCollapsed = true;
|
||||
collapsedStore.set(true);
|
||||
}
|
||||
|
||||
loading = false;
|
||||
};
|
||||
|
||||
init();
|
||||
|
||||
return cleanupErrorHandler;
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ Nach eingehender Analyse aller Web-Apps im Monorepo wurden folgende Bereiche auf
|
|||
5. ✅ **@manacore/shared-api-client Package erstellt** - 10 Apps migriert (clock, todo, contacts, storage, calendar, picture, nutriphi, planta, questions, skilltree)
|
||||
6. ✅ **i18n zu 6 Apps hinzugefügt** - todo, skilltree, nutriphi, planta, questions, matrix (jeweils DE + EN)
|
||||
7. ✅ **AuthGateModal zentralisiert** - `@manacore/shared-auth-ui` für 4 Apps (chat, todo, contacts, calendar)
|
||||
8. ✅ **Global Error Handler zentralisiert** - `@manacore/shared-ui` für 7 Apps (calendar, chat, clock, contacts, matrix, picture, storage)
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -220,18 +221,24 @@ Alle Apps nutzen **Mana Core Auth** mit `@manacore/shared-auth`.
|
|||
- Jede App hat eigene Version
|
||||
- Könnte mit `@manacore/shared-ui` Skeletons vereinheitlicht werden
|
||||
|
||||
#### Global Error Handler
|
||||
#### Global Error Handler ✅
|
||||
|
||||
- Nur in Contacts App vollständig implementiert
|
||||
- Sollte extrahiert werden
|
||||
> **Status: Erledigt (29.01.2026)**
|
||||
|
||||
- ✅ Zentraler Global Error Handler in `@manacore/shared-ui`
|
||||
- ✅ Migrierte Apps: calendar, chat, clock, contacts, matrix, picture, storage
|
||||
- Funktion: `setupGlobalErrorHandler(options?)`
|
||||
- Behandelt: Unhandled Promise Rejections, JS Errors, Offline/Online Status
|
||||
- i18n: DE + EN eingebaut, erweiterbar
|
||||
- Optional: `onAuthError` Callback für Redirect
|
||||
|
||||
### Empfehlungen (nach Priorität)
|
||||
|
||||
#### Hoch
|
||||
|
||||
1. **Toast Store & Component vereinheitlichen** - Svelte 5 Runes Standard
|
||||
2. **AuthGateModal nach shared-auth-ui** verschieben
|
||||
3. **Global Error Handler** als Composable extrahieren
|
||||
1. ~~**Toast Store & Component vereinheitlichen**~~ ✅ Erledigt
|
||||
2. ~~**AuthGateModal nach shared-auth-ui**~~ ✅ Erledigt
|
||||
3. ~~**Global Error Handler**~~ ✅ Erledigt
|
||||
|
||||
#### Mittel
|
||||
|
||||
|
|
@ -254,6 +261,7 @@ Alle Apps nutzen **Mana Core Auth** mit `@manacore/shared-auth`.
|
|||
| ~~API Client Package erstellen~~ | ✅ Erledigt (10 Apps migriert) |
|
||||
| ~~i18n zu 6 Apps hinzufügen~~ | ✅ Erledigt |
|
||||
| ~~AuthGateModal zentralisieren~~ | ✅ Erledigt (4 Apps migriert) |
|
||||
| ~~Global Error Handler extrahieren~~ | ✅ Erledigt (7 Apps migriert) |
|
||||
|
||||
### 🔴 Hohe Priorität
|
||||
|
||||
|
|
@ -261,10 +269,7 @@ _(Keine offenen Aufgaben mit hoher Priorität)_
|
|||
|
||||
### 🟡 Mittlere Priorität
|
||||
|
||||
| Aufgabe | Aufwand | Impact |
|
||||
|---------|---------|--------|
|
||||
| ~~AuthGateModal in Shared Package~~ | ~~Niedrig~~ | ✅ Erledigt |
|
||||
| Global Error Handler extrahieren | Niedrig | Error UX |
|
||||
_(Keine offenen Aufgaben mit mittlerer Priorität)_
|
||||
|
||||
### 🟢 Niedrige Priorität
|
||||
|
||||
|
|
@ -280,8 +285,9 @@ _(Keine offenen Aufgaben mit hoher Priorität)_
|
|||
1. ~~**API Client Package** als nächstes angehen (höchster Impact)~~ ✅ Erledigt
|
||||
2. ~~**i18n** zu fehlenden Apps hinzufügen~~ ✅ Erledigt (6 Apps)
|
||||
3. ~~**AuthGateModal** in Shared Package extrahieren~~ ✅ Erledigt (4 Apps)
|
||||
4. **Global Error Handler** extrahieren
|
||||
5. Schrittweise weitere Punkte abarbeiten
|
||||
4. ~~**Global Error Handler** extrahieren~~ ✅ Erledigt (7 Apps)
|
||||
5. **App-Skeletons vereinheitlichen** (niedrige Priorität)
|
||||
6. **Auth Store Pattern dokumentieren** (niedrige Priorität)
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -196,6 +196,18 @@ export type {
|
|||
// Immersive Mode
|
||||
export { default as ImmersiveModeToggle } from './components/ImmersiveModeToggle.svelte';
|
||||
|
||||
// Toast
|
||||
export { toastStore, toast, handleApiError, ToastContainer } from './toast';
|
||||
export type { Toast, ToastType } from './toast';
|
||||
// Toast & Global Error Handling
|
||||
export {
|
||||
toastStore,
|
||||
toast,
|
||||
handleApiError,
|
||||
ToastContainer,
|
||||
setupGlobalErrorHandler,
|
||||
GLOBAL_ERROR_TRANSLATIONS,
|
||||
} from './toast';
|
||||
export type {
|
||||
Toast,
|
||||
ToastType,
|
||||
GlobalErrorHandlerOptions,
|
||||
GlobalErrorHandlerTranslations,
|
||||
} from './toast';
|
||||
|
|
|
|||
180
packages/shared-ui/src/toast/globalErrorHandler.ts
Normal file
180
packages/shared-ui/src/toast/globalErrorHandler.ts
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
/**
|
||||
* Global Error Handler - Catches unhandled errors and shows toast notifications
|
||||
*
|
||||
* Usage:
|
||||
* ```ts
|
||||
* import { setupGlobalErrorHandler } from '@manacore/shared-ui';
|
||||
* import { onMount } from 'svelte';
|
||||
*
|
||||
* onMount(() => {
|
||||
* const cleanup = setupGlobalErrorHandler();
|
||||
* return cleanup; // Optional: cleanup on unmount
|
||||
* });
|
||||
*
|
||||
* // With custom translations:
|
||||
* setupGlobalErrorHandler({
|
||||
* networkError: 'Network error: Server unreachable',
|
||||
* sessionExpired: 'Session expired. Please log in again.',
|
||||
* unexpectedError: 'An unexpected error occurred',
|
||||
* genericError: 'An error occurred',
|
||||
* offline: 'No internet connection',
|
||||
* online: 'Connection restored',
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
|
||||
import { toastStore } from './toast.svelte';
|
||||
|
||||
export interface GlobalErrorHandlerTranslations {
|
||||
/** Message for network/fetch errors */
|
||||
networkError: string;
|
||||
/** Message for 401/unauthorized errors */
|
||||
sessionExpired: string;
|
||||
/** Fallback message for unhandled promise rejections */
|
||||
unexpectedError: string;
|
||||
/** Message for general JavaScript errors */
|
||||
genericError: string;
|
||||
/** Message when going offline */
|
||||
offline: string;
|
||||
/** Message when connection is restored */
|
||||
online: string;
|
||||
}
|
||||
|
||||
const DEFAULT_TRANSLATIONS_DE: GlobalErrorHandlerTranslations = {
|
||||
networkError: 'Netzwerkfehler: Server nicht erreichbar',
|
||||
sessionExpired: 'Sitzung abgelaufen. Bitte erneut anmelden.',
|
||||
unexpectedError: 'Ein unerwarteter Fehler ist aufgetreten',
|
||||
genericError: 'Ein Fehler ist aufgetreten',
|
||||
offline: 'Keine Internetverbindung',
|
||||
online: 'Verbindung wiederhergestellt',
|
||||
};
|
||||
|
||||
const DEFAULT_TRANSLATIONS_EN: GlobalErrorHandlerTranslations = {
|
||||
networkError: 'Network error: Server unreachable',
|
||||
sessionExpired: 'Session expired. Please log in again.',
|
||||
unexpectedError: 'An unexpected error occurred',
|
||||
genericError: 'An error occurred',
|
||||
offline: 'No internet connection',
|
||||
online: 'Connection restored',
|
||||
};
|
||||
|
||||
export const GLOBAL_ERROR_TRANSLATIONS = {
|
||||
de: DEFAULT_TRANSLATIONS_DE,
|
||||
en: DEFAULT_TRANSLATIONS_EN,
|
||||
} as const;
|
||||
|
||||
export interface GlobalErrorHandlerOptions {
|
||||
/** Custom translations (default: German) */
|
||||
translations?: Partial<GlobalErrorHandlerTranslations>;
|
||||
/** Locale key to use built-in translations (overridden by translations if provided) */
|
||||
locale?: 'de' | 'en';
|
||||
/** Duration for offline warning toast in ms (default: 10000) */
|
||||
offlineDuration?: number;
|
||||
/** Enable console logging for debugging (default: false) */
|
||||
debug?: boolean;
|
||||
/** Custom handler for auth errors (e.g., redirect to login) */
|
||||
onAuthError?: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up global error handling for unhandled promise rejections,
|
||||
* JavaScript errors, and network connectivity changes.
|
||||
*
|
||||
* @param options - Configuration options
|
||||
* @returns Cleanup function to remove event listeners
|
||||
*/
|
||||
export function setupGlobalErrorHandler(options: GlobalErrorHandlerOptions = {}): () => void {
|
||||
// Don't run on server
|
||||
if (typeof window === 'undefined') {
|
||||
return () => {};
|
||||
}
|
||||
|
||||
const {
|
||||
translations: customTranslations,
|
||||
locale = 'de',
|
||||
offlineDuration = 10000,
|
||||
debug = false,
|
||||
onAuthError,
|
||||
} = options;
|
||||
|
||||
// Merge built-in translations with custom overrides
|
||||
const baseTranslations = GLOBAL_ERROR_TRANSLATIONS[locale] || DEFAULT_TRANSLATIONS_DE;
|
||||
const translations: GlobalErrorHandlerTranslations = {
|
||||
...baseTranslations,
|
||||
...customTranslations,
|
||||
};
|
||||
|
||||
const log = (msg: string, ...args: unknown[]) => {
|
||||
if (debug) {
|
||||
console.log(`[GlobalErrorHandler] ${msg}`, ...args);
|
||||
}
|
||||
};
|
||||
|
||||
// Handle unhandled promise rejections
|
||||
const handleUnhandledRejection = (event: PromiseRejectionEvent) => {
|
||||
const error = event.reason;
|
||||
log('Unhandled rejection:', error);
|
||||
|
||||
let message = translations.unexpectedError;
|
||||
|
||||
if (error instanceof Error) {
|
||||
// Network errors
|
||||
if (error.message === 'Failed to fetch' || error.name === 'TypeError') {
|
||||
message = translations.networkError;
|
||||
}
|
||||
// Auth errors
|
||||
else if (
|
||||
error.message.includes('401') ||
|
||||
error.message.toLowerCase().includes('unauthorized')
|
||||
) {
|
||||
message = translations.sessionExpired;
|
||||
onAuthError?.();
|
||||
}
|
||||
// Other errors with messages
|
||||
else if (error.message) {
|
||||
message = error.message;
|
||||
}
|
||||
}
|
||||
|
||||
toastStore.error(message);
|
||||
event.preventDefault();
|
||||
};
|
||||
|
||||
// Handle general JavaScript errors
|
||||
const handleError = (event: ErrorEvent) => {
|
||||
log('Error event:', event);
|
||||
// Only handle non-script errors (network failures for resources, etc.)
|
||||
if (event.message && !event.filename) {
|
||||
toastStore.error(translations.genericError);
|
||||
}
|
||||
};
|
||||
|
||||
// Handle offline status
|
||||
const handleOffline = () => {
|
||||
log('Offline');
|
||||
toastStore.warning(translations.offline, offlineDuration);
|
||||
};
|
||||
|
||||
// Handle online status
|
||||
const handleOnline = () => {
|
||||
log('Online');
|
||||
toastStore.success(translations.online);
|
||||
};
|
||||
|
||||
// Add event listeners
|
||||
window.addEventListener('unhandledrejection', handleUnhandledRejection);
|
||||
window.addEventListener('error', handleError);
|
||||
window.addEventListener('offline', handleOffline);
|
||||
window.addEventListener('online', handleOnline);
|
||||
|
||||
log('Initialized');
|
||||
|
||||
// Return cleanup function
|
||||
return () => {
|
||||
window.removeEventListener('unhandledrejection', handleUnhandledRejection);
|
||||
window.removeEventListener('error', handleError);
|
||||
window.removeEventListener('offline', handleOffline);
|
||||
window.removeEventListener('online', handleOnline);
|
||||
log('Cleaned up');
|
||||
};
|
||||
}
|
||||
|
|
@ -1,3 +1,8 @@
|
|||
export { toastStore, toast, handleApiError } from './toast.svelte';
|
||||
export type { Toast, ToastType } from './toast.svelte';
|
||||
export { default as ToastContainer } from './ToastContainer.svelte';
|
||||
export { setupGlobalErrorHandler, GLOBAL_ERROR_TRANSLATIONS } from './globalErrorHandler';
|
||||
export type {
|
||||
GlobalErrorHandlerOptions,
|
||||
GlobalErrorHandlerTranslations,
|
||||
} from './globalErrorHandler';
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue