Initial commit: Club DynaSQY
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useParams, useNavigate, Link } from 'react-router-dom'
|
||||
import { useAuth } from '../context/AuthContext'
|
||||
|
||||
export default function GuestDetail() {
|
||||
const { id } = useParams()
|
||||
const navigate = useNavigate()
|
||||
const { authFetch, user } = useAuth()
|
||||
const [guest, setGuest] = useState(null)
|
||||
|
||||
useEffect(() => {
|
||||
authFetch(`/api/guests/${id}`).then((r) => (r.ok ? r.json() : null)).then(setGuest)
|
||||
}, [id])
|
||||
|
||||
const handleCandidature = async (action) => {
|
||||
const confirmMsg = action === 'start' ? 'Proposer la candidature de cet invité ?' :
|
||||
action === 'accept' ? 'Accepter → créer un compte membre et supprimer cet invité ?' :
|
||||
'Refuser cette candidature ?'
|
||||
if (!confirm(confirmMsg)) return
|
||||
const r = await authFetch(`/api/guests/${id}/candidature`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ action }),
|
||||
})
|
||||
if (r.ok) {
|
||||
if (action === 'accept') {
|
||||
alert('Membre créé ! Mot de passe par défaut : Bienvenue2026')
|
||||
navigate('/members')
|
||||
} else {
|
||||
const data = await r.json()
|
||||
alert(data.message)
|
||||
setGuest((g) => ({ ...g, statut_candidature: data.statut_candidature }))
|
||||
}
|
||||
} else {
|
||||
const err = await r.json()
|
||||
alert(err.error || 'Erreur')
|
||||
}
|
||||
}
|
||||
|
||||
if (!guest) return <p className="text-center text-gray-400 py-8">Chargement...</p>
|
||||
|
||||
const isOwner = guest.invite_par_id === user?.id || user?.role === 'admin'
|
||||
|
||||
const statutBadge = (s) => {
|
||||
if (s === 'acceptee') return <span className="text-green-600 text-sm font-medium">✓ Acceptée</span>
|
||||
if (s === 'refusee') return <span className="text-red-600 text-sm font-medium">✗ Refusée</span>
|
||||
return <span className="text-orange-400 text-sm font-medium">En attente</span>
|
||||
}
|
||||
|
||||
const candidatureBadge = (s) => {
|
||||
if (s === 'candidature') return <span className="inline-block text-yellow-800 bg-yellow-100 text-xs font-bold px-2 py-0.5 rounded-full">Candidature en cours</span>
|
||||
if (s === 'refuse') return <span className="inline-block text-red-800 bg-red-100 text-xs font-bold px-2 py-0.5 rounded-full">Candidature refusée</span>
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<Link to="/guests" className="text-blue-700 text-sm">← Retour</Link>
|
||||
<div className="bg-white rounded-xl p-6 shadow-sm text-center">
|
||||
{guest.photo_url ? (
|
||||
<img src={guest.photo_url} alt="" className="w-20 h-20 rounded-full object-cover mx-auto mb-3" />
|
||||
) : (
|
||||
<div className="w-20 h-20 bg-blue-900 rounded-full flex items-center justify-center text-white text-2xl font-bold mx-auto mb-3">
|
||||
{guest.prenom[0]}{guest.nom[0]}
|
||||
</div>
|
||||
)}
|
||||
<h2 className="text-xl font-bold text-gray-800">{guest.prenom} {guest.nom}</h2>
|
||||
{guest.societe && <p className="text-gray-500">{guest.societe}</p>}
|
||||
{guest.activite && <p className="text-gray-400 text-sm">{guest.activite}</p>}
|
||||
{guest.visit_number === 2 && <span className="inline-block mt-1 text-xs font-bold text-red-600 bg-red-100 px-2 py-0.5 rounded-full">2</span>}
|
||||
{guest.visit_number >= 3 && <span className="inline-block mt-1 text-xs font-bold text-purple-600 bg-purple-100 px-2 py-0.5 rounded-full">{guest.visit_number}</span>}
|
||||
<div className="mt-2">{statutBadge(guest.statut)}</div>
|
||||
<div className="mt-1">{candidatureBadge(guest.statut_candidature)}</div>
|
||||
{isOwner && (
|
||||
<Link to={`/guests/edit/${guest.id}`} className="inline-block mt-3 bg-blue-900 text-white px-4 py-2 rounded-lg text-sm font-semibold">Modifier</Link>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{user?.role === 'admin' && (
|
||||
<div className="bg-white rounded-xl p-4 shadow-sm space-y-2">
|
||||
<h3 className="font-semibold text-gray-700 text-sm">Candidature membre</h3>
|
||||
{!guest.statut_candidature && (
|
||||
<button onClick={() => handleCandidature('start')} className="w-full bg-yellow-500 text-white py-2 rounded-lg text-sm font-semibold active:bg-yellow-600">
|
||||
Proposer candidature
|
||||
</button>
|
||||
)}
|
||||
{guest.statut_candidature === 'candidature' && (
|
||||
<div className="flex gap-2">
|
||||
<button onClick={() => handleCandidature('accept')} className="flex-1 bg-green-600 text-white py-2 rounded-lg text-sm font-semibold active:bg-green-700">
|
||||
Accepter → Membre
|
||||
</button>
|
||||
<button onClick={() => handleCandidature('reject')} className="flex-1 bg-red-500 text-white py-2 rounded-lg text-sm font-semibold active:bg-red-600">
|
||||
Refuser
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{guest.statut_candidature === 'refuse' && (
|
||||
<p className="text-red-600 text-sm text-center">Candidature refusée</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="bg-white rounded-xl p-4 shadow-sm space-y-3">
|
||||
{guest.telephone && (
|
||||
<a href={`tel:${guest.telephone}`} className="flex items-center gap-3 text-green-600">
|
||||
<span className="text-lg">📞</span>
|
||||
<span className="font-medium">{guest.telephone}</span>
|
||||
</a>
|
||||
)}
|
||||
{guest.email && (
|
||||
<a href={`mailto:${guest.email}`} className="flex items-center gap-3 text-blue-600">
|
||||
<span className="text-lg">✉</span>
|
||||
<span className="font-medium">{guest.email}</span>
|
||||
</a>
|
||||
)}
|
||||
{guest.site_web && (
|
||||
<a href={guest.site_web.startsWith('http') ? guest.site_web : 'https://' + guest.site_web} target="_blank" rel="noopener noreferrer" className="flex items-center gap-3 text-purple-600">
|
||||
<span className="text-lg">🌐</span>
|
||||
<span className="font-medium">{guest.site_web}</span>
|
||||
</a>
|
||||
)}
|
||||
{guest.commentaires && <p className="text-sm text-gray-600">Note : {guest.commentaires}</p>}
|
||||
{guest.date_club && (
|
||||
<p className="text-sm text-gray-500">{new Date(guest.date_club) > new Date() ? 'Vient le' : 'Venue le'} {new Date(guest.date_club).toLocaleDateString('fr-FR', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' })}</p>
|
||||
)}
|
||||
{guest.invite_par_prenom && guest.invite_par_nom && (
|
||||
<p className="text-xs text-gray-400">Invité par {guest.invite_par_prenom} {guest.invite_par_nom}</p>
|
||||
)}
|
||||
{guest.mail_envoye && guest.invitation_sent_at && (
|
||||
<p className="text-xs text-gray-400">Email envoyé le {new Date(guest.invitation_sent_at).toLocaleDateString('fr-FR')}</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user