Files
yann64 6a73a2f001 Gestion utilisateurs, limites recherche, filtres lieux/sources, fix logo prod
- Admin : CRUD complet utilisateurs (créer, modifier nom/email/mdp/rôle, supprimer)
  avec garde-fous (dernier admin, compte propre)
- Recherche : limite configurable par l'admin (défaut 200), bannière d'avertissement
  quand la limite est atteinte, plus de pagination (résultats en bloc)
- Lieux : liste non chargée sans filtre actif (performance sur grands volumes)
- Sources : idem pour admin/responsables ; membres voient toujours leurs sources
- Logo 404 prod : +FollowSymLinks dans .htaccess, storage:link dans l'assistant
  d'installation, bouton "Recréer le lien" dans Administration → Paramètres

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 03:39:06 +02:00

179 lines
11 KiB
PHP
Raw Permalink 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 dark:text-gray-200">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 dark:bg-green-900/30 border border-green-200 dark:border-green-700 text-green-800 dark:text-green-200 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 dark:bg-gray-800 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 dark:text-gray-400 mb-1">Statut</label>
<select name="status"
class="block w-full rounded-md border-gray-300 dark:border-gray-600 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 dark:text-gray-400 mb-1">Type de source</label>
<select name="source_type_id"
class="block w-full rounded-md border-gray-300 dark:border-gray-600 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 dark:text-gray-400 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 dark:border-gray-600 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 dark:text-gray-400 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 dark:border-gray-600 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 dark:border-gray-600 text-gray-600 dark:text-gray-400 text-sm rounded-md hover:bg-gray-50 dark:hover:bg-gray-700">
Effacer les filtres
</a>
<span class="inline-flex items-center px-2 py-0.5 rounded-full text-xs bg-indigo-100 dark:bg-indigo-900/50 text-indigo-700">
filtres actifs
</span>
@endif
</div>
</form>
</div>
{{-- Tableau --}}
@if($sources === null)
<div class="text-center py-16 text-gray-400 dark:text-gray-500">
<svg class="mx-auto w-12 h-12 mb-4 text-gray-300 dark:text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/>
</svg>
<p class="text-sm">Utilisez les filtres ci-dessus pour afficher les sources.</p>
</div>
@else
<div class="bg-white dark:bg-gray-800 shadow rounded-lg overflow-hidden">
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700 text-sm">
<thead class="bg-gray-50 dark:bg-gray-700">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Nom</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Type</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Statut</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Lieu</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Période</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Relevés</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Dépôt</th>
<th class="px-6 py-3"></th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
@forelse($sources as $source)
@php
$statusColors = [
'a_faire' => 'bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-400',
'en_cours' => 'bg-blue-100 dark:bg-blue-900/50 text-blue-700',
'a_valider' => 'bg-yellow-100 dark:bg-yellow-900/50 text-yellow-700',
'termine' => 'bg-green-100 dark:bg-green-900/50 text-green-700',
];
$color = $statusColors[$source->status->value] ?? 'bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-400';
$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 dark:hover:bg-gray-700">
<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 dark:text-gray-500">{{ $source->cote }}</span> @endif
</td>
<td class="px-6 py-4 text-gray-500 dark:text-gray-400">{{ $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 dark:text-gray-400 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 dark:text-gray-400 whitespace-nowrap">{{ $periode }}</td>
<td class="px-6 py-4 text-gray-500 dark:text-gray-400">{{ $source->releves_count }}</td>
<td class="px-6 py-4 text-gray-500 dark:text-gray-400">{{ $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 dark:text-gray-400 hover:text-indigo-600">Modifier</a>
@endcan
</td>
</tr>
@empty
<tr>
<td colspan="8" class="px-6 py-10 text-center text-gray-400 dark:text-gray-500">
@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>
@endif
</div>
</x-app-layout>