From 580a70994a1332259f4346d514c83a1f5eb5a6c4 Mon Sep 17 00:00:00 2001 From: Anan Widianto Date: Wed, 6 Dec 2023 19:30:49 +0700 Subject: [PATCH] feature: product preferences --- module/feature/product/dto/response.go | 41 +++++++++++++ module/feature/product/handler/handler.go | 57 +++++++++++++++++++ module/feature/product/interface.go | 6 ++ .../feature/product/repository/repository.go | 49 ++++++++++++++++ module/feature/product/service/service.go | 20 +++++++ routes/routes.go | 2 + 6 files changed, 175 insertions(+) diff --git a/module/feature/product/dto/response.go b/module/feature/product/dto/response.go index 1347328..24c4a1a 100644 --- a/module/feature/product/dto/response.go +++ b/module/feature/product/dto/response.go @@ -263,3 +263,44 @@ func FormatReviewProductFormatter(products []*entities.ProductModels) []*ReviewP } return productFormatters } + +type OtherProductFormatter struct { + ID uint64 `json:"id"` + Name string `json:"name"` + Price uint64 `json:"price"` + Rating float64 `json:"rating"` + Images []ProductImageFormatter `json:"image_url"` +} + +func FormatOtherProduct(product *entities.ProductModels) *OtherProductFormatter { + productFormatter := &OtherProductFormatter{ + ID: product.ID, + Name: product.Name, + Price: product.Price, + Rating: product.Rating, + } + var images []ProductImageFormatter + for _, photo := range product.ProductPhotos { + if photo.DeletedAt == nil { + image := ProductImageFormatter{ + ID: photo.ID, + URL: photo.ImageURL, + } + images = append(images, image) + } + } + productFormatter.Images = images + + return productFormatter +} + +func FormatterOtherProduct(products []*entities.ProductModels) []*OtherProductFormatter { + var productFormatter []*OtherProductFormatter + + for _, product := range products { + formatProduct := FormatOtherProduct(product) + productFormatter = append(productFormatter, formatProduct) + } + + return productFormatter +} diff --git a/module/feature/product/handler/handler.go b/module/feature/product/handler/handler.go index f3c5f8f..96fe298 100644 --- a/module/feature/product/handler/handler.go +++ b/module/feature/product/handler/handler.go @@ -260,3 +260,60 @@ func (h *ProductHandler) DeleteProductImageById() echo.HandlerFunc { return response.SendStatusOkResponse(c, "Berhasil menghapus foto produk") } } + +func (h *ProductHandler) GetAllProductsPreferences() echo.HandlerFunc { + return func(c echo.Context) error { + currentUser := c.Get("CurrentUser").(*entities.UserModels) + page, _ := strconv.Atoi(c.QueryParam("page")) + pageConv, _ := strconv.Atoi(strconv.Itoa(page)) + perPage := 8 + + var products []*entities.ProductModels + var totalItems int64 + var err error + + search := c.QueryParam("search") + if search != "" { + products, totalItems, err = h.service.GetProductsByName(pageConv, perPage, search) + } else { + filter := c.QueryParam("filter") + switch filter { + case "": + products, totalItems, err = h.service.GetProductPreferences(currentUser.ID, pageConv, perPage) + case "abjad": + products, totalItems, err = h.service.GetProductByAlphabet(pageConv, perPage) + case "terbaru": + products, totalItems, err = h.service.GetProductByLatest(pageConv, perPage) + case "termahal": + products, totalItems, err = h.service.GetProductsByHighestPrice(pageConv, perPage) + case "termurah": + products, totalItems, err = h.service.GetProductsByLowestPrice(pageConv, perPage) + case "promo": + products, totalItems, err = h.service.GetDiscountedProducts(pageConv, perPage) + default: + return response.SendBadRequestResponse(c, "Filter tidak valid") + } + } + + if err != nil { + c.Logger().Error("handler: failed to fetch all products:", err.Error()) + return response.SendBadRequestResponse(c, "Gagal mendapatkan daftar produk: "+err.Error()) + } + + currentPage, totalPages := h.service.CalculatePaginationValues(pageConv, int(totalItems), perPage) + nextPage := h.service.GetNextPage(currentPage, totalPages) + prevPage := h.service.GetPrevPage(currentPage) + + return response.SendPaginationResponse(c, dto.FormatterProduct(products), currentPage, totalPages, int(totalItems), nextPage, prevPage, "Berhasil mendapatkan daftar produk") + } +} + +func (h *ProductHandler) GetTopRatedProducts() echo.HandlerFunc { + return func(c echo.Context) error { + result, err := h.service.GetTopRatedProducts() + if err != nil { + return response.SendStatusInternalServerResponse(c, "Gagal mendapatkan detail produk: "+err.Error()) + } + return response.SendSuccessResponse(c, "Berhasil mendapatkan detail produk", dto.FormatterOtherProduct(result)) + } +} diff --git a/module/feature/product/interface.go b/module/feature/product/interface.go index 1ddb49b..909720e 100644 --- a/module/feature/product/interface.go +++ b/module/feature/product/interface.go @@ -30,6 +30,8 @@ type RepositoryProductInterface interface { GetProductsByLowestPrice(page, perPage int) ([]*entities.ProductModels, int64, error) GetTotalProductSold() (uint64, error) GetDiscountedProducts(page, perPage int) ([]*entities.ProductModels, int64, error) + FindAllByUserPreference(userID uint64, page, perPage int) ([]*entities.ProductModels, error) + GetTopRatedProducts() ([]*entities.ProductModels, error) } type ServiceProductInterface interface { @@ -56,6 +58,8 @@ type ServiceProductInterface interface { GetProductsByLowestPrice(page, perPage int) ([]*entities.ProductModels, int64, error) GetTotalProductSold() (uint64, error) GetDiscountedProducts(page, perPage int) ([]*entities.ProductModels, int64, error) + GetProductPreferences(userID uint64, page, perPage int) ([]*entities.ProductModels, int64, error) + GetTopRatedProducts() ([]*entities.ProductModels, error) } type HandlerProductInterface interface { @@ -67,4 +71,6 @@ type HandlerProductInterface interface { UpdateProduct() echo.HandlerFunc DeleteProduct() echo.HandlerFunc DeleteProductImageById() echo.HandlerFunc + GetAllProductsPreferences() echo.HandlerFunc + GetTopRatedProducts() echo.HandlerFunc } diff --git a/module/feature/product/repository/repository.go b/module/feature/product/repository/repository.go index e47c497..5c03790 100644 --- a/module/feature/product/repository/repository.go +++ b/module/feature/product/repository/repository.go @@ -5,6 +5,7 @@ import ( "github.com/capstone-kelompok-7/backend-disappear/module/entities" "github.com/capstone-kelompok-7/backend-disappear/module/feature/product" "gorm.io/gorm" + "strings" "time" ) @@ -351,3 +352,51 @@ func (r *ProductRepository) GetDiscountedProducts(page, perPage int) ([]*entitie return products, totalItems, nil } + +func (r *ProductRepository) FindAllByUserPreference(userID uint64, page, perPage int) ([]*entities.ProductModels, error) { + var matchingProduct []*entities.ProductModels + var nonMatchingProduct []*entities.ProductModels + + userPreferences, err := r.getUserPreferences(userID) + if err != nil { + return nil, err + } + + searchPattern := "%" + strings.Join(userPreferences, "%") + "%" + offset := (page - 1) * perPage + + err = r.db.Where("deleted_at IS NULL").Where("description LIKE ?", searchPattern).Offset(offset).Limit(perPage).Find(&matchingProduct).Error + if err != nil { + return nil, err + } + + err = r.db.Where("deleted_at IS NULL").Where("description NOT LIKE ?", searchPattern).Offset(offset).Limit(perPage).Find(&nonMatchingProduct).Error + if err != nil { + return nil, err + } + + products := append(matchingProduct, nonMatchingProduct...) + + return products, nil +} + +func (r *ProductRepository) getUserPreferences(userID uint64) ([]string, error) { + var userPreferences []string + + err := r.db.Model(&entities.UserModels{}).Select("preferred_topics").Where("id = ?", userID).Pluck("preferred_topics", &userPreferences).Error + if err != nil { + return nil, err + } + + return userPreferences, nil +} + +func (r *ProductRepository) GetTopRatedProducts() ([]*entities.ProductModels, error) { + var products []*entities.ProductModels + + if err := r.db.Order("rating desc").Where("deleted_at IS NULL").Limit(5).Find(&products).Error; err != nil { + return nil, err + } + + return products, nil +} diff --git a/module/feature/product/service/service.go b/module/feature/product/service/service.go index a71555f..4f78b22 100644 --- a/module/feature/product/service/service.go +++ b/module/feature/product/service/service.go @@ -321,3 +321,23 @@ func (s *ProductService) GetDiscountedProducts(page, perPage int) ([]*entities.P } return products, totalItems, nil } + +func (s *ProductService) GetProductPreferences(userID uint64, page, perPage int) ([]*entities.ProductModels, int64, error) { + result, err := s.repo.FindAllByUserPreference(userID, page, perPage) + if err != nil { + return nil, 0, err + } + totalItems, err := s.repo.GetTotalProductCount() + if err != nil { + return nil, 0, err + } + return result, totalItems, nil +} + +func (s *ProductService) GetTopRatedProducts() ([]*entities.ProductModels, error) { + result, err := s.repo.GetTopRatedProducts() + if err != nil { + return nil, err + } + return result, nil +} diff --git a/routes/routes.go b/routes/routes.go index bd3c53b..0c21a64 100644 --- a/routes/routes.go +++ b/routes/routes.go @@ -69,6 +69,8 @@ func RouteProduct(e *echo.Echo, h product.HandlerProductInterface, jwtService ut productsGroup.PUT("/:id", h.UpdateProduct(), middlewares.AuthMiddleware(jwtService, userService)) productsGroup.DELETE("/:id", h.DeleteProduct(), middlewares.AuthMiddleware(jwtService, userService)) productsGroup.DELETE("/:idProduct/image/:idImage", h.DeleteProductImageById(), middlewares.AuthMiddleware(jwtService, userService)) + productsGroup.GET("/preferences", h.GetAllProductsPreferences(), middlewares.AuthMiddleware(jwtService, userService)) + productsGroup.GET("/other-products", h.GetTopRatedProducts(), middlewares.AuthMiddleware(jwtService, userService)) } func RouteArticle(e *echo.Echo, h article.HandlerArticleInterface, jwtService utils.JWTInterface, userService users.ServiceUserInterface) {