feat(admin/trips): surface dumpsite release records in trip detail panel
- Eager-load dumpsiteReleases.dumpsite + dumpsiteReleases.releasedByDriver
in AdminTripController::show()
- Add releases[] array to TripResource via whenLoaded('dumpsiteReleases')
- Fields: weight_kg, released_at, dumpsite_name, driver_name,
gate_pass_number, dumpsite_attendant, notes
- Admin Trips detail panel now shows a 'Dumpsite Releases' section
below the timeline with per-release cards
- Load row updated to show release count e.g. '450 kg (2 releases)'
This commit is contained in:
@@ -99,6 +99,7 @@ class AdminTripController extends ApiController
|
||||
$trip->load([
|
||||
'route', 'team.driver', 'team.scanner', 'truck', 'dumpsite',
|
||||
'stops.dropOffPoint', 'timelineEvents.recordedBy',
|
||||
'dumpsiteReleases.dumpsite', 'dumpsiteReleases.releasedByDriver',
|
||||
]);
|
||||
|
||||
return $this->ok(new TripResource($trip));
|
||||
|
||||
@@ -20,6 +20,7 @@ class TripResource extends JsonResource
|
||||
'dumpsite_arrival_time' => $this->dumpsite_arrival_time?->toIso8601String(),
|
||||
'dumpsite_departure_time' => $this->dumpsite_departure_time?->toIso8601String(),
|
||||
'total_load_kg' => $this->total_load_kg,
|
||||
'current_load_kg' => $this->current_load_kg,
|
||||
'is_detouring' => $this->is_detouring,
|
||||
'route' => RouteResource::make($this->whenLoaded('route')),
|
||||
'team' => CollectionTeamResource::make($this->whenLoaded('team')),
|
||||
@@ -28,6 +29,16 @@ class TripResource extends JsonResource
|
||||
'stops' => TripStopResource::collection($this->whenLoaded('stops')),
|
||||
'timeline' => TripTimelineEventResource::collection($this->whenLoaded('timelineEvents')),
|
||||
'notes' => $this->notes,
|
||||
'releases' => $this->whenLoaded('dumpsiteReleases', fn () => $this->dumpsiteReleases->map(fn ($r) => [
|
||||
'id' => $r->id,
|
||||
'weight_kg' => $r->weight_kg,
|
||||
'released_at' => $r->released_at?->toIso8601String(),
|
||||
'dumpsite_name' => $r->dumpsite?->name,
|
||||
'driver_name' => $r->releasedByDriver?->full_name,
|
||||
'gate_pass_number' => $r->gate_pass_number,
|
||||
'dumpsite_attendant' => $r->dumpsite_attendant_name,
|
||||
'notes' => $r->notes,
|
||||
])),
|
||||
'created_at' => $this->created_at?->toIso8601String(),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -226,12 +226,33 @@
|
||||
<dt class="text-neutral-500">Date</dt><dd>${window.Verde.escapeHtml(t.scheduled_date)}</dd>
|
||||
<dt class="text-neutral-500">Route</dt><dd>${window.Verde.escapeHtml(t.route?.name ?? '—')}</dd>
|
||||
<dt class="text-neutral-500">Team</dt><dd>${window.Verde.escapeHtml(t.team?.name ?? '—')}</dd>
|
||||
<dt class="text-neutral-500">Load</dt><dd>${t.total_load_kg ? `${t.total_load_kg} kg` : '—'}</dd>
|
||||
<dt class="text-neutral-500">Load</dt><dd>${t.total_load_kg
|
||||
? `${t.total_load_kg} kg${t.releases?.length ? ` (${t.releases.length} release${t.releases.length > 1 ? 's' : ''})` : ''}`
|
||||
: '—'}</dd>
|
||||
</div>
|
||||
<h4 class="mb-2 text-xs font-semibold uppercase tracking-wider text-neutral-500">Stops</h4>
|
||||
<ul class="mb-4 space-y-1.5">${stops || '<li class="text-xs text-neutral-400">No stops</li>'}</ul>
|
||||
<h4 class="mb-2 text-xs font-semibold uppercase tracking-wider text-neutral-500">Timeline</h4>
|
||||
<ul class="space-y-2">${timeline || '<li class="text-xs text-neutral-400">No events yet</li>'}</ul>
|
||||
<h4 class="mt-4 mb-2 text-xs font-semibold uppercase tracking-wider text-neutral-500">Dumpsite Releases</h4>
|
||||
${t.releases?.length
|
||||
? `<ul class="space-y-2">${t.releases.map(r => `
|
||||
<li class="rounded border border-neutral-200 bg-neutral-50 p-2.5 text-xs">
|
||||
<div class="flex items-center justify-between mb-1">
|
||||
<span class="font-semibold text-neutral-800">${window.Verde.escapeHtml(r.dumpsite_name || '—')}</span>
|
||||
<span class="font-mono text-neutral-400">${window.Verde.formatDate(r.released_at, { hour: '2-digit', minute: '2-digit' })}</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="font-bold text-verde-700">${r.weight_kg} kg</span>
|
||||
${r.gate_pass_number ? `<span class="text-neutral-500">Gate pass: ${window.Verde.escapeHtml(r.gate_pass_number)}</span>` : ''}
|
||||
</div>
|
||||
<div class="mt-1 text-neutral-500">Driver: ${window.Verde.escapeHtml(r.driver_name || '—')}</div>
|
||||
${r.dumpsite_attendant ? `<div class="text-neutral-500">Attendant: ${window.Verde.escapeHtml(r.dumpsite_attendant)}</div>` : ''}
|
||||
${r.notes ? `<div class="mt-1 italic text-neutral-400">${window.Verde.escapeHtml(r.notes)}</div>` : ''}
|
||||
</li>
|
||||
`).join('')}</ul>`
|
||||
: '<p class="text-xs text-neutral-400">No releases recorded yet</p>'
|
||||
}
|
||||
`;
|
||||
|
||||
if (tripMapInstance) {
|
||||
|
||||
Reference in New Issue
Block a user