Visitor sign in kiosk: multi-site, badge printing, WWCC expiry warnings, admin accounts with 2FA

This commit is contained in:
2026-09-03 14:43:03 +10:00
parent 8c97c314e0
commit e6731dbdfa
11 changed files with 169 additions and 31 deletions
+20 -3
View File
@@ -175,7 +175,8 @@ async function loadOnsite() {
(v) => `<tr>
<td>${v.hasPhoto ? `<img class="thumb" src="/admin/api/photo/${v.id}" alt="">` : ''}</td>
<td><strong>${esc(v.firstName)} ${esc(v.lastName)}</strong>
${v.visitorType === 'frequent' ? '<span class="pill">Recurring</span>' : ''}</td>
${v.visitorType === 'frequent' ? '<span class="pill">Recurring</span>' : ''}
${v.company ? `<small>${esc(v.company)}</small>` : ''}</td>
${showSite ? `<td>${esc(v.siteName || '—')}</td>` : ''}
<td>${esc(v.hostName)}</td>
<td>${v.checkType === 'NONE' ? '<span class="pill off">None</span>' : `${esc(v.checkType)} ${esc(v.checkNumber || '')}`}</td>
@@ -220,7 +221,8 @@ async function loadLog() {
rows.map(
(v) => `<tr>
${showSite ? `<td>${esc(v.siteName || '—')}</td>` : ''}
<td>${esc(v.firstName)} ${esc(v.lastName)}</td>
<td>${esc(v.firstName)} ${esc(v.lastName)}
${v.company ? `<small>${esc(v.company)}</small>` : ''}</td>
<td>${esc(v.hostName)}</td>
<td>${v.checkType === 'NONE' ? '—' : `${esc(v.checkType)} ${esc(v.checkNumber || '')}`}</td>
<td>${esc(v.phone || v.email || '—')}</td>
@@ -258,6 +260,7 @@ async function loadRecurring() {
rows.map(
(p) => `<tr class="${p.expiry.status === 'expired' ? 'row-bad' : p.expiry.status === 'expiring' ? 'row-warn' : ''}">
<td><strong>${esc(p.firstName)} ${esc(p.lastName)}</strong>
${p.company ? `<small>${esc(p.company)}</small>` : ''}
${p.email ? `<small>${esc(p.email)}</small>` : ''}</td>
<td class="mono">${esc(p.phone)}</td>
<td>${p.siteId ? esc(siteName(p.siteId)) : '<span class="pill off">Any site</span>'}</td>
@@ -470,6 +473,7 @@ function openRecurringModal(person = null) {
`
${field('First name', 'firstName', person?.firstName)}
${field('Last name', 'lastName', person?.lastName)}
${field('Company or organisation (optional)', 'company', person?.company)}
${field('Mobile number (their username)', 'phone', person?.phone, 'tel')}
${field('Email address', 'email', person?.email, 'email')}
<label class="modal-field"><span>Check held</span>
@@ -1155,7 +1159,20 @@ async function loadSystem() {
s.sheets.enabled
? `<dt>On the sheet</dt><dd>${
s.sheets.onSiteCount === null ? 'Not written yet' : `${s.sheets.onSiteCount} on site`
}, last written ${stamp(s.sheets.lastOk)}</dd>`
}, last written ${stamp(s.sheets.lastOk)}</dd>
<dt>Service account</dt>
<dd>${
s.sheets.serviceAccount
? `<code>${esc(s.sheets.serviceAccount)}</code>
<br><span class="hint">The spreadsheet must be shared with this address, with Editor access.</span>`
: '<span class="pill bad">No key file could be read</span>'
}</dd>
<dt>Spreadsheet</dt>
<dd>${
s.sheets.spreadsheetId
? `<a href="https://docs.google.com/spreadsheets/d/${esc(s.sheets.spreadsheetId)}/edit" target="_blank" rel="noopener">open the sheet</a>`
: '<span class="pill warn">SHEETS_SPREADSHEET_ID is not set</span>'
}</dd>`
: ''
}
</dl>