diff --git a/controllers/cartItemController.go b/controllers/cartItemController.go index 2ea4d04..8ff1f0f 100644 --- a/controllers/cartItemController.go +++ b/controllers/cartItemController.go @@ -22,6 +22,8 @@ type CartItemController interface { EditItemHandler(*gin.Context) CheckoutView(*gin.Context) CheckoutHandler(*gin.Context) + OrderView(*gin.Context) + OrderHandler(*gin.Context) } type cartItemController struct {} @@ -39,8 +41,8 @@ func GetShippingMethods() []models.Shipping { } } -func generateSessionId() string { - bytes := make([]byte, 16) // 16 bytes = 128 bits +func generateSessionId(length int) string { + bytes := make([]byte, length) // 16 bytes = 128 bits _, err := rand.Read(bytes) if err != nil { panic("failed to generate session ID") @@ -52,13 +54,18 @@ func GetSessionId(ctx *gin.Context) string { sessionId, err := ctx.Cookie("session_id") if err != nil { - sessionId = generateSessionId() + sessionId = generateSessionId(16) ctx.SetCookie("session_id", sessionId, 3600, "/", "", false, true) } return sessionId } +func GenerateToken() string { + return generateSessionId(8) +} + + func (rc *cartItemController) NewCartItemFromForm(ctx *gin.Context) (models.CartItem, error) { sessionId := GetSessionId(ctx) shopItemIdStr := ctx.PostForm("ShopItemId") @@ -92,6 +99,94 @@ func (rc *cartItemController) NewCartItemFromForm(ctx *gin.Context) (models.Cart return cartItem, nil } +func (rc *cartItemController) NewAddressFromForm(ctx *gin.Context) (models.AddressInfo, error) { + firstName := ctx.PostForm("firstName") + lastName := ctx.PostForm("lastName") + address := ctx.PostForm("address") + postalCode := ctx.PostForm("postalCode") + city := ctx.PostForm("city") + country := ctx.PostForm("country") + + if firstName == "" { + return models.AddressInfo{}, fmt.Errorf("first name missing.") + } + + if lastName == "" { + return models.AddressInfo{}, fmt.Errorf("Last name missing.") + } + + if address == "" { + return models.AddressInfo{}, fmt.Errorf("address missing.") + } + + if postalCode == "" { + return models.AddressInfo{}, fmt.Errorf("postalCode missing.") + } + + if city == "" { + return models.AddressInfo{}, fmt.Errorf("city missing.") + } + + if country == "" { + return models.AddressInfo{}, fmt.Errorf("country missing.") + } + + return models.AddressInfo{ + FirstName: firstName, + LastName: lastName, + Address: address, + PostalCode: postalCode, + City: city, + Country: country, + }, nil +} + +func (rc *cartItemController) NewOrderFromForm(ctx *gin.Context) (models.Order, error) { + sessionId := GetSessionId(ctx) + status := models.OrderStatus("Received") + token := GenerateToken() + email := ctx.PostForm("email") + comment := ctx.PostForm("comment") + shippingStr := ctx.PostForm("shippingMethod") + + address, err := rc.NewAddressFromForm(ctx) + if shippingStr != "pickup" { + if err != nil { + return models.Order{}, fmt.Errorf("Invalid address information.") + } + } + + var shipping models.Shipping + for _, shippingMethod := range GetShippingMethods() { + if shippingMethod.Id == shippingStr { + shipping = shippingMethod + } + } + + if shipping == (models.Shipping{}) { + return models.Order{}, fmt.Errorf("Invalid shipping method.") + } + + cartItems, err := repositories.CartItems.GetAllBySession(sessionId) + + if err != nil { + return models.Order{}, err + } + + cartItem := models.Order{ + SessionId: sessionId, + Status: status, + Token: token, + Email: email, + Comment: comment, + Address: address, + Shipping: shipping, + CartItems: cartItems, + } + + return cartItem, nil +} + func (rc *cartItemController) Create(c *gin.Context) { cartItem, err := rc.NewCartItemFromForm(c) @@ -248,6 +343,45 @@ func (rc *cartItemController) CheckoutView(c *gin.Context) { }) } -func (rc *cartItemController) CheckoutHandler(*gin.Context) { +func (rc *cartItemController) CheckoutHandler(c *gin.Context) { + order, err := rc.NewOrderFromForm(c) + + if err != nil { + fmt.Println(err) + c.HTML(http.StatusBadRequest, "error.html", gin.H{ "error": err }) + return + } + + _, err = repositories.Orders.Create(order) + if err != nil { + data := CreateSessionData(c, gin.H{ + "error": err, + "success": "", + }) + + c.HTML(http.StatusOK, "cart.html", data) + return + } + + data := CreateSessionData(c, gin.H{ + "error": "", + "success": "", + "order": order, + "isPreview": true, + }) + + c.HTML(http.StatusOK, "order.html", data) +} + +func (rc *cartItemController) OrderView(c *gin.Context) { + shippingMethod := c.Query("shippingMethod") + + c.HTML(http.StatusOK, "checkout.html", gin.H{ + "askAddress": (shippingMethod != "pickup"), + "shippingMethod": shippingMethod, + }) +} + +func (rc *cartItemController) OrderHandler(c *gin.Context) { } diff --git a/main.go b/main.go index 6699cf1..a5815ee 100644 --- a/main.go +++ b/main.go @@ -91,6 +91,8 @@ func main() { viewRoutes.POST("/cart/edit", cartItemController.EditItemHandler) viewRoutes.GET("/checkout", cartItemController.CheckoutView) viewRoutes.POST("/checkout", cartItemController.CheckoutHandler) + viewRoutes.GET("/order", cartItemController.OrderView) + viewRoutes.POST("/order", cartItemController.OrderHandler) //write middleware that redirects to homescreen on register/login/reset for logged in users viewRoutes.GET("/login", userController.LoginView) diff --git a/models/cart.go b/models/cart.go index 4ae4f14..06f809f 100644 --- a/models/cart.go +++ b/models/cart.go @@ -25,19 +25,21 @@ type AddressInfo struct { } type Shipping struct { - Id string `json:"name"` + Id string `json:"id"` Name string `json:"name"` Price float64 `json:"price"` } type Order struct { gorm.Model + SessionId string `json:"sessionid" binding:"required" gorm:"not null"` Status OrderStatus `json:"status"` Token string `json:"token" binding:"required" gorm:"not null"` - CartItems []CartItem `json:"cartitems"` Email string `json:"email"` Comment string `json:"comment"` - Shipping + Address AddressInfo `json:"addressinfo"` + Shipping Shipping `json:"shipping"` + CartItems []CartItem `json:"cartitems"` } type CartItem struct { diff --git a/repositories/repository.go b/repositories/repository.go index 3194fcc..bb5bcdb 100644 --- a/repositories/repository.go +++ b/repositories/repository.go @@ -13,6 +13,7 @@ var( Users UserRepository Tags TagRepository CartItems CartItemRepository + Orders OrderRepository ) func InitRepositories() { @@ -21,7 +22,13 @@ func InitRepositories() { panic("failed to connect to database") } - err = db.AutoMigrate(&models.ShopItem{}, &models.ItemVariant{}, &models.User{}, &models.Tag{}, &models.CartItem{}) + err = db.AutoMigrate(&models.ShopItem{}, + &models.ItemVariant{}, + &models.User{}, + &models.Tag{}, + &models.CartItem{}, + &models.Order{}) + if err != nil { panic("failed to migrate database") } @@ -30,4 +37,5 @@ func InitRepositories() { Users = NewGORMUserRepository(db) Tags = NewGORMTagRepository(db) CartItems = NewGORMCartItemRepository(db) + Orders = NewGORMOrderRepository(db) } diff --git a/static/output.css b/static/output.css index 583e2a3..28f6c8b 100644 --- a/static/output.css +++ b/static/output.css @@ -107,7 +107,7 @@ } /* -! tailwindcss v3.4.17 | MIT License | https://tailwindcss.com +! tailwindcss v3.4.16 | MIT License | https://tailwindcss.com */ /* @@ -1123,16 +1123,16 @@ video { line-height: 1.5rem; } -.text-xs { - font-size: 0.75rem; - line-height: 1rem; -} - .text-sm\/8 { font-size: 0.875rem; line-height: 2rem; } +.text-xs { + font-size: 0.75rem; + line-height: 1rem; +} + .font-bold { font-weight: 700; }