Files
fotospiel-app/resources/js/app.tsx
Codex Agent cff014ede5
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled
tests / ui (push) Has been cancelled
fix(i18n): restore missing translations and enable Suspense loading
2026-01-07 20:50:09 +01:00

104 lines
3.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import '../css/app.css';
import { createInertiaApp } from '@inertiajs/react';
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
import { createRoot } from 'react-dom/client';
import { AppearanceProvider, initializeTheme } from './hooks/use-appearance';
import AppLayout from './layouts/app/AppLayout';
import { I18nextProvider } from 'react-i18next';
import i18n from './i18n';
import { Toaster } from 'react-hot-toast';
import { ConsentProvider } from './contexts/consent';
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>
);
const LoadingFallback: React.FC = () => (
<div className="flex min-h-screen items-center justify-center text-sm text-muted-foreground">
Lade...
</div>
);
initSentry('inertia');
const LocaleSync: React.FC<{ children: React.ReactNode }> = ({ children }) => {
// usePage is only available inside Inertia-provided tree; guard for SSR/raw mounts
try {
const { props } = usePage<{ locale?: string }>();
useEffect(() => {
if (props.locale && i18n.language !== props.locale) {
i18n.changeLanguage(props.locale);
}
}, [props.locale]);
} catch (error) {
// noop will be hydrated once Inertia provides context
}
return <>{children}</>;
};
createInertiaApp({
title: (title) => title ? `${title} - ${appName}` : appName,
resolve: (name) =>
resolvePageComponent(
`./pages/${name}.tsx`,
import.meta.glob('./pages/**/*.tsx')
).then((page) => {
const resolved = page as { default?: { layout?: (page: React.ReactNode) => React.ReactNode } };
if (resolved?.default) {
const Component = resolved.default;
if (!Component.layout) {
Component.layout = (node: React.ReactNode) => <AppLayout>{node}</AppLayout>;
}
}
return resolved;
}),
setup({ el, App, props }) {
const root = createRoot(el);
// Sync i18n with initial locale from props
if (
props.initialPage &&
props.initialPage.props &&
typeof props.initialPage.props.locale === 'string'
) {
i18n.changeLanguage(props.initialPage.props.locale);
}
root.render(
<Sentry.ErrorBoundary fallback={<InertiaFallback />}>
<AppearanceProvider>
<ConsentProvider>
<I18nextProvider i18n={i18n}>
<React.Suspense fallback={<LoadingFallback />}>
<LocaleSync>
<App {...props} />
</LocaleSync>
<CookieBanner />
<Toaster position="top-right" toastOptions={{ duration: 4000 }} />
</React.Suspense>
</I18nextProvider>
</ConsentProvider>
</AppearanceProvider>
</Sentry.ErrorBoundary>
);
},
progress: {
color: '#4B5563',
},
});
// This will set light / dark mode on load...
initializeTheme();