Switch to phone auth via Twilio SMS and add feature flag system
Replace email-based auth (Resend) with phone-based auth (Twilio SMS). Add BBQ_FEATURES env var for toggling features at deploy time — when auth is disabled, no login routes are registered and the app works as before. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
{{template "layout" .}}
|
||||
|
||||
{{define "title"}}bbq — my events{{end}}
|
||||
|
||||
{{define "content"}}
|
||||
<div class="event-header">
|
||||
<div class="event-tag">Dashboard</div>
|
||||
<h1 class="event-title">My events</h1>
|
||||
<p style="font-family:'DM Mono',monospace;font-size:0.8rem;color:#555;margin-top:8px;">
|
||||
Welcome back, {{.User.Name}}.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom:24px;">
|
||||
<a href="/" class="btn-claim" style="text-decoration:none;display:inline-block;">+ Create event</a>
|
||||
</div>
|
||||
|
||||
{{if .Events}}
|
||||
<div class="slots-grid">
|
||||
{{range .Events}}
|
||||
<div class="slot-card">
|
||||
<div class="slot-info">
|
||||
<div class="slot-name">{{.Title}}</div>
|
||||
<div style="font-family:'DM Mono',monospace;font-size:0.72rem;color:#555;">
|
||||
{{.Date}} · {{.Time}} · {{.Location}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="slot-right">
|
||||
<a href="/e/{{.Slug}}/admin/{{.AdminToken}}" class="btn-claim" style="text-decoration:none;">Manage</a>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{else}}
|
||||
<p class="nobody" style="text-align:center;padding:40px 0;">No events yet. Create one above!</p>
|
||||
{{end}}
|
||||
{{end}}
|
||||
@@ -49,7 +49,7 @@
|
||||
hx-on::after-request="if(event.detail.successful) this.reset()">
|
||||
<div class="form-row">
|
||||
<label>Your name</label>
|
||||
<input type="text" name="name" placeholder="e.g. Sam" required>
|
||||
<input type="text" name="name" placeholder="e.g. Sam" required value="{{if .User}}{{.User.Name}}{{end}}">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label>Note (optional)</label>
|
||||
@@ -70,7 +70,7 @@
|
||||
hx-on::after-request="if(event.detail.successful) this.reset()">
|
||||
<div class="form-row">
|
||||
<label>Your name</label>
|
||||
<input type="text" name="name" placeholder="e.g. Sam" required>
|
||||
<input type="text" name="name" placeholder="e.g. Sam" required value="{{if .User}}{{.User.Name}}{{end}}">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label>Slot</label>
|
||||
|
||||
@@ -386,6 +386,9 @@
|
||||
{{block "admin-bar" .}}{{end}}
|
||||
<header>
|
||||
<a class="logo" href="/"><span>🍚</span> bbq</a>
|
||||
<nav style="font-family:'DM Mono',monospace;font-size:0.75rem;">
|
||||
{{if .User}}<a href="/dashboard" style="color:var(--ink);text-decoration:none;margin-right:12px;">{{.User.Name}}</a><form method="POST" action="/logout" style="display:inline;"><button type="submit" style="background:none;border:none;font-family:inherit;font-size:inherit;cursor:pointer;text-decoration:underline;">log out</button></form>{{else if .AuthEnabled}}<a href="/login" style="color:var(--ink);text-decoration:underline;">log in</a>{{end}}
|
||||
</nav>
|
||||
</header>
|
||||
<main>
|
||||
{{block "content" .}}{{end}}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
{{template "layout" .}}
|
||||
|
||||
{{define "title"}}bbq — log in{{end}}
|
||||
|
||||
{{define "content"}}
|
||||
<div class="event-header">
|
||||
<div class="event-tag">Account</div>
|
||||
<h1 class="event-title">Log in</h1>
|
||||
<p style="font-family:'DM Mono',monospace;font-size:0.8rem;color:#555;margin-top:8px;">
|
||||
Enter your phone number to receive a login code.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="claim-form-wrapper">
|
||||
{{if eq .Step "phone"}}
|
||||
<form method="POST" action="/login">
|
||||
<div class="form-row">
|
||||
<label>Phone</label>
|
||||
<input type="tel" name="phone" placeholder="(555) 123-4567" required autofocus>
|
||||
</div>
|
||||
<button class="btn-submit" type="submit">Send code ↗</button>
|
||||
</form>
|
||||
{{else}}
|
||||
<form method="POST" action="/login/verify">
|
||||
<input type="hidden" name="phone" value="{{.Phone}}">
|
||||
<p style="font-family:'DM Mono',monospace;font-size:0.78rem;color:#555;margin-bottom:16px;">
|
||||
Code sent to <strong>{{.Phone}}</strong>
|
||||
</p>
|
||||
{{if .Error}}
|
||||
<p style="color:#c44;font-size:0.85rem;margin-bottom:12px;">{{.Error}}</p>
|
||||
{{end}}
|
||||
<div class="form-row">
|
||||
<label>6-digit code</label>
|
||||
<input type="text" name="code" placeholder="000000" required autofocus
|
||||
inputmode="numeric" pattern="[0-9]{6}" maxlength="6"
|
||||
style="font-family:'DM Mono',monospace;font-size:1.5rem;letter-spacing:8px;text-align:center;">
|
||||
</div>
|
||||
<button class="btn-submit" type="submit">Verify ↗</button>
|
||||
</form>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
@@ -0,0 +1,24 @@
|
||||
{{template "layout" .}}
|
||||
|
||||
{{define "title"}}bbq — your name{{end}}
|
||||
|
||||
{{define "content"}}
|
||||
<div class="event-header">
|
||||
<div class="event-tag">Account</div>
|
||||
<h1 class="event-title">What's your name?</h1>
|
||||
<p style="font-family:'DM Mono',monospace;font-size:0.8rem;color:#555;margin-top:8px;">
|
||||
This will be used to autofill your name when you RSVP or claim a slot.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="claim-form-wrapper">
|
||||
<form method="POST" action="/account/name">
|
||||
<div class="form-row">
|
||||
<label>Name</label>
|
||||
<input type="text" name="name" placeholder="Your name" required autofocus
|
||||
value="{{if .User}}{{.User.Name}}{{end}}">
|
||||
</div>
|
||||
<button class="btn-submit" type="submit">Save ↗</button>
|
||||
</form>
|
||||
</div>
|
||||
{{end}}
|
||||
Reference in New Issue
Block a user