Created Turnpike, event attendee and volunteer management
Built after prototype, Traverse, an attendee and volunteer list maintainer.
This commit is contained in:
commit
1033cdb29b
59 changed files with 8663 additions and 0 deletions
151
frontend/src/pages/Settings.svelte
Normal file
151
frontend/src/pages/Settings.svelte
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
<script>
|
||||
import { onMount } from 'svelte'
|
||||
import { api } from '../api.js'
|
||||
|
||||
let loading = $state(true)
|
||||
let saving = $state(false)
|
||||
let testing = $state(false)
|
||||
let error = $state('')
|
||||
let success = $state('')
|
||||
|
||||
let smtpHost = $state('')
|
||||
let smtpPort = $state(587)
|
||||
let smtpUser = $state('')
|
||||
let smtpPassword = $state('')
|
||||
let smtpFrom = $state('')
|
||||
let smtpFromName = $state('')
|
||||
let baseURL = $state('')
|
||||
let testEmail = $state('')
|
||||
|
||||
onMount(async () => {
|
||||
try {
|
||||
const s = await api.settings.get()
|
||||
smtpHost = s.smtp_host ?? ''
|
||||
smtpPort = s.smtp_port ?? 587
|
||||
smtpUser = s.smtp_user ?? ''
|
||||
smtpPassword = '' // never pre-filled
|
||||
smtpFrom = s.smtp_from ?? ''
|
||||
smtpFromName = s.smtp_from_name ?? ''
|
||||
baseURL = s.base_url ?? ''
|
||||
} catch (err) {
|
||||
error = err.message
|
||||
} finally {
|
||||
loading = false
|
||||
}
|
||||
})
|
||||
|
||||
async function save(e) {
|
||||
e.preventDefault()
|
||||
saving = true
|
||||
error = ''
|
||||
success = ''
|
||||
try {
|
||||
await api.settings.update({
|
||||
smtp_host: smtpHost,
|
||||
smtp_port: smtpPort,
|
||||
smtp_user: smtpUser,
|
||||
smtp_password: smtpPassword, // empty = keep existing
|
||||
smtp_from: smtpFrom,
|
||||
smtp_from_name: smtpFromName,
|
||||
base_url: baseURL,
|
||||
})
|
||||
smtpPassword = ''
|
||||
success = 'Settings saved.'
|
||||
} catch (err) {
|
||||
error = err.message
|
||||
} finally {
|
||||
saving = false
|
||||
}
|
||||
}
|
||||
|
||||
async function sendTest() {
|
||||
if (!testEmail) return
|
||||
testing = true
|
||||
error = ''
|
||||
success = ''
|
||||
try {
|
||||
await api.settings.testEmail(testEmail)
|
||||
success = `Test email sent to ${testEmail}.`
|
||||
} catch (err) {
|
||||
error = err.message
|
||||
} finally {
|
||||
testing = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="page">
|
||||
<div class="page-header">
|
||||
<h1 class="page-title">Settings</h1>
|
||||
</div>
|
||||
|
||||
{#if error}
|
||||
<div class="alert alert-error">{error}</div>
|
||||
{/if}
|
||||
{#if success}
|
||||
<div class="alert alert-success">{success}</div>
|
||||
{/if}
|
||||
|
||||
{#if loading}
|
||||
<div class="text-muted">Loading…</div>
|
||||
{:else}
|
||||
<form onsubmit={save}>
|
||||
<div class="card" style="margin-bottom:1.5rem">
|
||||
<h2 style="font-size:0.95rem;font-weight:700;margin-bottom:1rem">SMTP Email</h2>
|
||||
|
||||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:1rem">
|
||||
<div class="form-group" style="grid-column:1">
|
||||
<label for="s-host">SMTP Host</label>
|
||||
<input id="s-host" bind:value={smtpHost} placeholder="smtp.fastmail.com" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="s-port">Port</label>
|
||||
<input id="s-port" type="number" bind:value={smtpPort} placeholder="587" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="s-user">Username</label>
|
||||
<input id="s-user" bind:value={smtpUser} placeholder="user@example.com" autocomplete="off" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="s-pass">Password</label>
|
||||
<input id="s-pass" type="password" bind:value={smtpPassword}
|
||||
placeholder="Leave blank to keep existing" autocomplete="new-password" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="s-from">From Address</label>
|
||||
<input id="s-from" type="email" bind:value={smtpFrom} placeholder="events@example.com" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="s-fname">From Name</label>
|
||||
<input id="s-fname" bind:value={smtpFromName} placeholder="Event Team" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="s-url">Base URL <span class="text-muted" style="font-weight:400">(for volunteer token links)</span></label>
|
||||
<input id="s-url" bind:value={baseURL} placeholder="https://events.example.com" />
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<button type="submit" class="btn btn-primary" disabled={saving}>
|
||||
{saving ? 'Saving…' : 'Save Settings'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Test email -->
|
||||
<div class="card">
|
||||
<h2 style="font-size:0.95rem;font-weight:700;margin-bottom:1rem">Test Email</h2>
|
||||
<div style="display:flex;gap:0.5rem;align-items:flex-end">
|
||||
<div class="form-group" style="flex:1;margin-bottom:0">
|
||||
<label for="s-test">Send to</label>
|
||||
<input id="s-test" type="email" bind:value={testEmail} placeholder="your@email.com" />
|
||||
</div>
|
||||
<button class="btn btn-ghost" onclick={sendTest} disabled={testing || !testEmail}>
|
||||
{testing ? 'Sending…' : 'Send Test'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
Loading…
Add table
Add a link
Reference in a new issue