Mode sombre, option désactivation mises à jour, user-picker avec recherche

- Dark mode complet : darkMode:'class' Tailwind, sélecteur clair/sombre/auto
  dans la navigation (mémorisé dans localStorage, sans flash au chargement) ;
  53 vues et 8 composants Breeze mis à jour avec classes dark:
- Composant user-picker : fenêtre modale avec recherche temps réel (nom/email)
  remplace les <select> d'ajout de membres dans sections et sources
- Paramètres : option "Désactiver la vérification automatique des mises à jour"
  (case à cochage auto-soumise, route POST parametres/updates)
- Panneau "Paramètres généraux" remonté en tête de la page de paramètres
- README recentré sur l'installation manuelle hébergement PHP+MySQL
- VERSION 1.0.1

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-04 19:46:22 +02:00
parent 07ab2a7063
commit f530f55577
73 changed files with 1288 additions and 913 deletions
+39 -39
View File
@@ -1,20 +1,20 @@
<x-app-layout>
<x-slot name="header">
<h2 class="text-xl font-semibold text-gray-800">Tableau de bord Administration</h2>
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">Tableau de bord Administration</h2>
</x-slot>
<div class="py-8 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 space-y-8">
{{-- Bandeau mise à jour disponible --}}
@if($updateAvailable)
<div class="bg-indigo-50 border border-indigo-300 rounded-xl p-4 flex items-center justify-between gap-4">
<div class="bg-indigo-50 dark:bg-indigo-900/30 border border-indigo-300 rounded-xl p-4 flex items-center justify-between gap-4">
<div class="flex items-center gap-3">
<svg class="w-5 h-5 text-indigo-500 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<svg class="w-5 h-5 text-indigo-500 dark:text-indigo-400 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12"/>
</svg>
<div>
<p class="text-sm font-semibold text-indigo-800">
<p class="text-sm font-semibold text-indigo-800 dark:text-indigo-200">
Mise à jour disponible : v{{ $latestRelease['version'] }}
<span class="ml-2 font-normal text-indigo-600">(installé : v{{ $installedVersion }})</span>
</p>
@@ -35,10 +35,10 @@
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
@php
$statusCards = [
['label' => 'À faire', 'key' => 'a_faire', 'color' => 'bg-gray-50 border-gray-200 text-gray-700'],
['label' => 'À faire', 'key' => 'a_faire', 'color' => 'bg-gray-50 dark:bg-gray-700 border-gray-200 dark:border-gray-700 text-gray-700 dark:text-gray-300'],
['label' => 'En cours', 'key' => 'en_cours', 'color' => 'bg-blue-50 border-blue-200 text-blue-700'],
['label' => 'À valider', 'key' => 'a_valider', 'color' => 'bg-yellow-50 border-yellow-200 text-yellow-700'],
['label' => 'Terminé', 'key' => 'termine', 'color' => 'bg-green-50 border-green-200 text-green-700'],
['label' => 'À valider', 'key' => 'a_valider', 'color' => 'bg-yellow-50 border-yellow-200 dark:border-yellow-700 text-yellow-700'],
['label' => 'Terminé', 'key' => 'termine', 'color' => 'bg-green-50 dark:bg-green-900/30 border-green-200 dark:border-green-700 text-green-700'],
];
@endphp
@foreach($statusCards as $card)
@@ -53,19 +53,19 @@
{{-- Ligne de métriques secondaires --}}
<div class="grid grid-cols-3 gap-4">
<div class="bg-white border border-gray-200 rounded-xl p-5 flex items-center gap-4">
<div class="p-3 bg-indigo-100 rounded-lg">
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl p-5 flex items-center gap-4">
<div class="p-3 bg-indigo-100 dark:bg-indigo-900/50 rounded-lg">
<svg class="w-6 h-6 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
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>
</div>
<div>
<p class="text-2xl font-bold text-gray-900">{{ number_format($totalReleves) }}</p>
<p class="text-sm text-gray-500">relevé{{ $totalReleves > 1 ? 's' : '' }} saisi{{ $totalReleves > 1 ? 's' : '' }}</p>
<p class="text-2xl font-bold text-gray-900 dark:text-white">{{ number_format($totalReleves) }}</p>
<p class="text-sm text-gray-500 dark:text-gray-400">relevé{{ $totalReleves > 1 ? 's' : '' }} saisi{{ $totalReleves > 1 ? 's' : '' }}</p>
</div>
</div>
<div class="bg-white border border-gray-200 rounded-xl p-5 flex items-center gap-4">
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl p-5 flex items-center gap-4">
<div class="p-3 bg-purple-100 rounded-lg">
<svg class="w-6 h-6 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
@@ -73,18 +73,18 @@
</svg>
</div>
<div>
<p class="text-2xl font-bold text-gray-900">{{ $totalUsers }}</p>
<p class="text-sm text-gray-500">utilisateur{{ $totalUsers > 1 ? 's' : '' }}</p>
<p class="text-2xl font-bold text-gray-900 dark:text-white">{{ $totalUsers }}</p>
<p class="text-sm text-gray-500 dark:text-gray-400">utilisateur{{ $totalUsers > 1 ? 's' : '' }}</p>
</div>
</div>
<div class="bg-white border border-gray-200 rounded-xl p-5">
<p class="text-xs font-medium text-gray-500 uppercase mb-3">Répartition des rôles</p>
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl p-5">
<p class="text-xs font-medium text-gray-500 dark:text-gray-400 uppercase mb-3">Répartition des rôles</p>
<div class="space-y-2">
@foreach(\App\Enums\UserRole::cases() as $role)
@php $count = (int)($usersByRole[$role->value] ?? 0); @endphp
<div class="flex items-center justify-between text-sm">
<span class="text-gray-600">{{ $role->label() }}</span>
<span class="font-semibold text-gray-900">{{ $count }}</span>
<span class="text-gray-600 dark:text-gray-400">{{ $role->label() }}</span>
<span class="font-semibold text-gray-900 dark:text-white">{{ $count }}</span>
</div>
@endforeach
</div>
@@ -93,16 +93,16 @@
{{-- Activité mensuelle (6 derniers mois) --}}
@if($activiteMensuelle->isNotEmpty())
<div class="bg-white border border-gray-200 rounded-xl p-6">
<h3 class="text-sm font-semibold text-gray-700 uppercase tracking-wide mb-4">Relevés saisis 6 derniers mois</h3>
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl p-6">
<h3 class="text-sm font-semibold text-gray-700 dark:text-gray-300 uppercase tracking-wide mb-4">Relevés saisis 6 derniers mois</h3>
@php $maxReleves = $activiteMensuelle->max('total') ?: 1; @endphp
<div class="flex items-end gap-3 h-24">
@foreach($activiteMensuelle as $mois)
@php $h = max(4, round(($mois->total / $maxReleves) * 96)); @endphp
<div class="flex-1 flex flex-col items-center gap-1">
<span class="text-xs text-gray-500">{{ $mois->total }}</span>
<div class="w-full bg-indigo-500 rounded-t" style="height: {{ $h }}px" title="{{ $mois->mois }} : {{ $mois->total }}"></div>
<span class="text-xs text-gray-400 whitespace-nowrap">{{ $mois->mois }}</span>
<span class="text-xs text-gray-500 dark:text-gray-400">{{ $mois->total }}</span>
<div class="w-full bg-indigo-50 dark:bg-indigo-900/300 rounded-t" style="height: {{ $h }}px" title="{{ $mois->mois }} : {{ $mois->total }}"></div>
<span class="text-xs text-gray-400 dark:text-gray-500 whitespace-nowrap">{{ $mois->mois }}</span>
</div>
@endforeach
</div>
@@ -118,8 +118,8 @@
['label' => 'Types de lieux', 'route' => 'admin.lieu-types.index', 'icon' => 'M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z'],
] as $link)
<a href="{{ route($link['route']) }}"
class="flex items-center gap-3 px-4 py-3 bg-white border border-gray-200 rounded-xl hover:border-indigo-300 hover:shadow-sm transition-all text-sm text-gray-700 font-medium">
<svg class="w-5 h-5 text-gray-400 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
class="flex items-center gap-3 px-4 py-3 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl hover:border-indigo-300 hover:shadow-sm transition-all text-sm text-gray-700 dark:text-gray-300 font-medium">
<svg class="w-5 h-5 text-gray-400 dark:text-gray-500 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="{{ $link['icon'] }}"/>
</svg>
{{ $link['label'] }}
@@ -130,57 +130,57 @@
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
{{-- Sources à valider --}}
<div class="bg-white border border-gray-200 rounded-xl p-6">
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl p-6">
<div class="flex items-center justify-between mb-4">
<h3 class="text-sm font-semibold text-gray-700 uppercase tracking-wide">En attente de validation</h3>
<h3 class="text-sm font-semibold text-gray-700 dark:text-gray-300 uppercase tracking-wide">En attente de validation</h3>
<a href="{{ route('sources.index', ['status' => 'a_valider']) }}"
class="text-xs text-indigo-600 hover:underline">Voir tout</a>
</div>
@forelse($sourcesAValider as $source)
<div class="flex items-center justify-between py-2 border-b border-gray-100 last:border-0">
<div class="flex items-center justify-between py-2 border-b border-gray-100 dark:border-gray-700 last:border-0">
<div>
<a href="{{ route('sources.show', $source) }}"
class="text-sm font-medium text-indigo-600 hover:underline">{{ $source->nom }}</a>
<p class="text-xs text-gray-400">{{ $source->sourceType->nom }}</p>
<p class="text-xs text-gray-400 dark:text-gray-500">{{ $source->sourceType->nom }}</p>
</div>
<span class="text-xs text-gray-400 whitespace-nowrap">
<span class="text-xs text-gray-400 dark:text-gray-500 whitespace-nowrap">
{{ $source->updated_at->diffForHumans() }}
</span>
</div>
@empty
<p class="text-sm text-gray-400 py-4 text-center">Aucune source en attente.</p>
<p class="text-sm text-gray-400 dark:text-gray-500 py-4 text-center">Aucune source en attente.</p>
@endforelse
</div>
{{-- Relevés récents --}}
<div class="bg-white border border-gray-200 rounded-xl p-6">
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl p-6">
<div class="flex items-center justify-between mb-4">
<h3 class="text-sm font-semibold text-gray-700 uppercase tracking-wide">Derniers relevés saisis</h3>
<h3 class="text-sm font-semibold text-gray-700 dark:text-gray-300 uppercase tracking-wide">Derniers relevés saisis</h3>
<a href="{{ route('recherche') }}" class="text-xs text-indigo-600 hover:underline">Recherche</a>
</div>
@forelse($relevesRecents as $releve)
<div class="flex items-center justify-between py-2 border-b border-gray-100 last:border-0">
<div class="flex items-center justify-between py-2 border-b border-gray-100 dark:border-gray-700 last:border-0">
<div class="min-w-0">
<a href="{{ route('releves.show', $releve) }}"
class="text-sm font-medium text-gray-900 hover:text-indigo-600 truncate block">
class="text-sm font-medium text-gray-900 dark:text-white hover:text-indigo-600 truncate block">
{{ $releve->nom ?? '—' }}
@if($releve->prenom) {{ $releve->prenom }} @endif
</a>
<p class="text-xs text-gray-400">
<p class="text-xs text-gray-400 dark:text-gray-500">
{{ $releve->source->nom }} · {{ $releve->createur?->name ?? '?' }}
</p>
</div>
<span class="text-xs text-gray-400 whitespace-nowrap ml-3">
<span class="text-xs text-gray-400 dark:text-gray-500 whitespace-nowrap ml-3">
{{ $releve->created_at->diffForHumans() }}
</span>
</div>
@empty
<p class="text-sm text-gray-400 py-4 text-center">Aucun relevé pour l'instant.</p>
<p class="text-sm text-gray-400 dark:text-gray-500 py-4 text-center">Aucun relevé pour l'instant.</p>
@endforelse
</div>
</div>
{{-- Version --}}
<div class="flex items-center justify-end gap-2 text-xs text-gray-400 pt-2">
<div class="flex items-center justify-end gap-2 text-xs text-gray-400 dark:text-gray-500 pt-2">
<span>MesRelevés v{{ $installedVersion }}</span>
@if(! $updateAvailable)
<span class="inline-flex items-center gap-1 text-green-600">
+8 -8
View File
@@ -1,24 +1,24 @@
<div class="space-y-5">
<div>
<label for="nom" class="block text-sm font-medium text-gray-700">Nom <span class="text-red-500">*</span></label>
<label for="nom" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Nom <span class="text-red-500">*</span></label>
<input type="text" id="nom" name="nom" value="{{ old('nom', $depot?->nom) }}" required
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
@error('nom') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
<div>
<label for="description" class="block text-sm font-medium text-gray-700">Description</label>
<label for="description" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Description</label>
<textarea id="description" name="description" rows="3"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">{{ old('description', $depot?->description) }}</textarea>
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">{{ old('description', $depot?->description) }}</textarea>
</div>
<div>
<label for="adresse_postale" class="block text-sm font-medium text-gray-700">Adresse postale</label>
<label for="adresse_postale" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Adresse postale</label>
<input type="text" id="adresse_postale" name="adresse_postale" value="{{ old('adresse_postale', $depot?->adresse_postale) }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
</div>
<div>
<label for="url" class="block text-sm font-medium text-gray-700">Site internet</label>
<label for="url" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Site internet</label>
<input type="url" id="url" name="url" value="{{ old('url', $depot?->url) }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
@error('url') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
</div>
@@ -1,13 +1,13 @@
<x-app-layout>
<x-slot name="header"><h2 class="text-xl font-semibold text-gray-800">Nouveau dépôt</h2></x-slot>
<x-slot name="header"><h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">Nouveau dépôt</h2></x-slot>
<div class="py-8 max-w-2xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="bg-white shadow rounded-lg p-6">
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6">
<form method="POST" action="{{ route('admin.depots.store') }}">
@csrf
@include('admin.depots._form', ['depot' => null])
<div class="mt-6 flex gap-4">
<button type="submit" class="px-5 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700">Créer</button>
<a href="{{ route('admin.depots.index') }}" class="text-sm text-gray-500 self-center hover:text-gray-700">Annuler</a>
<a href="{{ route('admin.depots.index') }}" class="text-sm text-gray-500 dark:text-gray-400 self-center hover:text-gray-700 dark:hover:text-gray-300">Annuler</a>
</div>
</form>
</div>
+3 -3
View File
@@ -1,13 +1,13 @@
<x-app-layout>
<x-slot name="header"><h2 class="text-xl font-semibold text-gray-800">Modifier : {{ $depot->nom }}</h2></x-slot>
<x-slot name="header"><h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">Modifier : {{ $depot->nom }}</h2></x-slot>
<div class="py-8 max-w-2xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="bg-white shadow rounded-lg p-6">
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6">
<form method="POST" action="{{ route('admin.depots.update', $depot) }}">
@csrf @method('PUT')
@include('admin.depots._form', ['depot' => $depot])
<div class="mt-6 flex gap-4">
<button type="submit" class="px-5 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700">Enregistrer</button>
<a href="{{ route('admin.depots.show', $depot) }}" class="text-sm text-gray-500 self-center hover:text-gray-700">Annuler</a>
<a href="{{ route('admin.depots.show', $depot) }}" class="text-sm text-gray-500 dark:text-gray-400 self-center hover:text-gray-700 dark:hover:text-gray-300">Annuler</a>
</div>
</form>
</div>
+15 -15
View File
@@ -1,37 +1,37 @@
<x-app-layout>
<x-slot name="header">
<div class="flex items-center justify-between">
<h2 class="text-xl font-semibold text-gray-800">Dépôts d'archives</h2>
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">Dépôts d'archives</h2>
<a href="{{ route('admin.depots.create') }}" class="px-4 py-2 bg-indigo-600 text-white text-sm rounded-md hover:bg-indigo-700">+ Nouveau dépôt</a>
</div>
</x-slot>
<div class="py-8 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
@if(session('success')) <div class="mb-4 p-4 bg-green-50 border border-green-200 text-green-800 rounded-md">{{ session('success') }}</div> @endif
@if(session('error')) <div class="mb-4 p-4 bg-red-50 border border-red-200 text-red-800 rounded-md">{{ session('error') }}</div> @endif
<div class="bg-white shadow rounded-lg overflow-hidden">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
@if(session('success')) <div class="mb-4 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
@if(session('error')) <div class="mb-4 p-4 bg-red-50 dark:bg-red-900/30 border border-red-200 dark:border-red-700 text-red-800 dark:text-red-200 rounded-md">{{ session('error') }}</div> @endif
<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">
<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 uppercase">Nom</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Sources</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Site</th>
<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">Sources</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Site</th>
<th class="px-6 py-3"></th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
@forelse($depots as $depot)
<tr class="hover:bg-gray-50">
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700">
<td class="px-6 py-4 font-medium">
<a href="{{ route('admin.depots.show', $depot) }}" class="text-indigo-600 hover:underline">{{ $depot->nom }}</a>
</td>
<td class="px-6 py-4 text-sm text-gray-500">{{ $depot->sources_count }}</td>
<td class="px-6 py-4 text-sm text-gray-500">
<td class="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">{{ $depot->sources_count }}</td>
<td class="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">
@if($depot->url) <a href="{{ $depot->url }}" target="_blank" class="text-indigo-600 hover:underline truncate max-w-xs block">{{ $depot->url }}</a>
@else
@endif
</td>
<td class="px-6 py-4 text-right text-sm space-x-3">
<a href="{{ route('admin.depots.edit', $depot) }}" class="text-gray-600 hover:text-indigo-600">Modifier</a>
<a href="{{ route('admin.depots.edit', $depot) }}" class="text-gray-600 dark:text-gray-400 hover:text-indigo-600">Modifier</a>
<form method="POST" action="{{ route('admin.depots.destroy', $depot) }}" class="inline"
x-data @submit.prevent="if(confirm('Supprimer ce dépôt ?')) $el.submit()">
@csrf @method('DELETE')
@@ -40,7 +40,7 @@
</td>
</tr>
@empty
<tr><td colspan="4" class="px-6 py-10 text-center text-gray-400">Aucun dépôt.</td></tr>
<tr><td colspan="4" class="px-6 py-10 text-center text-gray-400 dark:text-gray-500">Aucun dépôt.</td></tr>
@endforelse
</tbody>
</table>
+9 -9
View File
@@ -1,29 +1,29 @@
<x-app-layout>
<x-slot name="header">
<div class="flex items-center justify-between">
<h2 class="text-xl font-semibold text-gray-800">{{ $depot->nom }}</h2>
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">{{ $depot->nom }}</h2>
<a href="{{ route('admin.depots.edit', $depot) }}" class="px-4 py-2 bg-indigo-600 text-white text-sm rounded-md hover:bg-indigo-700">Modifier</a>
</div>
</x-slot>
<div class="py-8 max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 space-y-6">
<div class="bg-white shadow rounded-lg divide-y divide-gray-100 text-sm">
<div class="bg-white dark:bg-gray-800 shadow rounded-lg divide-y divide-gray-100 dark:divide-gray-700 text-sm">
@if($depot->description)
<div class="px-6 py-4 grid grid-cols-3 gap-4"><dt class="font-medium text-gray-500">Description</dt><dd class="col-span-2">{{ $depot->description }}</dd></div>
<div class="px-6 py-4 grid grid-cols-3 gap-4"><dt class="font-medium text-gray-500 dark:text-gray-400">Description</dt><dd class="col-span-2">{{ $depot->description }}</dd></div>
@endif
@if($depot->adresse_postale)
<div class="px-6 py-4 grid grid-cols-3 gap-4"><dt class="font-medium text-gray-500">Adresse</dt><dd class="col-span-2">{{ $depot->adresse_postale }}</dd></div>
<div class="px-6 py-4 grid grid-cols-3 gap-4"><dt class="font-medium text-gray-500 dark:text-gray-400">Adresse</dt><dd class="col-span-2">{{ $depot->adresse_postale }}</dd></div>
@endif
@if($depot->url)
<div class="px-6 py-4 grid grid-cols-3 gap-4"><dt class="font-medium text-gray-500">Site</dt><dd class="col-span-2"><a href="{{ $depot->url }}" target="_blank" class="text-indigo-600 hover:underline">{{ $depot->url }}</a></dd></div>
<div class="px-6 py-4 grid grid-cols-3 gap-4"><dt class="font-medium text-gray-500 dark:text-gray-400">Site</dt><dd class="col-span-2"><a href="{{ $depot->url }}" target="_blank" class="text-indigo-600 hover:underline">{{ $depot->url }}</a></dd></div>
@endif
</div>
@if($depot->sources->isNotEmpty())
<div class="bg-white shadow rounded-lg overflow-hidden">
<div class="px-6 py-4 border-b font-medium text-gray-900">Sources ({{ $depot->sources->count() }})</div>
<ul class="divide-y divide-gray-100">
<div class="bg-white dark:bg-gray-800 shadow rounded-lg overflow-hidden">
<div class="px-6 py-4 border-b font-medium text-gray-900 dark:text-white">Sources ({{ $depot->sources->count() }})</div>
<ul class="divide-y divide-gray-100 dark:divide-gray-700">
@foreach($depot->sources as $source)
<li class="px-6 py-3 text-sm text-gray-700">{{ $source->nom }}</li>
<li class="px-6 py-3 text-sm text-gray-700 dark:text-gray-300">{{ $source->nom }}</li>
@endforeach
</ul>
</div>
@@ -1,17 +1,17 @@
<div class="space-y-5">
<div>
<label for="nom" class="block text-sm font-medium text-gray-700">Nom <span class="text-red-500">*</span></label>
<label for="nom" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Nom <span class="text-red-500">*</span></label>
<input type="text" id="nom" name="nom" value="{{ old('nom', $lieuType?->nom) }}" required
placeholder="ex : Pays, Région, Département, Ville…"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 @error('nom') border-red-500 @enderror">
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 @error('nom') border-red-500 @enderror">
@error('nom') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
<div>
<label for="ordre" class="block text-sm font-medium text-gray-700">Ordre d'affichage <span class="text-red-500">*</span></label>
<label for="ordre" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Ordre d'affichage <span class="text-red-500">*</span></label>
<input type="number" id="ordre" name="ordre" value="{{ old('ordre', $lieuType?->ordre ?? 0) }}"
min="0" max="999" required
class="mt-1 block w-32 rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
<p class="mt-1 text-xs text-gray-400">Les valeurs les plus basses apparaissent en premier (ex : Pays=0, Région=10, Département=20, Ville=30)</p>
class="mt-1 block w-32 rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
<p class="mt-1 text-xs text-gray-400 dark:text-gray-500">Les valeurs les plus basses apparaissent en premier (ex : Pays=0, Région=10, Département=20, Ville=30)</p>
</div>
</div>
@@ -1,13 +1,13 @@
<x-app-layout>
<x-slot name="header"><h2 class="text-xl font-semibold text-gray-800">Nouveau type de lieu</h2></x-slot>
<x-slot name="header"><h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">Nouveau type de lieu</h2></x-slot>
<div class="py-8 max-w-lg mx-auto px-4 sm:px-6 lg:px-8">
<div class="bg-white shadow rounded-lg p-6">
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6">
<form method="POST" action="{{ route('admin.lieu-types.store') }}">
@csrf
@include('admin.lieu-types._form', ['lieuType' => null])
<div class="mt-6 flex gap-4">
<button type="submit" class="px-5 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700">Créer</button>
<a href="{{ route('admin.lieu-types.index') }}" class="text-sm text-gray-500 self-center hover:text-gray-700">Annuler</a>
<a href="{{ route('admin.lieu-types.index') }}" class="text-sm text-gray-500 dark:text-gray-400 self-center hover:text-gray-700 dark:hover:text-gray-300">Annuler</a>
</div>
</form>
</div>
@@ -1,13 +1,13 @@
<x-app-layout>
<x-slot name="header"><h2 class="text-xl font-semibold text-gray-800">Modifier : {{ $lieuType->nom }}</h2></x-slot>
<x-slot name="header"><h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">Modifier : {{ $lieuType->nom }}</h2></x-slot>
<div class="py-8 max-w-lg mx-auto px-4 sm:px-6 lg:px-8">
<div class="bg-white shadow rounded-lg p-6">
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6">
<form method="POST" action="{{ route('admin.lieu-types.update', $lieuType) }}">
@csrf @method('PUT')
@include('admin.lieu-types._form', ['lieuType' => $lieuType])
<div class="mt-6 flex gap-4">
<button type="submit" class="px-5 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700">Enregistrer</button>
<a href="{{ route('admin.lieu-types.index') }}" class="text-sm text-gray-500 self-center hover:text-gray-700">Annuler</a>
<a href="{{ route('admin.lieu-types.index') }}" class="text-sm text-gray-500 dark:text-gray-400 self-center hover:text-gray-700 dark:hover:text-gray-300">Annuler</a>
</div>
</form>
</div>
@@ -1,7 +1,7 @@
<x-app-layout>
<x-slot name="header">
<div class="flex items-center justify-between">
<h2 class="text-xl font-semibold text-gray-800">Types de lieux</h2>
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">Types de lieux</h2>
<a href="{{ route('admin.lieu-types.create') }}"
class="px-4 py-2 bg-indigo-600 text-white text-sm rounded-md hover:bg-indigo-700">+ Nouveau type</a>
</div>
@@ -10,31 +10,31 @@
<div class="py-8 max-w-3xl mx-auto px-4 sm:px-6 lg:px-8">
@foreach(['success','error'] as $flash)
@if(session($flash))
<div class="mb-4 p-4 rounded-md {{ $flash === 'success' ? 'bg-green-50 border border-green-200 text-green-800' : 'bg-red-50 border border-red-200 text-red-800' }}">
<div class="mb-4 p-4 rounded-md {{ $flash === 'success' ? 'bg-green-50 dark:bg-green-900/30 border border-green-200 dark:border-green-700 text-green-800 dark:text-green-200' : 'bg-red-50 dark:bg-red-900/30 border border-red-200 dark:border-red-700 text-red-800 dark:text-red-200' }}">
{{ session($flash) }}
</div>
@endif
@endforeach
<div class="bg-white shadow rounded-lg overflow-hidden">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<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">
<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 uppercase">Ordre</th>
<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">Lieux</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Ordre</th>
<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">Lieux</th>
<th class="px-6 py-3"></th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
@forelse($lieuTypes as $lt)
<tr class="hover:bg-gray-50">
<td class="px-6 py-4 text-sm text-gray-400 w-16">{{ $lt->ordre }}</td>
<td class="px-6 py-4 font-medium text-gray-900">{{ $lt->nom }}</td>
<td class="px-6 py-4 text-sm text-gray-500">{{ $lt->lieux_count }}</td>
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700">
<td class="px-6 py-4 text-sm text-gray-400 dark:text-gray-500 w-16">{{ $lt->ordre }}</td>
<td class="px-6 py-4 font-medium text-gray-900 dark:text-white">{{ $lt->nom }}</td>
<td class="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">{{ $lt->lieux_count }}</td>
<td class="px-6 py-4 text-right text-sm space-x-3">
<a href="{{ route('admin.lieu-types.edit', $lt) }}"
class="text-gray-600 hover:text-indigo-600">Modifier</a>
class="text-gray-600 dark:text-gray-400 hover:text-indigo-600">Modifier</a>
<form method="POST" action="{{ route('admin.lieu-types.destroy', $lt) }}" class="inline"
x-data @submit.prevent="if(confirm('Supprimer ce type ?')) $el.submit()">
@csrf @method('DELETE')
@@ -44,7 +44,7 @@
</tr>
@empty
<tr>
<td colspan="4" class="px-6 py-10 text-center text-gray-400">
<td colspan="4" class="px-6 py-10 text-center text-gray-400 dark:text-gray-500">
Aucun type de lieu défini.
</td>
</tr>
+129 -94
View File
@@ -1,23 +1,76 @@
<x-app-layout>
<x-slot name="header">
<h2 class="text-xl font-semibold text-gray-800">Paramètres du site</h2>
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">Paramètres du site</h2>
</x-slot>
<div class="py-8 max-w-2xl 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>
<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
{{-- Paramètres généraux (titre + inscriptions) --}}
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6 space-y-6">
<h3 class="text-sm font-semibold text-gray-700 dark:text-gray-300 uppercase tracking-wide">Paramètres généraux</h3>
<form method="POST" action="{{ route('admin.parametres.update') }}" class="space-y-5">
@csrf
{{-- Titre du site --}}
<div>
<label for="site_name" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Titre du site
</label>
<input type="text" id="site_name" name="site_name"
value="{{ old('site_name', \App\Services\SiteSettingsService::get('site_name')) }}"
placeholder="{{ config('app.name', 'MesRelevés') }}"
maxlength="100"
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">
<p class="mt-1 text-xs text-gray-400 dark:text-gray-500">
Affiché dans la navigation, les e-mails et les exports.
Laisser vide pour utiliser la valeur par défaut
(« {{ config('app.name', 'MesRelevés') }} »).
</p>
@error('site_name')
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
@enderror
</div>
{{-- Inscriptions --}}
<div class="pt-4 border-t border-gray-100 dark:border-gray-700">
<p class="text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Inscription publique des comptes</p>
<p class="text-xs text-gray-500 dark:text-gray-400 mb-3">
Autorise ou non les visiteurs à créer un compte via la page d'inscription.
Quand désactivée, seul un administrateur peut créer des comptes.
</p>
<label class="flex items-center gap-3 cursor-pointer">
<input type="hidden" name="registration_enabled" value="0">
<input type="checkbox" name="registration_enabled" value="1"
{{ $registrationEnabled ? 'checked' : '' }}
class="w-4 h-4 text-indigo-600 border-gray-300 dark:border-gray-600 rounded focus:ring-indigo-500">
<span class="text-sm text-gray-700 dark:text-gray-300">Autoriser l'inscription de nouveaux comptes</span>
</label>
</div>
<div>
<button type="submit"
class="px-5 py-2 bg-indigo-600 text-white text-sm font-medium rounded-md hover:bg-indigo-700">
Enregistrer
</button>
</div>
</form>
</div>
{{-- Logo --}}
<div class="bg-white shadow rounded-lg p-6 space-y-5">
<h3 class="text-sm font-semibold text-gray-700 uppercase tracking-wide">Logo du site</h3>
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6 space-y-5">
<h3 class="text-sm font-semibold text-gray-700 dark:text-gray-300 uppercase tracking-wide">Logo du site</h3>
@if($logoUrl)
<div class="flex items-center gap-6">
<img src="{{ $logoUrl }}" alt="Logo actuel" class="h-20 w-auto object-contain rounded border border-gray-200 p-2">
<img src="{{ $logoUrl }}" alt="Logo actuel" class="h-20 w-auto object-contain rounded border border-gray-200 dark:border-gray-700 p-2">
<div>
<p class="text-sm text-gray-600 mb-2">Logo actuel</p>
<p class="text-sm text-gray-600 dark:text-gray-400 mb-2">Logo actuel</p>
<form method="POST" action="{{ route('admin.parametres.logo.delete') }}"
x-data @submit.prevent="if(confirm('Supprimer le logo ?')) $el.submit()">
@csrf @method('DELETE')
@@ -26,19 +79,19 @@
</div>
</div>
@else
<p class="text-sm text-gray-400">Aucun logo configuré le nom de l'application est affiché.</p>
<p class="text-sm text-gray-400 dark:text-gray-500">Aucun logo configuré le nom de l'application est affiché.</p>
@endif
<form method="POST" action="{{ route('admin.parametres.logo.update') }}"
enctype="multipart/form-data" class="space-y-4">
@csrf
<div>
<label for="logo" class="block text-sm font-medium text-gray-700 mb-1">
<label for="logo" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
{{ $logoUrl ? 'Remplacer le logo' : 'Téléverser un logo' }}
</label>
<input type="file" id="logo" name="logo" accept="image/*"
class="block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:text-sm file:font-medium file:bg-indigo-50 file:text-indigo-700 hover:file:bg-indigo-100">
<p class="mt-1 text-xs text-gray-400">PNG, JPG, SVG ou WebP · max 2 Mo · format recommandé : carré ou paysage, fond transparent</p>
class="block w-full text-sm text-gray-500 dark:text-gray-400 file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:text-sm file:font-medium file:bg-indigo-50 file:text-indigo-700 hover:file:bg-indigo-100">
<p class="mt-1 text-xs text-gray-400 dark:text-gray-500">PNG, JPG, SVG ou WebP · max 2 Mo · format recommandé : carré ou paysage, fond transparent</p>
@error('logo') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
<button type="submit"
@@ -50,7 +103,7 @@
{{-- SMTP --}}
@php $smtp = \App\Services\SiteSettingsService::smtpConfig(); @endphp
<div class="bg-white shadow rounded-lg p-6 space-y-5"
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6 space-y-5"
x-data="{
host: '{{ $smtp['host'] ?? '' }}',
port: '{{ $smtp['port'] ?? 587 }}',
@@ -98,13 +151,13 @@
<div class="flex items-start justify-between">
<div>
<h3 class="text-sm font-semibold text-gray-700 uppercase tracking-wide">Serveur SMTP</h3>
<p class="text-xs text-gray-400 mt-0.5">
<h3 class="text-sm font-semibold text-gray-700 dark:text-gray-300 uppercase tracking-wide">Serveur SMTP</h3>
<p class="text-xs text-gray-400 dark:text-gray-500 mt-0.5">
Quand configuré, la connexion nécessitera un code PIN envoyé par e-mail (2FA).
</p>
</div>
@if(\App\Services\SiteSettingsService::smtpConfigured())
<span class="inline-flex items-center gap-1.5 text-xs text-green-700 bg-green-50 border border-green-200 px-2.5 py-1 rounded-full">
<span class="inline-flex items-center gap-1.5 text-xs text-green-700 bg-green-50 dark:bg-green-900/30 border border-green-200 dark:border-green-700 px-2.5 py-1 rounded-full">
<svg class="w-3 h-3 fill-current" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/>
</svg>
@@ -118,24 +171,24 @@
<div class="grid grid-cols-3 gap-4">
<div class="col-span-2">
<label class="block text-sm font-medium text-gray-700 mb-1">Hôte SMTP</label>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Hôte SMTP</label>
<input type="text" name="smtp_host" x-model="host"
placeholder="smtp.exemple.fr"
class="w-full rounded-md border-gray-300 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
class="w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
@error('smtp_host') <p class="mt-1 text-xs text-red-600">{{ $message }}</p> @enderror
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Port</label>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Port</label>
<input type="number" name="smtp_port" x-model="port"
class="w-full rounded-md border-gray-300 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
class="w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
@error('smtp_port') <p class="mt-1 text-xs text-red-600">{{ $message }}</p> @enderror
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Chiffrement</label>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Chiffrement</label>
<select name="smtp_encryption" x-model="encryption"
class="w-full rounded-md border-gray-300 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
class="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="tls">TLS / STARTTLS (port 587 recommandé)</option>
<option value="ssl">SSL (port 465)</option>
<option value="">Aucun (déconseillé)</option>
@@ -144,39 +197,39 @@
<div class="grid grid-cols-2 gap-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Identifiant</label>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Identifiant</label>
<input type="text" name="smtp_username" x-model="username"
autocomplete="off"
class="w-full rounded-md border-gray-300 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
class="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>
<label class="block text-sm font-medium text-gray-700 mb-1">Mot de passe</label>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Mot de passe</label>
<input type="password" name="smtp_password" x-model="password"
autocomplete="new-password"
class="w-full rounded-md border-gray-300 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500"
class="w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500"
placeholder="{{ \App\Services\SiteSettingsService::smtpConfigured() ? '(inchangé si vide)' : '' }}">
</div>
</div>
<div class="grid grid-cols-2 gap-4 pt-2 border-t border-gray-100">
<div class="grid grid-cols-2 gap-4 pt-2 border-t border-gray-100 dark:border-gray-700">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Adresse d'expéditeur</label>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Adresse d'expéditeur</label>
<input type="email" name="smtp_from_address" x-model="fromAddress"
placeholder="noreply@exemple.fr"
class="w-full rounded-md border-gray-300 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
class="w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
@error('smtp_from_address') <p class="mt-1 text-xs text-red-600">{{ $message }}</p> @enderror
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Nom d'expéditeur</label>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Nom d'expéditeur</label>
<input type="text" name="smtp_from_name" x-model="fromName"
class="w-full rounded-md border-gray-300 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
class="w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
@error('smtp_from_name') <p class="mt-1 text-xs text-red-600">{{ $message }}</p> @enderror
</div>
</div>
{{-- Résultat test --}}
<div x-show="tested" x-cloak class="p-3 rounded-lg text-sm flex items-start gap-2"
:class="testOk ? 'bg-green-50 border border-green-200 text-green-800' : 'bg-red-50 border border-red-200 text-red-800'">
:class="testOk ? 'bg-green-50 dark:bg-green-900/30 border border-green-200 dark:border-green-700 text-green-800 dark:text-green-200' : 'bg-red-50 dark:bg-red-900/30 border border-red-200 dark:border-red-700 text-red-800 dark:text-red-200'">
<span x-text="testOk ? '✓' : '✗'" class="font-bold shrink-0"></span>
<span x-text="testMsg" class="break-all"></span>
</div>
@@ -210,26 +263,26 @@
</form>
</div>
{{-- Version --}}
<div class="bg-white shadow rounded-lg p-6 space-y-4">
<h3 class="text-sm font-semibold text-gray-700 uppercase tracking-wide">Version du logiciel</h3>
{{-- Version du logiciel --}}
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6 space-y-4">
<h3 class="text-sm font-semibold text-gray-700 dark:text-gray-300 uppercase tracking-wide">Version du logiciel</h3>
@if($updateAvailable)
<div class="flex items-start gap-3 p-4 bg-indigo-50 border border-indigo-200 rounded-lg">
<svg class="w-5 h-5 text-indigo-500 shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<div class="flex items-start gap-3 p-4 bg-indigo-50 dark:bg-indigo-900/30 border border-indigo-200 dark:border-indigo-700 rounded-lg">
<svg class="w-5 h-5 text-indigo-500 dark:text-indigo-400 shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12"/>
</svg>
<div>
<p class="text-sm font-semibold text-indigo-800">
<p class="text-sm font-semibold text-indigo-800 dark:text-indigo-200">
Mise à jour disponible : v{{ $latestRelease['version'] }}
</p>
@if($latestRelease['published_at'])
<p class="text-xs text-indigo-500 mt-0.5">
<p class="text-xs text-indigo-500 dark:text-indigo-400 mt-0.5">
Publié {{ \Carbon\Carbon::parse($latestRelease['published_at'])->diffForHumans() }}
</p>
@endif
<p class="text-xs text-indigo-600 mt-2 font-mono bg-indigo-100 inline-block px-2 py-1 rounded">
<p class="text-xs text-indigo-600 mt-2 font-mono bg-indigo-100 dark:bg-indigo-900/50 inline-block px-2 py-1 rounded">
php artisan app:update
</p>
</div>
@@ -238,16 +291,16 @@
<div class="flex items-center justify-between">
<div>
<p class="text-sm text-gray-700 font-medium">MesRelevés v{{ $installedVersion }}</p>
<p class="text-sm text-gray-700 dark:text-gray-300 font-medium">MesRelevés v{{ $installedVersion }}</p>
@php $installedAt = storage_path('installed'); @endphp
@if(file_exists($installedAt))
<p class="text-xs text-gray-400 mt-0.5">
<p class="text-xs text-gray-400 dark:text-gray-500 mt-0.5">
Installé le {{ \Carbon\Carbon::createFromTimestamp(filemtime($installedAt))->isoFormat('LL') }}
</p>
@endif
</div>
@if(! $updateAvailable)
<span class="inline-flex items-center gap-1.5 text-xs text-green-700 bg-green-50 border border-green-200 px-3 py-1.5 rounded-full">
@if(! $updateAvailable && ! $updatesDisabled)
<span class="inline-flex items-center gap-1.5 text-xs text-green-700 bg-green-50 dark:bg-green-900/30 border border-green-200 dark:border-green-700 px-3 py-1.5 rounded-full">
<svg class="w-3.5 h-3.5" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/>
</svg>
@@ -255,59 +308,41 @@
</span>
@endif
</div>
{{-- Option désactiver les mises à jour --}}
<div class="pt-4 border-t border-gray-100 dark:border-gray-700">
<form method="POST" action="{{ route('admin.parametres.updates') }}">
@csrf
<div class="flex items-start gap-3">
<div class="flex items-center h-5 mt-0.5">
<input type="hidden" name="updates_disabled" value="0">
<input type="checkbox" id="updates_disabled" name="updates_disabled" value="1"
{{ $updatesDisabled ? 'checked' : '' }}
onchange="this.form.submit()"
class="w-4 h-4 text-amber-600 border-gray-300 dark:border-gray-600 rounded focus:ring-amber-500">
</div>
<div>
<label for="updates_disabled" class="text-sm font-medium text-gray-700 dark:text-gray-300 cursor-pointer">
Désactiver la vérification automatique des mises à jour
</label>
<p class="text-xs text-gray-400 dark:text-gray-500 mt-0.5">
Quand coché, le site ne contacte plus le serveur distant pour vérifier l'existence
d'une nouvelle version. Utile en environnement sans accès Internet ou en production
isolée.
</p>
</div>
</div>
@if($updatesDisabled)
<p class="mt-2 ml-7 text-xs text-amber-600 flex items-center gap-1">
<svg class="w-3.5 h-3.5 shrink-0" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd"/>
</svg>
Vérification des mises à jour désactivée les nouvelles versions ne seront pas signalées.
</p>
@endif
</form>
</div>
</div>
{{-- Titre du site + Inscriptions (formulaire commun) --}}
<div class="bg-white shadow rounded-lg p-6 space-y-6">
<h3 class="text-sm font-semibold text-gray-700 uppercase tracking-wide">Paramètres généraux</h3>
<form method="POST" action="{{ route('admin.parametres.update') }}" class="space-y-5">
@csrf
{{-- Titre du site --}}
<div>
<label for="site_name" class="block text-sm font-medium text-gray-700 mb-1">
Titre du site
</label>
<input type="text" id="site_name" name="site_name"
value="{{ old('site_name', \App\Services\SiteSettingsService::get('site_name')) }}"
placeholder="{{ config('app.name', 'MesRelevés') }}"
maxlength="100"
class="block w-full rounded-md border-gray-300 shadow-sm text-sm
focus:border-indigo-500 focus:ring-indigo-500">
<p class="mt-1 text-xs text-gray-400">
Affiché dans la navigation, les e-mails et les exports.
Laisser vide pour utiliser la valeur par défaut
(« {{ config('app.name', 'MesRelevés') }} »).
</p>
@error('site_name')
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
@enderror
</div>
{{-- Inscriptions --}}
<div class="pt-4 border-t border-gray-100">
<p class="text-sm font-medium text-gray-700 mb-2">Inscription publique des comptes</p>
<p class="text-xs text-gray-500 mb-3">
Autorise ou non les visiteurs à créer un compte via la page d'inscription.
Quand désactivée, seul un administrateur peut créer des comptes.
</p>
<label class="flex items-center gap-3 cursor-pointer">
<input type="hidden" name="registration_enabled" value="0">
<input type="checkbox" name="registration_enabled" value="1"
{{ $registrationEnabled ? 'checked' : '' }}
class="w-4 h-4 text-indigo-600 border-gray-300 rounded focus:ring-indigo-500">
<span class="text-sm text-gray-700">Autoriser l'inscription de nouveaux comptes</span>
</label>
</div>
<div>
<button type="submit"
class="px-5 py-2 bg-indigo-600 text-white text-sm font-medium rounded-md hover:bg-indigo-700">
Enregistrer
</button>
</div>
</form>
</div>
</div>
</x-app-layout>
@@ -1,8 +1,8 @@
<div class="space-y-5">
<div>
<label for="nom" class="block text-sm font-medium text-gray-700">Nom <span class="text-red-500">*</span></label>
<label for="nom" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Nom <span class="text-red-500">*</span></label>
<input type="text" id="nom" name="nom" value="{{ old('nom', $section?->nom) }}" required
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 @error('nom') border-red-500 @enderror">
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 @error('nom') border-red-500 @enderror">
@error('nom') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
@@ -16,22 +16,22 @@
/>
<div>
<label for="adresse" class="block text-sm font-medium text-gray-700">Adresse</label>
<label for="adresse" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Adresse</label>
<input type="text" id="adresse" name="adresse" value="{{ old('adresse', $section?->adresse) }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
</div>
<div>
<label for="email_contact" class="block text-sm font-medium text-gray-700">Email de contact</label>
<label for="email_contact" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Email de contact</label>
<input type="email" id="email_contact" name="email_contact" value="{{ old('email_contact', $section?->email_contact) }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 @error('email_contact') border-red-500 @enderror">
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 @error('email_contact') border-red-500 @enderror">
@error('email_contact') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
<div>
<label for="url" class="block text-sm font-medium text-gray-700">Site internet</label>
<label for="url" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Site internet</label>
<input type="url" id="url" name="url" value="{{ old('url', $section?->url) }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 @error('url') border-red-500 @enderror">
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 @error('url') border-red-500 @enderror">
@error('url') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
</div>
@@ -1,13 +1,13 @@
<x-app-layout>
<x-slot name="header"><h2 class="text-xl font-semibold text-gray-800">Nouvelle section</h2></x-slot>
<x-slot name="header"><h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">Nouvelle section</h2></x-slot>
<div class="py-8 max-w-2xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="bg-white shadow rounded-lg p-6">
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6">
<form method="POST" action="{{ route('admin.sections.store') }}">
@csrf
@include('admin.sections._form', ['section' => null])
<div class="mt-6 flex gap-4">
<button type="submit" class="px-5 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700">Créer</button>
<a href="{{ route('admin.sections.index') }}" class="text-sm text-gray-500 hover:text-gray-700 self-center">Annuler</a>
<a href="{{ route('admin.sections.index') }}" class="text-sm text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 self-center">Annuler</a>
</div>
</form>
</div>
@@ -1,13 +1,13 @@
<x-app-layout>
<x-slot name="header"><h2 class="text-xl font-semibold text-gray-800">Modifier : {{ $section->nom }}</h2></x-slot>
<x-slot name="header"><h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">Modifier : {{ $section->nom }}</h2></x-slot>
<div class="py-8 max-w-2xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="bg-white shadow rounded-lg p-6">
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6">
<form method="POST" action="{{ route('admin.sections.update', $section) }}">
@csrf @method('PUT')
@include('admin.sections._form', ['section' => $section])
<div class="mt-6 flex gap-4">
<button type="submit" class="px-5 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700">Enregistrer</button>
<a href="{{ route('admin.sections.show', $section) }}" class="text-sm text-gray-500 hover:text-gray-700 self-center">Annuler</a>
<a href="{{ route('admin.sections.show', $section) }}" class="text-sm text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 self-center">Annuler</a>
</div>
</form>
</div>
+14 -14
View File
@@ -1,7 +1,7 @@
<x-app-layout>
<x-slot name="header">
<div class="flex items-center justify-between">
<h2 class="text-xl font-semibold text-gray-800">Sections locales</h2>
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">Sections locales</h2>
<a href="{{ route('admin.sections.create') }}"
class="px-4 py-2 bg-indigo-600 text-white text-sm rounded-md hover:bg-indigo-700">+ Nouvelle section</a>
</div>
@@ -9,29 +9,29 @@
<div class="py-8 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
@if(session('success'))
<div class="mb-4 p-4 bg-green-50 border border-green-200 text-green-800 rounded-md">{{ session('success') }}</div>
<div class="mb-4 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
<div class="bg-white shadow rounded-lg overflow-hidden">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<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">
<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 uppercase">Nom</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">Contact</th>
<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">Lieu</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Contact</th>
<th class="px-6 py-3"></th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
@forelse($sections as $section)
<tr class="hover:bg-gray-50">
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700">
<td class="px-6 py-4 font-medium">
<a href="{{ route('admin.sections.show', $section) }}" class="text-indigo-600 hover:underline">{{ $section->nom }}</a>
</td>
<td class="px-6 py-4 text-sm text-gray-500">{{ $section->lieu?->nom ?? '—' }}</td>
<td class="px-6 py-4 text-sm text-gray-500">{{ $section->email_contact ?? '—' }}</td>
<td class="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">{{ $section->lieu?->nom ?? '—' }}</td>
<td class="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">{{ $section->email_contact ?? '—' }}</td>
<td class="px-6 py-4 text-right text-sm space-x-3">
<a href="{{ route('admin.sections.edit', $section) }}" class="text-gray-600 hover:text-indigo-600">Modifier</a>
<a href="{{ route('admin.sections.edit', $section) }}" class="text-gray-600 dark:text-gray-400 hover:text-indigo-600">Modifier</a>
<form method="POST" action="{{ route('admin.sections.destroy', $section) }}" class="inline"
x-data @submit.prevent="if(confirm('Supprimer cette section ?')) $el.submit()">
@csrf @method('DELETE')
@@ -40,7 +40,7 @@
</td>
</tr>
@empty
<tr><td colspan="4" class="px-6 py-10 text-center text-gray-400">Aucune section.</td></tr>
<tr><td colspan="4" class="px-6 py-10 text-center text-gray-400 dark:text-gray-500">Aucune section.</td></tr>
@endforelse
</tbody>
</table>
+31 -31
View File
@@ -1,7 +1,7 @@
<x-app-layout>
<x-slot name="header">
<div class="flex items-center justify-between">
<h2 class="text-xl font-semibold text-gray-800">{{ $section->nom }}</h2>
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">{{ $section->nom }}</h2>
<a href="{{ route('admin.sections.edit', $section) }}"
class="px-4 py-2 bg-indigo-600 text-white text-sm rounded-md hover:bg-indigo-700">Modifier</a>
</div>
@@ -10,42 +10,42 @@
<div class="py-8 max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 space-y-6">
@foreach(['success','error'] as $flash)
@if(session($flash))
<div class="p-4 rounded-md {{ $flash === 'success' ? 'bg-green-50 border border-green-200 text-green-800' : 'bg-red-50 border border-red-200 text-red-800' }}">
<div class="p-4 rounded-md {{ $flash === 'success' ? 'bg-green-50 dark:bg-green-900/30 border border-green-200 dark:border-green-700 text-green-800 dark:text-green-200' : 'bg-red-50 dark:bg-red-900/30 border border-red-200 dark:border-red-700 text-red-800 dark:text-red-200' }}">
{{ session($flash) }}
</div>
@endif
@endforeach
{{-- Fiche --}}
<div class="bg-white shadow rounded-lg divide-y divide-gray-100 text-sm">
<div class="bg-white dark:bg-gray-800 shadow rounded-lg divide-y divide-gray-100 dark:divide-gray-700 text-sm">
@foreach([['Lieu', $section->lieu?->nom_long ?? '—'], ['Adresse', $section->adresse ?? '—'], ['Email', $section->email_contact ?? '—'], ['Site', $section->url ?? '—']] as [$label, $val])
<div class="px-6 py-4 grid grid-cols-3 gap-4">
<dt class="font-medium text-gray-500">{{ $label }}</dt>
<dd class="col-span-2 text-gray-900">{{ $val }}</dd>
<dt class="font-medium text-gray-500 dark:text-gray-400">{{ $label }}</dt>
<dd class="col-span-2 text-gray-900 dark:text-white">{{ $val }}</dd>
</div>
@endforeach
</div>
{{-- Membres --}}
<div class="bg-white shadow rounded-lg overflow-hidden">
<div class="px-6 py-4 border-b border-gray-200 font-medium text-gray-900">
<div class="bg-white dark:bg-gray-800 shadow rounded-lg overflow-hidden">
<div class="px-6 py-4 border-b border-gray-200 dark:border-gray-700 font-medium text-gray-900 dark:text-white">
Membres ({{ $section->membres->count() }})
</div>
@if($section->membres->isNotEmpty())
<table class="min-w-full divide-y divide-gray-200 text-sm">
<thead class="bg-gray-50">
<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 uppercase">Nom</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Email</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Rôle dans la section</th>
<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">Email</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Rôle dans la section</th>
<th class="px-6 py-3"></th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
@foreach($section->membres as $membre)
<tr>
<td class="px-6 py-3">{{ $membre->name }}</td>
<td class="px-6 py-3 text-gray-500">{{ $membre->email }}</td>
<td class="px-6 py-3 text-gray-500 dark:text-gray-400">{{ $membre->email }}</td>
<td class="px-6 py-3">
{{ $membre->pivot->role_in_section === 'section_manager' ? 'Responsable' : 'Membre' }}
</td>
@@ -63,25 +63,25 @@
@endif
{{-- Ajouter un membre --}}
<div class="px-6 py-4 bg-gray-50 border-t border-gray-200">
<form method="POST" action="{{ route('admin.sections.membres.add', $section) }}" class="flex gap-3 items-end">
<div class="px-6 py-4 bg-gray-50 dark:bg-gray-700 border-t border-gray-200 dark:border-gray-700">
<form method="POST" action="{{ route('admin.sections.membres.add', $section) }}"
x-data="{ canSubmit: false }"
@submit.prevent="if ($el.querySelector('[name=user_id]').value) $el.submit()">
@csrf
<div class="flex-1">
<label class="block text-xs font-medium text-gray-600 mb-1">Utilisateur</label>
<select name="user_id" class="block w-full rounded-md border-gray-300 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
@foreach($users as $user)
<option value="{{ $user->id }}">{{ $user->name }} ({{ $user->email }})</option>
@endforeach
</select>
<div class="flex flex-col sm:flex-row gap-3 items-stretch sm:items-end">
<div class="flex-1">
<label class="block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1">Utilisateur</label>
<x-user-picker :users="$users" placeholder="Rechercher un utilisateur…" required />
</div>
<div>
<label class="block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1">Rôle</label>
<select name="role_in_section" class="block w-full rounded-md border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
<option value="member">Membre</option>
<option value="section_manager">Responsable</option>
</select>
</div>
<button type="submit" class="px-4 py-2 bg-indigo-600 text-white text-sm rounded-md hover:bg-indigo-700 shrink-0">Ajouter</button>
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">Rôle</label>
<select name="role_in_section" class="block w-full rounded-md border-gray-300 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
<option value="member">Membre</option>
<option value="section_manager">Responsable</option>
</select>
</div>
<button type="submit" class="px-4 py-2 bg-indigo-600 text-white text-sm rounded-md hover:bg-indigo-700">Ajouter</button>
</form>
</div>
</div>
@@ -1,25 +1,25 @@
<x-app-layout>
<x-slot name="header"><h2 class="text-xl font-semibold text-gray-800">Nouveau type de source</h2></x-slot>
<x-slot name="header"><h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">Nouveau type de source</h2></x-slot>
<div class="py-8 max-w-2xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="bg-white shadow rounded-lg p-6">
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6">
<form method="POST" action="{{ route('admin.source-types.store') }}">
@csrf
<div class="space-y-5">
<div>
<label for="nom" class="block text-sm font-medium text-gray-700">Nom <span class="text-red-500">*</span></label>
<label for="nom" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Nom <span class="text-red-500">*</span></label>
<input type="text" id="nom" name="nom" value="{{ old('nom') }}" required
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
@error('nom') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
<div>
<label for="description" class="block text-sm font-medium text-gray-700">Description</label>
<label for="description" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Description</label>
<textarea id="description" name="description" rows="3"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">{{ old('description') }}</textarea>
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">{{ old('description') }}</textarea>
</div>
</div>
<div class="mt-6 flex gap-4">
<button type="submit" class="px-5 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700">Créer et définir les champs</button>
<a href="{{ route('admin.source-types.index') }}" class="text-sm text-gray-500 self-center hover:text-gray-700">Annuler</a>
<a href="{{ route('admin.source-types.index') }}" class="text-sm text-gray-500 dark:text-gray-400 self-center hover:text-gray-700 dark:hover:text-gray-300">Annuler</a>
</div>
</form>
</div>
@@ -1,24 +1,24 @@
<x-app-layout>
<x-slot name="header"><h2 class="text-xl font-semibold text-gray-800">Modifier : {{ $sourceType->nom }}</h2></x-slot>
<x-slot name="header"><h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">Modifier : {{ $sourceType->nom }}</h2></x-slot>
<div class="py-8 max-w-2xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="bg-white shadow rounded-lg p-6">
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6">
<form method="POST" action="{{ route('admin.source-types.update', $sourceType) }}">
@csrf @method('PUT')
<div class="space-y-5">
<div>
<label for="nom" class="block text-sm font-medium text-gray-700">Nom <span class="text-red-500">*</span></label>
<label for="nom" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Nom <span class="text-red-500">*</span></label>
<input type="text" id="nom" name="nom" value="{{ old('nom', $sourceType->nom) }}" required
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
</div>
<div>
<label for="description" class="block text-sm font-medium text-gray-700">Description</label>
<label for="description" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Description</label>
<textarea id="description" name="description" rows="3"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">{{ old('description', $sourceType->description) }}</textarea>
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">{{ old('description', $sourceType->description) }}</textarea>
</div>
</div>
<div class="mt-6 flex gap-4">
<button type="submit" class="px-5 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700">Enregistrer</button>
<a href="{{ route('admin.source-types.show', $sourceType) }}" class="text-sm text-gray-500 self-center hover:text-gray-700">Annuler</a>
<a href="{{ route('admin.source-types.show', $sourceType) }}" class="text-sm text-gray-500 dark:text-gray-400 self-center hover:text-gray-700 dark:hover:text-gray-300">Annuler</a>
</div>
</form>
</div>
@@ -1,33 +1,33 @@
<x-app-layout>
<x-slot name="header">
<div class="flex items-center justify-between">
<h2 class="text-xl font-semibold text-gray-800">Types de sources</h2>
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">Types de sources</h2>
<a href="{{ route('admin.source-types.create') }}" class="px-4 py-2 bg-indigo-600 text-white text-sm rounded-md hover:bg-indigo-700">+ Nouveau type</a>
</div>
</x-slot>
<div class="py-8 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
@if(session('success')) <div class="mb-4 p-4 bg-green-50 border border-green-200 text-green-800 rounded-md">{{ session('success') }}</div> @endif
@if(session('error')) <div class="mb-4 p-4 bg-red-50 border border-red-200 text-red-800 rounded-md">{{ session('error') }}</div> @endif
<div class="bg-white shadow rounded-lg overflow-hidden">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
@if(session('success')) <div class="mb-4 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
@if(session('error')) <div class="mb-4 p-4 bg-red-50 dark:bg-red-900/30 border border-red-200 dark:border-red-700 text-red-800 dark:text-red-200 rounded-md">{{ session('error') }}</div> @endif
<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">
<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 uppercase">Nom</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Champs</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Sources liées</th>
<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">Champs</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Sources liées</th>
<th class="px-6 py-3"></th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
@forelse($sourceTypes as $st)
<tr class="hover:bg-gray-50">
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700">
<td class="px-6 py-4 font-medium">
<a href="{{ route('admin.source-types.show', $st) }}" class="text-indigo-600 hover:underline">{{ $st->nom }}</a>
</td>
<td class="px-6 py-4 text-sm text-gray-500">{{ $st->fields_count ?? '—' }}</td>
<td class="px-6 py-4 text-sm text-gray-500">{{ $st->sources_count }}</td>
<td class="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">{{ $st->fields_count ?? '—' }}</td>
<td class="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">{{ $st->sources_count }}</td>
<td class="px-6 py-4 text-right text-sm space-x-3">
<a href="{{ route('admin.source-types.edit', $st) }}" class="text-gray-600 hover:text-indigo-600">Modifier</a>
<a href="{{ route('admin.source-types.edit', $st) }}" class="text-gray-600 dark:text-gray-400 hover:text-indigo-600">Modifier</a>
<form method="POST" action="{{ route('admin.source-types.destroy', $st) }}" class="inline"
x-data @submit.prevent="if(confirm('Supprimer ce type ?')) $el.submit()">
@csrf @method('DELETE')
@@ -36,7 +36,7 @@
</td>
</tr>
@empty
<tr><td colspan="4" class="px-6 py-10 text-center text-gray-400">Aucun type de source.</td></tr>
<tr><td colspan="4" class="px-6 py-10 text-center text-gray-400 dark:text-gray-500">Aucun type de source.</td></tr>
@endforelse
</tbody>
</table>
@@ -1,7 +1,7 @@
<x-app-layout>
<x-slot name="header">
<div class="flex items-center justify-between">
<h2 class="text-xl font-semibold text-gray-800">{{ $sourceType->nom }}</h2>
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">{{ $sourceType->nom }}</h2>
<a href="{{ route('admin.source-types.edit', $sourceType) }}" class="px-4 py-2 bg-indigo-600 text-white text-sm rounded-md hover:bg-indigo-700">Modifier</a>
</div>
</x-slot>
@@ -9,21 +9,21 @@
<div class="py-8 max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 space-y-6">
@foreach(['success','error'] as $flash)
@if(session($flash))
<div class="p-4 rounded-md {{ $flash === 'success' ? 'bg-green-50 border border-green-200 text-green-800' : 'bg-red-50 border border-red-200 text-red-800' }}">
<div class="p-4 rounded-md {{ $flash === 'success' ? 'bg-green-50 dark:bg-green-900/30 border border-green-200 dark:border-green-700 text-green-800 dark:text-green-200' : 'bg-red-50 dark:bg-red-900/30 border border-red-200 dark:border-red-700 text-red-800 dark:text-red-200' }}">
{{ session($flash) }}
</div>
@endif
@endforeach
@if($sourceType->description)
<div class="bg-white shadow rounded-lg px-6 py-4 text-sm text-gray-700">{{ $sourceType->description }}</div>
<div class="bg-white dark:bg-gray-800 shadow rounded-lg px-6 py-4 text-sm text-gray-700 dark:text-gray-300">{{ $sourceType->description }}</div>
@endif
{{-- Champs existants --}}
<div class="bg-white shadow rounded-lg overflow-hidden">
<div class="px-6 py-4 border-b border-gray-200 flex items-center justify-between">
<h3 class="font-medium text-gray-900">Champs ({{ $sourceType->fields->count() }})</h3>
<span class="text-xs text-gray-400">Glisser-déposer pour réordonner</span>
<div class="bg-white dark:bg-gray-800 shadow rounded-lg overflow-hidden">
<div class="px-6 py-4 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between">
<h3 class="font-medium text-gray-900 dark:text-white">Champs ({{ $sourceType->fields->count() }})</h3>
<span class="text-xs text-gray-400 dark:text-gray-500">Glisser-déposer pour réordonner</span>
</div>
@if($sourceType->fields->isNotEmpty())
@@ -31,21 +31,21 @@
@csrf
</form>
<ul id="fields-list" class="divide-y divide-gray-100">
<ul id="fields-list" class="divide-y divide-gray-100 dark:divide-gray-700">
@foreach($sourceType->fields as $field)
<li class="px-6 py-3 flex items-center gap-4" data-id="{{ $field->id }}">
<span class="cursor-move text-gray-300 hover:text-gray-500 select-none"></span>
<span class="cursor-move text-gray-300 dark:text-gray-600 hover:text-gray-500 select-none"></span>
<div class="flex-1 grid grid-cols-4 gap-3 text-sm">
<span class="font-mono text-indigo-700">{{ $field->name }}</span>
<span class="text-gray-700">{{ $field->label }}</span>
<span class="text-gray-500">{{ $field->type->value }}</span>
<span class="text-gray-400">{{ $field->required ? 'Obligatoire' : 'Optionnel' }}</span>
<span class="text-gray-700 dark:text-gray-300">{{ $field->label }}</span>
<span class="text-gray-500 dark:text-gray-400">{{ $field->type->value }}</span>
<span class="text-gray-400 dark:text-gray-500">{{ $field->required ? 'Obligatoire' : 'Optionnel' }}</span>
</div>
<div class="flex gap-2">
<button type="button"
x-data="{ open: false }"
@click="open = !open"
class="text-xs text-gray-500 hover:text-indigo-600">Modifier</button>
class="text-xs text-gray-500 dark:text-gray-400 hover:text-indigo-600">Modifier</button>
<form method="POST" action="{{ route('admin.source-types.fields.destroy', [$sourceType, $field]) }}"
x-data @submit.prevent="if(confirm('Supprimer ce champ ?')) $el.submit()">
@csrf @method('DELETE')
@@ -56,34 +56,34 @@
@endforeach
</ul>
@else
<p class="px-6 py-8 text-center text-gray-400 text-sm">Aucun champ défini. Ajoutez-en ci-dessous.</p>
<p class="px-6 py-8 text-center text-gray-400 dark:text-gray-500 text-sm">Aucun champ défini. Ajoutez-en ci-dessous.</p>
@endif
</div>
{{-- Ajouter un champ --}}
<div class="bg-white shadow rounded-lg p-6">
<h3 class="font-medium text-gray-900 mb-4">Ajouter un champ</h3>
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6">
<h3 class="font-medium text-gray-900 dark:text-white mb-4">Ajouter un champ</h3>
<form method="POST" action="{{ route('admin.source-types.fields.store', $sourceType) }}">
@csrf
<div class="grid grid-cols-2 gap-4">
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">Nom technique <span class="text-red-500">*</span></label>
<label class="block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1">Nom technique <span class="text-red-500">*</span></label>
<input type="text" name="name" value="{{ old('name') }}" required
placeholder="ex: nom_pere"
class="block w-full rounded-md border-gray-300 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500 @error('name') border-red-500 @enderror">
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 @error('name') border-red-500 @enderror">
@error('name') <p class="mt-1 text-xs text-red-600">{{ $message }}</p> @enderror
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">Libellé affiché <span class="text-red-500">*</span></label>
<label class="block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1">Libellé affiché <span class="text-red-500">*</span></label>
<input type="text" name="label" value="{{ old('label') }}" required
placeholder="ex: Nom du père"
class="block w-full rounded-md border-gray-300 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500 @error('label') border-red-500 @enderror">
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 @error('label') border-red-500 @enderror">
@error('label') <p class="mt-1 text-xs text-red-600">{{ $message }}</p> @enderror
</div>
<div x-data="{ type: '{{ old('type', 'text') }}' }">
<label class="block text-xs font-medium text-gray-600 mb-1">Type <span class="text-red-500">*</span></label>
<label class="block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1">Type <span class="text-red-500">*</span></label>
<select name="type" x-model="type"
class="block w-full rounded-md border-gray-300 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
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">
@foreach(\App\Enums\FieldType::cases() as $ft)
<option value="{{ $ft->value }}" {{ old('type') === $ft->value ? 'selected' : '' }}>{{ $ft->value }}</option>
@endforeach
@@ -91,15 +91,15 @@
{{-- Options pour type=select --}}
<div x-show="type === 'select'" x-cloak class="mt-3">
<label class="block text-xs font-medium text-gray-600 mb-1">Options (une par ligne)</label>
<label class="block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1">Options (une par ligne)</label>
<textarea name="options_raw" rows="3" placeholder="Option A&#10;Option B&#10;Option C"
class="block w-full rounded-md border-gray-300 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">{{ old('options_raw') }}</textarea>
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">{{ old('options_raw') }}</textarea>
</div>
</div>
<div class="flex items-end">
<label class="flex items-center gap-2 text-sm text-gray-700">
<label class="flex items-center gap-2 text-sm text-gray-700 dark:text-gray-300">
<input type="checkbox" name="required" value="1" {{ old('required') ? 'checked' : '' }}
class="rounded border-gray-300 text-indigo-600 focus:ring-indigo-500">
class="rounded border-gray-300 dark:border-gray-600 text-indigo-600 focus:ring-indigo-500">
Champ obligatoire
</label>
</div>
@@ -2,48 +2,48 @@
<x-slot name="header">
<div class="flex items-center gap-3">
<a href="{{ route('admin.utilisateurs.index') }}" class="text-sm text-indigo-600 hover:underline"> Utilisateurs</a>
<span class="text-gray-400">/</span>
<h2 class="text-xl font-semibold text-gray-800">{{ $user->name }}</h2>
<span class="text-gray-400 dark:text-gray-500">/</span>
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">{{ $user->name }}</h2>
</div>
</x-slot>
<div class="py-8 max-w-2xl 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>
<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
@if(session('error'))
<div class="p-4 bg-red-50 border border-red-200 text-red-800 rounded-md">{{ session('error') }}</div>
<div class="p-4 bg-red-50 dark:bg-red-900/30 border border-red-200 dark:border-red-700 text-red-800 dark:text-red-200 rounded-md">{{ session('error') }}</div>
@endif
{{-- Informations --}}
<div class="bg-white shadow rounded-lg p-6 space-y-3">
<h3 class="text-sm font-semibold text-gray-700 uppercase tracking-wide">Informations</h3>
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6 space-y-3">
<h3 class="text-sm font-semibold text-gray-700 dark:text-gray-300 uppercase tracking-wide">Informations</h3>
<dl class="grid grid-cols-2 gap-x-6 gap-y-3 text-sm">
<dt class="text-gray-500">Nom</dt>
<dd class="text-gray-900 font-medium">{{ $user->name }}</dd>
<dt class="text-gray-500">E-mail</dt>
<dd class="text-gray-900">{{ $user->email }}</dd>
<dt class="text-gray-500">Inscrit le</dt>
<dd class="text-gray-900">{{ $user->created_at->format('d/m/Y') }}</dd>
<dt class="text-gray-500">Sections</dt>
<dd class="text-gray-900">
<dt class="text-gray-500 dark:text-gray-400">Nom</dt>
<dd class="text-gray-900 dark:text-white font-medium">{{ $user->name }}</dd>
<dt class="text-gray-500 dark:text-gray-400">E-mail</dt>
<dd class="text-gray-900 dark:text-white">{{ $user->email }}</dd>
<dt class="text-gray-500 dark:text-gray-400">Inscrit le</dt>
<dd class="text-gray-900 dark:text-white">{{ $user->created_at->format('d/m/Y') }}</dd>
<dt class="text-gray-500 dark:text-gray-400">Sections</dt>
<dd class="text-gray-900 dark:text-white">
@if($user->sections->isNotEmpty())
{{ $user->sections->pluck('nom')->join(', ') }}
@else
@endif
</dd>
<dt class="text-gray-500">Sources assignées</dt>
<dd class="text-gray-900">{{ $user->sourcesAssignees->count() }}</dd>
<dt class="text-gray-500 dark:text-gray-400">Sources assignées</dt>
<dd class="text-gray-900 dark:text-white">{{ $user->sourcesAssignees->count() }}</dd>
</dl>
</div>
{{-- Statut actif / inactif --}}
<div class="bg-white shadow rounded-lg p-6 flex items-center justify-between">
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6 flex items-center justify-between">
<div>
<p class="text-sm font-medium text-gray-900">Statut du compte</p>
<p class="text-sm text-gray-500 mt-0.5">
<p class="text-sm font-medium text-gray-900 dark:text-white">Statut du compte</p>
<p class="text-sm text-gray-500 dark:text-gray-400 mt-0.5">
@if($user->is_active)
Le compte est <span class="text-green-600 font-medium">actif</span> l'utilisateur peut se connecter et être assigné à des sources.
@else
@@ -59,8 +59,8 @@
<button type="submit"
class="px-4 py-2 text-sm font-medium rounded-md
{{ $user->is_active
? 'bg-red-50 text-red-700 border border-red-200 hover:bg-red-100'
: 'bg-green-50 text-green-700 border border-green-200 hover:bg-green-100' }}">
? 'bg-red-50 dark:bg-red-900/30 text-red-700 border border-red-200 dark:border-red-700 hover:bg-red-100'
: 'bg-green-50 dark:bg-green-900/30 text-green-700 border border-green-200 dark:border-green-700 hover:bg-green-100' }}">
{{ $user->is_active ? 'Désactiver le compte' : 'Activer le compte' }}
</button>
</form>
@@ -68,20 +68,20 @@
</div>
{{-- Modifier le rôle --}}
<div class="bg-white shadow rounded-lg p-6">
<h3 class="text-sm font-semibold text-gray-700 uppercase tracking-wide mb-4">Rôle</h3>
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6">
<h3 class="text-sm font-semibold text-gray-700 dark:text-gray-300 uppercase tracking-wide mb-4">Rôle</h3>
<form method="POST" action="{{ route('admin.utilisateurs.update', $user) }}">
@csrf @method('PUT')
<div class="space-y-3">
@foreach(\App\Enums\UserRole::cases() as $role)
<label class="flex items-start gap-3 p-3 border rounded-lg cursor-pointer hover:bg-gray-50
{{ $user->role === $role ? 'border-indigo-400 bg-indigo-50' : 'border-gray-200' }}">
<label class="flex items-start gap-3 p-3 border rounded-lg cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-700
{{ $user->role === $role ? 'border-indigo-400 bg-indigo-50 dark:bg-indigo-900/30' : 'border-gray-200 dark:border-gray-700' }}">
<input type="radio" name="role" value="{{ $role->value }}"
{{ $user->role === $role ? 'checked' : '' }}
class="mt-0.5 text-indigo-600">
<div>
<p class="text-sm font-medium text-gray-900">{{ $role->label() }}</p>
<p class="text-xs text-gray-500 mt-0.5">
<p class="text-sm font-medium text-gray-900 dark:text-white">{{ $role->label() }}</p>
<p class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
@if($role === \App\Enums\UserRole::Admin)
Accès complet : gestion des utilisateurs, sections, dépôts, types de sources et statistiques.
@elseif($role === \App\Enums\UserRole::SectionManager)
@@ -100,7 +100,7 @@
Enregistrer
</button>
<a href="{{ route('admin.utilisateurs.index') }}"
class="text-sm text-gray-500 self-center hover:text-gray-700">
class="text-sm text-gray-500 dark:text-gray-400 self-center hover:text-gray-700 dark:hover:text-gray-300">
Annuler
</a>
</div>
@@ -1,7 +1,7 @@
<x-app-layout>
<x-slot name="header">
<div class="flex items-center justify-between">
<h2 class="text-xl font-semibold text-gray-800">Importer des utilisateurs</h2>
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">Importer des utilisateurs</h2>
<a href="{{ route('admin.utilisateurs.index') }}"
class="text-sm text-indigo-600 hover:underline"> Retour à la liste</a>
</div>
@@ -11,7 +11,7 @@
{{-- Résultats d'import --}}
@if(isset($results))
<div class="bg-white shadow rounded-lg p-6 space-y-4">
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6 space-y-4">
<div class="flex items-center gap-4">
@if($created > 0)
<span class="text-green-700 font-semibold text-sm">
@@ -26,31 +26,31 @@
</div>
@if($created > 0)
<div class="p-3 bg-amber-50 border border-amber-200 rounded-lg text-xs text-amber-800">
<div class="p-3 bg-amber-50 dark:bg-amber-900/30 border border-amber-200 rounded-lg text-xs text-amber-800">
Les mots de passe temporaires ci-dessous sont affichés <strong>une seule fois</strong>.
Notez-les et communiquez-les aux utilisateurs concernés. Ils pourront les changer via leur profil.
</div>
@endif
<div class="overflow-x-auto">
<table class="min-w-full text-sm divide-y divide-gray-200">
<thead class="bg-gray-50">
<table class="min-w-full text-sm divide-y divide-gray-200 dark:divide-gray-700">
<thead class="bg-gray-50 dark:bg-gray-700">
<tr>
<th class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase">Ligne</th>
<th class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase">Nom</th>
<th class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase">E-mail</th>
<th class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase">Rôle</th>
<th class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase">Mot de passe temporaire</th>
<th class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase">Statut</th>
<th class="px-4 py-2 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Ligne</th>
<th class="px-4 py-2 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Nom</th>
<th class="px-4 py-2 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">E-mail</th>
<th class="px-4 py-2 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Rôle</th>
<th class="px-4 py-2 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Mot de passe temporaire</th>
<th class="px-4 py-2 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Statut</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200 bg-white">
<tbody class="divide-y divide-gray-200 dark:divide-gray-700 bg-white dark:bg-gray-800">
@foreach($results as $r)
<tr class="{{ $r['ok'] ? '' : 'bg-red-50' }}">
<td class="px-4 py-2 text-gray-400">{{ $r['line'] }}</td>
<td class="px-4 py-2 font-medium text-gray-900">{{ $r['name'] }}</td>
<td class="px-4 py-2 text-gray-600">{{ $r['email'] }}</td>
<td class="px-4 py-2 text-gray-500">{{ $r['role'] ?? '' }}</td>
<tr class="{{ $r['ok'] ? '' : 'bg-red-50 dark:bg-red-900/30' }}">
<td class="px-4 py-2 text-gray-400 dark:text-gray-500">{{ $r['line'] }}</td>
<td class="px-4 py-2 font-medium text-gray-900 dark:text-white">{{ $r['name'] }}</td>
<td class="px-4 py-2 text-gray-600 dark:text-gray-400">{{ $r['email'] }}</td>
<td class="px-4 py-2 text-gray-500 dark:text-gray-400">{{ $r['role'] ?? '' }}</td>
<td class="px-4 py-2 font-mono text-indigo-700">
{{ $r['ok'] ? $r['password'] : '' }}
</td>
@@ -77,26 +77,26 @@
@endif
{{-- Formulaire d'import --}}
<div class="bg-white shadow rounded-lg p-6 space-y-5">
<h3 class="text-sm font-semibold text-gray-700 uppercase tracking-wide">Importer un fichier CSV</h3>
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6 space-y-5">
<h3 class="text-sm font-semibold text-gray-700 dark:text-gray-300 uppercase tracking-wide">Importer un fichier CSV</h3>
@if($errors->any())
<div class="p-4 bg-red-50 border border-red-200 text-red-700 text-sm rounded-md space-y-1">
<div class="p-4 bg-red-50 dark:bg-red-900/30 border border-red-200 dark:border-red-700 text-red-700 text-sm rounded-md space-y-1">
@foreach($errors->all() as $e)<p>{{ $e }}</p>@endforeach
</div>
@endif
<div class="p-4 bg-blue-50 border border-blue-200 rounded-lg text-sm text-blue-800 space-y-1">
<div class="p-4 bg-blue-50 border border-blue-200 rounded-lg text-sm text-blue-800 dark:text-blue-200 space-y-1">
<p class="font-semibold">Format attendu du fichier CSV :</p>
<ul class="list-disc list-inside text-xs space-y-0.5">
<li>Séparateur : <code class="bg-blue-100 px-1 rounded">;</code> ou <code class="bg-blue-100 px-1 rounded">,</code></li>
<li>Séparateur : <code class="bg-blue-100 dark:bg-blue-900/50 px-1 rounded">;</code> ou <code class="bg-blue-100 dark:bg-blue-900/50 px-1 rounded">,</code></li>
<li>Encodage : UTF-8 (avec ou sans BOM)</li>
<li>Colonnes obligatoires : <code class="bg-blue-100 px-1 rounded">name</code>, <code class="bg-blue-100 px-1 rounded">email</code>, <code class="bg-blue-100 px-1 rounded">role</code></li>
<li>Colonne optionnelle : <code class="bg-blue-100 px-1 rounded">is_active</code> (1 ou 0, défaut : 1)</li>
<li>Valeurs acceptées pour <code class="bg-blue-100 px-1 rounded">role</code> :
<code class="bg-blue-100 px-1 rounded">member</code>,
<code class="bg-blue-100 px-1 rounded">section_manager</code>,
<code class="bg-blue-100 px-1 rounded">admin</code>
<li>Colonnes obligatoires : <code class="bg-blue-100 dark:bg-blue-900/50 px-1 rounded">name</code>, <code class="bg-blue-100 dark:bg-blue-900/50 px-1 rounded">email</code>, <code class="bg-blue-100 dark:bg-blue-900/50 px-1 rounded">role</code></li>
<li>Colonne optionnelle : <code class="bg-blue-100 dark:bg-blue-900/50 px-1 rounded">is_active</code> (1 ou 0, défaut : 1)</li>
<li>Valeurs acceptées pour <code class="bg-blue-100 dark:bg-blue-900/50 px-1 rounded">role</code> :
<code class="bg-blue-100 dark:bg-blue-900/50 px-1 rounded">member</code>,
<code class="bg-blue-100 dark:bg-blue-900/50 px-1 rounded">section_manager</code>,
<code class="bg-blue-100 dark:bg-blue-900/50 px-1 rounded">admin</code>
</li>
<li>Un mot de passe temporaire aléatoire sera généré pour chaque compte importé.</li>
</ul>
@@ -110,15 +110,15 @@
enctype="multipart/form-data" class="space-y-4">
@csrf
<div>
<label for="file" class="block text-sm font-medium text-gray-700 mb-1">
<label for="file" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Fichier CSV <span class="text-red-500">*</span>
</label>
<input type="file" id="file" name="file" accept=".csv,.txt" required
class="block w-full text-sm text-gray-500
class="block w-full text-sm text-gray-500 dark:text-gray-400
file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0
file:text-sm file:font-medium file:bg-indigo-50 file:text-indigo-700
hover:file:bg-indigo-100">
<p class="mt-1 text-xs text-gray-400">Taille maximale : 2 Mo.</p>
<p class="mt-1 text-xs text-gray-400 dark:text-gray-500">Taille maximale : 2 Mo.</p>
@error('file') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
@@ -1,10 +1,10 @@
<x-app-layout>
<x-slot name="header">
<div class="flex items-center justify-between">
<h2 class="text-xl font-semibold text-gray-800">Gestion des utilisateurs</h2>
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">Gestion des utilisateurs</h2>
<div class="flex items-center gap-3">
<a href="{{ route('admin.utilisateurs.import') }}"
class="flex items-center gap-1.5 px-4 py-2 border border-gray-300 text-sm text-gray-700 rounded-md hover:bg-gray-50 transition-colors">
class="flex items-center gap-1.5 px-4 py-2 border border-gray-300 dark:border-gray-600 text-sm text-gray-700 dark:text-gray-300 rounded-md hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/>
@@ -12,7 +12,7 @@
Importer CSV
</a>
<a href="{{ route('admin.utilisateurs.export', request()->only(['role', 'status', 'q'])) }}"
class="flex items-center gap-1.5 px-4 py-2 border border-gray-300 text-sm text-gray-700 rounded-md hover:bg-gray-50 transition-colors">
class="flex items-center gap-1.5 px-4 py-2 border border-gray-300 dark:border-gray-600 text-sm text-gray-700 dark:text-gray-300 rounded-md hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4 4m0 0l4 4m-4-4h12"/>
@@ -26,33 +26,33 @@
<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 text-sm rounded-md">
<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 text-sm rounded-md">
{{ session('success') }}
</div>
@endif
@if(session('error'))
<div class="p-4 bg-red-50 border border-red-200 text-red-800 text-sm rounded-md">
<div class="p-4 bg-red-50 dark:bg-red-900/30 border border-red-200 dark:border-red-700 text-red-800 dark:text-red-200 text-sm rounded-md">
{{ session('error') }}
</div>
@endif
{{-- Filtres --}}
@php $hasFilters = request()->anyFilled(['role', 'q', 'status']); @endphp
<div class="bg-white shadow rounded-lg p-5">
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-5">
<form method="GET" action="{{ route('admin.utilisateurs.index') }}"
class="flex flex-wrap items-end gap-4">
<div class="flex-1 min-w-[180px]">
<label class="block text-xs font-medium text-gray-600 mb-1">Recherche</label>
<label class="block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1">Recherche</label>
<input type="text" name="q" value="{{ request('q') }}"
placeholder="Nom ou e-mail…"
class="block w-full rounded-md border-gray-300 shadow-sm text-sm
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 class="w-44">
<label class="block text-xs font-medium text-gray-600 mb-1">Rôle</label>
<label class="block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1">Rôle</label>
<select name="role"
class="block w-full rounded-md border-gray-300 shadow-sm text-sm
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\UserRole::cases() as $r)
@@ -64,9 +64,9 @@
</div>
<div class="w-40">
<label class="block text-xs font-medium text-gray-600 mb-1">Statut</label>
<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 shadow-sm text-sm
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>
<option value="active" {{ request('status') === 'active' ? 'selected' : '' }}>Actifs</option>
@@ -81,7 +81,7 @@
</button>
@if($hasFilters)
<a href="{{ route('admin.utilisateurs.index') }}"
class="px-4 py-2 border border-gray-300 text-gray-600 text-sm rounded-md hover:bg-gray-50">
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
</a>
@endif
@@ -90,52 +90,52 @@
</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">
<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 uppercase">Nom</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">E-mail</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Rôle</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Sections</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Sources</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Inscrit le</th>
<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">E-mail</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Rôle</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Sections</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Sources</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Inscrit le</th>
<th class="px-6 py-3"></th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
@forelse($users as $user)
@php
$roleColors = [
'admin' => 'bg-red-100 text-red-700',
'section_manager' => 'bg-blue-100 text-blue-700',
'member' => 'bg-gray-100 text-gray-600',
'admin' => 'bg-red-100 dark:bg-red-900/50 text-red-700',
'section_manager' => 'bg-blue-100 dark:bg-blue-900/50 text-blue-700',
'member' => 'bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-400',
];
$color = $roleColors[$user->role->value] ?? 'bg-gray-100 text-gray-600';
$color = $roleColors[$user->role->value] ?? 'bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-400';
@endphp
<tr class="hover:bg-gray-50 {{ ! $user->is_active ? 'opacity-60' : '' }}">
<td class="px-6 py-4 font-medium text-gray-900">
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700 {{ ! $user->is_active ? 'opacity-60' : '' }}">
<td class="px-6 py-4 font-medium text-gray-900 dark:text-white">
{{ $user->name }}
@if($user->id === auth()->id())
<span class="ml-1 text-xs text-gray-400">(vous)</span>
<span class="ml-1 text-xs text-gray-400 dark:text-gray-500">(vous)</span>
@endif
@if(! $user->is_active)
<span class="ml-2 inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-red-100 text-red-600">
<span class="ml-2 inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-red-100 dark:bg-red-900/50 text-red-600">
Inactif
</span>
@endif
</td>
<td class="px-6 py-4 text-gray-500">{{ $user->email }}</td>
<td class="px-6 py-4 text-gray-500 dark:text-gray-400">{{ $user->email }}</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 }}">
{{ $user->role->label() }}
</span>
</td>
<td class="px-6 py-4 text-gray-500">
<td class="px-6 py-4 text-gray-500 dark:text-gray-400">
{{ $user->sections->isNotEmpty() ? $user->sections->pluck('nom')->join(', ') : '—' }}
</td>
<td class="px-6 py-4 text-gray-500">{{ $user->sources_assignees_count ?: '—' }}</td>
<td class="px-6 py-4 text-gray-500 whitespace-nowrap">
<td class="px-6 py-4 text-gray-500 dark:text-gray-400">{{ $user->sources_assignees_count ?: '—' }}</td>
<td class="px-6 py-4 text-gray-500 dark:text-gray-400 whitespace-nowrap">
{{ $user->created_at->format('d/m/Y') }}
</td>
<td class="px-6 py-4 text-right space-x-3">
@@ -157,7 +157,7 @@
</tr>
@empty
<tr>
<td colspan="7" class="px-6 py-10 text-center text-gray-400">
<td colspan="7" class="px-6 py-10 text-center text-gray-400 dark:text-gray-500">
Aucun utilisateur trouvé.
</td>
</tr>
@@ -1,5 +1,5 @@
<x-guest-layout>
<div class="mb-4 text-sm text-gray-600">
<div class="mb-4 text-sm text-gray-600 dark:text-gray-400">
{{ __('This is a secure area of the application. Please confirm your password before continuing.') }}
</div>
@@ -1,5 +1,5 @@
<x-guest-layout>
<div class="mb-4 text-sm text-gray-600">
<div class="mb-4 text-sm text-gray-600 dark:text-gray-400">
{{ __('Forgot your password? No problem. Just let us know your email address and we will email you a password reset link that will allow you to choose a new one.') }}
</div>
+3 -3
View File
@@ -27,14 +27,14 @@
<!-- Remember Me -->
<div class="block mt-4">
<label for="remember_me" class="inline-flex items-center">
<input id="remember_me" type="checkbox" class="rounded border-gray-300 text-indigo-600 shadow-sm focus:ring-indigo-500" name="remember">
<span class="ms-2 text-sm text-gray-600">{{ __('Remember me') }}</span>
<input id="remember_me" type="checkbox" class="rounded border-gray-300 dark:border-gray-600 text-indigo-600 shadow-sm focus:ring-indigo-500" name="remember">
<span class="ms-2 text-sm text-gray-600 dark:text-gray-400">{{ __('Remember me') }}</span>
</label>
</div>
<div class="flex items-center justify-end mt-4">
@if (Route::has('password.request'))
<a class="underline text-sm text-gray-600 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" href="{{ route('password.request') }}">
<a class="underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" href="{{ route('password.request') }}">
{{ __('Forgot your password?') }}
</a>
@endif
+1 -1
View File
@@ -40,7 +40,7 @@
</div>
<div class="flex items-center justify-end mt-4">
<a class="underline text-sm text-gray-600 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" href="{{ route('login') }}">
<a class="underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" href="{{ route('login') }}">
{{ __('Already registered?') }}
</a>
+7 -7
View File
@@ -1,20 +1,20 @@
<x-guest-layout>
<div class="mb-6 text-center">
<div class="inline-flex items-center justify-center w-14 h-14 rounded-full bg-indigo-100 mb-3">
<div class="inline-flex items-center justify-center w-14 h-14 rounded-full bg-indigo-100 dark:bg-indigo-900/50 mb-3">
<svg class="w-7 h-7 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/>
</svg>
</div>
<h2 class="text-lg font-semibold text-gray-900">Vérification en deux étapes</h2>
<p class="text-sm text-gray-500 mt-1">
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">Vérification en deux étapes</h2>
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">
Un code à 6 chiffres a été envoyé à<br>
<span class="font-medium text-gray-700">{{ $maskedEmail }}</span>
<span class="font-medium text-gray-700 dark:text-gray-300">{{ $maskedEmail }}</span>
</p>
</div>
@if(session('resent'))
<div class="mb-4 p-3 bg-green-50 border border-green-200 text-green-800 text-sm rounded-md text-center">
<div class="mb-4 p-3 bg-green-50 dark:bg-green-900/30 border border-green-200 dark:border-green-700 text-green-800 dark:text-green-200 text-sm rounded-md text-center">
Un nouveau code a été envoyé.
</div>
@endif
@@ -28,7 +28,7 @@
inputmode="numeric" pattern="[0-9]{6}" maxlength="6" autocomplete="one-time-code"
autofocus required
class="mt-1 block w-full text-center text-3xl tracking-[.5em] font-mono
border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm"
border-gray-300 dark:border-gray-600 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm"
placeholder="——————">
<x-input-error :messages="$errors->get('pin')" class="mt-2"/>
</div>
@@ -45,7 +45,7 @@
Renvoyer le code
</button>
</form>
<a href="{{ route('login') }}" class="text-sm text-gray-400 hover:text-gray-600">
<a href="{{ route('login') }}" class="text-sm text-gray-400 dark:text-gray-500 hover:text-gray-600">
Retour à la connexion
</a>
</div>
+2 -2
View File
@@ -1,5 +1,5 @@
<x-guest-layout>
<div class="mb-4 text-sm text-gray-600">
<div class="mb-4 text-sm text-gray-600 dark:text-gray-400">
{{ __('Thanks for signing up! Before getting started, could you verify your email address by clicking on the link we just emailed to you? If you didn\'t receive the email, we will gladly send you another.') }}
</div>
@@ -23,7 +23,7 @@
<form method="POST" action="{{ route('logout') }}">
@csrf
<button type="submit" class="underline text-sm text-gray-600 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
<button type="submit" class="underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
{{ __('Log Out') }}
</button>
</form>
@@ -1 +1 @@
<a {{ $attributes->merge(['class' => 'block w-full px-4 py-2 text-start text-sm leading-5 text-gray-700 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 transition duration-150 ease-in-out']) }}>{{ $slot }}</a>
<a {{ $attributes->merge(['class' => 'block w-full px-4 py-2 text-start text-sm leading-5 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none focus:bg-gray-100 dark:focus:bg-gray-700 transition duration-150 ease-in-out']) }}>{{ $slot }}</a>
@@ -1,4 +1,4 @@
@props(['align' => 'right', 'width' => '48', 'contentClasses' => 'py-1 bg-white'])
@props(['align' => 'right', 'width' => '48', 'contentClasses' => 'py-1 bg-white dark:bg-gray-800'])
@php
$alignmentClasses = match ($align) {
@@ -28,7 +28,7 @@ $width = match ($width) {
class="absolute z-50 mt-2 {{ $width }} rounded-md shadow-lg {{ $alignmentClasses }}"
style="display: none;"
@click="open = false">
<div class="rounded-md ring-1 ring-black ring-opacity-5 {{ $contentClasses }}">
<div class="rounded-md ring-1 ring-black ring-opacity-5 dark:ring-gray-700 {{ $contentClasses }}">
{{ $content }}
</div>
</div>
@@ -1,5 +1,5 @@
@props(['value'])
<label {{ $attributes->merge(['class' => 'block font-medium text-sm text-gray-700']) }}>
<label {{ $attributes->merge(['class' => 'block font-medium text-sm text-gray-700 dark:text-gray-300']) }}>
{{ $value ?? $slot }}
</label>
+2 -4
View File
@@ -18,10 +18,8 @@ $maxWidth = [
x-data="{
show: @js($show),
focusables() {
// All focusable element types...
let selector = 'a, button, input:not([type=\'hidden\']), textarea, select, details, [tabindex]:not([tabindex=\'-1\'])'
return [...$el.querySelectorAll(selector)]
// All non-disabled elements...
.filter(el => ! el.hasAttribute('disabled'))
},
firstFocusable() { return this.focusables()[0] },
@@ -60,12 +58,12 @@ $maxWidth = [
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
>
<div class="absolute inset-0 bg-gray-500 opacity-75"></div>
<div class="absolute inset-0 bg-gray-500 dark:bg-gray-900 opacity-75"></div>
</div>
<div
x-show="show"
class="mb-6 bg-white rounded-lg overflow-hidden shadow-xl transform transition-all sm:w-full {{ $maxWidth }} sm:mx-auto"
class="mb-6 bg-white dark:bg-gray-800 rounded-lg overflow-hidden shadow-xl dark:shadow-gray-900/50 transform transition-all sm:w-full {{ $maxWidth }} sm:mx-auto"
x-transition:enter="ease-out duration-300"
x-transition:enter-start="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100"
@@ -2,8 +2,8 @@
@php
$classes = ($active ?? false)
? 'inline-flex items-center px-1 pt-1 border-b-2 border-indigo-400 text-sm font-medium leading-5 text-gray-900 focus:outline-none focus:border-indigo-700 transition duration-150 ease-in-out'
: 'inline-flex items-center px-1 pt-1 border-b-2 border-transparent text-sm font-medium leading-5 text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-300 transition duration-150 ease-in-out';
? 'inline-flex items-center px-1 pt-1 border-b-2 border-indigo-400 text-sm font-medium leading-5 text-gray-900 dark:text-white focus:outline-none focus:border-indigo-700 transition duration-150 ease-in-out'
: 'inline-flex items-center px-1 pt-1 border-b-2 border-transparent text-sm font-medium leading-5 text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 hover:border-gray-300 dark:hover:border-gray-600 focus:outline-none focus:text-gray-700 dark:focus:text-gray-200 focus:border-gray-300 dark:focus:border-gray-600 transition duration-150 ease-in-out';
@endphp
<a {{ $attributes->merge(['class' => $classes]) }}>
@@ -1,3 +1,3 @@
<button {{ $attributes->merge(['type' => 'submit', 'class' => 'inline-flex items-center px-4 py-2 bg-gray-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700 focus:bg-gray-700 active:bg-gray-900 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition ease-in-out duration-150']) }}>
<button {{ $attributes->merge(['type' => 'submit', 'class' => 'inline-flex items-center px-4 py-2 bg-gray-800 dark:bg-gray-200 border border-transparent rounded-md font-semibold text-xs text-white dark:text-gray-800 uppercase tracking-widest hover:bg-gray-700 dark:hover:bg-gray-300 focus:bg-gray-700 active:bg-gray-900 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 transition ease-in-out duration-150']) }}>
{{ $slot }}
</button>
@@ -2,8 +2,8 @@
@php
$classes = ($active ?? false)
? 'block w-full ps-3 pe-4 py-2 border-l-4 border-indigo-400 text-start text-base font-medium text-indigo-700 bg-indigo-50 focus:outline-none focus:text-indigo-800 focus:bg-indigo-100 focus:border-indigo-700 transition duration-150 ease-in-out'
: 'block w-full ps-3 pe-4 py-2 border-l-4 border-transparent text-start text-base font-medium text-gray-600 hover:text-gray-800 hover:bg-gray-50 hover:border-gray-300 focus:outline-none focus:text-gray-800 focus:bg-gray-50 focus:border-gray-300 transition duration-150 ease-in-out';
? 'block w-full ps-3 pe-4 py-2 border-l-4 border-indigo-400 text-start text-base font-medium text-indigo-700 dark:text-indigo-300 bg-indigo-50 dark:bg-indigo-900/30 focus:outline-none focus:text-indigo-800 focus:bg-indigo-100 focus:border-indigo-700 transition duration-150 ease-in-out'
: 'block w-full ps-3 pe-4 py-2 border-l-4 border-transparent text-start text-base font-medium text-gray-600 dark:text-gray-400 hover:text-gray-800 dark:hover:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700 hover:border-gray-300 dark:hover:border-gray-600 focus:outline-none focus:text-gray-800 focus:bg-gray-50 focus:border-gray-300 transition duration-150 ease-in-out';
@endphp
<a {{ $attributes->merge(['class' => $classes]) }}>
@@ -1,3 +1,3 @@
<button {{ $attributes->merge(['type' => 'button', 'class' => 'inline-flex items-center px-4 py-2 bg-white border border-gray-300 rounded-md font-semibold text-xs text-gray-700 uppercase tracking-widest shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 disabled:opacity-25 transition ease-in-out duration-150']) }}>
<button {{ $attributes->merge(['type' => 'button', 'class' => 'inline-flex items-center px-4 py-2 bg-white dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-md font-semibold text-xs text-gray-700 dark:text-gray-300 uppercase tracking-widest shadow-sm hover:bg-gray-50 dark:hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 disabled:opacity-25 transition ease-in-out duration-150']) }}>
{{ $slot }}
</button>
@@ -1,3 +1,3 @@
@props(['disabled' => false])
<input @disabled($disabled) {{ $attributes->merge(['class' => 'border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm']) }}>
<input @disabled($disabled) {{ $attributes->merge(['class' => 'border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100 dark:placeholder-gray-400 focus:border-indigo-500 dark:focus:border-indigo-400 focus:ring-indigo-500 dark:focus:ring-indigo-400 rounded-md shadow-sm']) }}>
@@ -0,0 +1,159 @@
{{--
Sélecteur d'utilisateur avec recherche (fenêtre modale).
Props :
name nom du champ hidden (défaut : user_id)
users collection/array d'objets avec {id, name, email}
placeholder texte affiché avant sélection
required ajoute l'attribut required sur le champ hidden (pour validation formulaire)
--}}
@props([
'name' => 'user_id',
'users' => [],
'placeholder' => 'Sélectionner un utilisateur…',
'required' => false,
])
@php
$usersJson = collect($users)->map(fn ($u) => [
'id' => $u->id,
'name' => $u->name,
'email' => $u->email,
])->values()->toJson();
@endphp
<div x-data="{
open: false,
search: '',
selectedId: null,
selectedLabel: '',
users: {{ $usersJson }},
get filtered() {
if (! this.search.trim()) return this.users;
const q = this.search.toLowerCase();
return this.users.filter(u =>
u.name.toLowerCase().includes(q) || u.email.toLowerCase().includes(q)
);
},
select(u) {
this.selectedId = u.id;
this.selectedLabel = u.name + ' (' + u.email + ')';
this.open = false;
this.search = '';
},
clear() {
this.selectedId = null;
this.selectedLabel = '';
}
}" @keydown.escape.window="open = false">
<input type="hidden" name="{{ $name }}" :value="selectedId" {{ $required ? 'required' : '' }}>
{{-- Bouton déclencheur --}}
<button type="button" @click="open = true"
class="w-full flex items-center justify-between gap-2 px-3 py-2
bg-white dark:bg-gray-700 border border-gray-300 dark:border-gray-600
rounded-md shadow-sm text-sm text-left
hover:bg-gray-50 dark:hover:bg-gray-600 transition-colors
focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-1 dark:focus:ring-offset-gray-800">
<span :class="selectedId ? 'text-gray-900 dark:text-gray-100' : 'text-gray-400 dark:text-gray-500'"
x-text="selectedLabel || '{{ $placeholder }}'"></span>
<svg class="w-4 h-4 text-gray-400 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
</svg>
</button>
{{-- Fenêtre modale --}}
<div x-show="open" x-cloak
class="fixed inset-0 z-50 flex items-start justify-center pt-16 sm:pt-24 px-4"
x-transition:enter="transition ease-out duration-150"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition ease-in duration-100"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0">
{{-- Fond semi-transparent --}}
<div class="absolute inset-0 bg-gray-900/50 dark:bg-gray-950/70" @click="open = false"></div>
{{-- Panneau --}}
<div class="relative w-full max-w-md bg-white dark:bg-gray-800 rounded-xl shadow-xl dark:shadow-gray-900/50 overflow-hidden"
@click.stop
x-transition:enter="transition ease-out duration-150"
x-transition:enter-start="opacity-0 -translate-y-2"
x-transition:enter-end="opacity-100 translate-y-0">
{{-- Champ de recherche --}}
<div class="flex items-center gap-2 px-4 py-3 border-b border-gray-200 dark:border-gray-700">
<svg class="w-4 h-4 text-gray-400 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
</svg>
<input type="text" x-model="search" x-ref="searchInput"
x-init="$watch('open', v => v && $nextTick(() => $refs.searchInput && $refs.searchInput.focus()))"
placeholder="Rechercher par nom ou email…"
class="flex-1 bg-transparent border-none outline-none p-0 text-sm
text-gray-900 dark:text-gray-100
placeholder-gray-400 dark:placeholder-gray-500
focus:ring-0">
<button type="button" @click="open = false"
class="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
</div>
{{-- Liste des utilisateurs --}}
<div class="overflow-y-auto" style="max-height: 18rem;">
<template x-if="filtered.length === 0">
<p class="px-4 py-8 text-center text-sm text-gray-400 dark:text-gray-500">
Aucun résultat pour « <span x-text="search"></span> »
</p>
</template>
<template x-for="u in filtered" :key="u.id">
<button type="button" @click="select(u)"
class="w-full flex items-center gap-3 px-4 py-2.5 text-left transition-colors
hover:bg-gray-50 dark:hover:bg-gray-700"
:class="selectedId === u.id
? 'bg-indigo-50 dark:bg-indigo-900/30'
: ''">
{{-- Avatar initiale --}}
<div class="w-8 h-8 rounded-full bg-indigo-100 dark:bg-indigo-900/50
flex items-center justify-center shrink-0">
<span class="text-xs font-semibold text-indigo-700 dark:text-indigo-300"
x-text="u.name.charAt(0).toUpperCase()"></span>
</div>
<div class="min-w-0 flex-1">
<p class="text-sm font-medium text-gray-900 dark:text-gray-100 truncate"
x-text="u.name"></p>
<p class="text-xs text-gray-500 dark:text-gray-400 truncate"
x-text="u.email"></p>
</div>
<template x-if="selectedId === u.id">
<svg class="w-4 h-4 text-indigo-600 dark:text-indigo-400 shrink-0"
fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd"
d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"
clip-rule="evenodd"/>
</svg>
</template>
</button>
</template>
</div>
{{-- Pied : compteur --}}
<div class="px-4 py-2 border-t border-gray-100 dark:border-gray-700
text-xs text-gray-400 dark:text-gray-500 flex items-center justify-between">
<span>
<span x-text="filtered.length"></span> /
<span x-text="users.length"></span> utilisateur<span x-show="users.length !== 1">s</span>
</span>
<button x-show="selectedId" type="button" @click="clear()"
class="text-red-500 hover:text-red-700 dark:hover:text-red-400 transition-colors">
Effacer la sélection
</button>
</div>
</div>
</div>
</div>
+47 -47
View File
@@ -1,6 +1,6 @@
<x-app-layout>
<x-slot name="header">
<h2 class="text-xl font-semibold text-gray-800">Tableau de bord</h2>
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">Tableau de bord</h2>
</x-slot>
<div class="py-8 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 space-y-8">
@@ -9,9 +9,9 @@
{{-- Bloc admin : lien vers le dashboard admin --}}
@if($user->isAdmin())
<div class="bg-indigo-50 border border-indigo-200 rounded-xl p-5 flex items-center justify-between">
<div class="bg-indigo-50 dark:bg-indigo-900/30 border border-indigo-200 dark:border-indigo-700 rounded-xl p-5 flex items-center justify-between">
<div>
<p class="text-sm font-semibold text-indigo-800">Accès administrateur</p>
<p class="text-sm font-semibold text-indigo-800 dark:text-indigo-200">Accès administrateur</p>
<p class="text-xs text-indigo-600 mt-0.5">Statistiques globales, gestion des utilisateurs et des sections.</p>
</div>
<a href="{{ route('admin.dashboard') }}"
@@ -26,10 +26,10 @@
@foreach($sectionsStats as $stat)
@php
$statusColors = [
'a_faire' => ['bg' => 'bg-gray-100', 'text' => 'text-gray-700'],
'en_cours' => ['bg' => 'bg-blue-100', 'text' => 'text-blue-700'],
'a_valider' => ['bg' => 'bg-yellow-100', 'text' => 'text-yellow-700'],
'termine' => ['bg' => 'bg-green-100', 'text' => 'text-green-700'],
'a_faire' => ['bg' => 'bg-gray-100 dark:bg-gray-700', 'text' => 'text-gray-700 dark:text-gray-300'],
'en_cours' => ['bg' => 'bg-blue-100 dark:bg-blue-900/50', 'text' => 'text-blue-700'],
'a_valider' => ['bg' => 'bg-yellow-100 dark:bg-yellow-900/50', 'text' => 'text-yellow-700'],
'termine' => ['bg' => 'bg-green-100 dark:bg-green-900/50', 'text' => 'text-green-700'],
];
$statusLabels = [
'a_faire' => 'À faire',
@@ -39,17 +39,17 @@
];
@endphp
<div class="space-y-4">
<h3 class="text-base font-semibold text-gray-800 flex items-center gap-2">
<h3 class="text-base font-semibold text-gray-800 dark:text-gray-200 flex items-center gap-2">
<span>Section {{ $stat['section']->nom }}</span>
@if($user->isManagerOfSection($stat['section']))
<span class="text-xs px-2 py-0.5 bg-blue-100 text-blue-700 rounded-full">Responsable</span>
<span class="text-xs px-2 py-0.5 bg-blue-100 dark:bg-blue-900/50 text-blue-700 rounded-full">Responsable</span>
@endif
</h3>
{{-- Compteurs par statut --}}
<div class="grid grid-cols-2 sm:grid-cols-4 gap-3">
@foreach($stat['by_status'] as $statusVal => $count)
@php $c = $statusColors[$statusVal] ?? ['bg' => 'bg-gray-100', 'text' => 'text-gray-700']; @endphp
@php $c = $statusColors[$statusVal] ?? ['bg' => 'bg-gray-100 dark:bg-gray-700', 'text' => 'text-gray-700 dark:text-gray-300']; @endphp
<a href="{{ route('sources.index', ['status' => $statusVal]) }}"
class="rounded-xl border p-4 flex flex-col gap-1 hover:shadow-md transition-shadow
{{ $c['bg'] }} border-transparent">
@@ -62,38 +62,38 @@
{{-- Métriques globales section --}}
<div class="grid grid-cols-2 gap-4">
<div class="bg-white border border-gray-200 rounded-xl px-5 py-4 flex items-center gap-4">
<div class="p-2 bg-indigo-100 rounded-lg">
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl px-5 py-4 flex items-center gap-4">
<div class="p-2 bg-indigo-100 dark:bg-indigo-900/50 rounded-lg">
<svg class="w-5 h-5 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8"/>
</svg>
</div>
<div>
<p class="text-xl font-bold text-gray-900">{{ $stat['total_sources'] }}</p>
<p class="text-xs text-gray-500">source{{ $stat['total_sources'] > 1 ? 's' : '' }} au total</p>
<p class="text-xl font-bold text-gray-900 dark:text-white">{{ $stat['total_sources'] }}</p>
<p class="text-xs text-gray-500 dark:text-gray-400">source{{ $stat['total_sources'] > 1 ? 's' : '' }} au total</p>
</div>
</div>
<div class="bg-white border border-gray-200 rounded-xl px-5 py-4 flex items-center gap-4">
<div class="p-2 bg-green-100 rounded-lg">
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl px-5 py-4 flex items-center gap-4">
<div class="p-2 bg-green-100 dark:bg-green-900/50 rounded-lg">
<svg class="w-5 h-5 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" 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>
</div>
<div>
<p class="text-xl font-bold text-gray-900">{{ number_format($stat['total_releves']) }}</p>
<p class="text-xs text-gray-500">relevé{{ $stat['total_releves'] > 1 ? 's' : '' }} saisi{{ $stat['total_releves'] > 1 ? 's' : '' }}</p>
<p class="text-xl font-bold text-gray-900 dark:text-white">{{ number_format($stat['total_releves']) }}</p>
<p class="text-xs text-gray-500 dark:text-gray-400">relevé{{ $stat['total_releves'] > 1 ? 's' : '' }} saisi{{ $stat['total_releves'] > 1 ? 's' : '' }}</p>
</div>
</div>
</div>
{{-- Sources récentes de la section --}}
@if($stat['sources_recentes']->isNotEmpty())
<div class="bg-white border border-gray-200 rounded-xl p-5">
<p class="text-xs font-semibold text-gray-500 uppercase mb-3">Sources récentes</p>
<div class="divide-y divide-gray-100">
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl p-5">
<p class="text-xs font-semibold text-gray-500 dark:text-gray-400 uppercase mb-3">Sources récentes</p>
<div class="divide-y divide-gray-100 dark:divide-gray-700">
@foreach($stat['sources_recentes'] as $src)
@php
$sc = $statusColors[$src->status->value] ?? ['bg' => 'bg-gray-100', 'text' => 'text-gray-600'];
$sc = $statusColors[$src->status->value] ?? ['bg' => 'bg-gray-100 dark:bg-gray-700', 'text' => 'text-gray-600 dark:text-gray-400'];
@endphp
<div class="flex items-center justify-between py-2.5">
<div class="min-w-0">
@@ -101,7 +101,7 @@
class="text-sm font-medium text-indigo-600 hover:underline truncate block">
{{ $src->nom }}
</a>
<p class="text-xs text-gray-400">
<p class="text-xs text-gray-400 dark:text-gray-500">
{{ $src->sourceType->nom }} · {{ $src->releves_count }} relevé{{ $src->releves_count > 1 ? 's' : '' }}
</p>
</div>
@@ -119,45 +119,45 @@
{{-- ── Mes sources assignées ────────────────────────────────────────── --}}
@if($mesSources->isNotEmpty())
<div class="bg-white border border-gray-200 rounded-xl p-6">
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl p-6">
<div class="flex items-center justify-between mb-4">
<h3 class="text-sm font-semibold text-gray-700 uppercase tracking-wide">Mes sources assignées</h3>
<h3 class="text-sm font-semibold text-gray-700 dark:text-gray-300 uppercase tracking-wide">Mes sources assignées</h3>
<a href="{{ route('sources.index') }}" class="text-xs text-indigo-600 hover:underline">Voir toutes</a>
</div>
<div class="overflow-x-auto">
<table class="min-w-full text-sm divide-y divide-gray-100">
<table class="min-w-full text-sm divide-y divide-gray-100 dark:divide-gray-700">
<thead>
<tr>
<th class="pb-2 text-left text-xs font-medium text-gray-500 uppercase">Source</th>
<th class="pb-2 text-left text-xs font-medium text-gray-500 uppercase">Type</th>
<th class="pb-2 text-left text-xs font-medium text-gray-500 uppercase">Statut</th>
<th class="pb-2 text-left text-xs font-medium text-gray-500 uppercase">Relevés</th>
<th class="pb-2 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Source</th>
<th class="pb-2 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Type</th>
<th class="pb-2 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Statut</th>
<th class="pb-2 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Relevés</th>
<th class="pb-2"></th>
</tr>
</thead>
<tbody class="divide-y divide-gray-50">
<tbody class="divide-y divide-gray-50 dark:divide-gray-700">
@foreach($mesSources as $source)
@php
$colors = [
'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',
'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',
];
$c = $colors[$source->status->value] ?? 'bg-gray-100 text-gray-600';
$c = $colors[$source->status->value] ?? 'bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-400';
@endphp
<tr class="hover:bg-gray-50">
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700">
<td class="py-2.5 pr-4">
<a href="{{ route('sources.show', $source) }}"
class="font-medium text-indigo-600 hover:underline">{{ $source->nom }}</a>
</td>
<td class="py-2.5 pr-4 text-gray-500">{{ $source->sourceType->nom }}</td>
<td class="py-2.5 pr-4 text-gray-500 dark:text-gray-400">{{ $source->sourceType->nom }}</td>
<td class="py-2.5 pr-4">
<span class="inline-flex px-2 py-0.5 rounded-full text-xs font-medium {{ $c }}">
{{ $source->status->label() }}
</span>
</td>
<td class="py-2.5 pr-4 text-gray-500">{{ $source->releves_count }}</td>
<td class="py-2.5 pr-4 text-gray-500 dark:text-gray-400">{{ $source->releves_count }}</td>
<td class="py-2.5 text-right">
<a href="{{ route('sources.releves.index', $source) }}"
class="text-xs text-indigo-600 hover:underline">Saisir </a>
@@ -169,8 +169,8 @@
</div>
</div>
@elseif(! $sectionsStats || $sectionsStats->isEmpty())
<div class="bg-white border border-gray-200 rounded-xl p-10 text-center text-gray-400">
<svg class="mx-auto w-10 h-10 mb-3 text-gray-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl p-10 text-center text-gray-400 dark:text-gray-500">
<svg class="mx-auto w-10 h-10 mb-3 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="M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8"/>
</svg>
@@ -183,22 +183,22 @@
{{-- ── Mes derniers relevés ─────────────────────────────────────────── --}}
@if($mesReleves->isNotEmpty())
<div class="bg-white border border-gray-200 rounded-xl p-6">
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl p-6">
<div class="flex items-center justify-between mb-4">
<h3 class="text-sm font-semibold text-gray-700 uppercase tracking-wide">Mes derniers relevés</h3>
<h3 class="text-sm font-semibold text-gray-700 dark:text-gray-300 uppercase tracking-wide">Mes derniers relevés</h3>
<a href="{{ route('recherche') }}" class="text-xs text-indigo-600 hover:underline">Recherche</a>
</div>
<div class="space-y-0 divide-y divide-gray-100">
<div class="space-y-0 divide-y divide-gray-100 dark:divide-gray-700">
@foreach($mesReleves as $releve)
<div class="flex items-center justify-between py-2.5">
<div class="min-w-0">
<a href="{{ route('releves.show', $releve) }}"
class="text-sm font-medium text-gray-900 hover:text-indigo-600">
class="text-sm font-medium text-gray-900 dark:text-white hover:text-indigo-600">
{{ $releve->nom ?? '—' }}{{ $releve->prenom ? ', ' . $releve->prenom : '' }}
</a>
<p class="text-xs text-gray-400">{{ $releve->source->nom }}</p>
<p class="text-xs text-gray-400 dark:text-gray-500">{{ $releve->source->nom }}</p>
</div>
<span class="text-xs text-gray-400 whitespace-nowrap ml-4">
<span class="text-xs text-gray-400 dark:text-gray-500 whitespace-nowrap ml-4">
{{ $releve->created_at->diffForHumans() }}
</span>
</div>
+18 -4
View File
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}" class="">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
@@ -11,6 +11,20 @@
<link rel="icon" href="{{ $siteLogoUrl }}">
@endif
<!-- Dark mode init must run before first paint to avoid flash -->
<script>
(function () {
var t = localStorage.getItem('colorTheme') || 'auto';
var dark = t === 'dark' || (t === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches);
document.documentElement.classList.toggle('dark', dark);
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', function (e) {
if ((localStorage.getItem('colorTheme') || 'auto') === 'auto') {
document.documentElement.classList.toggle('dark', e.matches);
}
});
})();
</script>
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet" />
@@ -18,13 +32,13 @@
<!-- Scripts -->
@vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body class="font-sans antialiased">
<div class="min-h-screen bg-gray-100">
<body class="font-sans antialiased bg-gray-100 dark:bg-gray-900 text-gray-900 dark:text-gray-100">
<div class="min-h-screen">
@include('layouts.navigation')
<!-- Page Heading -->
@isset($header)
<header class="bg-white shadow">
<header class="bg-white dark:bg-gray-800 shadow dark:shadow-gray-900/50">
<div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
{{ $header }}
</div>
+19 -5
View File
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}" class="">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
@@ -11,6 +11,20 @@
<link rel="icon" href="{{ $siteLogoUrl }}">
@endif
<!-- Dark mode init -->
<script>
(function () {
var t = localStorage.getItem('colorTheme') || 'auto';
var dark = t === 'dark' || (t === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches);
document.documentElement.classList.toggle('dark', dark);
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', function (e) {
if ((localStorage.getItem('colorTheme') || 'auto') === 'auto') {
document.documentElement.classList.toggle('dark', e.matches);
}
});
})();
</script>
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet" />
@@ -18,19 +32,19 @@
<!-- Scripts -->
@vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body class="font-sans text-gray-900 antialiased">
<div class="min-h-screen flex flex-col sm:justify-center items-center pt-6 sm:pt-0 bg-gray-100">
<body class="font-sans text-gray-900 dark:text-gray-100 antialiased">
<div class="min-h-screen flex flex-col sm:justify-center items-center pt-6 sm:pt-0 bg-gray-100 dark:bg-gray-900">
<div class="mb-2">
<a href="/">
@if($siteLogoUrl)
<img src="{{ $siteLogoUrl }}" alt="{{ config('app.name') }}" class="h-16 w-auto object-contain">
@else
<x-application-logo class="w-16 h-16 fill-current text-gray-400" />
<x-application-logo class="w-16 h-16 fill-current text-gray-400 dark:text-gray-500" />
@endif
</a>
</div>
<div class="w-full sm:max-w-md mt-6 px-6 py-4 bg-white shadow-md overflow-hidden sm:rounded-lg">
<div class="w-full sm:max-w-md mt-6 px-6 py-4 bg-white dark:bg-gray-800 shadow-md dark:shadow-gray-900/50 overflow-hidden sm:rounded-lg">
{{ $slot }}
</div>
</div>
+98 -19
View File
@@ -1,8 +1,8 @@
<nav x-data="{ open: false }" class="bg-white border-b border-gray-100">
<nav x-data="{ open: false }" class="bg-white dark:bg-gray-800 border-b border-gray-100 dark:border-gray-700">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between h-16">
<div class="flex">
<!-- Logo max-h contraint sur l'image directement, sans chaîne h-full -->
<!-- Logo -->
<div class="shrink-0 flex items-center">
<a href="{{ route('dashboard') }}" class="flex items-center">
@if($siteLogoUrl)
@@ -10,7 +10,7 @@
class="block w-auto object-contain"
style="max-height: 40px; max-width: 200px;">
@else
<span class="font-semibold text-gray-800 text-lg">{{ config('app.name') }}</span>
<span class="font-semibold text-gray-800 dark:text-gray-200 text-lg">{{ config('app.name') }}</span>
@endif
</a>
</div>
@@ -34,12 +34,11 @@
</x-nav-link>
@if(auth()->user()->isSectionManager())
<!-- Menu Administration utilise le composant x-dropdown (même positionnement que le menu utilisateur) -->
<div class="hidden sm:flex sm:items-center">
<x-dropdown align="left" width="w-56">
<x-slot name="trigger">
<button class="inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium leading-5 transition duration-150 ease-in-out
{{ request()->routeIs('admin.*') ? 'border-indigo-400 text-gray-900' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300' }}">
{{ request()->routeIs('admin.*') ? 'border-indigo-400 text-gray-900 dark:text-white' : 'border-transparent text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 hover:border-gray-300 dark:hover:border-gray-600' }}">
Administration
<svg class="ms-1 h-4 w-4 fill-current" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/>
@@ -70,7 +69,7 @@
<x-dropdown-link :href="route('admin.lieu-types.index')">
Types de lieux
</x-dropdown-link>
<div class="border-t border-gray-100 my-1"></div>
<div class="border-t border-gray-100 dark:border-gray-700 my-1"></div>
<x-dropdown-link :href="route('admin.parametres')">
Paramètres du site
</x-dropdown-link>
@@ -82,11 +81,53 @@
</div>
</div>
<!-- Cloche notifications -->
<div class="hidden sm:flex sm:items-center sm:ms-4">
<!-- Right side: theme toggle + notifications + user menu -->
<div class="hidden sm:flex sm:items-center sm:gap-1">
<!-- Sélecteur de thème -->
<div x-data="{
theme: localStorage.getItem('colorTheme') || 'auto',
apply(t) {
this.theme = t;
localStorage.setItem('colorTheme', t);
var dark = t === 'dark' || (t === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches);
document.documentElement.classList.toggle('dark', dark);
}
}" class="flex items-center">
<div class="flex items-center bg-gray-100 dark:bg-gray-700 rounded-full p-0.5 gap-0.5">
<!-- Clair -->
<button @click="apply('light')"
:class="theme === 'light' ? 'bg-white dark:bg-gray-600 shadow text-gray-800 dark:text-gray-100' : 'text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-300'"
class="p-1.5 rounded-full transition-all" title="Mode clair">
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364-6.364l-.707.707M6.343 17.657l-.707.707M17.657 17.657l-.707-.707M6.343 6.343l-.707-.707M12 7a5 5 0 100 10A5 5 0 0012 7z"/>
</svg>
</button>
<!-- Automatique -->
<button @click="apply('auto')"
:class="theme === 'auto' ? 'bg-white dark:bg-gray-600 shadow text-gray-800 dark:text-gray-100' : 'text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-300'"
class="p-1.5 rounded-full transition-all" title="Automatique (système)">
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/>
</svg>
</button>
<!-- Sombre -->
<button @click="apply('dark')"
:class="theme === 'dark' ? 'bg-white dark:bg-gray-600 shadow text-gray-800 dark:text-gray-100' : 'text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-300'"
class="p-1.5 rounded-full transition-all" title="Mode sombre">
<svg class="w-3.5 h-3.5" fill="currentColor" viewBox="0 0 24 24">
<path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"/>
</svg>
</button>
</div>
</div>
<!-- Notifications -->
@php $unreadCount = auth()->user()->unreadNotifications->count(); @endphp
<a href="{{ route('notifications.index') }}"
class="relative p-2 text-gray-500 hover:text-indigo-600 transition-colors"
class="relative p-2 text-gray-500 dark:text-gray-400 hover:text-indigo-600 dark:hover:text-indigo-400 transition-colors"
title="Notifications">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
@@ -98,13 +139,11 @@
</span>
@endif
</a>
</div>
<!-- Menu utilisateur (Profil / Déconnexion) -->
<div class="hidden sm:flex sm:items-center sm:ms-2">
<!-- Menu utilisateur -->
<x-dropdown align="right" width="48">
<x-slot name="trigger">
<button class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 bg-white hover:text-gray-700 focus:outline-none transition ease-in-out duration-150">
<button class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 dark:text-gray-400 bg-white dark:bg-gray-800 hover:text-gray-700 dark:hover:text-gray-200 focus:outline-none transition ease-in-out duration-150">
<div>{{ Auth::user()->name }}</div>
<div class="ms-1">
<svg class="fill-current h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
@@ -115,7 +154,7 @@
</x-slot>
<x-slot name="content">
<div class="px-4 py-2 text-xs text-gray-400 border-b border-gray-100">
<div class="px-4 py-2 text-xs text-gray-400 dark:text-gray-500 border-b border-gray-100 dark:border-gray-700">
{{ Auth::user()->role->label() }}
</div>
<x-dropdown-link :href="route('profile.edit')">
@@ -134,7 +173,7 @@
<!-- Hamburger (mobile) -->
<div class="-me-2 flex items-center sm:hidden">
<button @click="open = ! open" class="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none transition duration-150 ease-in-out">
<button @click="open = ! open" class="inline-flex items-center justify-center p-2 rounded-md text-gray-400 dark:text-gray-500 hover:text-gray-500 dark:hover:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none transition duration-150 ease-in-out">
<svg class="h-6 w-6" stroke="currentColor" fill="none" viewBox="0 0 24 24">
<path :class="{'hidden': open, 'inline-flex': ! open }" class="inline-flex" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
<path :class="{'hidden': ! open, 'inline-flex': open }" class="hidden" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
@@ -189,12 +228,52 @@
</div>
<!-- Options utilisateur (mobile) -->
<div class="pt-4 pb-1 border-t border-gray-200">
<div class="pt-4 pb-1 border-t border-gray-200 dark:border-gray-700">
<div class="px-4">
<div class="font-medium text-base text-gray-800">{{ Auth::user()->name }}</div>
<div class="font-medium text-sm text-gray-500">{{ Auth::user()->email }}</div>
<div class="text-xs text-gray-400">{{ Auth::user()->role->label() }}</div>
<div class="font-medium text-base text-gray-800 dark:text-gray-200">{{ Auth::user()->name }}</div>
<div class="font-medium text-sm text-gray-500 dark:text-gray-400">{{ Auth::user()->email }}</div>
<div class="text-xs text-gray-400 dark:text-gray-500">{{ Auth::user()->role->label() }}</div>
</div>
<!-- Sélecteur de thème mobile -->
<div x-data="{
theme: localStorage.getItem('colorTheme') || 'auto',
apply(t) {
this.theme = t;
localStorage.setItem('colorTheme', t);
var dark = t === 'dark' || (t === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches);
document.documentElement.classList.toggle('dark', dark);
}
}" class="px-4 pt-3 pb-1">
<p class="text-xs text-gray-400 dark:text-gray-500 mb-2">Apparence</p>
<div class="flex gap-2">
<button @click="apply('light')"
:class="theme === 'light' ? 'bg-indigo-50 dark:bg-indigo-900/50 text-indigo-700 dark:text-indigo-300 border-indigo-300 dark:border-indigo-600' : 'border-gray-200 dark:border-gray-600 text-gray-600 dark:text-gray-400'"
class="flex-1 flex items-center justify-center gap-1.5 py-1.5 text-xs border rounded-md transition-colors">
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364-6.364l-.707.707M6.343 17.657l-.707.707M17.657 17.657l-.707-.707M6.343 6.343l-.707-.707M12 7a5 5 0 100 10A5 5 0 0012 7z"/>
</svg>
Clair
</button>
<button @click="apply('auto')"
:class="theme === 'auto' ? 'bg-indigo-50 dark:bg-indigo-900/50 text-indigo-700 dark:text-indigo-300 border-indigo-300 dark:border-indigo-600' : 'border-gray-200 dark:border-gray-600 text-gray-600 dark:text-gray-400'"
class="flex-1 flex items-center justify-center gap-1.5 py-1.5 text-xs border rounded-md transition-colors">
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/>
</svg>
Auto
</button>
<button @click="apply('dark')"
:class="theme === 'dark' ? 'bg-indigo-50 dark:bg-indigo-900/50 text-indigo-700 dark:text-indigo-300 border-indigo-300 dark:border-indigo-600' : 'border-gray-200 dark:border-gray-600 text-gray-600 dark:text-gray-400'"
class="flex-1 flex items-center justify-center gap-1.5 py-1.5 text-xs border rounded-md transition-colors">
<svg class="w-3.5 h-3.5" fill="currentColor" viewBox="0 0 24 24">
<path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"/>
</svg>
Sombre
</button>
</div>
</div>
<div class="mt-3 space-y-1">
<x-responsive-nav-link :href="route('profile.edit')">Mon profil</x-responsive-nav-link>
<form method="POST" action="{{ route('logout') }}">
+12 -12
View File
@@ -1,19 +1,19 @@
<div class="space-y-5">
{{-- Nom --}}
<div>
<label for="nom" class="block text-sm font-medium text-gray-700">Nom <span class="text-red-500">*</span></label>
<label for="nom" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Nom <span class="text-red-500">*</span></label>
<input type="text" id="nom" name="nom"
value="{{ old('nom', $lieu?->nom) }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 @error('nom') border-red-500 @enderror"
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 @error('nom') border-red-500 @enderror"
required>
@error('nom') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
{{-- Type de lieu --}}
<div>
<label for="lieu_type_id" class="block text-sm font-medium text-gray-700">Type <span class="text-red-500">*</span></label>
<label for="lieu_type_id" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Type <span class="text-red-500">*</span></label>
<select id="lieu_type_id" name="lieu_type_id" required
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 @error('lieu_type_id') border-red-500 @enderror">
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 @error('lieu_type_id') border-red-500 @enderror">
<option value=""> Choisir un type </option>
@foreach($lieuTypes as $lt)
<option value="{{ $lt->id }}" {{ old('lieu_type_id', $lieu?->lieu_type_id) == $lt->id ? 'selected' : '' }}>
@@ -32,10 +32,10 @@
{{-- Code --}}
<div>
<label for="code" class="block text-sm font-medium text-gray-700">Code (INSEE, postal…)</label>
<label for="code" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Code (INSEE, postal…)</label>
<input type="text" id="code" name="code"
value="{{ old('code', $lieu?->code) }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500"
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500"
maxlength="20">
</div>
@@ -53,18 +53,18 @@
{{-- Coordonnées --}}
<div class="grid grid-cols-2 gap-4">
<div>
<label for="latitude" class="block text-sm font-medium text-gray-700">Latitude</label>
<label for="latitude" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Latitude</label>
<input type="number" id="latitude" name="latitude" step="0.0000001"
value="{{ old('latitude', $lieu?->latitude) }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500"
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500"
placeholder="48.8566">
@error('latitude') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
<div>
<label for="longitude" class="block text-sm font-medium text-gray-700">Longitude</label>
<label for="longitude" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Longitude</label>
<input type="number" id="longitude" name="longitude" step="0.0000001"
value="{{ old('longitude', $lieu?->longitude) }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500"
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500"
placeholder="2.3522">
@error('longitude') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
@@ -72,8 +72,8 @@
{{-- Note --}}
<div>
<label for="note" class="block text-sm font-medium text-gray-700">Note</label>
<label for="note" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Note</label>
<textarea id="note" name="note" rows="3"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">{{ old('note', $lieu?->note) }}</textarea>
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">{{ old('note', $lieu?->note) }}</textarea>
</div>
</div>
+3 -3
View File
@@ -1,10 +1,10 @@
<x-app-layout>
<x-slot name="header">
<h2 class="text-xl font-semibold text-gray-800">Nouveau lieu</h2>
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">Nouveau lieu</h2>
</x-slot>
<div class="py-8 max-w-2xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="bg-white shadow rounded-lg p-6">
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6">
<form method="POST" action="{{ route('lieux.store') }}">
@csrf
@include('lieux._form', ['lieu' => null])
@@ -14,7 +14,7 @@
class="px-5 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700">
Créer
</button>
<a href="{{ route('lieux.index') }}" class="text-sm text-gray-500 hover:text-gray-700">Annuler</a>
<a href="{{ route('lieux.index') }}" class="text-sm text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300">Annuler</a>
</div>
</form>
</div>
+3 -3
View File
@@ -1,10 +1,10 @@
<x-app-layout>
<x-slot name="header">
<h2 class="text-xl font-semibold text-gray-800">Modifier : {{ $lieu->nom }}</h2>
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">Modifier : {{ $lieu->nom }}</h2>
</x-slot>
<div class="py-8 max-w-2xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="bg-white shadow rounded-lg p-6">
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6">
<form method="POST" action="{{ route('lieux.update', $lieu) }}">
@csrf @method('PUT')
@include('lieux._form', ['lieu' => $lieu])
@@ -14,7 +14,7 @@
class="px-5 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700">
Enregistrer
</button>
<a href="{{ route('lieux.show', $lieu) }}" class="text-sm text-gray-500 hover:text-gray-700">Annuler</a>
<a href="{{ route('lieux.show', $lieu) }}" class="text-sm text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300">Annuler</a>
</div>
</form>
</div>
+27 -27
View File
@@ -1,7 +1,7 @@
<x-app-layout>
<x-slot name="header">
<div class="flex items-center justify-between">
<h2 class="text-xl font-semibold text-gray-800">Lieux</h2>
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">Lieux</h2>
@can('create', App\Models\Lieu::class)
<a href="{{ route('lieux.create') }}"
class="px-4 py-2 bg-indigo-600 text-white text-sm rounded-md hover:bg-indigo-700">
@@ -14,29 +14,29 @@
<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>
<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
@if(session('error'))
<div class="p-4 bg-red-50 border border-red-200 text-red-800 rounded-md">{{ session('error') }}</div>
<div class="p-4 bg-red-50 dark:bg-red-900/30 border border-red-200 dark:border-red-700 text-red-800 dark:text-red-200 rounded-md">{{ session('error') }}</div>
@endif
{{-- Filtres --}}
@php $hasFilters = request()->anyFilled(['lieu_type_id', 'q', 'lieu_id']); @endphp
<div class="bg-white shadow rounded-lg p-5">
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-5">
<form method="GET" action="{{ route('lieux.index') }}">
<div class="flex flex-wrap items-end gap-4">
<div class="flex-1 min-w-[200px]">
<label class="block text-xs font-medium text-gray-600 mb-1">Recherche</label>
<label class="block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1">Recherche</label>
<input type="text" name="q" value="{{ request('q') }}"
placeholder="Nom, code INSEE…"
class="block w-full rounded-md border-gray-300 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
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 class="w-52">
<label class="block text-xs font-medium text-gray-600 mb-1">Type de lieu</label>
<label class="block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1">Type de lieu</label>
<select name="lieu_type_id"
class="block w-full rounded-md border-gray-300 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
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 les types </option>
@foreach($lieuTypes as $lt)
<option value="{{ $lt->id }}" {{ request('lieu_type_id') == $lt->id ? 'selected' : '' }}>
@@ -53,10 +53,10 @@
</button>
@if($hasFilters)
<a href="{{ route('lieux.index') }}"
class="px-4 py-2 border border-gray-300 text-gray-600 text-sm rounded-md hover:bg-gray-50">
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
</a>
<span class="inline-flex items-center px-2 py-0.5 rounded-full text-xs bg-indigo-100 text-indigo-700">
<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
@@ -77,29 +77,29 @@
</div>
{{-- Tableau --}}
<div class="bg-white shadow rounded-lg overflow-hidden">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<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">
<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 uppercase tracking-wider">Lieu</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Type</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Code</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Parent</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Coordonnées</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Lieu</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Type</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Code</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Parent</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Coordonnées</th>
<th class="px-6 py-3"></th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
@forelse($lieux as $lieu)
<tr class="hover:bg-gray-50">
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700">
<td class="px-6 py-4">
<a href="{{ route('lieux.show', $lieu) }}" class="font-medium text-indigo-600 hover:underline">
{{ $lieu->nom }}
</a>
</td>
<td class="px-6 py-4 text-sm text-gray-500">{{ $lieu->lieuType?->nom ?? '—' }}</td>
<td class="px-6 py-4 text-sm text-gray-500">{{ $lieu->code ?? '—' }}</td>
<td class="px-6 py-4 text-sm text-gray-500">
<td class="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">{{ $lieu->lieuType?->nom ?? '—' }}</td>
<td class="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">{{ $lieu->code ?? '—' }}</td>
<td class="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">
@if($lieu->parent)
<a href="{{ route('lieux.show', $lieu->parent) }}" class="text-indigo-600 hover:underline">
{{ $lieu->parent->nom }}
@@ -108,7 +108,7 @@
@endif
</td>
<td class="px-6 py-4 text-sm text-gray-500">
<td class="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">
@if($lieu->latitude && $lieu->longitude)
{{ number_format($lieu->latitude, 4) }}, {{ number_format($lieu->longitude, 4) }}
@else
@@ -117,7 +117,7 @@
</td>
<td class="px-6 py-4 text-right text-sm space-x-3">
@can('update', $lieu)
<a href="{{ route('lieux.edit', $lieu) }}" class="text-gray-600 hover:text-indigo-600">Modifier</a>
<a href="{{ route('lieux.edit', $lieu) }}" class="text-gray-600 dark:text-gray-400 hover:text-indigo-600">Modifier</a>
@endcan
@can('delete', $lieu)
<form method="POST" action="{{ route('lieux.destroy', $lieu) }}" class="inline"
@@ -131,7 +131,7 @@
</tr>
@empty
<tr>
<td colspan="6" class="px-6 py-10 text-center text-gray-400">
<td colspan="6" class="px-6 py-10 text-center text-gray-400 dark:text-gray-500">
@if($hasFilters) Aucun lieu ne correspond aux filtres.
@else Aucun lieu enregistré. @endif
</td>
@@ -141,7 +141,7 @@
</table>
@if($lieux->hasPages())
<div class="px-6 py-4 border-t border-gray-200">
<div class="px-6 py-4 border-t border-gray-200 dark:border-gray-700">
{{ $lieux->links() }}
</div>
@endif
+20 -20
View File
@@ -1,7 +1,7 @@
<x-app-layout>
<x-slot name="header">
<div class="flex items-center justify-between">
<h2 class="text-xl font-semibold text-gray-800">{{ $lieu->nom }}</h2>
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">{{ $lieu->nom }}</h2>
<div class="flex gap-3">
@can('update', $lieu)
<a href="{{ route('lieux.edit', $lieu) }}"
@@ -26,67 +26,67 @@
<div class="py-8 max-w-4xl 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">
<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
{{-- Fiche --}}
<div class="bg-white shadow rounded-lg divide-y divide-gray-100">
<div class="bg-white dark:bg-gray-800 shadow rounded-lg divide-y divide-gray-100 dark:divide-gray-700">
<div class="px-6 py-4 grid grid-cols-3 gap-4 text-sm">
<dt class="font-medium text-gray-500">Nom complet</dt>
<dd class="col-span-2 text-gray-900">{{ $lieu->nom_long ?? $lieu->nom }}</dd>
<dt class="font-medium text-gray-500 dark:text-gray-400">Nom complet</dt>
<dd class="col-span-2 text-gray-900 dark:text-white">{{ $lieu->nom_long ?? $lieu->nom }}</dd>
</div>
<div class="px-6 py-4 grid grid-cols-3 gap-4 text-sm">
<dt class="font-medium text-gray-500">Type</dt>
<dd class="col-span-2 text-gray-900">{{ $lieu->lieuType?->nom ?? '—' }}</dd>
<dt class="font-medium text-gray-500 dark:text-gray-400">Type</dt>
<dd class="col-span-2 text-gray-900 dark:text-white">{{ $lieu->lieuType?->nom ?? '—' }}</dd>
</div>
@if($lieu->code)
<div class="px-6 py-4 grid grid-cols-3 gap-4 text-sm">
<dt class="font-medium text-gray-500">Code</dt>
<dd class="col-span-2 text-gray-900">{{ $lieu->code }}</dd>
<dt class="font-medium text-gray-500 dark:text-gray-400">Code</dt>
<dd class="col-span-2 text-gray-900 dark:text-white">{{ $lieu->code }}</dd>
</div>
@endif
<div class="px-6 py-4 grid grid-cols-3 gap-4 text-sm">
<dt class="font-medium text-gray-500">Lieu parent</dt>
<dt class="font-medium text-gray-500 dark:text-gray-400">Lieu parent</dt>
<dd class="col-span-2">
@if($lieu->parent)
<a href="{{ route('lieux.show', $lieu->parent) }}" class="text-indigo-600 hover:underline">
{{ $lieu->parent->nom_long ?? $lieu->parent->nom }}
</a>
@else
<span class="text-gray-400">Lieu racine</span>
<span class="text-gray-400 dark:text-gray-500">Lieu racine</span>
@endif
</dd>
</div>
@if($lieu->latitude && $lieu->longitude)
<div class="px-6 py-4 grid grid-cols-3 gap-4 text-sm">
<dt class="font-medium text-gray-500">Coordonnées</dt>
<dd class="col-span-2 text-gray-900">{{ $lieu->latitude }}, {{ $lieu->longitude }}</dd>
<dt class="font-medium text-gray-500 dark:text-gray-400">Coordonnées</dt>
<dd class="col-span-2 text-gray-900 dark:text-white">{{ $lieu->latitude }}, {{ $lieu->longitude }}</dd>
</div>
@endif
@if($lieu->note)
<div class="px-6 py-4 grid grid-cols-3 gap-4 text-sm">
<dt class="font-medium text-gray-500">Note</dt>
<dd class="col-span-2 text-gray-900 whitespace-pre-line">{{ $lieu->note }}</dd>
<dt class="font-medium text-gray-500 dark:text-gray-400">Note</dt>
<dd class="col-span-2 text-gray-900 dark:text-white whitespace-pre-line">{{ $lieu->note }}</dd>
</div>
@endif
</div>
{{-- Enfants --}}
@if($lieu->enfants->isNotEmpty())
<div class="bg-white shadow rounded-lg overflow-hidden">
<div class="px-6 py-4 border-b border-gray-200">
<h3 class="font-medium text-gray-900">Subdivisions ({{ $lieu->enfants->count() }})</h3>
<div class="bg-white dark:bg-gray-800 shadow rounded-lg overflow-hidden">
<div class="px-6 py-4 border-b border-gray-200 dark:border-gray-700">
<h3 class="font-medium text-gray-900 dark:text-white">Subdivisions ({{ $lieu->enfants->count() }})</h3>
</div>
<ul class="divide-y divide-gray-100">
<ul class="divide-y divide-gray-100 dark:divide-gray-700">
@foreach($lieu->enfants->sortBy('nom') as $enfant)
<li class="px-6 py-3">
<a href="{{ route('lieux.show', $enfant) }}" class="text-indigo-600 hover:underline">
{{ $enfant->nom }}
</a>
@if($enfant->code)
<span class="ml-2 text-xs text-gray-400">({{ $enfant->code }})</span>
<span class="ml-2 text-xs text-gray-400 dark:text-gray-500">({{ $enfant->code }})</span>
@endif
</li>
@endforeach
+11 -11
View File
@@ -1,7 +1,7 @@
<x-app-layout>
<x-slot name="header">
<div class="flex items-center justify-between">
<h2 class="text-xl font-semibold text-gray-800">Notifications</h2>
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">Notifications</h2>
@if(auth()->user()->unreadNotifications->isNotEmpty())
<form method="POST" action="{{ route('notifications.read-all') }}">
@csrf
@@ -16,12 +16,12 @@
<div class="py-8 max-w-3xl mx-auto px-4 sm:px-6 lg:px-8">
@if(session('success'))
<div class="mb-4 p-4 bg-green-50 border border-green-200 text-green-800 rounded-md">
<div class="mb-4 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
<div class="bg-white shadow rounded-lg divide-y divide-gray-100">
<div class="bg-white dark:bg-gray-800 shadow rounded-lg divide-y divide-gray-100 dark:divide-gray-700">
@forelse($notifications as $notification)
@php
$data = $notification->data;
@@ -32,13 +32,13 @@
{{-- Icône --}}
<div class="shrink-0 mt-0.5">
@if($isRejet)
<span class="inline-flex items-center justify-center w-8 h-8 rounded-full bg-red-100 text-red-600">
<span class="inline-flex items-center justify-center w-8 h-8 rounded-full bg-red-100 dark:bg-red-900/50 text-red-600">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
</span>
@else
<span class="inline-flex items-center justify-center w-8 h-8 rounded-full bg-yellow-100 text-yellow-600">
<span class="inline-flex items-center justify-center w-8 h-8 rounded-full bg-yellow-100 dark:bg-yellow-900/50 text-yellow-600">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
@@ -48,7 +48,7 @@
{{-- Contenu --}}
<div class="flex-1 min-w-0">
<p class="text-sm text-gray-900">
<p class="text-sm text-gray-900 dark:text-white">
@if($isRejet)
<strong>{{ $data['rejete_par'] }}</strong> a renvoyé la source
<strong>{{ $data['source_nom'] }}</strong> en cours de saisie.
@@ -57,10 +57,10 @@
<strong>{{ $data['source_nom'] }}</strong> pour validation.
@endif
</p>
<div class="mt-1 flex items-center gap-3 text-xs text-gray-400">
<div class="mt-1 flex items-center gap-3 text-xs text-gray-400 dark:text-gray-500">
<span>{{ $notification->created_at->diffForHumans() }}</span>
@if(!$isRead)
<span class="inline-block w-2 h-2 rounded-full bg-indigo-500"></span>
<span class="inline-block w-2 h-2 rounded-full bg-indigo-50 dark:bg-indigo-900/300"></span>
@endif
</div>
</div>
@@ -74,14 +74,14 @@
@if(!$isRead)
<form method="POST" action="{{ route('notifications.read', $notification->id) }}">
@csrf
<button type="submit" class="text-xs text-gray-400 hover:text-gray-600" title="Marquer comme lu"></button>
<button type="submit" class="text-xs text-gray-400 dark:text-gray-500 hover:text-gray-600" title="Marquer comme lu"></button>
</form>
@endif
</div>
</div>
@empty
<div class="px-6 py-16 text-center text-gray-400">
<svg class="mx-auto w-10 h-10 mb-3 text-gray-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<div class="px-6 py-16 text-center text-gray-400 dark:text-gray-500">
<svg class="mx-auto w-10 h-10 mb-3 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="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"/>
</svg>
<p>Aucune notification</p>
+4 -4
View File
@@ -1,25 +1,25 @@
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
<h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">
Mon profil
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8 space-y-6">
<div class="p-4 sm:p-8 bg-white shadow sm:rounded-lg">
<div class="p-4 sm:p-8 bg-white dark:bg-gray-800 shadow sm:rounded-lg">
<div class="max-w-xl">
@include('profile.partials.update-profile-information-form')
</div>
</div>
<div class="p-4 sm:p-8 bg-white shadow sm:rounded-lg">
<div class="p-4 sm:p-8 bg-white dark:bg-gray-800 shadow sm:rounded-lg">
<div class="max-w-xl">
@include('profile.partials.update-password-form')
</div>
</div>
<div class="p-4 sm:p-8 bg-white shadow sm:rounded-lg">
<div class="p-4 sm:p-8 bg-white dark:bg-gray-800 shadow sm:rounded-lg">
<div class="max-w-xl">
@include('profile.partials.delete-user-form')
</div>
@@ -1,7 +1,7 @@
<section class="space-y-6">
<header>
<h2 class="text-lg font-medium text-gray-900">Supprimer le compte</h2>
<p class="mt-1 text-sm text-gray-600">
<h2 class="text-lg font-medium text-gray-900 dark:text-white">Supprimer le compte</h2>
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
Une fois votre compte supprimé, toutes ses données seront définitivement effacées.
Téléchargez toute information que vous souhaitez conserver avant de procéder.
</p>
@@ -17,11 +17,11 @@
@csrf
@method('delete')
<h2 class="text-lg font-medium text-gray-900">
<h2 class="text-lg font-medium text-gray-900 dark:text-white">
Êtes-vous sûr de vouloir supprimer votre compte ?
</h2>
<p class="mt-1 text-sm text-gray-600">
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
Cette action est irréversible. Toutes vos données seront définitivement supprimées.
Saisissez votre mot de passe pour confirmer.
</p>
@@ -1,7 +1,7 @@
<section>
<header>
<h2 class="text-lg font-medium text-gray-900">Changer le mot de passe</h2>
<p class="mt-1 text-sm text-gray-600">
<h2 class="text-lg font-medium text-gray-900 dark:text-white">Changer le mot de passe</h2>
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
Utilisez un mot de passe long et aléatoire pour sécuriser votre compte.
</p>
</header>
@@ -37,7 +37,7 @@
@if (session('status') === 'password-updated')
<p x-data="{ show: true }" x-show="show" x-transition
x-init="setTimeout(() => show = false, 2000)"
class="text-sm text-gray-600">
class="text-sm text-gray-600 dark:text-gray-400">
Enregistré.
</p>
@endif
@@ -1,7 +1,7 @@
<section>
<header>
<h2 class="text-lg font-medium text-gray-900">Informations du profil</h2>
<p class="mt-1 text-sm text-gray-600">
<h2 class="text-lg font-medium text-gray-900 dark:text-white">Informations du profil</h2>
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
Mettez à jour votre nom et votre adresse e-mail.
</p>
</header>
@@ -29,10 +29,10 @@
@if ($user instanceof \Illuminate\Contracts\Auth\MustVerifyEmail && ! $user->hasVerifiedEmail())
<div>
<p class="text-sm mt-2 text-gray-800">
<p class="text-sm mt-2 text-gray-800 dark:text-gray-200">
Votre adresse e-mail n'est pas vérifiée.
<button form="send-verification"
class="underline text-sm text-gray-600 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
class="underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
Cliquez ici pour renvoyer l'e-mail de vérification.
</button>
</p>
@@ -51,7 +51,7 @@
@if (session('status') === 'profile-updated')
<p x-data="{ show: true }" x-show="show" x-transition
x-init="setTimeout(() => show = false, 2000)"
class="text-sm text-gray-600">
class="text-sm text-gray-600 dark:text-gray-400">
Enregistré.
</p>
@endif
+34 -34
View File
@@ -1,19 +1,19 @@
<x-app-layout>
<x-slot name="header">
<h2 class="text-xl font-semibold text-gray-800">Recherche dans les relevés</h2>
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">Recherche dans les relevés</h2>
</x-slot>
<div class="py-8 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 space-y-6">
{{-- Formulaire de recherche --}}
<div class="bg-white shadow rounded-lg p-6">
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6">
<form method="GET" action="{{ route('recherche') }}" class="space-y-4">
{{-- Barre principale --}}
<div class="flex gap-3">
<div class="flex-1 relative">
<div class="absolute inset-y-0 left-3 flex items-center pointer-events-none">
<svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<svg class="w-5 h-5 text-gray-400 dark:text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M21 21l-4.35-4.35M17 11A6 6 0 1 1 5 11a6 6 0 0 1 12 0z"/>
</svg>
@@ -21,7 +21,7 @@
<input type="text" name="q" value="{{ request('q') }}"
placeholder="Nom, prénom, lieu, note…"
autofocus
class="block w-full pl-10 pr-4 py-2.5 border border-gray-300 rounded-md shadow-sm
class="block w-full pl-10 pr-4 py-2.5 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm
text-sm focus:border-indigo-500 focus:ring-indigo-500">
</div>
<button type="submit"
@@ -30,7 +30,7 @@
</button>
@if(request()->anyFilled(['q', 'source_type_id', 'annee_debut', 'annee_fin']))
<a href="{{ route('recherche') }}"
class="px-4 py-2.5 border border-gray-300 text-gray-600 text-sm rounded-md hover:bg-gray-50">
class="px-4 py-2.5 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
</a>
@endif
@@ -45,7 +45,7 @@
class="text-sm text-indigo-600 hover:underline flex items-center gap-1">
<span x-text="open ? '▲ Masquer les filtres' : '▼ Filtres avancés'"></span>
@if($hasAdvanced)
<span class="ml-1 inline-flex items-center px-1.5 py-0.5 rounded-full text-xs bg-indigo-100 text-indigo-700">
<span class="ml-1 inline-flex items-center px-1.5 py-0.5 rounded-full text-xs bg-indigo-100 dark:bg-indigo-900/50 text-indigo-700">
actifs
</span>
@endif
@@ -54,9 +54,9 @@
<div x-show="open" x-cloak class="mt-4 space-y-4">
<div class="grid grid-cols-3 gap-4">
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">Type de source</label>
<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 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
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 les types </option>
@foreach($sourceTypes as $st)
<option value="{{ $st->id }}" {{ request('source_type_id') == $st->id ? 'selected' : '' }}>
@@ -66,16 +66,16 @@
</select>
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">Année de début</label>
<label class="block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1">Année de début</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">
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>
<label class="block text-xs font-medium text-gray-600 mb-1">Année de fin</label>
<label class="block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1">Année de fin</label>
<input type="number" name="annee_fin" value="{{ request('annee_fin') }}"
min="1000" max="2100" placeholder="ex : 1830"
class="block w-full rounded-md border-gray-300 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
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>
@@ -89,7 +89,7 @@
placeholder="— Tous les lieux —"
/>
@if($lieuSelectionne)
<p class="mt-1 text-xs text-gray-400">
<p class="mt-1 text-xs text-gray-400 dark:text-gray-500">
Inclut toutes les subdivisions de {{ $lieuSelectionne->nom_long ?? $lieuSelectionne->nom }}.
</p>
@endif
@@ -102,7 +102,7 @@
{{-- Résultats --}}
@if($resultats !== null)
<div>
<p class="text-sm text-gray-500 mb-3">
<p class="text-sm text-gray-500 dark:text-gray-400 mb-3">
@if($total === 0)
Aucun relevé trouvé.
@else
@@ -117,20 +117,20 @@
</p>
@if($resultats->isNotEmpty())
<div class="bg-white shadow rounded-lg overflow-hidden">
<div class="bg-white dark:bg-gray-800 shadow rounded-lg overflow-hidden">
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200 text-sm">
<thead class="bg-gray-50">
<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-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Nom</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Prénom</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Date</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Source</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Type</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Nom</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Prénom</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Date</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Source</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Type</th>
<th class="px-4 py-3"></th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
@foreach($resultats as $releve)
@php
$data = $releve->data;
@@ -139,32 +139,32 @@
? ($dateEvt['valeur'] ?? '—') . ($dateEvt['calendrier'] !== 'gregorien' ? ' (' . $dateEvt['calendrier'] . ')' : '')
: ($releve->date_evenement ?? '—');
@endphp
<tr class="hover:bg-gray-50">
<td class="px-4 py-3 font-medium text-gray-900">
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700">
<td class="px-4 py-3 font-medium text-gray-900 dark:text-white">
@if(request('q') && $releve->nom)
{!! preg_replace('/(' . preg_quote(request('q'), '/') . ')/i', '<mark class="bg-yellow-100 rounded px-0.5">$1</mark>', e($releve->nom)) !!}
{!! preg_replace('/(' . preg_quote(request('q'), '/') . ')/i', '<mark class="bg-yellow-100 dark:bg-yellow-900/50 rounded px-0.5">$1</mark>', e($releve->nom)) !!}
@else
{{ $releve->nom ?? '—' }}
@endif
</td>
<td class="px-4 py-3 text-gray-700">
<td class="px-4 py-3 text-gray-700 dark:text-gray-300">
@if(request('q') && $releve->prenom)
{!! preg_replace('/(' . preg_quote(request('q'), '/') . ')/i', '<mark class="bg-yellow-100 rounded px-0.5">$1</mark>', e($releve->prenom)) !!}
{!! preg_replace('/(' . preg_quote(request('q'), '/') . ')/i', '<mark class="bg-yellow-100 dark:bg-yellow-900/50 rounded px-0.5">$1</mark>', e($releve->prenom)) !!}
@else
{{ $releve->prenom ?? '—' }}
@endif
</td>
<td class="px-4 py-3 text-gray-600 whitespace-nowrap">
<td class="px-4 py-3 text-gray-600 dark:text-gray-400 whitespace-nowrap">
{{ $dateAffichee }}
</td>
<td class="px-4 py-3 text-gray-600">
<td class="px-4 py-3 text-gray-600 dark:text-gray-400">
<a href="{{ route('sources.show', $releve->source) }}"
class="hover:text-indigo-600 hover:underline">
{{ $releve->source->nom }}
</a>
</td>
<td class="px-4 py-3">
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-100 text-gray-600">
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-400">
{{ $releve->source->sourceType->nom }}
</span>
</td>
@@ -181,7 +181,7 @@
</div>
@if($resultats->hasPages())
<div class="px-6 py-4 border-t border-gray-200">
<div class="px-6 py-4 border-t border-gray-200 dark:border-gray-700">
{{ $resultats->links() }}
</div>
@endif
@@ -190,8 +190,8 @@
</div>
@else
{{-- État initial --}}
<div class="text-center py-16 text-gray-400">
<svg class="mx-auto w-12 h-12 mb-4 text-gray-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<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="M21 21l-4.35-4.35M17 11A6 6 0 1 1 5 11a6 6 0 0 1 12 0z"/>
</svg>
+10 -10
View File
@@ -10,7 +10,7 @@
@endphp
<div class="space-y-1">
<label for="{{ $inputId }}" class="block text-sm font-medium text-gray-700">
<label for="{{ $inputId }}" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
{{ $field->label }}
@if($field->required) <span class="text-red-500">*</span> @endif
</label>
@@ -21,20 +21,20 @@
<input type="text" id="{{ $inputId }}" name="{{ $name }}"
value="{{ $oldValue }}"
{{ $field->required ? 'required' : '' }}
class="block w-full rounded-md border-gray-300 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500 @error("data.{$field->name}") border-red-500 @enderror">
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 @error("data.{$field->name}") border-red-500 @enderror">
@break
@case(FieldType::Textarea)
<textarea id="{{ $inputId }}" name="{{ $name }}" rows="3"
{{ $field->required ? 'required' : '' }}
class="block w-full rounded-md border-gray-300 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500 @error("data.{$field->name}") border-red-500 @enderror">{{ $oldValue }}</textarea>
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 @error("data.{$field->name}") border-red-500 @enderror">{{ $oldValue }}</textarea>
@break
@case(FieldType::Number)
<input type="number" id="{{ $inputId }}" name="{{ $name }}"
value="{{ $oldValue }}" step="any"
{{ $field->required ? 'required' : '' }}
class="block w-full rounded-md border-gray-300 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500 @error("data.{$field->name}") border-red-500 @enderror">
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 @error("data.{$field->name}") border-red-500 @enderror">
@break
@case(FieldType::Boolean)
@@ -43,15 +43,15 @@
<input type="hidden" name="{{ $name }}" value="0">
<input type="checkbox" id="{{ $inputId }}" name="{{ $name }}" value="1"
{{ $checked ? 'checked' : '' }}
class="rounded border-gray-300 text-indigo-600 focus:ring-indigo-500">
<span class="text-sm text-gray-600">{{ $field->label }}</span>
class="rounded border-gray-300 dark:border-gray-600 text-indigo-600 focus:ring-indigo-500">
<span class="text-sm text-gray-600 dark:text-gray-400">{{ $field->label }}</span>
</div>
@break
@case(FieldType::Select)
<select id="{{ $inputId }}" name="{{ $name }}"
{{ $field->required ? 'required' : '' }}
class="block w-full rounded-md border-gray-300 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500 @error("data.{$field->name}") border-red-500 @enderror">
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 @error("data.{$field->name}") border-red-500 @enderror">
@if(!$field->required) <option value=""> Choisir </option> @endif
@foreach($field->options ?? [] as $opt)
<option value="{{ $opt }}" {{ $oldValue === $opt ? 'selected' : '' }}>{{ $opt }}</option>
@@ -67,7 +67,7 @@
<div x-data="{ cal: '{{ $dateCal }}' }" class="flex gap-2">
{{-- Sélecteur de calendrier --}}
<select name="{{ $name }}[calendrier]" x-model="cal"
class="w-40 rounded-md border-gray-300 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
class="w-40 rounded-md border-gray-300 dark:border-gray-600 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
<option value="gregorien">Grégorien</option>
<option value="julien">Julien</option>
<option value="republicain">Républicain</option>
@@ -78,14 +78,14 @@
type="date" name="{{ $name }}[valeur]"
value="{{ $dateCal !== 'republicain' ? $dateVal : '' }}"
{{ $field->required ? 'required' : '' }}
class="flex-1 rounded-md border-gray-300 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
class="flex-1 rounded-md border-gray-300 dark:border-gray-600 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
{{-- Date républicaine : saisie texte libre (ex: "15 Vendémiaire An III") --}}
<input x-show="cal === 'republicain'" x-cloak
type="text" name="{{ $name }}[valeur]"
value="{{ $dateCal === 'republicain' ? $dateVal : '' }}"
placeholder="ex : 15 Vendémiaire An III"
class="flex-1 rounded-md border-gray-300 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
class="flex-1 rounded-md border-gray-300 dark:border-gray-600 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
</div>
@error("data.{$field->name}.valeur")
<p class="text-sm text-red-600">{{ $message }}</p>
+1 -1
View File
@@ -7,7 +7,7 @@
@endphp
@include('releves._field', ['field' => $field, 'value' => $rawValue])
@empty
<p class="text-sm text-gray-400 italic">
<p class="text-sm text-gray-400 dark:text-gray-500 italic">
Ce type de source n'a aucun champ défini.
<a href="{{ route('admin.source-types.show', $source->sourceType) }}" class="text-indigo-600 hover:underline">Configurer les champs </a>
</p>
+5 -5
View File
@@ -1,8 +1,8 @@
<x-app-layout>
<x-slot name="header">
<div>
<h2 class="text-xl font-semibold text-gray-800">Nouveau relevé</h2>
<p class="text-sm text-gray-500 mt-0.5">
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">Nouveau relevé</h2>
<p class="text-sm text-gray-500 dark:text-gray-400 mt-0.5">
Source : <a href="{{ route('sources.show', $source) }}" class="text-indigo-600 hover:underline">{{ $source->nom }}</a>
· Type : {{ $source->sourceType->nom }}
</p>
@@ -10,17 +10,17 @@
</x-slot>
<div class="py-8 max-w-3xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="bg-white shadow rounded-lg p-6">
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6">
<form method="POST" action="{{ route('sources.releves.store', $source) }}">
@csrf
@include('releves._form', ['releve' => null])
<div class="mt-8 pt-6 border-t border-gray-200 flex items-center gap-4">
<div class="mt-8 pt-6 border-t border-gray-200 dark:border-gray-700 flex items-center gap-4">
<button type="submit"
class="px-5 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700">
Enregistrer le relevé
</button>
<a href="{{ route('sources.releves.index', $source) }}"
class="text-sm text-gray-500 hover:text-gray-700">Annuler</a>
class="text-sm text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300">Annuler</a>
</div>
</form>
</div>
+5 -5
View File
@@ -1,25 +1,25 @@
<x-app-layout>
<x-slot name="header">
<div>
<h2 class="text-xl font-semibold text-gray-800">Modifier le relevé #{{ $releve->id }}</h2>
<p class="text-sm text-gray-500 mt-0.5">
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">Modifier le relevé #{{ $releve->id }}</h2>
<p class="text-sm text-gray-500 dark:text-gray-400 mt-0.5">
Source : <a href="{{ route('sources.show', $source) }}" class="text-indigo-600 hover:underline">{{ $source->nom }}</a>
</p>
</div>
</x-slot>
<div class="py-8 max-w-3xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="bg-white shadow rounded-lg p-6">
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6">
<form method="POST" action="{{ route('releves.update', $releve) }}">
@csrf @method('PUT')
@include('releves._form', ['releve' => $releve])
<div class="mt-8 pt-6 border-t border-gray-200 flex items-center gap-4">
<div class="mt-8 pt-6 border-t border-gray-200 dark:border-gray-700 flex items-center gap-4">
<button type="submit"
class="px-5 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700">
Enregistrer
</button>
<a href="{{ route('releves.show', $releve) }}"
class="text-sm text-gray-500 hover:text-gray-700">Annuler</a>
class="text-sm text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300">Annuler</a>
</div>
</form>
</div>
+21 -21
View File
@@ -2,8 +2,8 @@
<x-slot name="header">
<div class="flex items-center justify-between">
<div>
<h2 class="text-xl font-semibold text-gray-800">Relevés {{ $source->nom }}</h2>
<p class="text-sm text-gray-500 mt-0.5">
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">Relevés {{ $source->nom }}</h2>
<p class="text-sm text-gray-500 dark:text-gray-400 mt-0.5">
Type : {{ $source->sourceType->nom }}
@if($source->cote) · Cote : {{ $source->cote }} @endif
</p>
@@ -11,7 +11,7 @@
<div class="flex items-center gap-3">
<a href="{{ route('sources.show', $source) }}" class="text-sm text-indigo-600 hover:underline"> Source</a>
<a href="{{ route('export.source', $source) }}"
class="px-4 py-2 border border-gray-300 text-gray-700 text-sm rounded-md hover:bg-gray-50"
class="px-4 py-2 border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 text-sm rounded-md hover:bg-gray-50 dark:hover:bg-gray-700"
title="Télécharger au format GEDCOM 5.5.1">
GEDCOM
</a>
@@ -27,7 +27,7 @@
<div class="py-8 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
@if(session('success'))
<div class="mb-4 p-4 bg-green-50 border border-green-200 text-green-800 rounded-md">{{ session('success') }}</div>
<div class="mb-4 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
@php
@@ -35,31 +35,31 @@
$colonnes = $source->sourceType->fields->take(5);
@endphp
<div class="bg-white shadow rounded-lg overflow-hidden">
<div class="bg-white dark:bg-gray-800 shadow rounded-lg overflow-hidden">
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200 text-sm">
<thead class="bg-gray-50">
<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>
@foreach($colonnes as $col)
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase whitespace-nowrap">
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase whitespace-nowrap">
{{ $col->label }}
</th>
@endforeach
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Saisi par</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Date</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Saisi par</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Date</th>
<th class="px-4 py-3"></th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
@forelse($releves as $releve)
<tr class="hover:bg-gray-50">
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700">
@foreach($colonnes as $col)
<td class="px-4 py-3 text-gray-700">
<td class="px-4 py-3 text-gray-700 dark:text-gray-300">
@php $val = $releve->data[$col->name] ?? null; @endphp
@if(is_array($val))
{{ $val['valeur'] ?? '' }}
@if(!empty($val['calendrier']) && $val['calendrier'] !== 'gregorien')
<span class="text-xs text-gray-400">({{ $val['calendrier'] }})</span>
<span class="text-xs text-gray-400 dark:text-gray-500">({{ $val['calendrier'] }})</span>
@endif
@elseif(is_bool($val))
{{ $val ? 'Oui' : 'Non' }}
@@ -68,12 +68,12 @@
@endif
</td>
@endforeach
<td class="px-4 py-3 text-gray-500">{{ $releve->createur?->name ?? '—' }}</td>
<td class="px-4 py-3 text-gray-500 whitespace-nowrap">{{ $releve->created_at->format('d/m/Y') }}</td>
<td class="px-4 py-3 text-gray-500 dark:text-gray-400">{{ $releve->createur?->name ?? '—' }}</td>
<td class="px-4 py-3 text-gray-500 dark:text-gray-400 whitespace-nowrap">{{ $releve->created_at->format('d/m/Y') }}</td>
<td class="px-4 py-3 text-right whitespace-nowrap space-x-3">
<a href="{{ route('releves.show', $releve) }}" class="text-indigo-600 hover:underline">Voir</a>
@can('update', $releve)
<a href="{{ route('releves.edit', $releve) }}" class="text-gray-600 hover:text-indigo-600">Modifier</a>
<a href="{{ route('releves.edit', $releve) }}" class="text-gray-600 dark:text-gray-400 hover:text-indigo-600">Modifier</a>
@endcan
@can('delete', $releve)
<form method="POST" action="{{ route('releves.destroy', $releve) }}" class="inline"
@@ -87,7 +87,7 @@
@empty
<tr>
<td colspan="{{ $colonnes->count() + 3 }}"
class="px-6 py-10 text-center text-gray-400">
class="px-6 py-10 text-center text-gray-400 dark:text-gray-500">
Aucun relevé pour cette source.
</td>
</tr>
@@ -98,10 +98,10 @@
{{-- Navigation curseur (keyset pagination) --}}
@if($releves->hasPages())
<div class="px-6 py-4 border-t border-gray-200 flex items-center justify-between text-sm">
<div class="px-6 py-4 border-t border-gray-200 dark:border-gray-700 flex items-center justify-between text-sm">
<div>
@if($releves->onFirstPage())
<span class="text-gray-400"> Précédent</span>
<span class="text-gray-400 dark:text-gray-500"> Précédent</span>
@else
<a href="{{ $releves->previousPageUrl() }}" class="text-indigo-600 hover:underline"> Précédent</a>
@endif
@@ -110,7 +110,7 @@
@if($releves->hasMorePages())
<a href="{{ $releves->nextPageUrl() }}" class="text-indigo-600 hover:underline">Suivant </a>
@else
<span class="text-gray-400">Suivant </span>
<span class="text-gray-400 dark:text-gray-500">Suivant </span>
@endif
</div>
</div>
+10 -10
View File
@@ -2,8 +2,8 @@
<x-slot name="header">
<div class="flex items-center justify-between">
<div>
<h2 class="text-xl font-semibold text-gray-800">Relevé #{{ $releve->id }}</h2>
<p class="text-sm text-gray-500 mt-0.5">
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">Relevé #{{ $releve->id }}</h2>
<p class="text-sm text-gray-500 dark:text-gray-400 mt-0.5">
Source : <a href="{{ route('sources.show', $source) }}" class="text-indigo-600 hover:underline">{{ $source->nom }}</a>
</p>
</div>
@@ -30,25 +30,25 @@
<div class="py-8 max-w-3xl 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>
<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
{{-- Champs du relevé --}}
<div class="bg-white shadow rounded-lg divide-y divide-gray-100">
<div class="bg-white dark:bg-gray-800 shadow rounded-lg divide-y divide-gray-100 dark:divide-gray-700">
@foreach($source->sourceType->fields as $field)
@php $val = $releve->data[$field->name] ?? null; @endphp
<div class="px-6 py-4 grid grid-cols-3 gap-4 text-sm">
<dt class="font-medium text-gray-500">{{ $field->label }}</dt>
<dd class="col-span-2 text-gray-900">
<dt class="font-medium text-gray-500 dark:text-gray-400">{{ $field->label }}</dt>
<dd class="col-span-2 text-gray-900 dark:text-white">
@if($val === null || $val === '')
<span class="text-gray-400"></span>
<span class="text-gray-400 dark:text-gray-500"></span>
@elseif(is_array($val))
{{ $val['valeur'] ?? '—' }}
@if(!empty($val['calendrier']) && $val['calendrier'] !== 'gregorien')
<span class="ml-1 text-xs text-gray-400 capitalize">({{ $val['calendrier'] }})</span>
<span class="ml-1 text-xs text-gray-400 dark:text-gray-500 capitalize">({{ $val['calendrier'] }})</span>
@endif
@elseif(is_bool($val))
<span class="{{ $val ? 'text-green-700' : 'text-gray-400' }}">
<span class="{{ $val ? 'text-green-700' : 'text-gray-400 dark:text-gray-500' }}">
{{ $val ? 'Oui' : 'Non' }}
</span>
@else
@@ -60,7 +60,7 @@
</div>
{{-- Méta-données de saisie --}}
<div class="bg-gray-50 rounded-lg px-6 py-4 text-xs text-gray-500 space-y-1">
<div class="bg-gray-50 dark:bg-gray-700 rounded-lg px-6 py-4 text-xs text-gray-500 dark:text-gray-400 space-y-1">
<p>Saisi par <strong>{{ $releve->createur?->name ?? '?' }}</strong> le {{ $releve->created_at->format('d/m/Y à H:i') }}</p>
@if($releve->updated_at != $releve->created_at)
<p>Modifié par <strong>{{ $releve->modificateur?->name ?? '?' }}</strong> le {{ $releve->updated_at->format('d/m/Y à H:i') }}</p>
+18 -18
View File
@@ -1,23 +1,23 @@
<div class="space-y-5">
<div>
<label for="nom" class="block text-sm font-medium text-gray-700">Nom <span class="text-red-500">*</span></label>
<label for="nom" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Nom <span class="text-red-500">*</span></label>
<input type="text" id="nom" name="nom" value="{{ old('nom', $source?->nom) }}" required
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 @error('nom') border-red-500 @enderror">
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 @error('nom') border-red-500 @enderror">
@error('nom') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
<div>
<label for="description" class="block text-sm font-medium text-gray-700">Description</label>
<label for="description" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Description</label>
<textarea id="description" name="description" rows="3"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">{{ old('description', $source?->description) }}</textarea>
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">{{ old('description', $source?->description) }}</textarea>
</div>
{{-- Section propriétaire --}}
@if($sections->isNotEmpty())
<div>
<label for="section_id" class="block text-sm font-medium text-gray-700">Section</label>
<label for="section_id" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Section</label>
<select id="section_id" name="section_id"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 text-sm">
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 text-sm">
<option value=""> Aucune (globale) </option>
@foreach($sections as $sec)
<option value="{{ $sec->id }}" {{ old('section_id', $source?->section_id) == $sec->id ? 'selected' : '' }}>
@@ -31,9 +31,9 @@
<div class="grid grid-cols-2 gap-4">
<div>
<label for="source_type_id" class="block text-sm font-medium text-gray-700">Type de source <span class="text-red-500">*</span></label>
<label for="source_type_id" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Type de source <span class="text-red-500">*</span></label>
<select id="source_type_id" name="source_type_id" required
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 @error('source_type_id') border-red-500 @enderror">
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 @error('source_type_id') border-red-500 @enderror">
<option value=""> Choisir </option>
@foreach($sourceTypes as $st)
<option value="{{ $st->id }}" {{ old('source_type_id', $source?->source_type_id) == $st->id ? 'selected' : '' }}>
@@ -45,9 +45,9 @@
</div>
<div>
<label for="depot_id" class="block text-sm font-medium text-gray-700">Dépôt d'archives</label>
<label for="depot_id" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Dépôt d'archives</label>
<select id="depot_id" name="depot_id"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
<option value=""> Aucun </option>
@foreach($depots as $depot)
<option value="{{ $depot->id }}" {{ old('depot_id', $source?->depot_id) == $depot->id ? 'selected' : '' }}>
@@ -83,33 +83,33 @@
{{-- Période couverte --}}
<div class="grid grid-cols-2 gap-4">
<div>
<label for="annee_debut" class="block text-sm font-medium text-gray-700">Année de début</label>
<label for="annee_debut" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Année de début</label>
<input type="number" id="annee_debut" name="annee_debut"
value="{{ old('annee_debut', $source?->annee_debut) }}"
min="1000" max="2100" placeholder="ex : 1820"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 @error('annee_debut') border-red-500 @enderror">
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 @error('annee_debut') border-red-500 @enderror">
@error('annee_debut') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
<div>
<label for="annee_fin" class="block text-sm font-medium text-gray-700">Année de fin</label>
<label for="annee_fin" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Année de fin</label>
<input type="number" id="annee_fin" name="annee_fin"
value="{{ old('annee_fin', $source?->annee_fin) }}"
min="1000" max="2100" placeholder="ex : 1870"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 @error('annee_fin') border-red-500 @enderror">
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 @error('annee_fin') border-red-500 @enderror">
@error('annee_fin') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
</div>
<div class="grid grid-cols-2 gap-4">
<div>
<label for="cote" class="block text-sm font-medium text-gray-700">Cote</label>
<label for="cote" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Cote</label>
<input type="text" id="cote" name="cote" value="{{ old('cote', $source?->cote) }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
</div>
<div>
<label for="auteur" class="block text-sm font-medium text-gray-700">Auteur</label>
<label for="auteur" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Auteur</label>
<input type="text" id="auteur" name="auteur" value="{{ old('auteur', $source?->auteur) }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
</div>
</div>
</div>
+3 -3
View File
@@ -1,13 +1,13 @@
<x-app-layout>
<x-slot name="header"><h2 class="text-xl font-semibold text-gray-800">Nouvelle source</h2></x-slot>
<x-slot name="header"><h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">Nouvelle source</h2></x-slot>
<div class="py-8 max-w-2xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="bg-white shadow rounded-lg p-6">
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6">
<form method="POST" action="{{ route('sources.store') }}">
@csrf
@include('sources._form', ['source' => null])
<div class="mt-6 flex gap-4">
<button type="submit" class="px-5 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700">Créer</button>
<a href="{{ route('sources.index') }}" class="text-sm text-gray-500 self-center hover:text-gray-700">Annuler</a>
<a href="{{ route('sources.index') }}" class="text-sm text-gray-500 dark:text-gray-400 self-center hover:text-gray-700 dark:hover:text-gray-300">Annuler</a>
</div>
</form>
</div>
+3 -3
View File
@@ -1,13 +1,13 @@
<x-app-layout>
<x-slot name="header"><h2 class="text-xl font-semibold text-gray-800">Modifier : {{ $source->nom }}</h2></x-slot>
<x-slot name="header"><h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">Modifier : {{ $source->nom }}</h2></x-slot>
<div class="py-8 max-w-2xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="bg-white shadow rounded-lg p-6">
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6">
<form method="POST" action="{{ route('sources.update', $source) }}">
@csrf @method('PUT')
@include('sources._form', ['source' => $source])
<div class="mt-6 flex gap-4">
<button type="submit" class="px-5 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700">Enregistrer</button>
<a href="{{ route('sources.show', $source) }}" class="text-sm text-gray-500 self-center hover:text-gray-700">Annuler</a>
<a href="{{ route('sources.show', $source) }}" class="text-sm text-gray-500 dark:text-gray-400 self-center hover:text-gray-700 dark:hover:text-gray-300">Annuler</a>
</div>
</form>
</div>
+38 -38
View File
@@ -1,7 +1,7 @@
<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>
<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>
@@ -11,22 +11,22 @@
<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>
<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 shadow rounded-lg p-5">
<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 mb-1">Statut</label>
<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 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
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' : '' }}>
@@ -38,9 +38,9 @@
{{-- Type de source --}}
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">Type de source</label>
<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 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
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' : '' }}>
@@ -52,18 +52,18 @@
{{-- Année de début --}}
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">Période de</label>
<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 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
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 mb-1">Période à</label>
<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 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
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>
@@ -85,10 +85,10 @@
</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">
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 text-indigo-700">
<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
@@ -97,30 +97,30 @@
</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">
<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 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 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">
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
@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',
'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 text-gray-600';
$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,
@@ -128,32 +128,32 @@
default => '—',
};
@endphp
<tr class="hover:bg-gray-50">
<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">{{ $source->cote }}</span> @endif
@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">{{ $source->sourceType->nom }}</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 max-w-[180px] truncate" title="{{ $source->lieu?->nom_long ?? $source->lieu?->nom }}">
<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 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-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 hover:text-indigo-600">Modifier</a>
<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">
<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>
+32 -33
View File
@@ -2,15 +2,15 @@
<x-slot name="header">
<div class="flex items-center justify-between">
<div>
<h2 class="text-xl font-semibold text-gray-800">{{ $source->nom }}</h2>
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">{{ $source->nom }}</h2>
@if($source->cote)
<p class="text-sm text-gray-500 mt-0.5">Cote : {{ $source->cote }}</p>
<p class="text-sm text-gray-500 dark:text-gray-400 mt-0.5">Cote : {{ $source->cote }}</p>
@endif
</div>
<div class="flex items-center gap-3">
@can('update', $source)
<a href="{{ route('sources.edit', $source) }}"
class="px-4 py-2 bg-white border border-gray-300 text-gray-700 text-sm rounded-md hover:bg-gray-50">Modifier</a>
class="px-4 py-2 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 text-sm rounded-md hover:bg-gray-50 dark:hover:bg-gray-700">Modifier</a>
@endcan
@can('delete', $source)
<form method="POST" action="{{ route('sources.destroy', $source) }}"
@@ -26,7 +26,7 @@
<div class="py-8 max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 space-y-6">
@foreach(['success','error'] as $flash)
@if(session($flash))
<div class="p-4 rounded-md {{ $flash === 'success' ? 'bg-green-50 border border-green-200 text-green-800' : 'bg-red-50 border border-red-200 text-red-800' }}">
<div class="p-4 rounded-md {{ $flash === 'success' ? 'bg-green-50 dark:bg-green-900/30 border border-green-200 dark:border-green-700 text-green-800 dark:text-green-200' : 'bg-red-50 dark:bg-red-900/30 border border-red-200 dark:border-red-700 text-red-800 dark:text-red-200' }}">
{{ session($flash) }}
</div>
@endif
@@ -34,33 +34,33 @@
<div class="grid grid-cols-3 gap-6">
{{-- Fiche source --}}
<div class="col-span-2 bg-white shadow rounded-lg divide-y divide-gray-100 text-sm">
<div class="col-span-2 bg-white dark:bg-gray-800 shadow rounded-lg divide-y divide-gray-100 dark:divide-gray-700 text-sm">
@foreach([
['Type', $source->sourceType->nom],
['Dépôt', $source->depot?->nom ?? '—'],
['Auteur', $source->auteur ?? '—'],
] as [$label, $val])
<div class="px-6 py-4 grid grid-cols-3 gap-4">
<dt class="font-medium text-gray-500">{{ $label }}</dt>
<dd class="col-span-2 text-gray-900">{{ $val }}</dd>
<dt class="font-medium text-gray-500 dark:text-gray-400">{{ $label }}</dt>
<dd class="col-span-2 text-gray-900 dark:text-white">{{ $val }}</dd>
</div>
@endforeach
@if($source->description)
<div class="px-6 py-4 grid grid-cols-3 gap-4">
<dt class="font-medium text-gray-500">Description</dt>
<dd class="col-span-2 text-gray-900 whitespace-pre-line">{{ $source->description }}</dd>
<dt class="font-medium text-gray-500 dark:text-gray-400">Description</dt>
<dd class="col-span-2 text-gray-900 dark:text-white whitespace-pre-line">{{ $source->description }}</dd>
</div>
@endif
</div>
{{-- Statut + transitions --}}
<div class="bg-white shadow rounded-lg p-6 space-y-4">
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6 space-y-4">
@php
$statusColors = ['a_faire'=>'gray','en_cours'=>'blue','a_valider'=>'yellow','termine'=>'green'];
$color = $statusColors[$source->status->value] ?? 'gray';
@endphp
<div>
<p class="text-xs font-medium text-gray-500 uppercase mb-2">Statut</p>
<p class="text-xs font-medium text-gray-500 dark:text-gray-400 uppercase mb-2">Statut</p>
<span class="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-{{ $color }}-100 text-{{ $color }}-700">
{{ $source->status->label() }}
</span>
@@ -70,14 +70,14 @@
@php $transitions = $source->status->transitions(); @endphp
@if(count($transitions))
<div class="space-y-2">
<p class="text-xs font-medium text-gray-500 uppercase">Changer le statut</p>
<p class="text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Changer le statut</p>
@foreach($transitions as $next)
@if($source->canTransitionTo($next, auth()->user()))
<form method="POST" action="{{ route('sources.transition', $source) }}">
@csrf
<input type="hidden" name="status" value="{{ $next->value }}">
<button type="submit"
class="w-full text-left px-3 py-2 text-sm border border-gray-200 rounded-md hover:bg-gray-50 hover:border-indigo-300 transition-colors">
class="w-full text-left px-3 py-2 text-sm border border-gray-200 dark:border-gray-700 rounded-md hover:bg-gray-50 dark:hover:bg-gray-700 hover:border-indigo-300 transition-colors">
{{ $next->label() }}
</button>
</form>
@@ -91,17 +91,17 @@
{{-- Membres assignés --}}
@can('assignMembre', $source)
<div class="bg-white shadow rounded-lg overflow-hidden">
<div class="px-6 py-4 border-b border-gray-200 font-medium text-gray-900">
<div class="bg-white dark:bg-gray-800 shadow rounded-lg overflow-hidden">
<div class="px-6 py-4 border-b border-gray-200 dark:border-gray-700 font-medium text-gray-900 dark:text-white">
Membres assignés ({{ $source->membres->count() }})
</div>
@if($source->membres->isNotEmpty())
<table class="min-w-full divide-y divide-gray-200 text-sm">
<tbody class="divide-y divide-gray-200">
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700 text-sm">
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
@foreach($source->membres as $membre)
<tr>
<td class="px-6 py-3">{{ $membre->name }}</td>
<td class="px-6 py-3 text-gray-500">{{ $membre->email }}</td>
<td class="px-6 py-3 text-gray-500 dark:text-gray-400">{{ $membre->email }}</td>
<td class="px-6 py-3 text-right">
<form method="POST" action="{{ route('sources.membres.remove', [$source, $membre]) }}"
x-data @submit.prevent="if(confirm('Retirer ce membre ?')) $el.submit()">
@@ -114,27 +114,26 @@
</tbody>
</table>
@endif
<div class="px-6 py-4 bg-gray-50 border-t border-gray-200">
<form method="POST" action="{{ route('sources.membres.add', $source) }}" class="flex gap-3 items-end">
<div class="px-6 py-4 bg-gray-50 dark:bg-gray-700 border-t border-gray-200 dark:border-gray-700">
<form method="POST" action="{{ route('sources.membres.add', $source) }}"
@submit.prevent="if ($el.querySelector('[name=user_id]').value) $el.submit()">
@csrf
<div class="flex-1">
<label class="block text-xs font-medium text-gray-600 mb-1">Ajouter un membre</label>
<select name="user_id" class="block w-full rounded-md border-gray-300 shadow-sm text-sm focus:border-indigo-500 focus:ring-indigo-500">
@foreach($availableUsers as $u)
<option value="{{ $u->id }}">{{ $u->name }} ({{ $u->email }})</option>
@endforeach
</select>
<div class="flex flex-col sm:flex-row gap-3 items-stretch sm:items-end">
<div class="flex-1">
<label class="block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1">Ajouter un membre</label>
<x-user-picker :users="$availableUsers" placeholder="Rechercher un membre à assigner…" required />
</div>
<button type="submit" class="px-4 py-2 bg-indigo-600 text-white text-sm rounded-md hover:bg-indigo-700 shrink-0">Assigner</button>
</div>
<button type="submit" class="px-4 py-2 bg-indigo-600 text-white text-sm rounded-md hover:bg-indigo-700">Assigner</button>
</form>
</div>
</div>
@endcan
{{-- Liste des relevés (aperçu) --}}
<div class="bg-white shadow rounded-lg overflow-hidden">
<div class="px-6 py-4 border-b border-gray-200 flex items-center justify-between">
<h3 class="font-medium text-gray-900">Relevés ({{ $source->releves->count() }})</h3>
<div class="bg-white dark:bg-gray-800 shadow rounded-lg overflow-hidden">
<div class="px-6 py-4 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between">
<h3 class="font-medium text-gray-900 dark:text-white">Relevés ({{ $source->releves->count() }})</h3>
@can('create', [App\Models\Releve::class, $source])
<a href="{{ route('sources.releves.create', $source) }}"
class="px-3 py-1.5 bg-indigo-600 text-white text-xs rounded-md hover:bg-indigo-700">
@@ -143,9 +142,9 @@
@endcan
</div>
@if($source->releves->isEmpty())
<p class="px-6 py-8 text-center text-gray-400 text-sm">Aucun relevé pour cette source.</p>
<p class="px-6 py-8 text-center text-gray-400 dark:text-gray-500 text-sm">Aucun relevé pour cette source.</p>
@else
<p class="px-6 py-4 text-sm text-gray-500">
<p class="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">
<a href="{{ route('sources.releves.index', $source) }}" class="text-indigo-600 hover:underline">
Voir les {{ $source->releves->count() }} relevé(s)
</a>
+5 -5
View File
@@ -14,7 +14,7 @@
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet"/>
@endif
</head>
<body class="font-sans antialiased bg-gray-50 min-h-screen flex flex-col items-center justify-center px-4">
<body class="font-sans antialiased bg-gray-50 dark:bg-gray-700 min-h-screen flex flex-col items-center justify-center px-4">
<div class="text-center max-w-md w-full">
@@ -23,10 +23,10 @@
<img src="{{ $siteLogoUrl }}" alt="{{ config('app.name') }}"
class="h-28 w-auto object-contain mx-auto mb-8">
@else
<h1 class="text-3xl font-bold text-gray-900 mb-4">{{ config('app.name') }}</h1>
<h1 class="text-3xl font-bold text-gray-900 dark:text-white mb-4">{{ config('app.name') }}</h1>
@endif
<p class="text-gray-500 text-sm mb-10">
<p class="text-gray-500 dark:text-gray-400 text-sm mb-10">
Application de relevés généalogiques
</p>
@@ -43,7 +43,7 @@
</a>
@if($registrationEnabled && Route::has('register'))
<a href="{{ route('register') }}"
class="px-8 py-3 border border-gray-300 text-gray-700 font-medium rounded-lg hover:bg-gray-100 transition-colors">
class="px-8 py-3 border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 font-medium rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors">
Créer un compte
</a>
@endif
@@ -51,7 +51,7 @@
@endauth
</div>
<footer class="absolute bottom-6 text-xs text-gray-300">
<footer class="absolute bottom-6 text-xs text-gray-300 dark:text-gray-600">
{{ config('app.name') }}
</footer>