Files
Tim Basten 564f78dcda
All checks were successful
linter / quality (push) Successful in 1m37s
tests / ci (8.4) (push) Successful in 2m13s
tests / ci (8.5) (push) Successful in 1m25s
initial
2026-03-05 11:41:39 +08:00

187 lines
8.2 KiB
PHP

<?php
use App\Enums\TravelStatus;
use App\Models\TravelRequest;
use Livewire\Attributes\Layout;
use Livewire\Component;
new #[Layout('components.layouts.app')] class extends Component {
public TravelRequest $travelRequest;
public function mount(int $id): void
{
$this->travelRequest = TravelRequest::with([
'user', 'workflow', 'journeys', 'costCodes',
'approvals.step', 'approvals.approver',
])->findOrFail($id);
$user = auth()->user();
abort_unless(
$user->id === $this->travelRequest->user_id || $user->hasAnyRole(['travel_approver', 'administrator']),
403
);
}
public function render(): mixed
{
return view('livewire.travel-request.show');
}
}
?>
<div>
<div class="d-flex justify-content-between align-items-center mb-4">
<h2 class="h4 mb-0">Travel Request #{{ $travelRequest->id }}</h2>
<div class="d-flex gap-2">
@php
$badgeClass = match($travelRequest->status) {
\App\Enums\TravelStatus::Draft => 'secondary',
\App\Enums\TravelStatus::Pending => 'warning',
\App\Enums\TravelStatus::Approved => 'success',
\App\Enums\TravelStatus::Rejected => 'danger',
};
@endphp
<span class="badge bg-{{ $badgeClass }} fs-6">{{ $travelRequest->status->value }}</span>
@if ($travelRequest->status === \App\Enums\TravelStatus::Pending && auth()->user()->hasAnyRole(['travel_approver', 'administrator']))
<a href="{{ route('travel-requests.approve', $travelRequest) }}" class="btn btn-primary btn-sm">Review</a>
@endif
<a href="{{ route('dashboard') }}" class="btn btn-outline-secondary btn-sm">Back</a>
</div>
</div>
{{-- Applicant Details --}}
<div class="card mb-4">
<div class="card-header fw-semibold">Applicant Details</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<dl class="row mb-0">
<dt class="col-sm-4">Name</dt>
<dd class="col-sm-8">{{ $travelRequest->user->name }}</dd>
<dt class="col-sm-4">Email</dt>
<dd class="col-sm-8">{{ $travelRequest->user->email }}</dd>
<dt class="col-sm-4">Department</dt>
<dd class="col-sm-8">{{ $travelRequest->user->department ?? '—' }}</dd>
</dl>
</div>
<div class="col-md-6">
<dl class="row mb-0">
<dt class="col-sm-4">Submitted</dt>
<dd class="col-sm-8">{{ $travelRequest->submitted_at?->format('d M Y H:i') ?? 'Not submitted' }}</dd>
<dt class="col-sm-4">Workflow</dt>
<dd class="col-sm-8">{{ $travelRequest->workflow?->name ?? '—' }}</dd>
</dl>
</div>
</div>
</div>
</div>
{{-- Reason --}}
<div class="card mb-4">
<div class="card-header fw-semibold">Reason for Travel</div>
<div class="card-body">
<p class="mb-2">{{ $travelRequest->reason_summary }}</p>
@if ($travelRequest->event_type)
<span class="badge bg-info text-dark">Event: {{ $travelRequest->event_type->label() }}</span>
@elseif ($travelRequest->general_type)
<span class="badge bg-info text-dark">General: {{ $travelRequest->general_type->label() }}</span>
@endif
</div>
</div>
{{-- Journeys --}}
<div class="card mb-4">
<div class="card-header fw-semibold">Journeys</div>
<div class="table-responsive">
<table class="table table-sm mb-0">
<thead class="table-light">
<tr>
<th>Origin</th>
<th>Destination</th>
<th>Date</th>
<th>Time</th>
<th>Method</th>
</tr>
</thead>
<tbody>
@foreach ($travelRequest->journeys as $journey)
<tr>
<td>{{ $journey->origin }}</td>
<td>{{ $journey->destination }}</td>
<td>{{ $journey->date->format('d M Y') }}</td>
<td>{{ $journey->time ?? '—' }}</td>
<td>{{ $journey->method->label() }}</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
{{-- Additional Details --}}
<div class="card mb-4">
<div class="card-header fw-semibold">Additional Details</div>
<div class="card-body">
<div class="row mb-3">
<div class="col-auto">
<span class="badge {{ $travelRequest->needs_accommodation ? 'bg-primary' : 'bg-secondary' }}">
Accommodation: {{ $travelRequest->needs_accommodation ? 'Required' : 'Not Required' }}
</span>
</div>
<div class="col-auto">
<span class="badge {{ $travelRequest->needs_car_hire ? 'bg-primary' : 'bg-secondary' }}">
Car Hire: {{ $travelRequest->needs_car_hire ? 'Required' : 'Not Required' }}
</span>
</div>
</div>
<dl class="row mb-0">
<dt class="col-sm-3">Business Days</dt>
<dd class="col-sm-9">{{ $travelRequest->business_days }}</dd>
<dt class="col-sm-3">Private Days</dt>
<dd class="col-sm-9">{{ $travelRequest->private_days }}</dd>
@if ($travelRequest->additional_notes)
<dt class="col-sm-3">Notes</dt>
<dd class="col-sm-9">{{ $travelRequest->additional_notes }}</dd>
@endif
</dl>
</div>
</div>
{{-- Approval Timeline --}}
@if ($travelRequest->approvals->isNotEmpty())
<div class="card mb-4">
<div class="card-header fw-semibold">Approval Timeline</div>
<div class="card-body">
@foreach ($travelRequest->approvals as $approval)
<div class="d-flex align-items-start mb-3">
<div class="me-3 mt-1">
@php
$iconClass = match($approval->status) {
\App\Enums\ApprovalStatus::Approved => 'text-success',
\App\Enums\ApprovalStatus::Rejected => 'text-danger',
default => 'text-warning',
};
@endphp
<span class="badge bg-{{ $iconClass === 'text-success' ? 'success' : ($iconClass === 'text-danger' ? 'danger' : 'warning') }}">
Step {{ $approval->step->order }}
</span>
</div>
<div>
<strong>{{ $approval->step->name }}</strong>
<span class="ms-2 badge bg-{{ $approval->status === \App\Enums\ApprovalStatus::Approved ? 'success' : ($approval->status === \App\Enums\ApprovalStatus::Rejected ? 'danger' : 'warning') }}">
{{ $approval->status->value }}
</span>
@if ($approval->approver)
<div class="text-muted small">By {{ $approval->approver->name }} on {{ $approval->acted_at?->format('d M Y H:i') }}</div>
@endif
@if ($approval->comments)
<div class="mt-1 text-muted small fst-italic">"{{ $approval->comments }}"</div>
@endif
</div>
</div>
@endforeach
</div>
</div>
@endif
</div>