Finishing up rsvp creation and confirmation from clients
This commit is contained in:
parent
78e24f2757
commit
b009a89de9
6 changed files with 165 additions and 21 deletions
|
|
@ -6,23 +6,29 @@
|
||||||
<body>
|
<body>
|
||||||
<h1 class="title fontXL textCenter backgroundLightGreen colorWhite">Collin and Lucy's Wedding</h1>
|
<h1 class="title fontXL textCenter backgroundLightGreen colorWhite">Collin and Lucy's Wedding</h1>
|
||||||
<div class="contents fontM">
|
<div class="contents fontM">
|
||||||
<form action="/api/rsvp" method="post">
|
<form id="rsvps" action="/api/rsvps" method="post">
|
||||||
<p>
|
<p>
|
||||||
<label for="name-0">Name:</label>
|
Attending:
|
||||||
<input type="text" id="name-0" name="name"/>
|
<label for="attending-yes">Yes</label>
|
||||||
|
<input type="radio" id="attending-yes" name="attending" value="true" required/>
|
||||||
|
<label for="attending-no">No</label>
|
||||||
|
<input type="radio" id="attending-no" name="attending" value="false" required/>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Age:
|
<label for="party-size">Party Size:</label>
|
||||||
<label for="age-child-0">Child</label>
|
<select name="party-size" name="party-size" id="party-size">
|
||||||
<input type="radio" id="age-child-0" name="child" value="true"/>
|
<option value="1">1</option>
|
||||||
<label for="age-adult-0">Adult</label>
|
<option value="2">2</option>
|
||||||
<input type="radio" id="age-adult-0" name="child" value="false"/>
|
<option value="3">3</option>
|
||||||
</p>
|
<option value="4">4</option>
|
||||||
<p>
|
<option value="5">5</option>
|
||||||
<label for="diet-0">Dietary preferences:</label>
|
</select>
|
||||||
<textarea id="diet-0" name="dietaryPreferences"></textarea>
|
|
||||||
</p>
|
</p>
|
||||||
|
<div class="members">
|
||||||
|
</div>
|
||||||
|
<button>RSVP</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
<script src="/rsvp.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
79
client/rsvp.js
Normal file
79
client/rsvp.js
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
let partySize = 0;
|
||||||
|
|
||||||
|
function createNewMember(id) {
|
||||||
|
const memberDiv = document.createElement("div");
|
||||||
|
memberDiv.classList.add("member");
|
||||||
|
|
||||||
|
const innerDiv = document.createElement("div");
|
||||||
|
|
||||||
|
const nameP = document.createElement("p");
|
||||||
|
|
||||||
|
const nameLabel = document.createElement("label");
|
||||||
|
nameLabel.htmlFor = `name-${id}`;
|
||||||
|
nameLabel.innerHTML = "Name:";
|
||||||
|
|
||||||
|
const nameInput = document.createElement("input");
|
||||||
|
nameInput.type = "text";
|
||||||
|
nameInput.id = `name-${id}`;
|
||||||
|
nameInput.name = `name-${id}`;
|
||||||
|
nameInput.required = true;
|
||||||
|
|
||||||
|
nameP.appendChild(nameLabel);
|
||||||
|
nameP.appendChild(nameInput);
|
||||||
|
|
||||||
|
const childP = document.createElement("p");
|
||||||
|
|
||||||
|
const childLabel = document.createElement("label");
|
||||||
|
childLabel.htmlFor = `child-${id}`;
|
||||||
|
childLabel.innerHTML = "Child:";
|
||||||
|
|
||||||
|
const childInput = document.createElement("input");
|
||||||
|
childInput.type = "checkbox";
|
||||||
|
childInput.id = `child-${id}`;
|
||||||
|
childInput.name = `child-${id}`;
|
||||||
|
|
||||||
|
childP.appendChild(childLabel);
|
||||||
|
childP.appendChild(childInput);
|
||||||
|
|
||||||
|
innerDiv.appendChild(nameP);
|
||||||
|
innerDiv.appendChild(childP);
|
||||||
|
|
||||||
|
const dietP = document.createElement("p");
|
||||||
|
|
||||||
|
const dietLabel = document.createElement("label");
|
||||||
|
dietLabel.htmlFor = `diet-${id}`;
|
||||||
|
dietLabel.innerHTML = "Dietary preferences:";
|
||||||
|
|
||||||
|
const dietInput = document.createElement("textarea");
|
||||||
|
dietInput.id = `diet-${id}`;
|
||||||
|
dietInput.name = `dietaryPreferences-${id}`;
|
||||||
|
|
||||||
|
dietP.appendChild(dietLabel);
|
||||||
|
dietP.appendChild(dietInput);
|
||||||
|
|
||||||
|
memberDiv.appendChild(innerDiv);
|
||||||
|
memberDiv.appendChild(dietP);
|
||||||
|
|
||||||
|
document.querySelector("div.members").appendChild(memberDiv);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updatePartySize(newPartySize) {
|
||||||
|
if (newPartySize > partySize) {
|
||||||
|
for (let i = partySize; i < newPartySize; i++) {
|
||||||
|
createNewMember(partySize);
|
||||||
|
}
|
||||||
|
} else if (newPartySize < partySize) {
|
||||||
|
for (let i = partySize; i > newPartySize; i--) {
|
||||||
|
document.querySelector("div.members").lastChild.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
partySize = newPartySize;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.onload = function () {
|
||||||
|
const partySizeDropdown = document.querySelector("select#party-size");
|
||||||
|
partySizeDropdown.addEventListener("change", () => {
|
||||||
|
updatePartySize(Number.parseInt(partySizeDropdown.value));
|
||||||
|
});
|
||||||
|
updatePartySize(1);
|
||||||
|
};
|
||||||
15
client/rsvp_confirmed.html
Normal file
15
client/rsvp_confirmed.html
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1 class="title fontXL textCenter backgroundLightGreen colorWhite">Collin and Lucy's Wedding</h1>
|
||||||
|
<div class="contents fontM">
|
||||||
|
See you there!
|
||||||
|
<br/>
|
||||||
|
<a href="/">Back</a>
|
||||||
|
</div>
|
||||||
|
<script src="/rsvp_confirmed.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -146,7 +146,7 @@ body {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* #endregion
|
/* #endregion */
|
||||||
|
|
||||||
/* #region rsvp */
|
/* #region rsvp */
|
||||||
.rsvpButton {
|
.rsvpButton {
|
||||||
|
|
@ -161,4 +161,24 @@ body {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
form#rsvps {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
form#rsvps div#members {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
form#rsvps div.members {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
form#rsvps div.members div.member div {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
/* #endregion */
|
/* #endregion */
|
||||||
|
|
@ -2,10 +2,10 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -24,7 +24,6 @@ func getStaticFile(relPath string, contentType string, w http.ResponseWriter) {
|
||||||
|
|
||||||
w.Header().Add("Content-Type", contentType)
|
w.Header().Add("Content-Type", contentType)
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
fmt.Printf("%s\n", w.Header().Get("Content-Type"))
|
|
||||||
w.Write(file)
|
w.Write(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -38,9 +37,15 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
case r.Method == "GET" && r.URL.Path == "/rsvp":
|
case r.Method == "GET" && r.URL.Path == "/rsvp":
|
||||||
getStaticFile("../client/rsvp.html", "text/html", w)
|
getStaticFile("../client/rsvp.html", "text/html", w)
|
||||||
|
|
||||||
|
case r.Method == "GET" && r.URL.Path == "/rsvp_confirmed":
|
||||||
|
getStaticFile("../client/rsvp_confirmed.html", "text/html", w)
|
||||||
|
|
||||||
case r.Method == "GET" && r.URL.Path == "/index.js":
|
case r.Method == "GET" && r.URL.Path == "/index.js":
|
||||||
getStaticFile("../client/index.js", "text/javascript", w)
|
getStaticFile("../client/index.js", "text/javascript", w)
|
||||||
|
|
||||||
|
case r.Method == "GET" && r.URL.Path == "/rsvp.js":
|
||||||
|
getStaticFile("../client/rsvp.js", "text/javascript", w)
|
||||||
|
|
||||||
case r.Method == "GET" && r.URL.Path == "/style.css":
|
case r.Method == "GET" && r.URL.Path == "/style.css":
|
||||||
getStaticFile("../client/style.css", "text/css", w)
|
getStaticFile("../client/style.css", "text/css", w)
|
||||||
|
|
||||||
|
|
@ -56,9 +61,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
fmt.Fprintf(w, "%#v", rsvps)
|
fmt.Fprintf(w, "%#v", rsvps)
|
||||||
|
|
||||||
case r.Method == "POST" && r.URL.Path == "/api/rsvps":
|
case r.Method == "POST" && r.URL.Path == "/api/rsvps":
|
||||||
var rsvp Rsvp
|
err := r.ParseForm()
|
||||||
|
|
||||||
err := json.NewDecoder(r.Body).Decode(&rsvp)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
|
|
@ -66,8 +69,29 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
attending := r.Form.Get("attending") == "true"
|
||||||
|
partySize, err := strconv.ParseInt(r.Form.Get("party-size"), 10, 1)
|
||||||
|
|
||||||
|
partyMembers := make([]Member, partySize)
|
||||||
|
for i := range partySize {
|
||||||
|
name := r.Form.Get(fmt.Sprintf("name-%d", i))
|
||||||
|
child := r.Form.Has(fmt.Sprintf("child-%d", i)) && r.Form.Get(fmt.Sprintf("child-%d", i)) == "true"
|
||||||
|
dietaryPreferences := r.Form.Get(fmt.Sprintf("diet-%d", i))
|
||||||
|
member := Member{
|
||||||
|
Name: name,
|
||||||
|
Child: child,
|
||||||
|
DietaryPreferences: dietaryPreferences,
|
||||||
|
}
|
||||||
|
partyMembers[i] = member
|
||||||
|
}
|
||||||
|
|
||||||
|
rsvp := Rsvp{
|
||||||
|
Attending: attending,
|
||||||
|
PartySize: partySize,
|
||||||
|
PartyMembers: partyMembers,
|
||||||
|
}
|
||||||
|
|
||||||
_, err = rsvp.CreateRsvp(h.db)
|
_, err = rsvp.CreateRsvp(h.db)
|
||||||
fmt.Printf("%#v\n", rsvp)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
|
|
@ -78,7 +102,8 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
if h.ntfy != nil {
|
if h.ntfy != nil {
|
||||||
SendRsvpNotification(h.ntfy, &rsvp)
|
SendRsvpNotification(h.ntfy, &rsvp)
|
||||||
}
|
}
|
||||||
w.WriteHeader(http.StatusAccepted)
|
w.Header().Add("Location", "/rsvp_confirmed")
|
||||||
|
w.WriteHeader(http.StatusSeeOther)
|
||||||
default:
|
default:
|
||||||
w.WriteHeader(http.StatusNotFound)
|
w.WriteHeader(http.StatusNotFound)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,6 @@ func (rsvp *Rsvp) CreateRsvp(db *sql.DB) (int64, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
fmt.Printf("%s\n", partyMembersBytes)
|
|
||||||
|
|
||||||
result, err := db.Exec(
|
result, err := db.Exec(
|
||||||
"INSERT INTO rsvps (attending, partySize, partyMembers) VALUES (?, ?, ?);",
|
"INSERT INTO rsvps (attending, partySize, partyMembers) VALUES (?, ?, ?);",
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue