diff --git a/config/connection.go b/config/connection.go index 35a8ca3..842d180 100644 --- a/config/connection.go +++ b/config/connection.go @@ -67,6 +67,8 @@ func InitDatabase() { &domain.CoverageSubdistrict{}, &domain.RequestPickup{}, &domain.RequestItem{}, + &domain.Product{}, + &domain.ProductImage{}, ) if err != nil { log.Fatal("Error: Failed to auto migrate domain:", err) diff --git a/domain/product.go b/domain/product.go new file mode 100644 index 0000000..ee862de --- /dev/null +++ b/domain/product.go @@ -0,0 +1,26 @@ +package domain + +import "time" + +type Product struct { + ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4()" json:"id"` + UserID string `gorm:"type:uuid;not null" json:"user_id"` + ProductTitle string `gorm:"not null" json:"product_title"` + ProductImages []ProductImage `gorm:"foreignKey:ProductID" json:"product_images"` + TrashDetailID string `gorm:"type:uuid;not null" json:"trash_detail_id"` + TrashDetail TrashDetail `gorm:"foreignKey:TrashDetailID" json:"trash_detail"` + SalePrice int64 `gorm:"not null" json:"sale_price"` + Quantity int `gorm:"not null" json:"quantity"` + ProductDescribe string `gorm:"type:text" json:"product_describe"` + Sold int `gorm:"default:0" json:"sold"` + CreatedAt time.Time `gorm:"default:current_timestamp" json:"created_at"` + UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updated_at"` +} + +type ProductImage struct { + ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4()" json:"id"` + ProductID string `gorm:"type:uuid;not null" json:"product_id"` + ImageURL string `gorm:"not null" json:"image_url"` + CreatedAt time.Time `gorm:"default:current_timestamp" json:"created_at"` + UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updated_at"` +} diff --git a/dto/product.go b/dto/product.go new file mode 100644 index 0000000..784afac --- /dev/null +++ b/dto/product.go @@ -0,0 +1,26 @@ +package dto + +type ProductResponseDTO struct { + ID string `json:"id"` + UserID string `json:"user_id"` + ProductTitle string `json:"product_title"` + ProductImages []ProductImageDTO `json:"product_images"` + TrashDetail TrashDetailResponseDTO `json:"trash_detail"` + + SalePrice int64 `json:"sale_price"` + Quantity int `json:"quantity"` + ProductDescribe string `json:"product_describe"` + Sold int `json:"sold"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` +} + +type ProductImageDTO struct { + ImageURL string `json:"image_url"` +} + +type TrashDetailResponseDTO struct { + ID string `json:"id"` + Description string `json:"description"` + Price int `json:"price"` +} diff --git a/internal/api/routes.go b/internal/api/routes.go index 01e4a06..b90b3fe 100644 --- a/internal/api/routes.go +++ b/internal/api/routes.go @@ -105,4 +105,8 @@ func AppRouter(app *fiber.App) { api.Get("/requestpickup", middleware.RoleRequired(utils.RoleMasyarakat), controllers.GetRequestPickupsByUser) api.Post("/addrequestpickup", middleware.RoleRequired(utils.RoleMasyarakat), controllers.CreateRequestPickup) api.Delete("/deleterequestpickup/:id", middleware.RoleRequired(utils.RoleMasyarakat), controllers.DeleteRequestPickup) + + // # product post by pengepul + api.Get("/post/products", middleware.RoleRequired(utils.RolePengepul), controllers.GetAllProducts) + api.Get("/post/product/:productid", middleware.RoleRequired(utils.RolePengepul), controllers.GetProductByID) } diff --git a/internal/controllers/product.go b/internal/controllers/product.go new file mode 100644 index 0000000..fdba795 --- /dev/null +++ b/internal/controllers/product.go @@ -0,0 +1,70 @@ +package controllers + +import ( + "github.com/gofiber/fiber/v2" + "github.com/pahmiudahgede/senggoldong/dto" + "github.com/pahmiudahgede/senggoldong/internal/services" + "github.com/pahmiudahgede/senggoldong/utils" +) + +func GetAllProducts(c *fiber.Ctx) error { + limit := c.QueryInt("limit", 0) + page := c.QueryInt("page", 1) + + if limit < 0 || page <= 0 { + return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( + fiber.StatusBadRequest, + "Invalid pagination parameters", + nil, + )) + } + + var products []dto.ProductResponseDTO + var err error + + if limit == 0 { + products, err = services.GetProducts(0, 0) + } else { + products, err = services.GetProducts(limit, page) + } + + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( + fiber.StatusInternalServerError, + "Failed to fetch products", + nil, + )) + } + + return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( + fiber.StatusOK, + "Products fetched successfully", + products, + )) +} + +func GetProductByID(c *fiber.Ctx) error { + productID := c.Params("productid") + if productID == "" { + return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( + fiber.StatusBadRequest, + "Product ID is required", + nil, + )) + } + + product, err := services.GetProductByID(productID) + if err != nil { + return c.Status(fiber.StatusNotFound).JSON(utils.FormatResponse( + fiber.StatusNotFound, + "Product not found", + nil, + )) + } + + return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( + fiber.StatusOK, + "Product fetched successfully", + product, + )) +} diff --git a/internal/repositories/product.go b/internal/repositories/product.go new file mode 100644 index 0000000..b1c8a58 --- /dev/null +++ b/internal/repositories/product.go @@ -0,0 +1,30 @@ +package repositories + +import ( + "github.com/pahmiudahgede/senggoldong/config" + "github.com/pahmiudahgede/senggoldong/domain" +) + +func GetAllProducts(limit, offset int) ([]domain.Product, error) { + var products []domain.Product + + query := config.DB.Preload("ProductImages").Preload("TrashDetail") + if limit > 0 { + query = query.Limit(limit).Offset(offset) + } + + err := query.Find(&products).Error + if err != nil { + return nil, err + } + return products, nil +} + +func GetProductByID(productID string) (domain.Product, error) { + var product domain.Product + err := config.DB.Preload("ProductImages").Preload("TrashDetail").Where("id = ?", productID).First(&product).Error + if err != nil { + return domain.Product{}, err + } + return product, nil +} diff --git a/internal/services/product.go b/internal/services/product.go new file mode 100644 index 0000000..810a71d --- /dev/null +++ b/internal/services/product.go @@ -0,0 +1,80 @@ +package services + +import ( + "github.com/pahmiudahgede/senggoldong/dto" + "github.com/pahmiudahgede/senggoldong/internal/repositories" + "github.com/pahmiudahgede/senggoldong/utils" +) + +func GetProducts(limit, page int) ([]dto.ProductResponseDTO, error) { + offset := (page - 1) * limit + + products, err := repositories.GetAllProducts(limit, offset) + if err != nil { + return nil, err + } + + var productResponses []dto.ProductResponseDTO + for _, product := range products { + var images []dto.ProductImageDTO + for _, img := range product.ProductImages { + images = append(images, dto.ProductImageDTO{ImageURL: img.ImageURL}) + } + + trashDetail := dto.TrashDetailResponseDTO{ + ID: product.TrashDetail.ID, + Description: product.TrashDetail.Description, + Price: product.TrashDetail.Price, + } + + productResponses = append(productResponses, dto.ProductResponseDTO{ + ID: product.ID, + UserID: product.UserID, + ProductTitle: product.ProductTitle, + ProductImages: images, + TrashDetail: trashDetail, + SalePrice: product.SalePrice, + Quantity: product.Quantity, + ProductDescribe: product.ProductDescribe, + Sold: product.Sold, + CreatedAt: utils.FormatDateToIndonesianFormat(product.CreatedAt), + UpdatedAt: utils.FormatDateToIndonesianFormat(product.UpdatedAt), + }) + } + + return productResponses, nil +} + +func GetProductByID(productID string) (dto.ProductResponseDTO, error) { + product, err := repositories.GetProductByID(productID) + if err != nil { + return dto.ProductResponseDTO{}, err + } + + var images []dto.ProductImageDTO + for _, img := range product.ProductImages { + images = append(images, dto.ProductImageDTO{ImageURL: img.ImageURL}) + } + + trashDetail := dto.TrashDetailResponseDTO{ + ID: product.TrashDetail.ID, + Description: product.TrashDetail.Description, + Price: product.TrashDetail.Price, + } + + productResponse := dto.ProductResponseDTO{ + ID: product.ID, + UserID: product.UserID, + ProductTitle: product.ProductTitle, + ProductImages: images, + TrashDetail: trashDetail, + SalePrice: product.SalePrice, + Quantity: product.Quantity, + ProductDescribe: product.ProductDescribe, + Sold: product.Sold, + CreatedAt: utils.FormatDateToIndonesianFormat(product.CreatedAt), + UpdatedAt: utils.FormatDateToIndonesianFormat(product.UpdatedAt), + } + + return productResponse, nil +}