feat: add archived services toggle to services list
- Backend: Accept archived query param to filter past vs future services - Frontend: Add pill-style toggle with Kommende/Vergangene labels - URL updates with ?archived=1 param when viewing past services - Empty state text changes based on archived state - Tests: Add coverage for archived filter functionality
This commit is contained in:
parent
d5abff0d82
commit
8dc26b8ae3
|
|
@ -8,6 +8,10 @@ const props = defineProps({
|
|||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
archived: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
})
|
||||
|
||||
const toastMessage = ref('')
|
||||
|
|
@ -16,6 +20,7 @@ const confirmDialog = ref(false)
|
|||
const confirmWarnings = ref([])
|
||||
const confirmServiceId = ref(null)
|
||||
const finalizing = ref(false)
|
||||
const showArchived = ref(props.archived)
|
||||
|
||||
function formatDate(dateStr) {
|
||||
if (!dateStr) return '—'
|
||||
|
|
@ -172,9 +177,39 @@ function stateIconClass(isDone) {
|
|||
|
||||
<AuthenticatedLayout>
|
||||
<template #header>
|
||||
<div class="flex flex-wrap items-center justify-between gap-3">
|
||||
<div class="flex flex-wrap items-center justify-between gap-4">
|
||||
<div>
|
||||
<h2 class="text-xl font-semibold leading-tight text-gray-800">Services</h2>
|
||||
<p class="text-sm text-gray-500">Hier siehst du alle heutigen und kommenden Services.</p>
|
||||
<p class="mt-1 text-sm text-gray-500">
|
||||
{{ showArchived ? 'Hier siehst du alle vergangenen Services.' : 'Hier siehst du alle heutigen und kommenden Services.' }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="inline-flex rounded-lg border border-gray-300 bg-white p-1 shadow-sm">
|
||||
<button
|
||||
type="button"
|
||||
:class="[
|
||||
'rounded-md px-4 py-2 text-sm font-medium transition-all',
|
||||
!showArchived
|
||||
? 'bg-blue-600 text-white shadow-sm'
|
||||
: 'text-gray-700 hover:bg-gray-100',
|
||||
]"
|
||||
@click="router.get(route('services.index'), { archived: 0 }, { preserveState: true, preserveScroll: true })"
|
||||
>
|
||||
Kommende
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
:class="[
|
||||
'rounded-md px-4 py-2 text-sm font-medium transition-all',
|
||||
showArchived
|
||||
? 'bg-blue-600 text-white shadow-sm'
|
||||
: 'text-gray-700 hover:bg-gray-100',
|
||||
]"
|
||||
@click="router.get(route('services.index'), { archived: 1 }, { preserveState: true, preserveScroll: true })"
|
||||
>
|
||||
Vergangene
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -199,7 +234,7 @@ function stateIconClass(isDone) {
|
|||
|
||||
<div class="overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm">
|
||||
<div v-if="services.length === 0" data-testid="service-list-empty" class="p-8 text-center text-sm text-gray-500">
|
||||
Aktuell gibt es keine heutigen oder kommenden Services.
|
||||
{{ showArchived ? 'Keine vergangenen Services vorhanden.' : 'Aktuell gibt es keine heutigen oder kommenden Services.' }}
|
||||
</div>
|
||||
|
||||
<div v-else class="overflow-x-auto">
|
||||
|
|
|
|||
|
|
@ -270,4 +270,79 @@ public function test_service_edit_erfordert_authentifizierung(): void
|
|||
|
||||
$response->assertRedirect(route('login'));
|
||||
}
|
||||
|
||||
public function test_services_index_zeigt_nur_zukuenftige_services_standardmaessig(): void
|
||||
{
|
||||
Carbon::setTestNow('2026-03-01 10:00:00');
|
||||
$this->withoutVite();
|
||||
|
||||
$user = User::factory()->create();
|
||||
|
||||
Service::factory()->create([
|
||||
'date' => Carbon::today()->subDays(5),
|
||||
'title' => 'Vergangener Service',
|
||||
]);
|
||||
|
||||
$todayService = Service::factory()->create([
|
||||
'date' => Carbon::today(),
|
||||
'title' => 'Heutiger Service',
|
||||
]);
|
||||
|
||||
$futureService = Service::factory()->create([
|
||||
'date' => Carbon::today()->addDays(3),
|
||||
'title' => 'Zukünftiger Service',
|
||||
]);
|
||||
|
||||
$response = $this->actingAs($user)->get(route('services.index'));
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertInertia(
|
||||
fn ($page) => $page
|
||||
->component('Services/Index')
|
||||
->has('services', 2)
|
||||
->where('services.0.title', 'Heutiger Service')
|
||||
->where('services.1.title', 'Zukünftiger Service')
|
||||
->where('archived', false)
|
||||
);
|
||||
}
|
||||
|
||||
public function test_services_index_zeigt_vergangene_services_mit_archived_parameter(): void
|
||||
{
|
||||
Carbon::setTestNow('2026-03-01 10:00:00');
|
||||
$this->withoutVite();
|
||||
|
||||
$user = User::factory()->create();
|
||||
|
||||
$pastService1 = Service::factory()->create([
|
||||
'date' => Carbon::today()->subDays(5),
|
||||
'title' => 'Vergangener Service 1',
|
||||
]);
|
||||
|
||||
$pastService2 = Service::factory()->create([
|
||||
'date' => Carbon::today()->subDays(2),
|
||||
'title' => 'Vergangener Service 2',
|
||||
]);
|
||||
|
||||
Service::factory()->create([
|
||||
'date' => Carbon::today(),
|
||||
'title' => 'Heutiger Service',
|
||||
]);
|
||||
|
||||
Service::factory()->create([
|
||||
'date' => Carbon::today()->addDays(3),
|
||||
'title' => 'Zukünftiger Service',
|
||||
]);
|
||||
|
||||
$response = $this->actingAs($user)->get(route('services.index', ['archived' => 1]));
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertInertia(
|
||||
fn ($page) => $page
|
||||
->component('Services/Index')
|
||||
->has('services', 2)
|
||||
->where('services.0.title', 'Vergangener Service 2')
|
||||
->where('services.1.title', 'Vergangener Service 1')
|
||||
->where('archived', true)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue