diff --git a/controllers/cartItemController.go b/controllers/cartItemController.go index e74c584..f86909b 100644 --- a/controllers/cartItemController.go +++ b/controllers/cartItemController.go @@ -2,6 +2,7 @@ package controllers import ( "fmt" + "strconv" "net/http" "crypto/rand" "encoding/hex" @@ -17,8 +18,8 @@ type CartItemController interface { //CRUDController CartItemView(*gin.Context) AddItemHandler(*gin.Context) - //EditCartItemHandler(*gin.Context) - //DeleteCartItemHandler(*gin.Context) + DeleteItemHandler(*gin.Context) + EditItemHandler(*gin.Context) } type cartItemController struct {} @@ -49,10 +50,16 @@ func GetSessionId(ctx *gin.Context) string { func (rc *cartItemController) NewCartItemFromForm(ctx *gin.Context) (models.CartItem, error) { sessionId := GetSessionId(ctx) - shopItemId := ctx.PostForm("ShopItemId") + shopItemIdStr := ctx.PostForm("ShopItemId") + shopItemId, err := strconv.Atoi(shopItemIdStr) + + if err != nil { + return models.CartItem{}, err + } + quantity := 1 - shopItem, err := repositories.ShopItems.GetById(shopItemId) + shopItem, err := repositories.ShopItems.GetById(shopItemIdStr) if err != nil { return models.CartItem{}, err @@ -60,6 +67,7 @@ func (rc *cartItemController) NewCartItemFromForm(ctx *gin.Context) (models.Cart cartItem := models.CartItem{ SessionId: sessionId, + ShopItemId: uint(shopItemId), ShopItem: shopItem, Quantity: quantity, } @@ -117,9 +125,10 @@ func (rc *cartItemController) Update(c *gin.Context) { //} func (rc *cartItemController) CartItemView(c *gin.Context) { - sessionId := GetSessionId(c) + //sessionId := GetSessionId(c) - cartItems, err := repositories.CartItems.GetAllBySession(sessionId) + //cartItems, err := repositories.CartItems.GetAllBySession(sessionId) + cartItems, err := repositories.CartItems.GetAll() if err != nil { c.HTML(http.StatusBadRequest, "cart.html", gin.H{ "data": gin.H{ "error": err } }) @@ -157,77 +166,53 @@ func (rc *cartItemController) AddItemHandler(c *gin.Context) { rc.CartItemView(c) } +func (rc *cartItemController) DeleteItemHandler(c *gin.Context) { + err := repositories.CartItems.DeleteById(c.PostForm("id")) -//func (rc *cartItemController) EditItemHandler(c *gin.Context) { -// cartItem, err := rc.NewCartItemFromForm(c) -// -// if err != nil { -// c.HTML(http.StatusBadRequest, "edititem.html", gin.H{ "error": err }) -// return -// } -// -// newCartItem, err := repositories.ShopItems.GetById(c.Param("id")) -// -// if err != nil { -// c.HTML(http.StatusBadRequest, "edititem.html", gin.H{ "error": err }) -// return -// } -// -// newCartItem.Name = cartItem.Name -// newCartItem.Abstract = cartItem.Abstract -// newCartItem.Description = cartItem.Description -// newCartItem.Price = cartItem.Price -// newCartItem.IsPublic = cartItem.IsPublic -// newCartItem.Tags = cartItem.Tags -// -// tags, err := repositories.Tags.GetAll() -// if err != nil { -// c.HTML(http.StatusBadRequest, "edititem.html", gin.H{ "error": err }) -// return -// } -// -// _, err = repositories.CartItems.Update(newShopItem) -// if err != nil { -// data := CreateSessionData(c, gin.H{ -// "error": err, -// "success": "", -// "tags": tags, -// }) -// -// c.HTML(http.StatusOK, "edititem.html", data) -// return -// } -// -// data := CreateSessionData(c, gin.H{ -// "error": "", -// "success": fmt.Sprintf("Item '%s' Updated", newCartItem.Name), -// "tags": tags, -// }) -// -// c.HTML(http.StatusOK, "edititem.html", data) -//} + if err != nil { + fmt.Println(err) + data := CreateSessionData(c, gin.H{ + "error": err, + "success": "", + }) -//func (rc *cartItemController) DeleteItemHandler(c *gin.Context) { -// err := repositories.CartItems.DeleteById(c.Param("id")) -// -// if err != nil { -// data := CreateSessionData(c, gin.H{ -// "error": err, -// "success": "", -// }) -// -// c.HTML(http.StatusOK, "deleteitem.html", data) -// } -// -// cartItems, _ := repositories.CartItems.GetAll() -// fmt.Println(len(cartItems)) -// -// data := CreateSessionData(c, gin.H{ -// "title": "cartItem Page", -// "cartItems": shopItems, -// }) -// -// fmt.Println(data) -// -// c.HTML(http.StatusOK, "index.html", data) -//} + c.HTML(http.StatusOK, "index.html", data) + } + + rc.CartItemView(c) +} + +func (rc *cartItemController) EditItemHandler(c *gin.Context) { + cartItemId := c.PostForm("id") + cartItem, err := repositories.CartItems.GetById(cartItemId) + + if err != nil { + fmt.Println("BLAA") + fmt.Println(err) + rc.CartItemView(c) + return + } + + action := c.PostForm("action") + + if action == "increase" { + cartItem.Quantity += 1 + } + + if action == "decrease" { + cartItem.Quantity -= 1 + + if cartItem.Quantity == 0 { + cartItem.Quantity = 1 + } + } + + _, err = repositories.CartItems.Update(cartItem) + + if err != nil { + fmt.Println("BLUB") + fmt.Println(err) + } + + rc.CartItemView(c) +} diff --git a/controllers/shopItemController.go b/controllers/shopItemController.go index 19e1f5f..341f984 100644 --- a/controllers/shopItemController.go +++ b/controllers/shopItemController.go @@ -160,6 +160,7 @@ func (rc *shopItemController) Update(c *gin.Context) { ReplyOK(c, "shopItem was updated") } +//TODO: delete associated cartitems func (rc *shopItemController) Delete(c *gin.Context) { err := repositories.ShopItems.DeleteById(c.Param("id")) diff --git a/main.go b/main.go index 52ec8eb..a9baab7 100644 --- a/main.go +++ b/main.go @@ -87,6 +87,8 @@ func main() { viewRoutes.POST("/tags", authValidator.RequireAuth, shopItemController.AddTagHandler) viewRoutes.GET("/cart", cartItemController.CartItemView) viewRoutes.POST("/cart", cartItemController.AddItemHandler) + viewRoutes.POST("/cart/delete", cartItemController.DeleteItemHandler) + viewRoutes.POST("/cart/edit", cartItemController.EditItemHandler) //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 7ada1c9..0aa8ded 100644 --- a/models/cart.go +++ b/models/cart.go @@ -7,6 +7,7 @@ import ( type CartItem struct { gorm.Model SessionId string `json:"sessionid" binding:"required" gorm:"not null"` - ShopItem ShopItem `json:"shopitem" gorm:"foreignKey:ID"` //gorm one2one + ShopItemId uint + ShopItem ShopItem `json:"shopitem" gorm:"foreignKey:ShopItemId"` //gorm one2one Quantity int `json:"quantity" binding:"required"` } diff --git a/repositories/cartItemRepository.go b/repositories/cartItemRepository.go index 0f85a85..f35162b 100644 --- a/repositories/cartItemRepository.go +++ b/repositories/cartItemRepository.go @@ -1,6 +1,7 @@ package repositories import( + "strconv" "gorm.io/gorm" "example.com/gin/test/models" @@ -9,8 +10,10 @@ import( type CartItemRepository interface { Create(models.CartItem) (models.CartItem, error) GetAll() ([]models.CartItem, error) + GetById(string) (models.CartItem, error) GetAllBySession(string) ([]models.CartItem, error) Update(models.CartItem) (models.CartItem, error) + DeleteById(string) (error) } type GORMCartItemRepository struct { @@ -24,7 +27,8 @@ func NewGORMCartItemRepository(db *gorm.DB) CartItemRepository { } func (r *GORMCartItemRepository) Create(cartItem models.CartItem) (models.CartItem, error) { - result := r.DB.Create(&cartItem) + //Omit the shopitem so it is not created again in db leading to unique constain fails + result := r.DB.Omit("ShopItem").Create(&cartItem) if result.Error != nil { return models.CartItem{}, result.Error } @@ -39,6 +43,24 @@ func (r *GORMCartItemRepository) GetAll() ([]models.CartItem, error) { return cartItems, result.Error } +func (t *GORMCartItemRepository) GetById(id string) (models.CartItem, error) { + cartItemId, err := strconv.Atoi(id) + + if err != nil { + return models.CartItem{}, err + } + + var cartItem models.CartItem + result := t.DB.First(&cartItem, uint(cartItemId)) + + if result.Error != nil { + return models.CartItem{}, result.Error + } + + return cartItem, nil +} + + func (r *GORMCartItemRepository) GetAllBySession(sessionId string) ([]models.CartItem, error) { var cartItems []models.CartItem result := r.DB.Preload("ShopItem").Where("session_id = ?", sessionId).Find(&cartItems) @@ -48,11 +70,6 @@ func (r *GORMCartItemRepository) GetAllBySession(sessionId string) ([]models.Car } func (r *GORMCartItemRepository) Update(cartItem models.CartItem) (models.CartItem, error) { - err := r.DB.Model(&cartItem).Association("Tags").Replace(cartItem.ShopItem) - if err != nil { - return models.CartItem{}, err - } - result := r.DB.Save(&cartItem) if result.Error != nil { return models.CartItem{}, result.Error @@ -60,3 +77,14 @@ func (r *GORMCartItemRepository) Update(cartItem models.CartItem) (models.CartIt return cartItem, nil } + +func (r *GORMCartItemRepository) DeleteById(id string) error { + cartItemId, err := strconv.Atoi(id) + + if err != nil { + return err + } + + result := r.DB.Omit("ShopItem").Delete(&models.CartItem{}, cartItemId) + return result.Error +} diff --git a/static/output.css b/static/output.css index ca8ab7c..31de76b 100644 --- a/static/output.css +++ b/static/output.css @@ -622,6 +622,18 @@ video { margin-bottom: 1rem; } +.mb-5 { + margin-bottom: 1.25rem; +} + +.mb-6 { + margin-bottom: 1.5rem; +} + +.mb-8 { + margin-bottom: 2rem; +} + .ml-2 { margin-left: 0.5rem; } @@ -658,18 +670,6 @@ video { margin-top: 1.5rem; } -.mb-5 { - margin-bottom: 1.25rem; -} - -.mb-6 { - margin-bottom: 1.5rem; -} - -.mb-8 { - margin-bottom: 2rem; -} - .block { display: block; } @@ -726,6 +726,10 @@ video { width: 33.333333%; } +.w-10 { + width: 2.5rem; +} + .w-12 { width: 3rem; } @@ -742,10 +746,6 @@ video { width: 100%; } -.w-10 { - width: 2.5rem; -} - .max-w-2xl { max-width: 42rem; } @@ -855,6 +855,14 @@ video { border-radius: 0.25rem; } +.rounded-3xl { + border-radius: 1.5rem; +} + +.rounded-\[50px\] { + border-radius: 50px; +} + .rounded-full { border-radius: 9999px; } @@ -867,14 +875,6 @@ video { border-radius: 0.375rem; } -.rounded-3xl { - border-radius: 1.5rem; -} - -.rounded-\[50px\] { - border-radius: 50px; -} - .rounded-l-md { border-top-left-radius: 0.375rem; border-bottom-left-radius: 0.375rem; @@ -896,16 +896,16 @@ video { border-style: dashed; } -.border-gray-300 { - --tw-border-opacity: 1; - border-color: rgb(209 213 219 / var(--tw-border-opacity, 1)); -} - .border-gray-200 { --tw-border-opacity: 1; border-color: rgb(229 231 235 / var(--tw-border-opacity, 1)); } +.border-gray-300 { + --tw-border-opacity: 1; + border-color: rgb(209 213 219 / var(--tw-border-opacity, 1)); +} + .bg-blue-600 { --tw-bg-opacity: 1; background-color: rgb(37 99 235 / var(--tw-bg-opacity, 1)); @@ -946,6 +946,11 @@ video { background-color: rgb(22 163 74 / var(--tw-bg-opacity, 1)); } +.bg-indigo-50 { + --tw-bg-opacity: 1; + background-color: rgb(238 242 255 / var(--tw-bg-opacity, 1)); +} + .bg-indigo-600 { --tw-bg-opacity: 1; background-color: rgb(79 70 229 / var(--tw-bg-opacity, 1)); @@ -966,11 +971,6 @@ video { background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1)); } -.bg-indigo-50 { - --tw-bg-opacity: 1; - background-color: rgb(238 242 255 / var(--tw-bg-opacity, 1)); -} - .fill-red-50 { fill: #fef2f2; } @@ -992,14 +992,14 @@ video { padding: 0.5rem; } -.p-4 { - padding: 1rem; -} - .p-2\.5 { padding: 0.625rem; } +.p-4 { + padding: 1rem; +} + .px-2 { padding-left: 0.5rem; padding-right: 0.5rem; @@ -1040,11 +1040,6 @@ video { padding-bottom: 0.5rem; } -.py-8 { - padding-top: 2rem; - padding-bottom: 2rem; -} - .py-2\.5 { padding-top: 0.625rem; padding-bottom: 0.625rem; @@ -1060,6 +1055,11 @@ video { padding-bottom: 1rem; } +.py-8 { + padding-top: 2rem; + padding-bottom: 2rem; +} + .pb-3 { padding-bottom: 0.75rem; } @@ -1102,6 +1102,16 @@ video { line-height: 2.25rem; } +.text-3xl { + font-size: 1.875rem; + line-height: 2.25rem; +} + +.text-4xl { + font-size: 2.25rem; + line-height: 2.5rem; +} + .text-base { font-size: 1rem; line-height: 1.5rem; @@ -1127,16 +1137,6 @@ video { line-height: 1rem; } -.text-3xl { - font-size: 1.875rem; - line-height: 2.25rem; -} - -.text-4xl { - font-size: 2.25rem; - line-height: 2.5rem; -} - .font-bold { font-weight: 700; } @@ -1145,14 +1145,14 @@ video { font-weight: 500; } -.font-semibold { - font-weight: 600; -} - .font-normal { font-weight: 400; } +.font-semibold { + font-weight: 600; +} + .leading-10 { line-height: 2.5rem; } @@ -1169,6 +1169,11 @@ video { letter-spacing: -0.025em; } +.text-black { + --tw-text-opacity: 1; + color: rgb(0 0 0 / var(--tw-text-opacity, 1)); +} + .text-gray-300 { --tw-text-opacity: 1; color: rgb(209 213 219 / var(--tw-text-opacity, 1)); @@ -1224,11 +1229,6 @@ video { color: rgb(255 255 255 / var(--tw-text-opacity, 1)); } -.text-black { - --tw-text-opacity: 1; - color: rgb(0 0 0 / var(--tw-text-opacity, 1)); -} - .shadow-sm { --tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); @@ -1240,11 +1240,6 @@ video { --tw-shadow: var(--tw-shadow-colored); } -.outline-none { - outline: 2px solid transparent; - outline-offset: 2px; -} - .outline { outline-style: solid; } @@ -1324,6 +1319,11 @@ video { background-color: rgb(156 163 175 / var(--tw-bg-opacity, 1)); } +.hover\:bg-gray-50:hover { + --tw-bg-opacity: 1; + background-color: rgb(249 250 251 / var(--tw-bg-opacity, 1)); +} + .hover\:bg-gray-700:hover { --tw-bg-opacity: 1; background-color: rgb(55 65 81 / var(--tw-bg-opacity, 1)); @@ -1339,31 +1339,26 @@ video { background-color: rgb(21 128 61 / var(--tw-bg-opacity, 1)); } -.hover\:bg-indigo-500:hover { - --tw-bg-opacity: 1; - background-color: rgb(99 102 241 / var(--tw-bg-opacity, 1)); -} - -.hover\:bg-red-900:hover { - --tw-bg-opacity: 1; - background-color: rgb(127 29 29 / var(--tw-bg-opacity, 1)); -} - -.hover\:bg-gray-50:hover { - --tw-bg-opacity: 1; - background-color: rgb(249 250 251 / var(--tw-bg-opacity, 1)); -} - .hover\:bg-indigo-100:hover { --tw-bg-opacity: 1; background-color: rgb(224 231 255 / var(--tw-bg-opacity, 1)); } +.hover\:bg-indigo-500:hover { + --tw-bg-opacity: 1; + background-color: rgb(99 102 241 / var(--tw-bg-opacity, 1)); +} + .hover\:bg-indigo-700:hover { --tw-bg-opacity: 1; background-color: rgb(67 56 202 / var(--tw-bg-opacity, 1)); } +.hover\:bg-red-900:hover { + --tw-bg-opacity: 1; + background-color: rgb(127 29 29 / var(--tw-bg-opacity, 1)); +} + .hover\:text-indigo-500:hover { --tw-text-opacity: 1; color: rgb(99 102 241 / var(--tw-text-opacity, 1)); @@ -1596,16 +1591,16 @@ video { padding: 2rem; } - .lg\:px-8 { - padding-left: 2rem; - padding-right: 2rem; - } - .lg\:px-6 { padding-left: 1.5rem; padding-right: 1.5rem; } + .lg\:px-8 { + padding-left: 2rem; + padding-right: 2rem; + } + .lg\:pl-3 { padding-left: 0.75rem; } diff --git a/views/cart.html b/views/cart.html index 83893b5..b4f5a0e 100644 --- a/views/cart.html +++ b/views/cart.html @@ -2,18 +2,21 @@
-

Shopping Cart

+ + {{ range .data.cartItems }} +
- speaker image + speaker image
-
Round white portable - speaker
- +

- Introducing our sleek round white portable speaker, the epitome of style and sound! Elevate your auditory experience with this compact yet powerful device that delivers crystal-clear audio wherever you go. More.... + {{ .ShopItem.Abstract }}

- - - +
-
$220
-
-
-
-
-
- speaker image -
-
-
-
Gray round portable - speaker
- -
-

- Introducing our sleek round white portable speaker, the epitome of style and sound! Elevate your auditory experience with this compact yet powerful device that delivers crystal-clear audio wherever you go. More.... -

-
-
- - - -
-
$220
+
{{ .ShopItem.Price }}€
+ {{ end }} + + + +
Subtotal
@@ -134,22 +92,5 @@ - {{ range .data.cartItems }} - -
-
-
-

- {{ .SessionId }} -

- {{ .ShopItem.Name }} - {{ .ShopItem.Abstract }} - {{ .ShopItem.Price }} -
-

{{ .Quantity }} pieces

-
-
- - {{ end }} {{ template "footer.html" . }}