Add ability to edit participant name and phone number
This commit is contained in:
@@ -48,6 +48,13 @@ export function QuestionnaireDetail() {
|
||||
const [editNameInput, setEditNameInput] = useState('')
|
||||
const [editDescriptionInput, setEditDescriptionInput] = useState('')
|
||||
const [editLoading, setEditLoading] = useState(false)
|
||||
|
||||
// Edit participant modal state
|
||||
const [showEditParticipantModal, setShowEditParticipantModal] = useState(false)
|
||||
const [editingParticipant, setEditingParticipant] = useState<Participant | null>(null)
|
||||
const [editParticipantName, setEditParticipantName] = useState('')
|
||||
const [editParticipantPhone, setEditParticipantPhone] = useState('')
|
||||
const [editParticipantLoading, setEditParticipantLoading] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
fetchData()
|
||||
@@ -153,6 +160,44 @@ export function QuestionnaireDetail() {
|
||||
}
|
||||
}
|
||||
|
||||
function openEditParticipantModal(participant: Participant) {
|
||||
setEditingParticipant(participant)
|
||||
setEditParticipantName(participant.name)
|
||||
setEditParticipantPhone(participant.phone || '')
|
||||
setShowEditParticipantModal(true)
|
||||
}
|
||||
|
||||
async function handleEditParticipant(e: FormEvent) {
|
||||
e.preventDefault()
|
||||
if (!editingParticipant || !editParticipantName.trim()) return
|
||||
|
||||
setEditParticipantLoading(true)
|
||||
try {
|
||||
const res = await fetch(`/api/admin/participants/${editingParticipant.id}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify({
|
||||
name: editParticipantName.trim(),
|
||||
phone: editParticipantPhone.trim() || null
|
||||
}),
|
||||
})
|
||||
const data = await res.json()
|
||||
if (data.success && data.participant) {
|
||||
setShowEditParticipantModal(false)
|
||||
setEditingParticipant(null)
|
||||
// Update the participant in the list
|
||||
setParticipants(participants.map(p =>
|
||||
p.id === editingParticipant.id ? data.participant : p
|
||||
))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to update participant:', error)
|
||||
} finally {
|
||||
setEditParticipantLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
async function handleDelete() {
|
||||
if (!confirm('Weet je zeker dat je deze vragenlijst wilt verwijderen? Dit verwijdert ook alle activiteiten en stemmen.')) {
|
||||
return
|
||||
@@ -332,6 +377,13 @@ export function QuestionnaireDetail() {
|
||||
)}
|
||||
<div className="text-xs font-mono text-text-faint truncate mt-1">{participantUrl}</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => openEditParticipantModal(participant)}
|
||||
className="px-2 py-1 text-xs font-medium text-text-muted hover:text-accent hover:bg-bg-card rounded transition-colors shrink-0"
|
||||
title="Bewerken"
|
||||
>
|
||||
✏️
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handleDeleteParticipant(participant.id)}
|
||||
className="px-2 py-1 text-xs font-medium text-danger hover:bg-danger-muted rounded transition-colors shrink-0"
|
||||
@@ -516,6 +568,80 @@ export function QuestionnaireDetail() {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Edit Participant Modal */}
|
||||
{showEditParticipantModal && editingParticipant && (
|
||||
<div
|
||||
className="fixed inset-0 bg-black/70 backdrop-blur-sm flex items-center justify-center z-50 p-4"
|
||||
onClick={() => setShowEditParticipantModal(false)}
|
||||
>
|
||||
<div
|
||||
className="bg-bg-card border border-border rounded-2xl w-full max-w-md"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between p-4 border-b border-border">
|
||||
<h3 className="font-semibold text-text">Deelnemer Bewerken</h3>
|
||||
<button
|
||||
onClick={() => setShowEditParticipantModal(false)}
|
||||
className="text-2xl text-text-muted hover:text-text leading-none"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Form */}
|
||||
<form onSubmit={handleEditParticipant} className="p-4 space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-text mb-2">
|
||||
Naam <span className="text-danger">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={editParticipantName}
|
||||
onChange={(e) => setEditParticipantName(e.target.value)}
|
||||
className="w-full px-4 py-2 bg-bg-input border border-border rounded-lg text-text placeholder-text-faint focus:outline-none focus:border-accent focus:ring-2 focus:ring-accent/20 transition-colors"
|
||||
required
|
||||
autoFocus
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-text mb-2">
|
||||
Telefoonnummer
|
||||
</label>
|
||||
<input
|
||||
type="tel"
|
||||
value={editParticipantPhone}
|
||||
onChange={(e) => setEditParticipantPhone(e.target.value)}
|
||||
placeholder="+31612345678 (optioneel, leeg laten om te verwijderen)"
|
||||
className="w-full px-4 py-2 bg-bg-input border border-border rounded-lg text-text placeholder-text-faint focus:outline-none focus:border-accent focus:ring-2 focus:ring-accent/20 transition-colors"
|
||||
/>
|
||||
<p className="text-xs text-text-faint mt-1">
|
||||
Laat leeg om het telefoonnummer te verwijderen
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-3 justify-end pt-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowEditParticipantModal(false)}
|
||||
className="px-4 py-2 border border-border rounded-lg text-text-muted hover:text-text hover:border-text-muted transition-colors"
|
||||
>
|
||||
Annuleren
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={editParticipantLoading}
|
||||
className="px-4 py-2 bg-accent hover:bg-accent-hover text-white font-semibold rounded-lg transition-colors disabled:opacity-50"
|
||||
>
|
||||
{editParticipantLoading ? 'Opslaan...' : 'Opslaan'}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user