feat(pdf): inline preview by default with ?download=1 override + vehicle photo fallback
- WorkOrder and InjectorProtocol PDF routes now respond with Content-Disposition: inline (opens in browser tab so the user can read/print/save from the built-in PDF viewer). ?download=1 forces the classic attachment download. - CalendarBoard exportPdf() switched to the same inline default. - WO edit action + WO table row action + injector protocol actions now use ->url(...)->openUrlInNewTab() instead of streaming the PDF inline into the current tab. - Dashboard Docs tab has both a preview link and a "Descarcă" link. - Vehicle card photo falls back to WO's first uploaded photo when Vehicle model has no MediaLibrary integration of its own. Test CalendarEnhancementsTest updated to assert the new inline response headers. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+20
-9
@@ -47,13 +47,21 @@ Route::post('/payments/paypal/webhook', [\App\Http\Controllers\PaymentController
|
||||
Route::post('/payments/paynet/webhook', [\App\Http\Controllers\PaymentController::class, 'paynetWebhook'])
|
||||
->withoutMiddleware([\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class]);
|
||||
|
||||
// PDF download for a work order (used from dashboard's Documents tab).
|
||||
Route::get('/app/work-orders/{workOrder}/pdf', function (int $workOrder) {
|
||||
// PDF for a work order. Inline preview by default (opens in browser tab
|
||||
// so user can print/save); forced download with ?download=1.
|
||||
Route::get('/app/work-orders/{workOrder}/pdf', function (Request $request, int $workOrder) {
|
||||
abort_unless(auth('web')->check(), 403);
|
||||
$wo = \App\Models\Tenant\WorkOrder::findOrFail($workOrder);
|
||||
$svc = app(\App\Services\WorkOrderPdfService::class);
|
||||
$pdf = $svc->generate($wo);
|
||||
return response()->streamDownload(fn () => print($pdf->output()), $svc->filename($wo));
|
||||
$bytes = $pdf->output();
|
||||
$filename = $svc->filename($wo);
|
||||
$disposition = $request->boolean('download') ? 'attachment' : 'inline';
|
||||
return response($bytes, 200, [
|
||||
'Content-Type' => 'application/pdf',
|
||||
'Content-Disposition' => $disposition . '; filename="' . $filename . '"',
|
||||
'Cache-Control' => 'private, no-store',
|
||||
]);
|
||||
})->name('work-orders.pdf');
|
||||
|
||||
// User invitation accept flow (no auth required — token is the credential).
|
||||
@@ -82,17 +90,20 @@ Route::middleware(['web', 'auth'])->group(function () {
|
||||
Route::post('/push/unsubscribe', [\App\Http\Controllers\PushSubscriptionController::class, 'unsubscribe'])
|
||||
->name('push.unsubscribe');
|
||||
|
||||
Route::get('/app/injector-protocols/{record}/pdf', function (\App\Models\Tenant\InjectorProtocol $record) {
|
||||
Route::get('/app/injector-protocols/{record}/pdf', function (Request $request, \App\Models\Tenant\InjectorProtocol $record) {
|
||||
abort_unless(
|
||||
auth()->user()?->canDo(\App\Auth\Permissions::INJECTOR_PROTOCOLS_VIEW),
|
||||
403
|
||||
);
|
||||
$svc = app(\App\Services\InjectorProtocolPdfService::class);
|
||||
return response()->streamDownload(
|
||||
fn () => print($svc->render($record)),
|
||||
$svc->filename($record),
|
||||
['Content-Type' => 'application/pdf']
|
||||
);
|
||||
$bytes = $svc->render($record);
|
||||
$filename = $svc->filename($record);
|
||||
$disposition = $request->boolean('download') ? 'attachment' : 'inline';
|
||||
return response($bytes, 200, [
|
||||
'Content-Type' => 'application/pdf',
|
||||
'Content-Disposition' => $disposition . '; filename="' . $filename . '"',
|
||||
'Cache-Control' => 'private, no-store',
|
||||
]);
|
||||
})->name('tenant.injector-protocols.pdf');
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user