Add edit RSVP modal, plus-one tracking, and unified signup form
Merge RSVP + slot claim into a single form. Add plus_one field to RSVPs. Add clickable RSVP names that open a modal to edit name/note/plus_one. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
{{define "edit-rsvp"}}
|
||||
<div class="modal-backdrop" onclick="if(event.target===this)document.getElementById('edit-modal').innerHTML=''">
|
||||
<div class="modal-card">
|
||||
<div class="form-title">Edit RSVP</div>
|
||||
<form hx-put="/e/{{.Slug}}/rsvp/{{.Rsvp.ID}}"
|
||||
hx-target="#slots-container"
|
||||
hx-swap="innerHTML settle:0.1s">
|
||||
<div class="form-row">
|
||||
<label>Your name</label>
|
||||
<input type="text" name="name" value="{{.Rsvp.Name}}" required>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label>Bringing anyone?</label>
|
||||
<input type="number" name="plus_one" value="{{.Rsvp.PlusOne}}" min="0" max="10">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label>Note (optional)</label>
|
||||
<input type="text" name="note" value="{{.Rsvp.Note}}">
|
||||
</div>
|
||||
<button class="btn-submit" type="submit">Save</button>
|
||||
<div style="text-align:center;margin-top:12px;">
|
||||
<button type="button" class="btn-cancel" onclick="document.getElementById('edit-modal').innerHTML=''">Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
+12
-27
@@ -51,43 +51,28 @@
|
||||
<label>Your name</label>
|
||||
<input type="text" name="name" placeholder="e.g. Sam" required value="{{if .User}}{{.User.Name}}{{end}}">
|
||||
</div>
|
||||
{{if .Slots}}
|
||||
<div class="form-row">
|
||||
<label>Note (optional)</label>
|
||||
<input type="text" name="note" placeholder="e.g. +1, arriving late, etc.">
|
||||
</div>
|
||||
<button class="btn-submit" type="submit">Count me in ↗</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{{if .Slots}}
|
||||
<div class="section-label" style="margin-top:40px">I'll bring something</div>
|
||||
|
||||
<div class="claim-form-wrapper">
|
||||
<div class="form-title">Claim a slot →</div>
|
||||
<form hx-post="/e/{{.Event.Slug}}/claim"
|
||||
hx-target="#slots-container"
|
||||
hx-swap="innerHTML settle:0.1s"
|
||||
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 value="{{if .User}}{{.User.Name}}{{end}}">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label>Slot</label>
|
||||
<select name="slot_id">
|
||||
<label>Bringing something?</label>
|
||||
<select name="slot_id" onchange="document.getElementById('claim-note').style.display = this.value ? '' : 'none'; document.getElementById('claim-note-input').placeholder = this.value ? 'e.g. bringing sparkling water + lemonade' : 'e.g. +1, arriving late, etc.'">
|
||||
<option value="">Just myself</option>
|
||||
{{range .Slots}}{{if not .IsFull}}
|
||||
<option value="{{.Slot.ID}}">{{.Slot.Emoji}} {{.Slot.Name}} ({{$left := sub .Slot.MaxClaims .ClaimCount}}{{$left}} spot{{if ne $left 1}}s{{end}} left)</option>
|
||||
{{end}}{{end}}
|
||||
</select>
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="form-row">
|
||||
<label>Note (optional)</label>
|
||||
<input type="text" name="note" placeholder="e.g. bringing sparkling water + lemonade">
|
||||
<label>Bringing anyone?</label>
|
||||
<input type="number" name="plus_one" value="0" min="0" max="10">
|
||||
</div>
|
||||
<button class="btn-submit" type="submit">Claim ↗</button>
|
||||
<div class="form-row" id="claim-note">
|
||||
<label>Note (optional)</label>
|
||||
<input type="text" id="claim-note-input" name="note" placeholder="e.g. arriving late, dietary restrictions, etc.">
|
||||
</div>
|
||||
<button class="btn-submit" type="submit">Count me in ↗</button>
|
||||
</form>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{if .IsAdmin}}
|
||||
<div class="section-label" style="margin-top:40px">Admin: Description</div>
|
||||
|
||||
@@ -372,6 +372,40 @@
|
||||
text-decoration: underline;
|
||||
}
|
||||
.btn-danger:hover { color: #a00; }
|
||||
.modal-backdrop {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0,0,0,0.45);
|
||||
z-index: 90;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 24px;
|
||||
}
|
||||
.modal-card {
|
||||
background: white;
|
||||
border: var(--border-w) solid var(--border);
|
||||
box-shadow: 5px 5px 0 var(--ink);
|
||||
padding: 24px;
|
||||
max-width: 480px;
|
||||
width: 100%;
|
||||
animation: fadeUp 0.2s ease both;
|
||||
}
|
||||
.btn-cancel {
|
||||
background: none;
|
||||
border: none;
|
||||
font-family: 'DM Mono', monospace;
|
||||
font-size: 0.78rem;
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
color: #888;
|
||||
}
|
||||
.btn-cancel:hover { color: var(--ink); }
|
||||
.rsvp-name-link {
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
}
|
||||
.rsvp-name-link:hover { text-decoration: underline; }
|
||||
@keyframes fadeUp {
|
||||
from { opacity: 0; transform: translateY(16px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
@@ -438,6 +472,10 @@ document.addEventListener('click', (e) => {
|
||||
}
|
||||
});
|
||||
document.addEventListener('DOMContentLoaded', initEmojiPickers);
|
||||
document.body.addEventListener('closeModal', function() {
|
||||
document.getElementById('edit-modal').innerHTML = '';
|
||||
});
|
||||
</script>
|
||||
<div id="edit-modal"></div>
|
||||
</body>
|
||||
</html>{{end}}
|
||||
|
||||
@@ -37,7 +37,10 @@
|
||||
{{if .GoingList}}
|
||||
{{range .GoingList}}
|
||||
<span class="claim-chip">
|
||||
{{.Name}}{{if .Note}} <small style="color:#888">({{.Note}})</small>{{end}}
|
||||
{{if gt .RsvpID 0}}<span class="rsvp-name-link"
|
||||
hx-get="/e/{{$.Event.Slug}}/rsvp/{{.RsvpID}}/edit"
|
||||
hx-target="#edit-modal"
|
||||
hx-swap="innerHTML">{{.Name}}</span>{{else}}{{.Name}}{{end}}{{if gt .PlusOne 0}} +{{.PlusOne}}{{end}}{{if .Note}} <small style="color:#888">({{.Note}})</small>{{end}}
|
||||
{{if gt .RsvpID 0}}
|
||||
<button hx-delete="/e/{{$.Event.Slug}}/rsvp/{{.RsvpID}}"
|
||||
hx-target="#slots-container"
|
||||
|
||||
Reference in New Issue
Block a user