Étapes 6-9 + types de lieux + picker + filtres

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

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-04 17:17:53 +02:00
parent 7609d35287
commit d064f8d28e
54 changed files with 2861 additions and 116 deletions
+100
View File
@@ -0,0 +1,100 @@
{{--
Rendu d'un champ dynamique selon son FieldType.
Variables attendues : $field (SourceTypeField), $value (valeur courante ou null)
--}}
@php
use App\Enums\FieldType;
$name = "data[{$field->name}]";
$inputId = "field_{$field->name}";
$oldValue = old("data.{$field->name}", $value);
@endphp
<div class="space-y-1">
<label for="{{ $inputId }}" class="block text-sm font-medium text-gray-700">
{{ $field->label }}
@if($field->required) <span class="text-red-500">*</span> @endif
</label>
@switch($field->type)
@case(FieldType::Text)
<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">
@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>
@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">
@break
@case(FieldType::Boolean)
@php $checked = old("data.{$field->name}", $value) ? true : false; @endphp
<div class="flex items-center gap-2 mt-1">
<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>
</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">
@if(!$field->required) <option value=""> Choisir </option> @endif
@foreach($field->options ?? [] as $opt)
<option value="{{ $opt }}" {{ $oldValue === $opt ? 'selected' : '' }}>{{ $opt }}</option>
@endforeach
</select>
@break
@case(FieldType::Date)
@php
$dateVal = is_array($oldValue) ? ($oldValue['valeur'] ?? '') : '';
$dateCal = is_array($oldValue) ? ($oldValue['calendrier'] ?? 'gregorien') : old("data.{$field->name}.calendrier", 'gregorien');
@endphp
<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">
<option value="gregorien">Grégorien</option>
<option value="julien">Julien</option>
<option value="republicain">Républicain</option>
</select>
{{-- Date grégorienne / julienne : input date HTML5 --}}
<input x-show="cal !== 'republicain'"
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">
{{-- 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">
</div>
@error("data.{$field->name}.valeur")
<p class="text-sm text-red-600">{{ $message }}</p>
@enderror
@break
@endswitch
@error("data.{$field->name}")
<p class="text-sm text-red-600">{{ $message }}</p>
@enderror
</div>