Publication initiale de RelaisSMS : documentation et sources nettoyees
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<section class="mx-auto max-w-3xl">
|
||||
<div class="border-b border-zinc-200 pb-6">
|
||||
<a href="{{ route('contacts.index') }}" class="text-sm font-medium text-teal-700 hover:text-teal-900">Retour aux contacts</a>
|
||||
<h1 class="mt-3 text-2xl font-semibold">Nouveau contact</h1>
|
||||
</div>
|
||||
|
||||
<form method="POST" action="{{ route('contacts.store') }}" class="mt-8 space-y-8">
|
||||
@csrf
|
||||
|
||||
<div class="rounded-lg border border-zinc-200 bg-white p-5">
|
||||
<h2 class="text-base font-semibold">Identite</h2>
|
||||
|
||||
<div class="mt-5 grid gap-5 sm:grid-cols-2">
|
||||
<div>
|
||||
<label for="first_name" class="block text-sm font-medium text-zinc-700">Prenom</label>
|
||||
<input id="first_name" name="first_name" value="{{ old('first_name') }}" class="mt-2 block w-full rounded-md border border-zinc-300 px-3 py-2 text-base shadow-sm outline-none focus:border-teal-600 focus:ring-2 focus:ring-teal-600/20">
|
||||
@error('first_name')
|
||||
<p class="mt-2 text-sm text-red-700">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="last_name" class="block text-sm font-medium text-zinc-700">Nom</label>
|
||||
<input id="last_name" name="last_name" value="{{ old('last_name') }}" required class="mt-2 block w-full rounded-md border border-zinc-300 px-3 py-2 text-base shadow-sm outline-none focus:border-teal-600 focus:ring-2 focus:ring-teal-600/20">
|
||||
@error('last_name')
|
||||
<p class="mt-2 text-sm text-red-700">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="organization" class="block text-sm font-medium text-zinc-700">Structure</label>
|
||||
<input id="organization" name="organization" value="{{ old('organization') }}" class="mt-2 block w-full rounded-md border border-zinc-300 px-3 py-2 text-base shadow-sm outline-none focus:border-teal-600 focus:ring-2 focus:ring-teal-600/20">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="email" class="block text-sm font-medium text-zinc-700">Email</label>
|
||||
<input id="email" name="email" type="email" value="{{ old('email') }}" class="mt-2 block w-full rounded-md border border-zinc-300 px-3 py-2 text-base shadow-sm outline-none focus:border-teal-600 focus:ring-2 focus:ring-teal-600/20">
|
||||
@error('email')
|
||||
<p class="mt-2 text-sm text-red-700">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-5">
|
||||
<label for="notes" class="block text-sm font-medium text-zinc-700">Notes</label>
|
||||
<textarea id="notes" name="notes" rows="4" class="mt-2 block w-full rounded-md border border-zinc-300 px-3 py-2 text-base shadow-sm outline-none focus:border-teal-600 focus:ring-2 focus:ring-teal-600/20">{{ old('notes') }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border border-zinc-200 bg-white p-5">
|
||||
<h2 class="text-base font-semibold">Telephone</h2>
|
||||
|
||||
<div class="mt-5 grid gap-5 sm:grid-cols-[12rem_minmax(0,1fr)]">
|
||||
<div>
|
||||
<label for="phone_label" class="block text-sm font-medium text-zinc-700">Libelle</label>
|
||||
<input id="phone_label" name="phone_label" value="{{ old('phone_label', 'Mobile') }}" class="mt-2 block w-full rounded-md border border-zinc-300 px-3 py-2 text-base shadow-sm outline-none focus:border-teal-600 focus:ring-2 focus:ring-teal-600/20">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="raw_phone_number" class="block text-sm font-medium text-zinc-700">Numero</label>
|
||||
<input id="raw_phone_number" name="raw_phone_number" value="{{ old('raw_phone_number') }}" class="mt-2 block w-full rounded-md border border-zinc-300 px-3 py-2 text-base shadow-sm outline-none focus:border-teal-600 focus:ring-2 focus:ring-teal-600/20">
|
||||
@error('raw_phone_number')
|
||||
<p class="mt-2 text-sm text-red-700">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border border-zinc-200 bg-white p-5">
|
||||
<h2 class="text-base font-semibold">Groupes et options</h2>
|
||||
|
||||
<div class="mt-5 grid gap-3 sm:grid-cols-2">
|
||||
@forelse ($groups as $group)
|
||||
<label class="flex items-center gap-2 rounded-md border border-zinc-200 px-3 py-2 text-sm text-zinc-700">
|
||||
<input
|
||||
name="group_ids[]"
|
||||
type="checkbox"
|
||||
value="{{ $group->id }}"
|
||||
@checked(in_array($group->id, old('group_ids', [])))
|
||||
class="h-4 w-4 rounded border-zinc-300 text-teal-700 focus:ring-teal-600"
|
||||
>
|
||||
{{ $group->name }}
|
||||
</label>
|
||||
@empty
|
||||
<p class="text-sm text-zinc-600">Aucun groupe disponible.</p>
|
||||
@endforelse
|
||||
</div>
|
||||
|
||||
<div class="mt-6 grid gap-3 sm:grid-cols-2">
|
||||
<label class="flex items-center gap-2 text-sm text-zinc-700">
|
||||
<input name="sms_opt_out" type="checkbox" value="1" class="h-4 w-4 rounded border-zinc-300 text-teal-700 focus:ring-teal-600">
|
||||
Refus SMS
|
||||
</label>
|
||||
|
||||
<label class="flex items-center gap-2 text-sm text-zinc-700">
|
||||
<input name="is_favorite" type="checkbox" value="1" class="h-4 w-4 rounded border-zinc-300 text-teal-700 focus:ring-teal-600">
|
||||
Favori
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-end gap-3">
|
||||
<a href="{{ route('contacts.index') }}" class="rounded-md border border-zinc-300 px-4 py-2.5 text-sm font-semibold text-zinc-800 hover:bg-zinc-100">Annuler</a>
|
||||
<button type="submit" class="rounded-md bg-teal-700 px-4 py-2.5 text-sm font-semibold text-white hover:bg-teal-800 focus:outline-none focus:ring-2 focus:ring-teal-600 focus:ring-offset-2">
|
||||
Creer le contact
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
@endsection
|
||||
@@ -0,0 +1,127 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<section class="mx-auto max-w-3xl">
|
||||
<div class="border-b border-zinc-200 pb-6">
|
||||
<a href="{{ route('contacts.show', $contact) }}" class="text-sm font-medium text-teal-700 hover:text-teal-900">Retour au contact</a>
|
||||
<h1 class="mt-3 text-2xl font-semibold">Modifier le contact</h1>
|
||||
</div>
|
||||
|
||||
<form method="POST" action="{{ route('contacts.update', $contact) }}" class="mt-8 space-y-8">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
|
||||
<div class="rounded-lg border border-zinc-200 bg-white p-5">
|
||||
<h2 class="text-base font-semibold">Identite</h2>
|
||||
|
||||
<div class="mt-5 grid gap-5 sm:grid-cols-2">
|
||||
<div>
|
||||
<label for="first_name" class="block text-sm font-medium text-zinc-700">Prenom</label>
|
||||
<input id="first_name" name="first_name" value="{{ old('first_name', $contact->first_name) }}" class="mt-2 block w-full rounded-md border border-zinc-300 px-3 py-2 text-base shadow-sm outline-none focus:border-teal-600 focus:ring-2 focus:ring-teal-600/20">
|
||||
@error('first_name')
|
||||
<p class="mt-2 text-sm text-red-700">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="last_name" class="block text-sm font-medium text-zinc-700">Nom</label>
|
||||
<input id="last_name" name="last_name" value="{{ old('last_name', $contact->last_name) }}" required class="mt-2 block w-full rounded-md border border-zinc-300 px-3 py-2 text-base shadow-sm outline-none focus:border-teal-600 focus:ring-2 focus:ring-teal-600/20">
|
||||
@error('last_name')
|
||||
<p class="mt-2 text-sm text-red-700">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="organization" class="block text-sm font-medium text-zinc-700">Structure</label>
|
||||
<input id="organization" name="organization" value="{{ old('organization', $contact->organization) }}" class="mt-2 block w-full rounded-md border border-zinc-300 px-3 py-2 text-base shadow-sm outline-none focus:border-teal-600 focus:ring-2 focus:ring-teal-600/20">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="email" class="block text-sm font-medium text-zinc-700">Email</label>
|
||||
<input id="email" name="email" type="email" value="{{ old('email', $contact->email) }}" class="mt-2 block w-full rounded-md border border-zinc-300 px-3 py-2 text-base shadow-sm outline-none focus:border-teal-600 focus:ring-2 focus:ring-teal-600/20">
|
||||
@error('email')
|
||||
<p class="mt-2 text-sm text-red-700">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-5">
|
||||
<label for="notes" class="block text-sm font-medium text-zinc-700">Notes</label>
|
||||
<textarea id="notes" name="notes" rows="4" class="mt-2 block w-full rounded-md border border-zinc-300 px-3 py-2 text-base shadow-sm outline-none focus:border-teal-600 focus:ring-2 focus:ring-teal-600/20">{{ old('notes', $contact->notes) }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border border-zinc-200 bg-white p-5">
|
||||
<h2 class="text-base font-semibold">Telephone principal</h2>
|
||||
|
||||
<div class="mt-5 grid gap-5 sm:grid-cols-[12rem_minmax(0,1fr)]">
|
||||
<div>
|
||||
<label for="phone_label" class="block text-sm font-medium text-zinc-700">Libelle</label>
|
||||
<input id="phone_label" name="phone_label" value="{{ old('phone_label', $primaryPhone?->label ?? 'Mobile') }}" class="mt-2 block w-full rounded-md border border-zinc-300 px-3 py-2 text-base shadow-sm outline-none focus:border-teal-600 focus:ring-2 focus:ring-teal-600/20">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="raw_phone_number" class="block text-sm font-medium text-zinc-700">Numero</label>
|
||||
<input id="raw_phone_number" name="raw_phone_number" value="{{ old('raw_phone_number', $primaryPhone?->raw_number) }}" class="mt-2 block w-full rounded-md border border-zinc-300 px-3 py-2 text-base shadow-sm outline-none focus:border-teal-600 focus:ring-2 focus:ring-teal-600/20">
|
||||
@error('raw_phone_number')
|
||||
<p class="mt-2 text-sm text-red-700">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border border-zinc-200 bg-white p-5">
|
||||
<h2 class="text-base font-semibold">Groupes et options</h2>
|
||||
|
||||
<div class="mt-5 grid gap-3 sm:grid-cols-2">
|
||||
@php($selectedGroups = old('group_ids', $contact->groups->pluck('id')->all()))
|
||||
|
||||
@forelse ($groups as $group)
|
||||
<label class="flex items-center gap-2 rounded-md border border-zinc-200 px-3 py-2 text-sm text-zinc-700">
|
||||
<input
|
||||
name="group_ids[]"
|
||||
type="checkbox"
|
||||
value="{{ $group->id }}"
|
||||
@checked(in_array($group->id, $selectedGroups))
|
||||
class="h-4 w-4 rounded border-zinc-300 text-teal-700 focus:ring-teal-600"
|
||||
>
|
||||
{{ $group->name }}
|
||||
</label>
|
||||
@empty
|
||||
<p class="text-sm text-zinc-600">Aucun groupe disponible.</p>
|
||||
@endforelse
|
||||
</div>
|
||||
|
||||
<div class="mt-6 grid gap-3 sm:grid-cols-2">
|
||||
<label class="flex items-center gap-2 text-sm text-zinc-700">
|
||||
<input name="sms_opt_out" type="checkbox" value="1" @checked(old('sms_opt_out', $contact->sms_opt_out)) class="h-4 w-4 rounded border-zinc-300 text-teal-700 focus:ring-teal-600">
|
||||
Refus SMS
|
||||
</label>
|
||||
|
||||
<label class="flex items-center gap-2 text-sm text-zinc-700">
|
||||
<input name="is_favorite" type="checkbox" value="1" @checked(old('is_favorite', $contact->is_favorite)) class="h-4 w-4 rounded border-zinc-300 text-teal-700 focus:ring-teal-600">
|
||||
Favori
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap items-center justify-between gap-3">
|
||||
<button type="submit" form="delete-contact-form" class="rounded-md border border-red-300 px-4 py-2.5 text-sm font-semibold text-red-700 hover:bg-red-50">
|
||||
Supprimer
|
||||
</button>
|
||||
|
||||
<div class="flex items-center gap-3">
|
||||
<a href="{{ route('contacts.show', $contact) }}" class="rounded-md border border-zinc-300 px-4 py-2.5 text-sm font-semibold text-zinc-800 hover:bg-zinc-100">Annuler</a>
|
||||
<button type="submit" class="rounded-md bg-teal-700 px-4 py-2.5 text-sm font-semibold text-white hover:bg-teal-800 focus:outline-none focus:ring-2 focus:ring-teal-600 focus:ring-offset-2">
|
||||
Enregistrer
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form id="delete-contact-form" method="POST" action="{{ route('contacts.destroy', $contact) }}" onsubmit="return confirm('Supprimer ce contact ?')">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
</form>
|
||||
</section>
|
||||
@endsection
|
||||
@@ -0,0 +1,264 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
@php
|
||||
$baseFilters = array_filter([
|
||||
'q' => $search,
|
||||
'group' => $selectedGroupId ?: null,
|
||||
'mobile' => $selectedMobileFilter,
|
||||
], fn ($value) => $value !== null && $value !== '');
|
||||
@endphp
|
||||
|
||||
<section class="page-wrap wide">
|
||||
<header class="topbar">
|
||||
<div class="title">
|
||||
<h1>Contacts</h1>
|
||||
<p>
|
||||
Contacts locaux, groupes et recherche.
|
||||
@if ($lastCardDavSyncRun)
|
||||
<span class="block sm:inline">CardDAV : {{ $lastCardDavSyncRun->status }} · {{ $lastCardDavSyncRun->started_at?->diffForHumans() }}</span>
|
||||
@endif
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
@if ($cardDavSyncEnabled)
|
||||
<form method="POST" action="{{ route('contacts.sync-carddav') }}">
|
||||
@csrf
|
||||
<button type="submit" class="secondary">
|
||||
↻ Synchroniser
|
||||
</button>
|
||||
</form>
|
||||
@endif
|
||||
|
||||
<a href="{{ route('contacts.create') }}" class="primary">
|
||||
+ Contact local
|
||||
</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="content-grid">
|
||||
<div class="stack">
|
||||
<form method="GET" action="{{ route('contacts.index') }}" class="panel flush">
|
||||
<div class="panel-body">
|
||||
<div class="form-grid contact-filters-grid">
|
||||
<div class="field">
|
||||
<label for="q">Recherche</label>
|
||||
<input
|
||||
id="q"
|
||||
name="q"
|
||||
value="{{ $search }}"
|
||||
type="search"
|
||||
class="input"
|
||||
placeholder="Nom, email ou telephone"
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label for="group">Groupe</label>
|
||||
<select
|
||||
id="group"
|
||||
name="group"
|
||||
class="select"
|
||||
>
|
||||
<option value="">Tous</option>
|
||||
@foreach ($groups as $group)
|
||||
<option value="{{ $group->id }}" @selected($selectedGroupId === $group->id)>{{ $group->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label for="mobile">Mobile</label>
|
||||
<select id="mobile" name="mobile" class="select">
|
||||
<option value="detected" @selected($selectedMobileFilter === 'detected')>Mobile detecte</option>
|
||||
<option value="all" @selected($selectedMobileFilter === 'all')>Tous</option>
|
||||
<option value="non_mobile" @selected($selectedMobileFilter === 'non_mobile')>Non mobile</option>
|
||||
<option value="invalid" @selected($selectedMobileFilter === 'invalid')>Numero invalide</option>
|
||||
<option value="missing" @selected($selectedMobileFilter === 'missing')>Sans telephone</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label for="status">Statut</label>
|
||||
<select id="status" name="status" class="select">
|
||||
<option value="" @selected($selectedStatus === '')>Tous</option>
|
||||
<option value="active" @selected($selectedStatus === 'active')>Actif</option>
|
||||
<option value="favorite" @selected($selectedStatus === 'favorite')>Favori</option>
|
||||
<option value="opt_out" @selected($selectedStatus === 'opt_out')>Refus SMS</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="secondary">Filtrer</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="panel">
|
||||
<div class="panel-header">
|
||||
<h2>Liste des contacts</h2>
|
||||
<div class="tabs" aria-label="Vue contacts">
|
||||
<a class="{{ (! $favoriteOnly && $selectedStatus === '') ? 'active' : '' }}" href="{{ route('contacts.index', $baseFilters) }}">Tous</a>
|
||||
<a class="{{ ($favoriteOnly || $selectedStatus === 'favorite') ? 'active' : '' }}" href="{{ route('contacts.index', array_merge($baseFilters, ['status' => 'favorite'])) }}">Favoris</a>
|
||||
<a class="{{ $selectedStatus === 'opt_out' ? 'active' : '' }}" href="{{ route('contacts.index', array_merge($baseFilters, ['status' => 'opt_out'])) }}">Refus SMS</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-wrap">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Contact</th>
|
||||
<th>Telephone</th>
|
||||
<th>Groupes</th>
|
||||
<th>Statut</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse ($contacts as $contact)
|
||||
@php($primaryPhone = $contact->phoneNumbers->firstWhere('is_primary', true) ?? $contact->phoneNumbers->first())
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ route('contacts.show', $contact) }}" class="link item-line">
|
||||
@if ($contact->is_favorite)
|
||||
<span class="favorite-star" aria-label="Favori">★</span>
|
||||
@endif
|
||||
<span class="truncate">{{ $contact->displayName() }}</span>
|
||||
</a>
|
||||
<div class="muted truncate">{{ $contact->email ?: $contact->organization ?: ucfirst($contact->source) }}</div>
|
||||
</td>
|
||||
<td>
|
||||
@if ($primaryPhone)
|
||||
{{ $primaryPhone->normalized_number ?: $primaryPhone->raw_number }}
|
||||
@if (! $primaryPhone->is_valid)
|
||||
<div class="muted">Numero invalide</div>
|
||||
@elseif (! $primaryPhone->hasDetectedMobileNumber())
|
||||
<div class="muted">Non mobile</div>
|
||||
@else
|
||||
<div class="muted">Mobile detecte</div>
|
||||
@endif
|
||||
@else
|
||||
<span class="muted">Aucun</span>
|
||||
@endif
|
||||
</td>
|
||||
<td>{{ $contact->groups_count }}</td>
|
||||
<td>
|
||||
<span class="inline-badges">
|
||||
@if ($contact->is_favorite)
|
||||
<span class="badge pending">Favori</span>
|
||||
@endif
|
||||
@if ($contact->sms_opt_out)
|
||||
<span class="badge error">Refus SMS</span>
|
||||
@endif
|
||||
@if (! $contact->is_favorite && ! $contact->sms_opt_out)
|
||||
<span class="badge">Actif</span>
|
||||
@endif
|
||||
</span>
|
||||
<form method="POST" action="{{ route('contacts.favorite', $contact) }}" class="mt-sm">
|
||||
@csrf
|
||||
@method('PATCH')
|
||||
<input type="hidden" name="is_favorite" value="{{ $contact->is_favorite ? '0' : '1' }}">
|
||||
<button type="submit" class="secondary">
|
||||
{{ $contact->is_favorite ? 'Retirer favori' : 'Favori' }}
|
||||
</button>
|
||||
</form>
|
||||
<form method="POST" action="{{ route('contacts.opt-out', $contact) }}" class="mt-sm">
|
||||
@csrf
|
||||
@method('PATCH')
|
||||
<input type="hidden" name="sms_opt_out" value="{{ $contact->sms_opt_out ? '0' : '1' }}">
|
||||
<button type="submit" class="secondary">
|
||||
{{ $contact->sms_opt_out ? 'Retirer Refus SMS' : 'Refus SMS' }}
|
||||
</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="4" class="empty-state">Aucun contact trouve.</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ $contacts->links() }}
|
||||
</div>
|
||||
|
||||
<aside class="stack">
|
||||
<form method="POST" action="{{ route('contact-groups.store') }}" class="panel">
|
||||
@csrf
|
||||
|
||||
<div class="panel-header">
|
||||
<h2>Nouveau groupe</h2>
|
||||
</div>
|
||||
|
||||
<div class="panel-body stack-sm">
|
||||
<div class="field">
|
||||
<label for="name">Nom</label>
|
||||
<input
|
||||
id="name"
|
||||
name="name"
|
||||
value="{{ old('name') }}"
|
||||
required
|
||||
class="input"
|
||||
>
|
||||
@error('name')
|
||||
<p class="notice error">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label for="description">Description</label>
|
||||
<textarea
|
||||
id="description"
|
||||
name="description"
|
||||
rows="3"
|
||||
class="textarea"
|
||||
>{{ old('description') }}</textarea>
|
||||
</div>
|
||||
|
||||
<label class="field-label inline-badges">
|
||||
<input name="is_favorite" type="checkbox" value="1">
|
||||
Favori
|
||||
</label>
|
||||
|
||||
<button type="submit" class="primary">
|
||||
Creer le groupe
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="panel">
|
||||
<div class="panel-header">
|
||||
<h2>Groupes</h2>
|
||||
</div>
|
||||
|
||||
<div class="panel-body stack-sm">
|
||||
@forelse ($groups as $group)
|
||||
<div class="summary-row {{ $group->is_favorite ? 'favorite-row' : '' }}">
|
||||
<a href="{{ route('contacts.index', ['group' => $group->id]) }}" class="link truncate flex-fill">
|
||||
@if ($group->is_favorite)
|
||||
<span class="favorite-star" aria-label="Favori">★</span>
|
||||
@endif
|
||||
{{ $group->name }}
|
||||
</a>
|
||||
<span class="pill">{{ $group->contacts_count }}</span>
|
||||
|
||||
@if ($group->source === 'local')
|
||||
<a href="{{ route('contact-groups.edit', $group) }}" class="secondary">
|
||||
Modifier
|
||||
</a>
|
||||
@else
|
||||
<span class="pill warn">{{ ucfirst($group->source) }}</span>
|
||||
@endif
|
||||
</div>
|
||||
@empty
|
||||
<p class="muted">Aucun groupe.</p>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
</section>
|
||||
@endsection
|
||||
@@ -0,0 +1,151 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<section class="mx-auto max-w-4xl space-y-6">
|
||||
<div class="border-b border-zinc-200 pb-6">
|
||||
<a href="{{ route('contacts.index') }}" class="text-sm font-medium text-teal-700 hover:text-teal-900">Retour aux contacts</a>
|
||||
<div class="mt-3 flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
|
||||
<div>
|
||||
<h1 class="text-2xl font-semibold">{{ $contact->displayName() }}</h1>
|
||||
<p class="mt-2 text-sm text-zinc-600">{{ $contact->organization ?: ucfirst($contact->source) }}</p>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-3 sm:items-end">
|
||||
<div class="flex flex-wrap gap-2">
|
||||
@if ($contact->is_favorite)
|
||||
<span class="rounded-full bg-amber-50 px-3 py-1 text-sm font-semibold text-amber-800">Favori</span>
|
||||
@endif
|
||||
@if ($contact->sms_opt_out)
|
||||
<span class="rounded-full bg-red-50 px-3 py-1 text-sm font-semibold text-red-700">Refus SMS</span>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<form method="POST" action="{{ route('contacts.favorite', $contact) }}" class="flex justify-end">
|
||||
@csrf
|
||||
@method('PATCH')
|
||||
<input type="hidden" name="is_favorite" value="{{ $contact->is_favorite ? '0' : '1' }}">
|
||||
<button type="submit" class="rounded-md border border-amber-300 px-4 py-2 text-sm font-semibold text-amber-800 hover:bg-amber-50">
|
||||
{{ $contact->is_favorite ? 'Retirer des favoris' : 'Mettre en favori' }}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<form method="POST" action="{{ route('contacts.opt-out', $contact) }}" class="flex justify-end">
|
||||
@csrf
|
||||
@method('PATCH')
|
||||
<input type="hidden" name="sms_opt_out" value="{{ $contact->sms_opt_out ? '0' : '1' }}">
|
||||
<button type="submit" class="rounded-md border border-red-300 px-4 py-2 text-sm font-semibold text-red-700 hover:bg-red-50">
|
||||
{{ $contact->sms_opt_out ? 'Retirer Refus SMS' : 'Refus SMS' }}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
@if ($contact->source === 'local')
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<a href="{{ route('contacts.edit', $contact) }}" class="rounded-md bg-teal-700 px-4 py-2 text-sm font-semibold text-white hover:bg-teal-800">
|
||||
Modifier
|
||||
</a>
|
||||
|
||||
<form method="POST" action="{{ route('contacts.destroy', $contact) }}" onsubmit="return confirm('Supprimer ce contact ?')">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="rounded-md border border-red-300 px-4 py-2 text-sm font-semibold text-red-700 hover:bg-red-50">
|
||||
Supprimer
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
@else
|
||||
<span class="rounded-full bg-amber-50 px-3 py-1 text-sm font-semibold text-amber-800">
|
||||
Fiche importee non modifiable
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (session('status'))
|
||||
<div class="rounded-md border border-teal-200 bg-teal-50 px-4 py-3 text-sm font-medium text-teal-900">
|
||||
{{ session('status') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="grid gap-6 lg:grid-cols-[minmax(0,1fr)_18rem]">
|
||||
<div class="space-y-6">
|
||||
<div class="rounded-lg border border-zinc-200 bg-white p-5">
|
||||
<h2 class="text-base font-semibold">Coordonnees</h2>
|
||||
|
||||
<dl class="mt-5 grid gap-4 sm:grid-cols-2">
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-zinc-500">Email</dt>
|
||||
<dd class="mt-1 text-sm text-zinc-900">{{ $contact->email ?: 'Non renseigne' }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-zinc-500">Source</dt>
|
||||
<dd class="mt-1 text-sm text-zinc-900">{{ $contact->source }}</dd>
|
||||
</div>
|
||||
@if ($contact->synced_at)
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-zinc-500">Derniere synchro</dt>
|
||||
<dd class="mt-1 text-sm text-zinc-900">{{ $contact->synced_at->format('d/m/Y H:i') }}</dd>
|
||||
</div>
|
||||
@endif
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border border-zinc-200 bg-white p-5">
|
||||
<h2 class="text-base font-semibold">Numeros</h2>
|
||||
|
||||
<div class="mt-5 space-y-3">
|
||||
@forelse ($contact->phoneNumbers as $phoneNumber)
|
||||
<div class="rounded-md border border-zinc-200 p-4">
|
||||
<div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div>
|
||||
<p class="text-sm font-semibold text-zinc-900">{{ $phoneNumber->label ?: 'Telephone' }}</p>
|
||||
<p class="mt-1 text-sm text-zinc-700">{{ $phoneNumber->normalized_number ?: $phoneNumber->raw_number }}</p>
|
||||
@if ($phoneNumber->normalized_number)
|
||||
<p class="mt-1 text-xs text-zinc-500">Brut : {{ $phoneNumber->raw_number }}</p>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<span class="rounded-full px-3 py-1 text-xs font-semibold {{ $phoneNumber->is_valid ? 'bg-teal-50 text-teal-800' : 'bg-red-50 text-red-700' }}">
|
||||
{{ $phoneNumber->is_valid ? 'Valide' : 'Invalide' }}
|
||||
</span>
|
||||
<span class="rounded-full px-3 py-1 text-xs font-semibold {{ $phoneNumber->hasDetectedMobileNumber() ? 'bg-teal-50 text-teal-800' : 'bg-zinc-100 text-zinc-700' }}">
|
||||
{{ $phoneNumber->hasDetectedMobileNumber() ? 'Mobile' : 'Non mobile' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if ($phoneNumber->validation_error)
|
||||
<p class="mt-3 text-sm text-red-700">{{ $phoneNumber->validation_error }}</p>
|
||||
@endif
|
||||
</div>
|
||||
@empty
|
||||
<p class="text-sm text-zinc-600">Aucun numero.</p>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if ($contact->notes)
|
||||
<div class="rounded-lg border border-zinc-200 bg-white p-5">
|
||||
<h2 class="text-base font-semibold">Notes</h2>
|
||||
<p class="mt-4 whitespace-pre-line text-sm text-zinc-700">{{ $contact->notes }}</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<aside class="rounded-lg border border-zinc-200 bg-white p-5">
|
||||
<h2 class="text-base font-semibold">Groupes</h2>
|
||||
|
||||
<div class="mt-4 space-y-2">
|
||||
@forelse ($contact->groups as $group)
|
||||
<a href="{{ route('contacts.index', ['group' => $group->id]) }}" class="block rounded-md border border-zinc-200 px-3 py-2 text-sm font-medium text-zinc-800 hover:bg-zinc-50">
|
||||
{{ $group->name }}
|
||||
</a>
|
||||
@empty
|
||||
<p class="text-sm text-zinc-600">Aucun groupe.</p>
|
||||
@endforelse
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
</section>
|
||||
@endsection
|
||||
Reference in New Issue
Block a user