Tweaked Participants and Settings pages

This commit is contained in:
Pen Anderson 2026-03-04 14:31:52 -06:00
parent 3906b73c61
commit 219acb62d6
3 changed files with 75 additions and 20 deletions

View file

@ -24,6 +24,15 @@
let newPronouns = $state('')
let newNote = $state('')
// Edit participant
let editId = $state(null)
let editName = $state('')
let editEmail = $state('')
let editPhone = $state('')
let editPronouns = $state('')
let editNote = $state('')
let saving = $state(false)
// Add ticket form (per participant)
let addTicketFor = $state(null) // participant id
let addingTicket = $state(false)
@ -57,14 +66,8 @@
return ticketsFor(participantId).filter(t => t.checked_in_at).length
}
async function toggleExpand(id) {
if (expandedId === id) {
expandedId = null
expandedTickets = []
return
}
expandedId = id
expandedTickets = ticketsFor(id)
function toggleExpand(id) {
expandedId = expandedId === id ? null : id
}
async function generateCodes() {
@ -148,6 +151,32 @@
}
}
function startEdit(p) {
editId = p.id
editName = p.preferred_name
editEmail = p.email
editPhone = p.phone
editPronouns = p.pronouns
editNote = p.note
}
async function saveEdit(e) {
e.preventDefault()
saving = true; error = ''
try {
const p = await api.participants.update(editId, {
preferred_name: editName, email: editEmail, phone: editPhone,
pronouns: editPronouns, note: editNote,
})
await db.participants.put(p)
editId = null
} catch (err) {
error = err.message
} finally {
saving = false
}
}
async function addTicket(e, participantId) {
e.preventDefault()
addingTicket = true; error = ''
@ -283,6 +312,26 @@
{@const ci = checkedInCount(p.id)}
{@const isExpanded = expandedId === p.id}
{@const isMergeTarget = mergeMode && mergeSource?.id !== p.id}
{@const isEditing = editId === p.id}
{#if isEditing}
<tr class="edit-row">
<td colspan={canManage ? 5 : 4}>
<form class="participant-edit-form" onsubmit={saveEdit}>
<div class="edit-fields">
<input bind:value={editName} placeholder="Preferred name" />
<input type="email" bind:value={editEmail} placeholder="Email" />
<input bind:value={editPhone} placeholder="Phone" />
<input bind:value={editPronouns} placeholder="Pronouns" />
<input bind:value={editNote} placeholder="Note" style="flex:2" />
</div>
<div class="actions" style="margin-top:0.5rem">
<button type="submit" class="btn btn-primary btn-sm" disabled={saving}>{saving ? 'Saving…' : 'Save'}</button>
<button type="button" class="btn btn-ghost btn-sm" onclick={() => editId = null}>Cancel</button>
</div>
</form>
</td>
</tr>
{:else}
<tr
class:merge-target={isMergeTarget}
onclick={mergeMode && mergeSource?.id !== p.id ? () => { mergeTarget = p } : null}
@ -297,7 +346,12 @@
<div class="text-muted" style="font-size:0.78rem">{p.note}</div>
{/if}
</td>
<td class="text-muted">{p.email || '—'}</td>
<td class="text-muted">
{p.email || '—'}
{#if p.phone}
<div style="font-size:0.78rem">{p.phone}</div>
{/if}
</td>
<td>
{#if pts.length > 0}
<button class="btn btn-ghost btn-sm" onclick={(e) => { e.stopPropagation(); toggleExpand(p.id) }}>
@ -320,13 +374,16 @@
{#if canManage}
<td>
{#if !mergeMode}
<button class="btn btn-ghost btn-sm" onclick={(e) => { e.stopPropagation(); startEdit(p) }}
title="Edit participant">✎</button>
<button class="btn btn-ghost btn-sm" onclick={(e) => { e.stopPropagation(); startMerge(p) }}
title="Merge this participant into another">⇄</button>
{/if}
</td>
{/if}
</tr>
{#if isExpanded}
{/if}
{#if isExpanded && !isEditing}
<tr class="ticket-rows">
<td colspan="5">
<div class="ticket-list">
@ -417,12 +474,9 @@
font-size: 0.825rem;
padding: 0.3rem 0.5rem;
}
.badge-partial {
background: rgba(245,158,11,0.15);
color: var(--c-warn);
padding: 0.15rem 0.5rem;
border-radius: 99px;
font-size: 0.75rem;
font-weight: 600;
}
.edit-row td { padding: 0.5rem 1rem; background: var(--c-bg); }
.participant-edit-form { display: flex; flex-direction: column; gap: 0.25rem; }
.edit-fields { display: flex; gap: 0.4rem; flex-wrap: wrap; }
.edit-fields input { flex: 1; min-width: 120px; font-size: 0.825rem; padding: 0.3rem 0.5rem; width: auto; }
</style>

View file

@ -232,8 +232,8 @@
Permanently delete all records of a given type. This cannot be undone.
</p>
<div style="display:flex;flex-wrap:wrap;gap:0.5rem">
<button class="btn btn-danger" onclick={() => resetModel('attendees', api.settings.resetAttendees)}>
Delete All Attendees
<button class="btn btn-danger" onclick={() => resetModel('tickets', api.settings.resetTickets)}>
Delete All Tickets
</button>
<button class="btn btn-danger" onclick={() => resetModel('volunteers', api.settings.resetVolunteers)}>
Delete All Volunteers