Updated Participant search and delete. Filtered import.
This commit is contained in:
parent
219acb62d6
commit
64ce97c74d
3 changed files with 30 additions and 9 deletions
|
|
@ -53,7 +53,7 @@
|
|||
<strong style="color:var(--c-text)">Supported formats:</strong><br>
|
||||
<strong>CrowdWork / ticketing platform:</strong> columns <code>Patron Name</code>, <code>Patron Email</code>, <code>Tier Name</code>, <code>Order Number</code><br>
|
||||
<strong>Generic:</strong> columns <code>name</code>, <code>email</code>, <code>ticket_id</code>, <code>ticket_type</code>, <code>note</code><br>
|
||||
Duplicate names are skipped.
|
||||
Duplicate tickets (same source + external ID) are skipped. Participants are matched or created by email.
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary" disabled={!file || importing}>
|
||||
|
|
|
|||
|
|
@ -53,7 +53,8 @@
|
|||
.filter(p => {
|
||||
if (!s) return true
|
||||
return p.preferred_name?.toLowerCase().includes(s) ||
|
||||
p.email?.toLowerCase().includes(s)
|
||||
p.email?.toLowerCase().includes(s) ||
|
||||
p.phone?.toLowerCase().includes(s)
|
||||
})
|
||||
.sort((a, b) => (a.preferred_name || a.email).localeCompare(b.preferred_name || b.email))
|
||||
})
|
||||
|
|
@ -177,6 +178,18 @@
|
|||
}
|
||||
}
|
||||
|
||||
async function deleteParticipant(id) {
|
||||
if (!confirm('Permanently delete this participant and all their records?')) return
|
||||
error = ''
|
||||
try {
|
||||
await api.participants.delete(id)
|
||||
await db.participants.delete(id)
|
||||
editId = null
|
||||
} catch (err) {
|
||||
error = err.message
|
||||
}
|
||||
}
|
||||
|
||||
async function addTicket(e, participantId) {
|
||||
e.preventDefault()
|
||||
addingTicket = true; error = ''
|
||||
|
|
@ -327,6 +340,8 @@
|
|||
<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>
|
||||
<span class="spacer"></span>
|
||||
<button type="button" class="btn btn-danger btn-sm" onclick={() => deleteParticipant(editId)}>Delete</button>
|
||||
</div>
|
||||
</form>
|
||||
</td>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
let adding = $state(false)
|
||||
let newName = $state('')
|
||||
let newEmail = $state('')
|
||||
let newPhone = $state('')
|
||||
let newDeptID = $state('')
|
||||
let newIsLead = $state(false)
|
||||
let newNote = $state('')
|
||||
|
|
@ -25,6 +24,7 @@
|
|||
const allVolunteers = liveQuery(() =>
|
||||
db.volunteers.filter(v => !v.deleted_at).toArray()
|
||||
)
|
||||
const allParticipants = liveQuery(() => db.participants.toArray())
|
||||
const allDepts = liveQuery(() =>
|
||||
db.departments.filter(d => !d.deleted_at).toArray()
|
||||
.then(arr => arr.sort((a, b) => a.name.localeCompare(b.name)))
|
||||
|
|
@ -62,7 +62,6 @@
|
|||
const data = {
|
||||
name: newName,
|
||||
email: newEmail,
|
||||
phone: newPhone,
|
||||
is_lead: newIsLead,
|
||||
note: newNote,
|
||||
}
|
||||
|
|
@ -70,7 +69,7 @@
|
|||
const v = await api.volunteers.create(data)
|
||||
await db.volunteers.put(v)
|
||||
showAdd = false
|
||||
newName = newEmail = newPhone = newNote = ''
|
||||
newName = newEmail = newNote = ''
|
||||
newDeptID = ''
|
||||
newIsLead = false
|
||||
} catch (err) {
|
||||
|
|
@ -93,6 +92,10 @@
|
|||
function deptFor(id) {
|
||||
return ($allDepts ?? []).find(d => d.id === id)
|
||||
}
|
||||
|
||||
function participantFor(id) {
|
||||
return ($allParticipants ?? []).find(p => p.id === id) ?? null
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="page">
|
||||
|
|
@ -121,10 +124,6 @@
|
|||
<label for="v-email">Email</label>
|
||||
<input id="v-email" type="email" bind:value={newEmail} placeholder="email@example.com" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="v-phone">Phone</label>
|
||||
<input id="v-phone" bind:value={newPhone} placeholder="Optional" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="v-dept">Department</label>
|
||||
<select id="v-dept" bind:value={newDeptID}>
|
||||
|
|
@ -195,12 +194,19 @@
|
|||
<tbody>
|
||||
{#each filtered as v (v.id)}
|
||||
{@const dept = deptFor(v.department_id)}
|
||||
{@const participant = participantFor(v.participant_id)}
|
||||
<tr>
|
||||
<td>
|
||||
<strong>{v.name}</strong>
|
||||
{#if v.is_lead}
|
||||
<span class="badge badge-lead" style="margin-left:0.4rem">Lead</span>
|
||||
{/if}
|
||||
{#if !v.participant_id}
|
||||
<span class="badge badge-unchecked" style="margin-left:0.4rem" title="Not linked to a participant — no ticket record">No ticket</span>
|
||||
{/if}
|
||||
{#if v.email}
|
||||
<div class="text-muted" style="font-size:0.78rem">{v.email}</div>
|
||||
{/if}
|
||||
{#if v.note}
|
||||
<div class="text-muted" style="font-size:0.78rem">{v.note}</div>
|
||||
{/if}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue