order validation
This commit is contained in:
parent
2a4110ee8c
commit
de22166113
6 changed files with 164 additions and 7 deletions
|
|
@ -223,7 +223,7 @@
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
& > input, & > fieldset {
|
& > input, & > fieldset, & > span{
|
||||||
background-color: var(--surface);
|
background-color: var(--surface);
|
||||||
}
|
}
|
||||||
& input:focus{
|
& input:focus{
|
||||||
|
|
@ -238,7 +238,9 @@
|
||||||
border: 1px solid var(--border-color);
|
border: 1px solid var(--border-color);
|
||||||
}
|
}
|
||||||
& > button {
|
& > button {
|
||||||
grid-column: -1 / 1;
|
&:hover {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
background-color: var(--swieta-red);
|
background-color: var(--swieta-red);
|
||||||
color: var(--surface);
|
color: var(--surface);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ templ product_form(product types.Product) {
|
||||||
<div>
|
<div>
|
||||||
<span>{product.Name} <span> · {product.Price} zł</span></span>
|
<span>{product.Name} <span> · {product.Price} zł</span></span>
|
||||||
<button type="button" onClick={templ.JSFuncCall("decrease", product.Id)}> - </button>
|
<button type="button" onClick={templ.JSFuncCall("decrease", product.Id)}> - </button>
|
||||||
<input name={product.Id} id={product.Id} value="0" type="number" step={step(product)} min="0" max="100"/>
|
<input class="order_item" data-price={product.Price} name={product.Id} id={product.Id} value="0" type="number" step={step(product)} min="0" max="100"/>
|
||||||
<button type="button" onClick={templ.JSFuncCall("increase", product.Id)}> + </button>
|
<button type="button" onClick={templ.JSFuncCall("increase", product.Id)}> + </button>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
@ -53,16 +53,19 @@ templ Swieta(products []types.Product) {
|
||||||
<div>
|
<div>
|
||||||
<h2>Złóż zamówienie</h2>
|
<h2>Złóż zamówienie</h2>
|
||||||
<p>Odbiór wszystkich zamówień: <b>24 grudnia</b>. Zamówienia przyjmujemy do <b>15 grudnia</b>. Potwierdzimy zamówienie telefonicznie.</p>
|
<p>Odbiór wszystkich zamówień: <b>24 grudnia</b>. Zamówienia przyjmujemy do <b>15 grudnia</b>. Potwierdzimy zamówienie telefonicznie.</p>
|
||||||
<form method="post" action="/order" >
|
<p>Wszystkie zamówienia obejmuje zaliczka o wysokości <b>50zł</b>. </p>
|
||||||
|
<form method="post" action="/order/" >
|
||||||
|
<input name="name" type="text" required placeholder="Imie i Nazwisko"/>
|
||||||
|
<input name="phone" type="tel" required placeholder="Numer Telefonu"/>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
for _, product := range products {
|
for _, product := range products {
|
||||||
@product_form(product)
|
@product_form(product)
|
||||||
}
|
}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<input name="name" type="text" required placeholder="Imie i Nazwisko"/>
|
<span>Wartość zamówienia: <span id="total_price">0</span></span>
|
||||||
<input name="phone" type="tel" required placeholder="Numer Telefonu"/>
|
|
||||||
<button type="submit">Wyślij zamówienie</button>
|
<button type="submit">Wyślij zamówienie</button>
|
||||||
</form>
|
</form>
|
||||||
|
<p>Po kliknięciu przycisku wyślij zamówienie, nastąpi przekierowanie do wpłaty zaliczki. Kwota zaliczki wynosi <b>50zł</b>. Po potwierdzeniu wpłaty otrzymasz numer zamówienia.</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
|
|
|
||||||
17
js/order.js
17
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) {
|
function min(a, b) {
|
||||||
if (a > b) {
|
if (a > b) {
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
function increase(id) {
|
function increase(id) {
|
||||||
input = document.getElementById(id)
|
input = document.getElementById(id)
|
||||||
step = parseFloat(input.step)
|
step = parseFloat(input.step)
|
||||||
input.value= min(parseFloat(input.value)+step, 0)
|
input.value= min(parseFloat(input.value)+step, 0)
|
||||||
|
calculate_total()
|
||||||
}
|
}
|
||||||
|
|
||||||
function decrease(id) {
|
function decrease(id) {
|
||||||
input = document.getElementById(id)
|
input = document.getElementById(id)
|
||||||
step = parseFloat(input.step)
|
step = parseFloat(input.step)
|
||||||
input.value= min(parseFloat(input.value)-step, 0)
|
input.value= min(parseFloat(input.value)-step, 0)
|
||||||
|
calculate_total()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
calculate_total()
|
||||||
|
|
|
||||||
6
main.go
6
main.go
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"piekarnikgosipl/data"
|
"piekarnikgosipl/data"
|
||||||
"piekarnikgosipl/html"
|
"piekarnikgosipl/html"
|
||||||
|
"piekarnikgosipl/orders"
|
||||||
"piekarnikgosipl/utils"
|
"piekarnikgosipl/utils"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -206,6 +207,9 @@ func main() {
|
||||||
if len(os.Args) > 1 {
|
if len(os.Args) > 1 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
server := http.ServeMux{}
|
||||||
|
server.Handle("/", http.FileServer(http.Dir("www")))
|
||||||
|
server.HandleFunc("POST /order/", orders.OrderHandler)
|
||||||
log.Println("listening on :8000")
|
log.Println("listening on :8000")
|
||||||
log.Fatal(http.ListenAndServe(":8000", http.FileServer(http.Dir("www"))))
|
log.Fatal(http.ListenAndServe(":8000", &server))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
74
orders/order.go
Normal file
74
orders/order.go
Normal file
|
|
@ -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)
|
||||||
|
}
|
||||||
57
orders/phone_validation.go
Normal file
57
orders/phone_validation.go
Normal file
|
|
@ -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
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue