added glitchtip using sentry sdk

This commit is contained in:
Codex Agent
2025-12-19 10:13:30 +01:00
parent 53ec427e6e
commit 778ffc8bb9
13 changed files with 1574 additions and 58 deletions

View File

@@ -16,12 +16,14 @@ import { EventProvider } from './context/EventContext';
import MatomoTracker from '@/components/analytics/MatomoTracker';
import { ConsentProvider } from '@/contexts/consent';
import CookieBanner from '@/components/consent/CookieBanner';
import { Sentry, initSentry } from '@/lib/sentry';
const DevTenantSwitcher = React.lazy(() => import('./DevTenantSwitcher'));
const enableDevSwitcher = import.meta.env.DEV || import.meta.env.VITE_ENABLE_TENANT_SWITCHER === 'true';
initializeTheme();
initSentry('admin');
const rootEl = document.getElementById('root')!;
const queryClient = new QueryClient({
defaultOptions: {
@@ -43,11 +45,19 @@ if ('serviceWorker' in navigator) {
});
}
const AdminFallback: React.FC<{ message: string }> = ({ message }) => (
<div className="flex min-h-screen items-center justify-center text-sm text-muted-foreground">
{message}
</div>
);
createRoot(rootEl).render(
<React.StrictMode>
<AppearanceProvider>
<AdminApp />
</AppearanceProvider>
<Sentry.ErrorBoundary fallback={<AdminFallback message="Oberfläche konnte nicht geladen werden." />}>
<AppearanceProvider>
<AdminApp />
</AppearanceProvider>
</Sentry.ErrorBoundary>
</React.StrictMode>
);

View File

@@ -13,8 +13,16 @@ import CookieBanner from '@/components/consent/CookieBanner';
import React from 'react';
import { usePage } from '@inertiajs/react';
import { useEffect } from 'react';
import { Sentry, initSentry } from './lib/sentry';
const appName = import.meta.env.VITE_APP_NAME || 'Laravel';
const InertiaFallback: React.FC = () => (
<div className="flex min-h-screen items-center justify-center text-sm text-muted-foreground">
Oberfläche konnte nicht geladen werden.
</div>
);
initSentry('inertia');
const LocaleSync: React.FC<{ children: React.ReactNode }> = ({ children }) => {
// usePage is only available inside Inertia-provided tree; guard for SSR/raw mounts
@@ -63,17 +71,19 @@ createInertiaApp({
}
root.render(
<AppearanceProvider>
<ConsentProvider>
<I18nextProvider i18n={i18n}>
<LocaleSync>
<App {...props} />
</LocaleSync>
<CookieBanner />
<Toaster position="top-right" toastOptions={{ duration: 4000 }} />
</I18nextProvider>
</ConsentProvider>
</AppearanceProvider>
<Sentry.ErrorBoundary fallback={<InertiaFallback />}>
<AppearanceProvider>
<ConsentProvider>
<I18nextProvider i18n={i18n}>
<LocaleSync>
<App {...props} />
</LocaleSync>
<CookieBanner />
<Toaster position="top-right" toastOptions={{ duration: 4000 }} />
</I18nextProvider>
</ConsentProvider>
</AppearanceProvider>
</Sentry.ErrorBoundary>
);
},
progress: {

View File

@@ -3,8 +3,16 @@ import { createRoot } from 'react-dom/client';
import '../../css/app.css';
import { AppearanceProvider, initializeTheme } from '@/hooks/use-appearance';
import { enableGuestDemoMode, shouldEnableGuestDemoMode } from './demo/demoMode';
import { Sentry, initSentry } from '@/lib/sentry';
const GuestFallback: React.FC<{ message: string }> = ({ message }) => (
<div className="flex min-h-screen items-center justify-center text-sm text-muted-foreground">
{message}
</div>
);
initializeTheme();
initSentry('guest');
if (shouldEnableGuestDemoMode()) {
enableGuestDemoMode();
}
@@ -14,11 +22,13 @@ const isShareRoute = typeof window !== 'undefined' && window.location.pathname.s
const shareRoot = async () => {
const { SharedPhotoStandalone } = await import('./pages/SharedPhotoPage');
createRoot(rootEl).render(
<React.StrictMode>
<AppearanceProvider>
<SharedPhotoStandalone />
</AppearanceProvider>
</React.StrictMode>
<Sentry.ErrorBoundary fallback={<GuestFallback message="Dieses Foto kann gerade nicht geladen werden." />}>
<React.StrictMode>
<AppearanceProvider>
<SharedPhotoStandalone />
</AppearanceProvider>
</React.StrictMode>
</Sentry.ErrorBoundary>
);
};
@@ -53,41 +63,29 @@ const appRoot = async () => {
}
createRoot(rootEl).render(
<React.StrictMode>
<AppearanceProvider>
<LocaleProvider>
<ToastProvider>
<MatomoTracker config={matomoConfig} />
<Suspense
fallback={(
<div className="flex min-h-screen items-center justify-center text-sm text-muted-foreground">
Erlebnisse werden geladen
</div>
)}
>
<RouterProvider router={router} />
</Suspense>
</ToastProvider>
</LocaleProvider>
</AppearanceProvider>
</React.StrictMode>
<Sentry.ErrorBoundary fallback={<GuestFallback message="Erlebnisse können nicht geladen werden." />}>
<React.StrictMode>
<AppearanceProvider>
<LocaleProvider>
<ToastProvider>
<MatomoTracker config={matomoConfig} />
<Suspense fallback={<GuestFallback message="Erlebnisse werden geladen …" />}>
<RouterProvider router={router} />
</Suspense>
</ToastProvider>
</LocaleProvider>
</AppearanceProvider>
</React.StrictMode>
</Sentry.ErrorBoundary>
);
};
if (isShareRoute) {
shareRoot().catch(() => {
createRoot(rootEl).render(
<div className="flex min-h-screen items-center justify-center text-sm text-muted-foreground">
Dieses Foto kann gerade nicht geladen werden.
</div>
);
createRoot(rootEl).render(<GuestFallback message="Dieses Foto kann gerade nicht geladen werden." />);
});
} else {
appRoot().catch(() => {
createRoot(rootEl).render(
<div className="flex min-h-screen items-center justify-center text-sm text-muted-foreground">
Erlebnisse können nicht geladen werden.
</div>
);
createRoot(rootEl).render(<GuestFallback message="Erlebnisse können nicht geladen werden." />);
});
}

View File

@@ -0,0 +1,41 @@
import * as Sentry from '@sentry/react';
type AppSurface = 'guest' | 'admin' | 'inertia';
const defaultTracesSampleRate = 0.05;
const parseSampleRate = (value: string | undefined): number => {
const parsed = Number.parseFloat(value ?? '');
if (Number.isNaN(parsed) || parsed < 0) {
return defaultTracesSampleRate;
}
return parsed;
};
export const initSentry = (app: AppSurface): void => {
const dsn = import.meta.env.VITE_SENTRY_DSN;
if (! dsn) {
return;
}
Sentry.init({
dsn,
environment: import.meta.env.VITE_SENTRY_ENV ?? import.meta.env.MODE,
release: import.meta.env.VITE_SENTRY_RELEASE,
tracesSampleRate: parseSampleRate(import.meta.env.VITE_SENTRY_TRACES_SAMPLE_RATE),
beforeSend(event) {
event.tags = {
...event.tags,
app,
};
return event;
},
normalizeDepth: 6,
});
};
export { Sentry };