route('install.welcome'); } return redirect()->route('login'); }); if (! is_link(public_path('storage'))) { Route::get('/storage/{path}', \App\Http\Controllers\StorageFallbackController::class) ->where('path', '.*') ->name('storage.fallback'); } Route::get('/manifest.webmanifest', function () { return response(json_encode([ 'name' => brand(), 'short_name' => brand(), 'display' => 'standalone', 'theme_color' => '#1e293b', 'background_color' => '#0f172a', 'start_url' => '/driver', 'scope' => '/', 'icons' => [ ['src' => '/pwa-icon-192x192.png', 'sizes' => '192x192', 'type' => 'image/png', 'purpose' => 'any'], ['src' => '/pwa-icon-192x192.png', 'sizes' => '192x192', 'type' => 'image/png', 'purpose' => 'maskable'], ['src' => '/pwa-icon-512x512.png', 'sizes' => '512x512', 'type' => 'image/png', 'purpose' => 'any'], ['src' => '/pwa-icon-512x512.png', 'sizes' => '512x512', 'type' => 'image/png', 'purpose' => 'maskable'], ], ], JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)) ->header('Content-Type', 'application/manifest+json'); })->name('manifest.webmanifest'); Route::get('/dashboard', function () { if (Auth::user()->isAdmin()) { return redirect()->route('admin.dashboard'); } $user = Auth::user(); $shiftActive = \App\Models\WorkShift::where('user_id', $user->id) ->whereNull('ended_at') ->exists(); $customers = \App\Models\Customer::with('objects')->orderBy('name')->get(); $vehicles = \App\Models\Vehicle::orderBy('name')->get(); $defaultVehicleId = $user->default_vehicle_id; return view('driver.dashboard', [ 'shiftActive' => $shiftActive, 'customers' => $customers, 'vehicles' => $vehicles, 'defaultVehicleId' => $defaultVehicleId, ]); })->middleware(['auth', 'dsgvo'])->name('dashboard'); Route::middleware(['auth', 'admin'])->prefix('admin')->name('admin.')->group(function () { Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard'); Route::post('/dashboard/dismiss-onboarding', [DashboardController::class, 'dismissOnboarding'])->name('dashboard.dismiss-onboarding'); Route::resource('customers', CustomerController::class)->except(['show']); Route::post('/customers/geocode', [CustomerController::class, 'geocode'])->name('customers.geocode'); Route::resource('customers.objects', CustomerObjectController::class)->except(['show'])->scoped(); Route::post('/customers/{customer}/portal-access', [CustomerPortalController::class, 'setupAccess'])->name('customers.portal-access'); Route::put('/customers/{customer}/portal-settings', [CustomerPortalController::class, 'updateSettings'])->name('customers.portal-settings'); Route::get('/drivers/export-all', [DriverExportController::class, 'exportAll'])->name('drivers.export-all'); Route::get('/drivers/archived', [ArchivedDriverController::class, 'index'])->name('drivers.archived'); Route::resource('drivers', DriverController::class)->except(['show', 'destroy']); Route::get('/drivers/{driver}/export', [DriverExportController::class, 'exportSingle'])->name('drivers.export'); Route::get('/drivers/{driver}/credentials', [DriverCredentialController::class, 'show'])->name('drivers.credentials'); Route::post('/drivers/{driver}/rotate-credentials', [DriverCredentialController::class, 'rotate'])->name('drivers.rotate-credentials'); Route::post('/drivers/{driver}/anonymize', DriverAnonymizationController::class)->name('drivers.anonymize'); Route::resource('vehicles', VehicleController::class)->except(['show']); Route::get('/dsgvo', [DsgvoAdminController::class, 'index'])->name('dsgvo.index'); Route::put('/dsgvo', [DsgvoAdminController::class, 'update'])->name('dsgvo.update'); Route::post('/dsgvo/preview', [DsgvoAdminController::class, 'preview'])->name('dsgvo.preview'); Route::get('/dsgvo/confirmations', [DsgvoAdminController::class, 'confirmations'])->name('dsgvo.confirmations'); Route::get('/dsgvo/confirmations/{confirmation}', [DsgvoAdminController::class, 'showConfirmation'])->name('dsgvo.confirmations.show'); Route::get('/customers/{customer}/objects/json', function (\App\Models\Customer $customer) { return $customer->objects()->orderBy('name')->get(['id', 'name', 'street', 'city']); })->name('customers.objects.json'); Route::get('/jobs', [AdminJobController::class, 'index'])->name('jobs.index'); Route::get('/jobs/manual/create', [AdminManualJobController::class, 'create'])->name('jobs.manual.create'); Route::post('/jobs/manual', [AdminManualJobController::class, 'store'])->name('jobs.manual.store'); Route::get('/jobs/{serviceJob}/edit', [AdminJobController::class, 'edit'])->name('jobs.edit'); Route::put('/jobs/{serviceJob}', [AdminJobController::class, 'update'])->name('jobs.update'); Route::get('/jobs/{serviceJob}', [AdminJobController::class, 'show'])->name('jobs.show'); Route::delete('/jobs/{serviceJob}', [AdminJobController::class, 'destroy'])->name('jobs.destroy'); Route::get('/jobs/{serviceJob}/pdf', [AdminJobController::class, 'pdf'])->name('jobs.pdf'); Route::post('/jobs/{serviceJob}/weather-retry/{moment}', WeatherRetryController::class) ->name('jobs.weather-retry') ->where('moment', 'start|end'); Route::get('/workshifts', [AdminWorkShiftController::class, 'index'])->name('workshifts.index'); Route::get('/workshifts/{workShift}', [AdminWorkShiftController::class, 'show'])->name('workshifts.show'); Route::get('/overview/daily', [OverviewController::class, 'daily'])->name('overview.daily'); Route::get('/overview/monthly', [OverviewController::class, 'monthly'])->name('overview.monthly'); Route::get('/overview/day-detail', [OverviewController::class, 'dayDetail'])->name('overview.day-detail'); Route::get('/overview/driver-report', [DriverReportController::class, 'index'])->name('overview.driver-report'); Route::get('/overview/customer-report', [CustomerReportController::class, 'index'])->name('overview.customer-report'); Route::post('/overview/customer-report/email', [CustomerReportEmailController::class, 'send'])->name('overview.customer-report.email'); Route::get('/exports/csv', [CsvExportController::class, 'index'])->name('exports.csv'); Route::get('/exports/csv/download', [CsvExportController::class, 'download'])->name('exports.csv.download'); Route::get('/exports/customer-pdf', [CustomerPdfController::class, 'index'])->name('exports.customer-pdf'); Route::post('/exports/customer-pdf', [CustomerPdfController::class, 'generate'])->name('exports.customer-pdf.generate'); Route::get('/alerts', [AlertController::class, 'index'])->name('alerts.index'); Route::post('/alerts/{serviceJob}/resolve', [AlertController::class, 'resolve'])->name('alerts.resolve'); Route::post('/alerts/bulk-resolve', [AlertController::class, 'bulkResolve'])->name('alerts.bulk-resolve'); Route::get('/owntracks/overview', OwntracksOverviewController::class)->name('owntracks.overview'); Route::get('/help', [HelpController::class, 'index'])->name('help.index'); Route::get('/help/{topic}', [HelpController::class, 'show'])->name('help.show'); Route::get('/settings', function () { return view('admin.settings.index'); })->name('settings.index'); Route::get('/settings/branding', [BrandingController::class, 'edit'])->name('settings.branding'); Route::post('/settings/branding', [BrandingController::class, 'update'])->name('settings.branding.update'); Route::delete('/settings/branding/logo', [BrandingController::class, 'deleteLogo'])->name('settings.branding.delete-logo'); Route::get('/settings/notification-log', [NotificationLogController::class, 'index'])->name('settings.notification-log'); Route::get('/settings/email', [EmailSettingsController::class, 'edit'])->name('settings.email'); Route::post('/settings/email', [EmailSettingsController::class, 'update'])->name('settings.email.update'); Route::post('/settings/email/test', [EmailSettingsController::class, 'sendTest'])->name('settings.email.test'); Route::get('/settings/company', [CompanyController::class, 'edit'])->name('settings.company'); Route::post('/settings/company', [CompanyController::class, 'update'])->name('settings.company.update'); Route::get('/settings/retention', [RetentionController::class, 'edit'])->name('settings.retention'); Route::post('/settings/retention', [RetentionController::class, 'update'])->name('settings.retention.update'); Route::get('/settings/weather', [WeatherSettingsController::class, 'edit'])->name('settings.weather'); Route::post('/settings/weather', [WeatherSettingsController::class, 'update'])->name('settings.weather.update'); Route::post('/settings/weather/test', [WeatherSettingsController::class, 'testConnection'])->name('settings.weather.test'); Route::get('/settings/update', [UpdateSettingsController::class, 'edit'])->name('settings.update'); Route::post('/settings/update', [UpdateSettingsController::class, 'update'])->name('settings.update.update'); Route::post('/settings/update/check', [UpdateSettingsController::class, 'checkNow'])->name('settings.update.check'); Route::post('/settings/update/install', [UpdateSettingsController::class, 'install'])->name('settings.update.install'); Route::get('/settings/modules', [AdminModuleController::class, 'index'])->name('settings.modules.index'); Route::post('/settings/modules/{slug}/install', [AdminModuleController::class, 'install'])->name('settings.modules.install'); Route::post('/settings/modules/{slug}/enable', [AdminModuleController::class, 'enable'])->name('settings.modules.enable'); Route::post('/settings/modules/{slug}/disable', [AdminModuleController::class, 'disable'])->name('settings.modules.disable'); Route::post('/settings/modules/{slug}/update', [AdminModuleController::class, 'update'])->name('settings.modules.update'); Route::delete('/settings/modules/{slug}/remove', [AdminModuleController::class, 'remove'])->name('settings.modules.remove'); }); Route::middleware(['auth', 'dsgvo', 'driver'])->prefix('driver')->name('driver.')->group(function () { Route::get('/', function () { $user = \Illuminate\Support\Facades\Auth::user(); $shiftActive = \App\Models\WorkShift::where('user_id', $user->id) ->whereNull('ended_at') ->exists(); $customers = \App\Models\Customer::with('objects')->orderBy('name')->get(); $vehicles = \App\Models\Vehicle::orderBy('name')->get(); $defaultVehicleId = $user->default_vehicle_id; return view('driver.dashboard', [ 'shiftActive' => $shiftActive, 'customers' => $customers, 'vehicles' => $vehicles, 'defaultVehicleId' => $defaultVehicleId, ]); })->name('home'); Route::post('/shift/start', [DriverShiftController::class, 'start'])->name('shift.start'); Route::post('/shift/end', [DriverShiftController::class, 'end'])->name('shift.end'); Route::post('/job/start', [DriverJobController::class, 'start'])->name('job.start'); Route::post('/job/end', [DriverJobController::class, 'end'])->name('job.end'); Route::get('/job/active', [DriverJobController::class, 'active'])->name('job.active'); Route::post('/job/photo', [DriverPhotoController::class, 'store'])->name('job.photo.store'); Route::get('/job/manual/create', [DriverManualJobController::class, 'create'])->name('job.manual.create'); Route::post('/job/manual', [DriverManualJobController::class, 'store'])->name('job.manual.store'); Route::get('/customers/{customer}/objects', function (\App\Models\Customer $customer) { return $customer->objects()->orderBy('name')->get(['id', 'name', 'street', 'city']); })->name('customer.objects'); Route::get('/jobs', [DriverJobHistoryController::class, 'index'])->name('jobs.index'); Route::get('/jobs/{job}', [DriverJobHistoryController::class, 'show'])->name('jobs.show'); }); Route::middleware('auth')->group(function () { Route::get('/onboarding/dsgvo', [DsgvoOnboardingController::class, 'show'])->name('onboarding.dsgvo'); Route::post('/onboarding/dsgvo', [DsgvoOnboardingController::class, 'confirm'])->name('onboarding.dsgvo.confirm'); Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit'); Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update'); Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy'); }); // Portal (customer-facing) Route::prefix('portal')->name('portal.')->group(function () { Route::middleware('guest:customer')->group(function () { Route::get('/login', [PortalAuthController::class, 'showLogin'])->name('login'); Route::post('/login', [PortalAuthController::class, 'login']); }); Route::middleware(['auth:customer', 'portal'])->group(function () { Route::get('/', PortalDashboardController::class)->name('home'); Route::get('/jobs', [PortalJobController::class, 'index'])->name('jobs.index'); Route::get('/jobs/{serviceJob}', [PortalJobController::class, 'show'])->name('jobs.show'); Route::get('/jobs/{serviceJob}/pdf', [PortalPdfController::class, 'jobPdf'])->name('jobs.pdf'); Route::get('/reports', [PortalPdfController::class, 'index'])->name('reports.index'); Route::post('/reports/generate', [PortalPdfController::class, 'generate'])->name('reports.generate'); Route::get('/notifications', [PortalNotificationController::class, 'index'])->name('notifications.index'); Route::get('/profile', [PortalProfileController::class, 'edit'])->name('profile.edit'); Route::patch('/profile', [PortalProfileController::class, 'update'])->name('profile.update'); Route::post('/logout', [PortalAuthController::class, 'logout'])->name('logout'); }); }); require __DIR__.'/auth.php';