Files
mesreleves-php/resources/views/sources/index.blade.php
T
yann64 d064f8d28e Étapes 6-9 + types de lieux + picker + filtres
- Étape 6 : formulaire de saisie dynamique des relevés (piloté par source_type_fields, calendriers grégorien/julien/républicain)
- Étape 7 : workflow de statut des sources + notifications mail+DB (SourceAValider, SourceRejetee)
- Étape 8 : recherche fulltext PostgreSQL avec filtres type/lieu/années et CTE récursive pour les subdivisions de lieux
- Étape 9 : export GEDCOM 5.5.1 (GedcomExportService + DateConversionService)
- Types de lieux : CRUD admin (LieuTypeController) avec champ ordre
- Composant lieu-picker : modale Alpine.js avec recherche AJAX + debounce
- Filtres sources : statut, type, lieu (CTE récursive), période annee_debut/annee_fin
- Filtres lieux : type, texte, lieu parent avec descendants (CTE récursive)
- Migration : lieu_id + annee_debut + annee_fin sur sources

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 17:17:53 +02:00

170 lines
9.5 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<x-app-layout>
<x-slot name="header">
<div class="flex items-center justify-between">
<h2 class="text-xl font-semibold text-gray-800">Sources</h2>
@can('create', App\Models\Source::class)
<a href="{{ route('sources.create') }}"
class="px-4 py-2 bg-indigo-600 text-white text-sm rounded-md hover:bg-indigo-700">+ Nouvelle source</a>
@endcan
</div>
</x-slot>
<div class="py-8 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 space-y-6">
@if(session('success'))
<div class="p-4 bg-green-50 border border-green-200 text-green-800 rounded-md">{{ session('success') }}</div>
@endif
{{-- Filtres --}}
@php
$hasFilters = request()->anyFilled(['status', 'source_type_id', 'lieu_id', 'annee_debut', 'annee_fin']);
@endphp
<div class="bg-white shadow rounded-lg p-5">
<form method="GET" action="{{ route('sources.index') }}">
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
{{-- Statut --}}
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">Statut</label>
<select name="status"
class="block w-full rounded-md border-gray-300 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
<option value=""> Tous </option>
@foreach(\App\Enums\SourceStatus::cases() as $s)
<option value="{{ $s->value }}" {{ request('status') === $s->value ? 'selected' : '' }}>
{{ $s->label() }}
</option>
@endforeach
</select>
</div>
{{-- Type de source --}}
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">Type de source</label>
<select name="source_type_id"
class="block w-full rounded-md border-gray-300 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
<option value=""> Tous </option>
@foreach($sourceTypes as $st)
<option value="{{ $st->id }}" {{ request('source_type_id') == $st->id ? 'selected' : '' }}>
{{ $st->nom }}
</option>
@endforeach
</select>
</div>
{{-- Année de début --}}
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">Période de</label>
<input type="number" name="annee_debut" value="{{ request('annee_debut') }}"
min="1000" max="2100" placeholder="ex : 1820"
class="block w-full rounded-md border-gray-300 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
</div>
{{-- Année de fin --}}
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">Période à</label>
<input type="number" name="annee_fin" value="{{ request('annee_fin') }}"
min="1000" max="2100" placeholder="ex : 1870"
class="block w-full rounded-md border-gray-300 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
</div>
</div>
{{-- Lieu --}}
<div class="mt-4 max-w-sm">
<x-lieu-picker
name="lieu_id"
label="Lieu (et ses subdivisions)"
:value="request('lieu_id')"
:display-value="$lieuSelectionne?->nom_long ?? $lieuSelectionne?->nom ?? ''"
placeholder="— Tous les lieux —"
/>
</div>
<div class="mt-4 flex items-center gap-3">
<button type="submit"
class="px-5 py-2 bg-indigo-600 text-white text-sm font-medium rounded-md hover:bg-indigo-700">
Filtrer
</button>
@if($hasFilters)
<a href="{{ route('sources.index') }}"
class="px-4 py-2 border border-gray-300 text-gray-600 text-sm rounded-md hover:bg-gray-50">
Effacer les filtres
</a>
<span class="inline-flex items-center px-2 py-0.5 rounded-full text-xs bg-indigo-100 text-indigo-700">
filtres actifs
</span>
@endif
</div>
</form>
</div>
{{-- Tableau --}}
<div class="bg-white shadow rounded-lg overflow-hidden">
<table class="min-w-full divide-y divide-gray-200 text-sm">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Nom</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Type</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Statut</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Lieu</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Période</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Relevés</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Dépôt</th>
<th class="px-6 py-3"></th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
@forelse($sources as $source)
@php
$statusColors = [
'a_faire' => 'bg-gray-100 text-gray-600',
'en_cours' => 'bg-blue-100 text-blue-700',
'a_valider' => 'bg-yellow-100 text-yellow-700',
'termine' => 'bg-green-100 text-green-700',
];
$color = $statusColors[$source->status->value] ?? 'bg-gray-100 text-gray-600';
$periode = match(true) {
$source->annee_debut && $source->annee_fin => $source->annee_debut . ' ' . $source->annee_fin,
(bool)$source->annee_debut => 'depuis ' . $source->annee_debut,
(bool)$source->annee_fin => 'jusqu\'en ' . $source->annee_fin,
default => '—',
};
@endphp
<tr class="hover:bg-gray-50">
<td class="px-6 py-4 font-medium">
<a href="{{ route('sources.show', $source) }}" class="text-indigo-600 hover:underline">{{ $source->nom }}</a>
@if($source->cote) <span class="ml-2 text-xs text-gray-400">{{ $source->cote }}</span> @endif
</td>
<td class="px-6 py-4 text-gray-500">{{ $source->sourceType->nom }}</td>
<td class="px-6 py-4">
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium {{ $color }}">
{{ $source->status->label() }}
</span>
</td>
<td class="px-6 py-4 text-gray-500 max-w-[180px] truncate" title="{{ $source->lieu?->nom_long ?? $source->lieu?->nom }}">
{{ $source->lieu?->nom ?? '—' }}
</td>
<td class="px-6 py-4 text-gray-500 whitespace-nowrap">{{ $periode }}</td>
<td class="px-6 py-4 text-gray-500">{{ $source->releves_count }}</td>
<td class="px-6 py-4 text-gray-500">{{ $source->depot?->nom ?? '—' }}</td>
<td class="px-6 py-4 text-right text-sm space-x-3">
@can('update', $source)
<a href="{{ route('sources.edit', $source) }}" class="text-gray-600 hover:text-indigo-600">Modifier</a>
@endcan
</td>
</tr>
@empty
<tr>
<td colspan="8" class="px-6 py-10 text-center text-gray-400">
@if($hasFilters) Aucune source ne correspond aux filtres.
@else Aucune source disponible. @endif
</td>
</tr>
@endforelse
</tbody>
</table>
@if($sources->hasPages())
<div class="px-6 py-4 border-t">{{ $sources->links() }}</div>
@endif
</div>
</div>
</x-app-layout>