Added ticket and participant creation. Revised Gate kiosk.
This commit is contained in:
parent
d30ee18e77
commit
3906b73c61
5 changed files with 231 additions and 117 deletions
|
|
@ -11,10 +11,25 @@
|
|||
let generating = $state(false)
|
||||
let emailing = $state(false)
|
||||
let mergeMode = $state(false)
|
||||
let mergeSource = $state(null) // participant being merged away
|
||||
let mergeTarget = $state(null) // participant to keep
|
||||
let mergeSource = $state(null)
|
||||
let mergeTarget = $state(null)
|
||||
let expandedId = $state(null)
|
||||
let expandedTickets = $state([])
|
||||
|
||||
// Add participant form
|
||||
let showAdd = $state(false)
|
||||
let adding = $state(false)
|
||||
let newName = $state('')
|
||||
let newEmail = $state('')
|
||||
let newPhone = $state('')
|
||||
let newPronouns = $state('')
|
||||
let newNote = $state('')
|
||||
|
||||
// Add ticket form (per participant)
|
||||
let addTicketFor = $state(null) // participant id
|
||||
let addingTicket = $state(false)
|
||||
let newTicketName = $state('')
|
||||
let newTicketType = $state('')
|
||||
let newTicketExtId = $state('')
|
||||
|
||||
const role = $derived(session?.user?.role ?? '')
|
||||
const canManage = $derived(['admin', 'ticketing'].includes(role))
|
||||
|
|
@ -114,6 +129,45 @@
|
|||
if (!ts) return ''
|
||||
return new Date(ts).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })
|
||||
}
|
||||
|
||||
async function addParticipant(e) {
|
||||
e.preventDefault()
|
||||
adding = true; error = ''
|
||||
try {
|
||||
const p = await api.participants.create({
|
||||
preferred_name: newName, email: newEmail, phone: newPhone,
|
||||
pronouns: newPronouns, note: newNote,
|
||||
})
|
||||
await db.participants.put(p)
|
||||
showAdd = false
|
||||
newName = newEmail = newPhone = newPronouns = newNote = ''
|
||||
} catch (err) {
|
||||
error = err.message
|
||||
} finally {
|
||||
adding = false
|
||||
}
|
||||
}
|
||||
|
||||
async function addTicket(e, participantId) {
|
||||
e.preventDefault()
|
||||
addingTicket = true; error = ''
|
||||
try {
|
||||
const tk = await api.tickets.create({
|
||||
participant_id: participantId,
|
||||
name: newTicketName,
|
||||
ticket_type: newTicketType,
|
||||
external_id: newTicketExtId,
|
||||
source: 'manual',
|
||||
})
|
||||
await db.tickets.put(tk)
|
||||
addTicketFor = null
|
||||
newTicketName = newTicketType = newTicketExtId = ''
|
||||
} catch (err) {
|
||||
error = err.message
|
||||
} finally {
|
||||
addingTicket = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="page">
|
||||
|
|
@ -121,6 +175,7 @@
|
|||
<h1 class="page-title">Participants</h1>
|
||||
<div class="actions">
|
||||
{#if canManage}
|
||||
<button class="btn btn-primary btn-sm" onclick={() => showAdd = !showAdd}>+ Add</button>
|
||||
<a href="/api/participants/export" class="btn btn-ghost btn-sm">Export CSV</a>
|
||||
<button class="btn btn-ghost btn-sm" onclick={generateCodes} disabled={generating}>
|
||||
{generating ? '…' : '⚿ Generate Codes'}
|
||||
|
|
@ -133,6 +188,41 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{#if showAdd && canManage}
|
||||
<div class="card" style="margin-bottom:1.5rem">
|
||||
<form onsubmit={addParticipant}>
|
||||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:1rem">
|
||||
<div class="form-group">
|
||||
<label for="p-name">Name</label>
|
||||
<input id="p-name" bind:value={newName} placeholder="Preferred name" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="p-email">Email</label>
|
||||
<input id="p-email" type="email" bind:value={newEmail} placeholder="email@example.com" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="p-phone">Phone</label>
|
||||
<input id="p-phone" bind:value={newPhone} placeholder="Optional" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="p-pronouns">Pronouns</label>
|
||||
<input id="p-pronouns" bind:value={newPronouns} placeholder="Optional" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="p-note">Note</label>
|
||||
<input id="p-note" bind:value={newNote} placeholder="Optional note" />
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button type="submit" class="btn btn-primary" disabled={adding || (!newName && !newEmail)}>
|
||||
{adding ? 'Adding…' : 'Add participant'}
|
||||
</button>
|
||||
<button type="button" class="btn btn-ghost" onclick={() => showAdd = false}>Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if mergeMode && mergeSource}
|
||||
<div class="card" style="margin-bottom:1.5rem;border-color:var(--c-accent)">
|
||||
<div style="margin-bottom:0.75rem">
|
||||
|
|
@ -236,7 +326,7 @@
|
|||
</td>
|
||||
{/if}
|
||||
</tr>
|
||||
{#if isExpanded && pts.length > 0}
|
||||
{#if isExpanded}
|
||||
<tr class="ticket-rows">
|
||||
<td colspan="5">
|
||||
<div class="ticket-list">
|
||||
|
|
@ -270,6 +360,24 @@
|
|||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
{#if canManage}
|
||||
{#if addTicketFor === p.id}
|
||||
<form class="ticket-add-form" onsubmit={(e) => addTicket(e, p.id)}>
|
||||
<input bind:value={newTicketName} placeholder="Name on ticket (optional)" style="flex:2" />
|
||||
<input bind:value={newTicketType} placeholder="Type (optional)" style="flex:1" />
|
||||
<input bind:value={newTicketExtId} placeholder="External ID (optional)" style="flex:1" />
|
||||
<button type="submit" class="btn btn-primary btn-sm" disabled={addingTicket}>
|
||||
{addingTicket ? '…' : 'Add'}
|
||||
</button>
|
||||
<button type="button" class="btn btn-ghost btn-sm" onclick={() => addTicketFor = null}>Cancel</button>
|
||||
</form>
|
||||
{:else}
|
||||
<button class="btn btn-ghost btn-sm" style="align-self:flex-start;margin-top:0.25rem"
|
||||
onclick={() => { addTicketFor = p.id; newTicketName = newTicketType = newTicketExtId = '' }}>
|
||||
+ Add ticket
|
||||
</button>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
@ -294,6 +402,21 @@
|
|||
background: var(--c-surface);
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
.ticket-add-form {
|
||||
display: flex;
|
||||
gap: 0.4rem;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
padding: 0.4rem 0.6rem;
|
||||
background: var(--c-bg);
|
||||
border-radius: 6px;
|
||||
border: 1px dashed var(--c-border);
|
||||
}
|
||||
.ticket-add-form input {
|
||||
min-width: 0;
|
||||
font-size: 0.825rem;
|
||||
padding: 0.3rem 0.5rem;
|
||||
}
|
||||
.badge-partial {
|
||||
background: rgba(245,158,11,0.15);
|
||||
color: var(--c-warn);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue