Set up Unconfirmed -> Registered -> Confirmed -> Ready flow for Volunteers
This commit is contained in:
parent
62b3dece84
commit
72b245d6d6
7 changed files with 95 additions and 20 deletions
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
let search = $state('')
|
||||
let filterDept = $state('')
|
||||
let filterChecked = $state('')
|
||||
let filterStatus = $state('')
|
||||
let error = $state('')
|
||||
let showAdd = $state(false)
|
||||
let adding = $state(false)
|
||||
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
const role = $derived(session?.user?.role ?? '')
|
||||
const canManage = $derived(['admin', 'ticketing', 'staffing', 'colead'].includes(role))
|
||||
const canConfirm = $derived(['admin', 'staffing', 'colead'].includes(role))
|
||||
const myDeptIDs = $derived(session?.user?.department_ids ?? [])
|
||||
|
||||
// Auto-filter coleads to their department on mount
|
||||
|
|
@ -33,6 +34,7 @@
|
|||
db.volunteers.filter(v => !v.deleted_at).toArray()
|
||||
)
|
||||
const allParticipants = liveQuery(() => db.participants.toArray())
|
||||
const allTickets = liveQuery(() => db.tickets.filter(t => !t.deleted_at).toArray())
|
||||
const allDepts = liveQuery(() =>
|
||||
db.departments.filter(d => !d.deleted_at).toArray()
|
||||
.then(arr => arr.sort((a, b) => a.name.localeCompare(b.name)))
|
||||
|
|
@ -44,8 +46,10 @@
|
|||
return list
|
||||
.filter(v => {
|
||||
if (filterDept && v.department_id !== parseInt(filterDept)) return false
|
||||
if (filterChecked === 'true' && !v.checked_in) return false
|
||||
if (filterChecked === 'false' && v.checked_in) return false
|
||||
if (filterStatus === 'unconfirmed' && v.email_confirmed) return false
|
||||
if (filterStatus === 'registered' && (!v.email_confirmed || v.confirmed)) return false
|
||||
if (filterStatus === 'confirmed' && (!v.confirmed || v.checked_in)) return false
|
||||
if (filterStatus === 'ready' && !v.checked_in) return false
|
||||
if (s && !v.name.toLowerCase().includes(s) &&
|
||||
!(v.email || '').toLowerCase().includes(s)) return false
|
||||
return true
|
||||
|
|
@ -62,6 +66,15 @@
|
|||
}
|
||||
}
|
||||
|
||||
async function confirmVolunteer(v) {
|
||||
try {
|
||||
const updated = await api.volunteers.confirm(v.id)
|
||||
await db.volunteers.put(updated)
|
||||
} catch (err) {
|
||||
error = err.message
|
||||
}
|
||||
}
|
||||
|
||||
async function addVolunteer(e) {
|
||||
e.preventDefault()
|
||||
adding = true
|
||||
|
|
@ -110,6 +123,11 @@
|
|||
return ($allDepts ?? []).find(d => d.id === id)
|
||||
}
|
||||
|
||||
function participantHasTickets(participantId) {
|
||||
if (!participantId) return false
|
||||
return ($allTickets ?? []).some(t => t.participant_id === participantId)
|
||||
}
|
||||
|
||||
function participantFor(id) {
|
||||
return ($allParticipants ?? []).find(p => p.id === id) ?? null
|
||||
}
|
||||
|
|
@ -181,10 +199,12 @@
|
|||
{/each}
|
||||
</select>
|
||||
{/if}
|
||||
<select bind:value={filterChecked} style="width:auto">
|
||||
<option value="">All</option>
|
||||
<option value="false">Not ready</option>
|
||||
<option value="true">Ready</option>
|
||||
<select bind:value={filterStatus} style="width:auto">
|
||||
<option value="">All statuses</option>
|
||||
<option value="unconfirmed">Unconfirmed</option>
|
||||
<option value="registered">Registered</option>
|
||||
<option value="confirmed">Confirmed</option>
|
||||
<option value="ready">Ready</option>
|
||||
</select>
|
||||
<span class="text-muted" style="font-size:0.85rem;white-space:nowrap">
|
||||
{filtered.length} shown
|
||||
|
|
@ -219,7 +239,9 @@
|
|||
<span class="badge badge-lead" style="margin-left:0.4rem">Co-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>
|
||||
<span class="badge badge-unchecked" style="margin-left:0.4rem" title="Not linked to a participant">No ticket</span>
|
||||
{:else if !participantHasTickets(v.participant_id)}
|
||||
<span class="badge badge-partial" style="margin-left:0.4rem" title="Registered as volunteer but no ticket on file">No ticket</span>
|
||||
{/if}
|
||||
{#if v.email}
|
||||
<div class="text-muted" style="font-size:0.78rem">{v.email}</div>
|
||||
|
|
@ -236,9 +258,15 @@
|
|||
{/if}
|
||||
</td>
|
||||
<td class="td-status">
|
||||
<span class="badge {v.checked_in ? 'badge-checked' : v.email_confirmed ? 'badge-confirmed' : 'badge-unchecked'}">
|
||||
{v.checked_in ? 'Ready' : v.email_confirmed ? 'Confirmed' : 'Unconfirmed'}
|
||||
</span>
|
||||
{#if v.checked_in}
|
||||
<span class="badge badge-checked">Ready</span>
|
||||
{:else if v.confirmed}
|
||||
<span class="badge badge-confirmed">Confirmed</span>
|
||||
{:else if v.email_confirmed}
|
||||
<span class="badge badge-registered">Registered</span>
|
||||
{:else}
|
||||
<span class="badge badge-unchecked">Unconfirmed</span>
|
||||
{/if}
|
||||
{#if v.checked_in_at}
|
||||
<div class="text-muted" style="font-size:0.75rem">
|
||||
{new Date(v.checked_in_at).toLocaleTimeString()}
|
||||
|
|
@ -252,6 +280,9 @@
|
|||
</td>
|
||||
{#if canManage}
|
||||
<td class="td-actions">
|
||||
{#if canConfirm && v.email_confirmed && !v.confirmed && v.department_id}
|
||||
<button class="btn btn-primary btn-sm" onclick={() => confirmVolunteer(v)}>Confirm</button>
|
||||
{/if}
|
||||
<button class="btn btn-ghost btn-sm" onclick={() => toggleLead(v)}
|
||||
title={v.is_lead ? 'Remove co-lead' : 'Mark as co-lead'}>
|
||||
{v.is_lead ? '− Co-Lead' : '+ Co-Lead'}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue