performance optimierungen, lazy loads etc. - plus requesttimingmiddleware, die lokal die performance trackt und loggt.
This commit is contained in:
45
app/Http/Middleware/RequestTimingMiddleware.php
Normal file
45
app/Http/Middleware/RequestTimingMiddleware.php
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
class RequestTimingMiddleware
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||||
|
*/
|
||||||
|
public function handle(Request $request, Closure $next): Response
|
||||||
|
{
|
||||||
|
$request->attributes->set('_timing_start', microtime(true));
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function terminate(Request $request, Response $response): void
|
||||||
|
{
|
||||||
|
if (! app()->environment('local')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$start = $request->attributes->get('_timing_start');
|
||||||
|
|
||||||
|
if (! is_float($start)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$duration = microtime(true) - $start;
|
||||||
|
|
||||||
|
Log::debug('request_timing', [
|
||||||
|
'path' => $request->path(),
|
||||||
|
'method' => $request->method(),
|
||||||
|
'status' => $response->getStatusCode(),
|
||||||
|
'duration_ms' => round($duration * 1000, 2),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -46,6 +46,7 @@ return Application::configure(basePath: dirname(__DIR__))
|
|||||||
\App\Http\Middleware\ContentSecurityPolicy::class,
|
\App\Http\Middleware\ContentSecurityPolicy::class,
|
||||||
HandleInertiaRequests::class,
|
HandleInertiaRequests::class,
|
||||||
AddLinkHeadersForPreloadedAssets::class,
|
AddLinkHeadersForPreloadedAssets::class,
|
||||||
|
\App\Http\Middleware\RequestTimingMiddleware::class,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$middleware->api(append: []);
|
$middleware->api(append: []);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React from 'react';
|
import React, { Suspense } from 'react';
|
||||||
import { createRoot } from 'react-dom/client';
|
import { createRoot } from 'react-dom/client';
|
||||||
import { RouterProvider } from 'react-router-dom';
|
import { RouterProvider } from 'react-router-dom';
|
||||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||||
@@ -9,7 +9,8 @@ import './i18n';
|
|||||||
import './dev-tools';
|
import './dev-tools';
|
||||||
import { initializeTheme } from '@/hooks/use-appearance';
|
import { initializeTheme } from '@/hooks/use-appearance';
|
||||||
import { OnboardingProgressProvider } from './onboarding';
|
import { OnboardingProgressProvider } from './onboarding';
|
||||||
import { DevTenantSwitcher } from './components/DevTenantSwitcher';
|
|
||||||
|
const DevTenantSwitcher = React.lazy(() => import('./components/DevTenantSwitcher'));
|
||||||
|
|
||||||
const enableDevSwitcher = import.meta.env.DEV || import.meta.env.VITE_ENABLE_TENANT_SWITCHER === 'true';
|
const enableDevSwitcher = import.meta.env.DEV || import.meta.env.VITE_ENABLE_TENANT_SWITCHER === 'true';
|
||||||
|
|
||||||
@@ -28,10 +29,22 @@ createRoot(rootEl).render(
|
|||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
<AuthProvider>
|
<AuthProvider>
|
||||||
<OnboardingProgressProvider>
|
<OnboardingProgressProvider>
|
||||||
<RouterProvider router={router} />
|
<Suspense
|
||||||
|
fallback={(
|
||||||
|
<div className="flex min-h-screen items-center justify-center text-sm text-muted-foreground">
|
||||||
|
Oberfläche wird geladen …
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<RouterProvider router={router} />
|
||||||
|
</Suspense>
|
||||||
</OnboardingProgressProvider>
|
</OnboardingProgressProvider>
|
||||||
</AuthProvider>
|
</AuthProvider>
|
||||||
{enableDevSwitcher ? <DevTenantSwitcher /> : null}
|
{enableDevSwitcher ? (
|
||||||
|
<Suspense fallback={null}>
|
||||||
|
<DevTenantSwitcher />
|
||||||
|
</Suspense>
|
||||||
|
) : null}
|
||||||
</QueryClientProvider>
|
</QueryClientProvider>
|
||||||
</React.StrictMode>
|
</React.StrictMode>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,26 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { createBrowserRouter, Outlet, Navigate, useLocation } from 'react-router-dom';
|
import { createBrowserRouter, Outlet, Navigate, useLocation } from 'react-router-dom';
|
||||||
import LoginPage from './pages/LoginPage';
|
|
||||||
import DashboardPage from './pages/DashboardPage';
|
|
||||||
import EventsPage from './pages/EventsPage';
|
|
||||||
import SettingsPage from './pages/SettingsPage';
|
|
||||||
import EventFormPage from './pages/EventFormPage';
|
|
||||||
import EventPhotosPage from './pages/EventPhotosPage';
|
|
||||||
import EventDetailPage from './pages/EventDetailPage';
|
|
||||||
import EventMembersPage from './pages/EventMembersPage';
|
|
||||||
import EventTasksPage from './pages/EventTasksPage';
|
|
||||||
import EventToolkitPage from './pages/EventToolkitPage';
|
|
||||||
import EventInvitesPage from './pages/EventInvitesPage';
|
|
||||||
import EngagementPage from './pages/EngagementPage';
|
|
||||||
import BillingPage from './pages/BillingPage';
|
|
||||||
import TasksPage from './pages/TasksPage';
|
|
||||||
import TaskCollectionsPage from './pages/TaskCollectionsPage';
|
|
||||||
import EmotionsPage from './pages/EmotionsPage';
|
|
||||||
import AuthCallbackPage from './pages/AuthCallbackPage';
|
|
||||||
import WelcomeTeaserPage from './pages/WelcomeTeaserPage';
|
|
||||||
import LoginStartPage from './pages/LoginStartPage';
|
|
||||||
import ProfilePage from './pages/ProfilePage';
|
|
||||||
import LogoutPage from './pages/LogoutPage';
|
|
||||||
import { useAuth } from './auth/context';
|
import { useAuth } from './auth/context';
|
||||||
import {
|
import {
|
||||||
ADMIN_BASE_PATH,
|
ADMIN_BASE_PATH,
|
||||||
@@ -31,10 +10,31 @@ import {
|
|||||||
ADMIN_PUBLIC_LANDING_PATH,
|
ADMIN_PUBLIC_LANDING_PATH,
|
||||||
} from './constants';
|
} from './constants';
|
||||||
import { consumeLastDestination } from './lib/returnTo';
|
import { consumeLastDestination } from './lib/returnTo';
|
||||||
import WelcomeLandingPage from './onboarding/pages/WelcomeLandingPage';
|
const LoginPage = React.lazy(() => import('./pages/LoginPage'));
|
||||||
import WelcomePackagesPage from './onboarding/pages/WelcomePackagesPage';
|
const DashboardPage = React.lazy(() => import('./pages/DashboardPage'));
|
||||||
import WelcomeEventSetupPage from './onboarding/pages/WelcomeEventSetupPage';
|
const EventsPage = React.lazy(() => import('./pages/EventsPage'));
|
||||||
import WelcomeOrderSummaryPage from './onboarding/pages/WelcomeOrderSummaryPage';
|
const SettingsPage = React.lazy(() => import('./pages/SettingsPage'));
|
||||||
|
const EventFormPage = React.lazy(() => import('./pages/EventFormPage'));
|
||||||
|
const EventPhotosPage = React.lazy(() => import('./pages/EventPhotosPage'));
|
||||||
|
const EventDetailPage = React.lazy(() => import('./pages/EventDetailPage'));
|
||||||
|
const EventMembersPage = React.lazy(() => import('./pages/EventMembersPage'));
|
||||||
|
const EventTasksPage = React.lazy(() => import('./pages/EventTasksPage'));
|
||||||
|
const EventToolkitPage = React.lazy(() => import('./pages/EventToolkitPage'));
|
||||||
|
const EventInvitesPage = React.lazy(() => import('./pages/EventInvitesPage'));
|
||||||
|
const EngagementPage = React.lazy(() => import('./pages/EngagementPage'));
|
||||||
|
const BillingPage = React.lazy(() => import('./pages/BillingPage'));
|
||||||
|
const TasksPage = React.lazy(() => import('./pages/TasksPage'));
|
||||||
|
const TaskCollectionsPage = React.lazy(() => import('./pages/TaskCollectionsPage'));
|
||||||
|
const EmotionsPage = React.lazy(() => import('./pages/EmotionsPage'));
|
||||||
|
const AuthCallbackPage = React.lazy(() => import('./pages/AuthCallbackPage'));
|
||||||
|
const WelcomeTeaserPage = React.lazy(() => import('./pages/WelcomeTeaserPage'));
|
||||||
|
const LoginStartPage = React.lazy(() => import('./pages/LoginStartPage'));
|
||||||
|
const ProfilePage = React.lazy(() => import('./pages/ProfilePage'));
|
||||||
|
const LogoutPage = React.lazy(() => import('./pages/LogoutPage'));
|
||||||
|
const WelcomeLandingPage = React.lazy(() => import('./onboarding/pages/WelcomeLandingPage'));
|
||||||
|
const WelcomePackagesPage = React.lazy(() => import('./onboarding/pages/WelcomePackagesPage'));
|
||||||
|
const WelcomeEventSetupPage = React.lazy(() => import('./onboarding/pages/WelcomeEventSetupPage'));
|
||||||
|
const WelcomeOrderSummaryPage = React.lazy(() => import('./onboarding/pages/WelcomeOrderSummaryPage'));
|
||||||
|
|
||||||
function RequireAuth() {
|
function RequireAuth() {
|
||||||
const { status } = useAuth();
|
const { status } = useAuth();
|
||||||
|
|||||||
@@ -308,7 +308,7 @@ export const messages: Record<LocaleCode, NestedMessages> = {
|
|||||||
limitWarning: 'Nur noch {remaining} von {max} Fotos möglich. Bitte kontaktiere die Veranstalter für ein Upgrade.',
|
limitWarning: 'Nur noch {remaining} von {max} Fotos möglich. Bitte kontaktiere die Veranstalter für ein Upgrade.',
|
||||||
galleryWarningDay: 'Galerie läuft in {days} Tag ab. Teile deine Fotos rechtzeitig!',
|
galleryWarningDay: 'Galerie läuft in {days} Tag ab. Teile deine Fotos rechtzeitig!',
|
||||||
galleryWarningDays: 'Galerie läuft in {days} Tagen ab. Teile deine Fotos rechtzeitig!',
|
galleryWarningDays: 'Galerie läuft in {days} Tagen ab. Teile deine Fotos rechtzeitig!',
|
||||||
status: {
|
packageStatus: {
|
||||||
title: 'Dein Paketstatus',
|
title: 'Dein Paketstatus',
|
||||||
subtitle: 'Behalte deine Kontingente im Blick, bevor es eng wird.',
|
subtitle: 'Behalte deine Kontingente im Blick, bevor es eng wird.',
|
||||||
badges: {
|
badges: {
|
||||||
@@ -736,7 +736,7 @@ export const messages: Record<LocaleCode, NestedMessages> = {
|
|||||||
limitWarning: 'Only {remaining} of {max} photos left. Please contact the organizers for an upgrade.',
|
limitWarning: 'Only {remaining} of {max} photos left. Please contact the organizers for an upgrade.',
|
||||||
galleryWarningDay: 'Gallery expires in {days} day. Upload your photos soon!',
|
galleryWarningDay: 'Gallery expires in {days} day. Upload your photos soon!',
|
||||||
galleryWarningDays: 'Gallery expires in {days} days. Upload your photos soon!',
|
galleryWarningDays: 'Gallery expires in {days} days. Upload your photos soon!',
|
||||||
status: {
|
packageStatus: {
|
||||||
title: 'Your package status',
|
title: 'Your package status',
|
||||||
subtitle: 'Keep an eye on your remaining allowances.',
|
subtitle: 'Keep an eye on your remaining allowances.',
|
||||||
badges: {
|
badges: {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React from 'react';
|
import React, { Suspense } from 'react';
|
||||||
import { createRoot } from 'react-dom/client';
|
import { createRoot } from 'react-dom/client';
|
||||||
import { RouterProvider } from 'react-router-dom';
|
import { RouterProvider } from 'react-router-dom';
|
||||||
import { router } from './router';
|
import { router } from './router';
|
||||||
@@ -28,7 +28,15 @@ createRoot(rootEl).render(
|
|||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<LocaleProvider>
|
<LocaleProvider>
|
||||||
<ToastProvider>
|
<ToastProvider>
|
||||||
<RouterProvider router={router} />
|
<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>
|
</ToastProvider>
|
||||||
</LocaleProvider>
|
</LocaleProvider>
|
||||||
</React.StrictMode>
|
</React.StrictMode>
|
||||||
|
|||||||
@@ -8,27 +8,28 @@ import { AlertTriangle, Loader2 } from 'lucide-react';
|
|||||||
import { EventStatsProvider } from './context/EventStatsContext';
|
import { EventStatsProvider } from './context/EventStatsContext';
|
||||||
import { GuestIdentityProvider } from './context/GuestIdentityContext';
|
import { GuestIdentityProvider } from './context/GuestIdentityContext';
|
||||||
import { EventBrandingProvider } from './context/EventBrandingContext';
|
import { EventBrandingProvider } from './context/EventBrandingContext';
|
||||||
import LandingPage from './pages/LandingPage';
|
|
||||||
import ProfileSetupPage from './pages/ProfileSetupPage';
|
|
||||||
import HomePage from './pages/HomePage';
|
|
||||||
import TaskPickerPage from './pages/TaskPickerPage';
|
|
||||||
import TaskDetailPage from './pages/TaskDetailPage';
|
|
||||||
import UploadPage from './pages/UploadPage';
|
|
||||||
import UploadQueuePage from './pages/UploadQueuePage';
|
|
||||||
import GalleryPage from './pages/GalleryPage';
|
|
||||||
import PhotoLightbox from './pages/PhotoLightbox';
|
|
||||||
import AchievementsPage from './pages/AchievementsPage';
|
|
||||||
import SlideshowPage from './pages/SlideshowPage';
|
|
||||||
import SettingsPage from './pages/SettingsPage';
|
|
||||||
import LegalPage from './pages/LegalPage';
|
|
||||||
import PublicGalleryPage from './pages/PublicGalleryPage';
|
|
||||||
import NotFoundPage from './pages/NotFoundPage';
|
|
||||||
import { LocaleProvider } from './i18n/LocaleContext';
|
import { LocaleProvider } from './i18n/LocaleContext';
|
||||||
import { DEFAULT_LOCALE, isLocaleCode } from './i18n/messages';
|
import { DEFAULT_LOCALE, isLocaleCode } from './i18n/messages';
|
||||||
import { useTranslation, type TranslateFn } from './i18n/useTranslation';
|
import { useTranslation, type TranslateFn } from './i18n/useTranslation';
|
||||||
import type { EventBranding } from './types/event-branding';
|
import type { EventBranding } from './types/event-branding';
|
||||||
import type { EventBrandingPayload, FetchEventErrorCode } from './services/eventApi';
|
import type { EventBrandingPayload, FetchEventErrorCode } from './services/eventApi';
|
||||||
|
|
||||||
|
const LandingPage = React.lazy(() => import('./pages/LandingPage'));
|
||||||
|
const ProfileSetupPage = React.lazy(() => import('./pages/ProfileSetupPage'));
|
||||||
|
const HomePage = React.lazy(() => import('./pages/HomePage'));
|
||||||
|
const TaskPickerPage = React.lazy(() => import('./pages/TaskPickerPage'));
|
||||||
|
const TaskDetailPage = React.lazy(() => import('./pages/TaskDetailPage'));
|
||||||
|
const UploadPage = React.lazy(() => import('./pages/UploadPage'));
|
||||||
|
const UploadQueuePage = React.lazy(() => import('./pages/UploadQueuePage'));
|
||||||
|
const GalleryPage = React.lazy(() => import('./pages/GalleryPage'));
|
||||||
|
const PhotoLightbox = React.lazy(() => import('./pages/PhotoLightbox'));
|
||||||
|
const AchievementsPage = React.lazy(() => import('./pages/AchievementsPage'));
|
||||||
|
const SlideshowPage = React.lazy(() => import('./pages/SlideshowPage'));
|
||||||
|
const SettingsPage = React.lazy(() => import('./pages/SettingsPage'));
|
||||||
|
const LegalPage = React.lazy(() => import('./pages/LegalPage'));
|
||||||
|
const PublicGalleryPage = React.lazy(() => import('./pages/PublicGalleryPage'));
|
||||||
|
const NotFoundPage = React.lazy(() => import('./pages/NotFoundPage'));
|
||||||
|
|
||||||
function HomeLayout() {
|
function HomeLayout() {
|
||||||
const { token } = useParams();
|
const { token } = useParams();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user