From de2216611365cbce223f7ae07c9faea5f470dcf8 Mon Sep 17 00:00:00 2001 From: bronku Date: Sun, 8 Nov 2026 19:05:53 +0100 Subject: [PATCH] order validation --- css/swieta.css | 6 ++-- html/swieta.templ | 11 +++--- js/order.js | 17 +++++++++ main.go | 6 +++- orders/order.go | 74 ++++++++++++++++++++++++++++++++++++++ orders/phone_validation.go | 57 +++++++++++++++++++++++++++++ 6 files changed, 164 insertions(+), 7 deletions(-) create mode 100644 orders/order.go create mode 100644 orders/phone_validation.go diff --git a/css/swieta.css b/css/swieta.css index fc43cc5..3ab85c8 100644 --- a/css/swieta.css +++ b/css/swieta.css @@ -223,7 +223,7 @@ } } - & > input, & > fieldset { + & > input, & > fieldset, & > span{ background-color: var(--surface); } & input:focus{ @@ -238,7 +238,9 @@ border: 1px solid var(--border-color); } & > button { - grid-column: -1 / 1; + &:hover { + opacity: 0.9; + } background-color: var(--swieta-red); color: var(--surface); } diff --git a/html/swieta.templ b/html/swieta.templ index 82ac8ea..e69f6ee 100644 --- a/html/swieta.templ +++ b/html/swieta.templ @@ -12,7 +12,7 @@ templ product_form(product types.Product) {
{product.Name} · {product.Price} zł - +
} @@ -53,16 +53,19 @@ templ Swieta(products []types.Product) {

Złóż zamówienie

Odbiór wszystkich zamówień: 24 grudnia. Zamówienia przyjmujemy do 15 grudnia. Potwierdzimy zamówienie telefonicznie.

-
+

Wszystkie zamówienia obejmuje zaliczka o wysokości 50zł.

+ + +
for _, product := range products { @product_form(product) }
- - + Wartość zamówienia: 0
+

Po kliknięciu przycisku wyślij zamówienie, nastąpi przekierowanie do wpłaty zaliczki. Kwota zaliczki wynosi 50zł. Po potwierdzeniu wpłaty otrzymasz numer zamówienia.

diff --git a/js/order.js b/js/order.js index 0d93940..fe503de 100644 --- a/js/order.js +++ b/js/order.js @@ -1,16 +1,33 @@ +function calculate_total() { + var total = 0 + items = document.getElementsByClassName("order_item") + for (const item of items){ + price = parseInt(item.dataset.price) + count = parseFloat(item.value) + total += count * price + } + document.getElementById("total_price").innerText = total + "zł" +} + function min(a, b) { if (a > b) { return a } return b } + function increase(id) { input = document.getElementById(id) step = parseFloat(input.step) input.value= min(parseFloat(input.value)+step, 0) + calculate_total() } + function decrease(id) { input = document.getElementById(id) step = parseFloat(input.step) input.value= min(parseFloat(input.value)-step, 0) + calculate_total() } + +calculate_total() diff --git a/main.go b/main.go index d1659f4..88e8b51 100644 --- a/main.go +++ b/main.go @@ -13,6 +13,7 @@ import ( "path/filepath" "piekarnikgosipl/data" "piekarnikgosipl/html" + "piekarnikgosipl/orders" "piekarnikgosipl/utils" "sort" "strings" @@ -206,6 +207,9 @@ func main() { if len(os.Args) > 1 { return } + server := http.ServeMux{} + server.Handle("/", http.FileServer(http.Dir("www"))) + server.HandleFunc("POST /order/", orders.OrderHandler) log.Println("listening on :8000") - log.Fatal(http.ListenAndServe(":8000", http.FileServer(http.Dir("www")))) + log.Fatal(http.ListenAndServe(":8000", &server)) } diff --git a/orders/order.go b/orders/order.go new file mode 100644 index 0000000..50ccc7e --- /dev/null +++ b/orders/order.go @@ -0,0 +1,74 @@ +package orders + +import ( + "errors" + "fmt" + "log" + "math" + "net/http" + "piekarnikgosipl/data" + "strconv" +) + +type listItem struct { + id string + count int // count multiplied by 100 to allow for half item purchases +} + +type order struct { + name string + phone string + items []listItem +} + +func parseFloat(input string) (int, error) { + val, err := strconv.ParseFloat(input, 64) + if err != nil { + return 0, fmt.Errorf("Invalid float format") + } + + if val < 0 || val > 100 { + return 0, fmt.Errorf("Value must be between 0 and 100") + } + + doubled := val * 2 + if math.Abs(doubled-math.Round(doubled)) > 1e-9 { + return 0, fmt.Errorf("Value must be a multiple of 0.5") + } + + return int(math.Round(val * 100)), nil + +} + +func parseOrder(r *http.Request) (order, error) { + var o order + var err error + var errorList []error + o.name = r.PostFormValue("name") + if o.name == "" { + errorList = append(errorList, fmt.Errorf("Invalid name")) + } + o.phone, err = parseAndValidatePolishMobile(r.PostFormValue("phone")) + if err != nil { + errorList = append(errorList, err) + } + for _, item := range data.Swieta { + count, err := parseFloat(r.PostFormValue(item.Id)) + if err != nil { + errorList = append(errorList, fmt.Errorf("Can't parse the count for %v: %e", item.Name, err)) + continue + } + if count%10 == 5 && !item.Halveable { + errorList = append(errorList, fmt.Errorf("This item can't be bought in fractions %v", item.Name)) + continue + } + o.items = append(o.items, listItem{item.Id, count}) + } + return o, errors.Join(errorList...) +} + +func OrderHandler(w http.ResponseWriter, r *http.Request) { + o, err := parseOrder(r) + log.Println(o, err) + fmt.Fprintf(w, "%v, %v", o, err) +} diff --git a/orders/phone_validation.go b/orders/phone_validation.go new file mode 100644 index 0000000..eff5c8e --- /dev/null +++ b/orders/phone_validation.go @@ -0,0 +1,57 @@ +package orders + +import ( + "fmt" + "regexp" + "strings" +) + +func isValidPolishMobile(nineDigitNum string) bool { + if len(nineDigitNum) != 9 { + return false + } + + firstDigit := nineDigitNum[0] + + if firstDigit < '4' || firstDigit > '8' { + return false + } + + prefix2 := nineDigitNum[:2] + validPrefixes := map[string]bool{ + "45": true, + "50": true, "51": true, "53": true, "57": true, + "60": true, "66": true, "69": true, + "72": true, "73": true, "78": true, "79": true, + "88": true, + } + + return validPrefixes[prefix2] +} + +func parseAndValidatePolishMobile(input string) (string, error) { + input = strings.TrimSpace(input) + + if strings.HasPrefix(input, "+48") { + input = strings.TrimPrefix(input, "+48") + } else if strings.HasPrefix(input, "0048") { + input = strings.TrimPrefix(input, "0048") + } + + re := regexp.MustCompile(`\D`) + cleaned := re.ReplaceAllString(input, "") + + if len(cleaned) == 11 && strings.HasPrefix(cleaned, "48") { + cleaned = cleaned[2:] + } + + if len(cleaned) != 9 { + return "", fmt.Errorf("invalid length: expected 9 digits, got %d", len(cleaned)) + } + + if !isValidPolishMobile(cleaned) { + return "", fmt.Errorf("invalid mobile prefix: %s does not match Polish mobile allocations", cleaned[:2]) + } + + return cleaned, nil +}