From f1b10e172c2a028d73648c2355c343cc4ae685b3 Mon Sep 17 00:00:00 2001 From: collin Date: Mon, 30 Jun 2025 12:37:33 +0200 Subject: [PATCH] Finishing up rsvp creation and confirmation from clients --- client/rsvp.html | 30 +++++++++------ client/rsvp.js | 79 ++++++++++++++++++++++++++++++++++++++ client/rsvp_confirmed.html | 15 ++++++++ client/style.css | 22 ++++++++++- server/controller.go | 39 +++++++++++++++---- server/rsvp.go | 1 - 6 files changed, 165 insertions(+), 21 deletions(-) create mode 100644 client/rsvp.js create mode 100644 client/rsvp_confirmed.html diff --git a/client/rsvp.html b/client/rsvp.html index 44ee632..3aa8896 100644 --- a/client/rsvp.html +++ b/client/rsvp.html @@ -6,23 +6,29 @@

Collin and Lucy's Wedding

-
+

- - + Attending: + + + +

- Age: - - - - -

-

- - + +

+
+
+
+ \ No newline at end of file diff --git a/client/rsvp.js b/client/rsvp.js new file mode 100644 index 0000000..d66f6d0 --- /dev/null +++ b/client/rsvp.js @@ -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); +}; diff --git a/client/rsvp_confirmed.html b/client/rsvp_confirmed.html new file mode 100644 index 0000000..c49f81f --- /dev/null +++ b/client/rsvp_confirmed.html @@ -0,0 +1,15 @@ + + + + + + +

Collin and Lucy's Wedding

+
+ See you there! +
+ Back +
+ + + \ No newline at end of file diff --git a/client/style.css b/client/style.css index 3cbd9ff..b4403d0 100644 --- a/client/style.css +++ b/client/style.css @@ -146,7 +146,7 @@ body { } } -/* #endregion +/* #endregion */ /* #region rsvp */ .rsvpButton { @@ -161,4 +161,24 @@ body { 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 */ \ No newline at end of file diff --git a/server/controller.go b/server/controller.go index baf807f..b4b0b88 100644 --- a/server/controller.go +++ b/server/controller.go @@ -2,10 +2,10 @@ package main import ( "database/sql" - "encoding/json" "fmt" "net/http" "os" + "strconv" "time" ) @@ -24,7 +24,6 @@ func getStaticFile(relPath string, contentType string, w http.ResponseWriter) { w.Header().Add("Content-Type", contentType) w.WriteHeader(http.StatusOK) - fmt.Printf("%s\n", w.Header().Get("Content-Type")) 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": 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": 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": 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) case r.Method == "POST" && r.URL.Path == "/api/rsvps": - var rsvp Rsvp - - err := json.NewDecoder(r.Body).Decode(&rsvp) + err := r.ParseForm() if err != nil { fmt.Println(err) @@ -66,8 +69,29 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 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) - fmt.Printf("%#v\n", rsvp) if err != nil { fmt.Println(err) @@ -78,7 +102,8 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if h.ntfy != nil { SendRsvpNotification(h.ntfy, &rsvp) } - w.WriteHeader(http.StatusAccepted) + w.Header().Add("Location", "/rsvp_confirmed") + w.WriteHeader(http.StatusSeeOther) default: w.WriteHeader(http.StatusNotFound) } diff --git a/server/rsvp.go b/server/rsvp.go index 2cfdb66..1ed32e6 100644 --- a/server/rsvp.go +++ b/server/rsvp.go @@ -78,7 +78,6 @@ func (rsvp *Rsvp) CreateRsvp(db *sql.DB) (int64, error) { if err != nil { return -1, err } - fmt.Printf("%s\n", partyMembersBytes) result, err := db.Exec( "INSERT INTO rsvps (attending, partySize, partyMembers) VALUES (?, ?, ?);",