diff --git a/config/connection.go b/config/connection.go index 0911c2a..03a0c7f 100644 --- a/config/connection.go +++ b/config/connection.go @@ -58,6 +58,8 @@ func InitDatabase() { &domain.PlatformHandle{}, &domain.Address{}, &domain.Article{}, + &domain.TrashCategory{}, + &domain.TrashDetail{}, ) if err != nil { log.Fatal("Error: Failed to auto migrate domain:", err) diff --git a/domain/trashtype.go b/domain/trashtype.go new file mode 100644 index 0000000..4144a80 --- /dev/null +++ b/domain/trashtype.go @@ -0,0 +1,20 @@ +package domain + +import "time" + +type TrashCategory struct { + ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4()" json:"id"` + Name string `gorm:"not null" json:"name"` + Details []TrashDetail `gorm:"foreignKey:CategoryID" json:"details"` + CreatedAt time.Time `gorm:"default:current_timestamp" json:"createdAt"` + UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updatedAt"` +} + +type TrashDetail struct { + ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4()" json:"id"` + CategoryID string `gorm:"type:uuid;not null" json:"category_id"` + Description string `gorm:"not null" json:"description"` + Price int `gorm:"not null" json:"price"` + CreatedAt time.Time `gorm:"default:current_timestamp" json:"createdAt"` + UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updatedAt"` +} diff --git a/dto/article.go b/dto/article.go index 24fb97e..28bd171 100644 --- a/dto/article.go +++ b/dto/article.go @@ -91,7 +91,3 @@ func (c *ArticleUpdateRequest) ValidateUpdateArticle() error { } return nil } - -// func (ar *ArticleRequest) Validate() error { -// return validate.Struct(ar) -// } diff --git a/dto/trashtype.go b/dto/trashtype.go new file mode 100644 index 0000000..9cd591a --- /dev/null +++ b/dto/trashtype.go @@ -0,0 +1,57 @@ +package dto + +import "github.com/go-playground/validator/v10" + +type TrashCategoryDTO struct { + Name string `json:"name" validate:"required,min=3,max=100"` +} + +func (t *TrashCategoryDTO) Validate() error { + validate := validator.New() + return validate.Struct(t) +} + +type TrashDetailDTO struct { + CategoryID string `json:"category_id" validate:"required,uuid4"` + Description string `json:"description" validate:"required,min=3,max=255"` + Price int `json:"price" validate:"required,min=0"` +} + +func (t *TrashDetailDTO) Validate() error { + validate := validator.New() + return validate.Struct(t) +} + +type TrashCategoryResponse struct { + ID string `json:"id"` + Name string `json:"name"` + CreatedAt string `json:"createdAt"` + UpdatedAt string `json:"updatedAt"` +} + +func NewTrashCategoryResponse(id, name, createdAt, updatedAt string) TrashCategoryResponse { + return TrashCategoryResponse{ + ID: id, + Name: name, + CreatedAt: createdAt, + UpdatedAt: updatedAt, + } +} + +type TrashDetailResponse struct { + ID string `json:"id"` + Description string `json:"description"` + Price int `json:"price"` + CreatedAt string `json:"createdAt"` + UpdatedAt string `json:"updatedAt"` +} + +func NewTrashDetailResponse(id, description string, price int, createdAt, updatedAt string) TrashDetailResponse { + return TrashDetailResponse{ + ID: id, + Description: description, + Price: price, + CreatedAt: createdAt, + UpdatedAt: updatedAt, + } +} diff --git a/internal/api/routes.go b/internal/api/routes.go index 903b384..79ecd47 100644 --- a/internal/api/routes.go +++ b/internal/api/routes.go @@ -38,4 +38,10 @@ func AppRouter(app *fiber.App) { app.Get("/articles/:id", middleware.AuthMiddleware, controllers.GetArticleByID) app.Put("/articles/:id", middleware.AuthMiddleware, controllers.UpdateArticle) app.Delete("/articles/:id", middleware.AuthMiddleware, controllers.DeleteArticle) + + // # trash type + app.Get("/trash-category", controllers.GetTrashCategories) + app.Get("/trash-categorydetail/:id", controllers.GetTrashCategoryDetail) + app.Post("/addtrash-category", controllers.CreateTrashCategory) + app.Post("/addtrash-categorydetail", controllers.CreateTrashDetail) } diff --git a/internal/controllers/trashtype.go b/internal/controllers/trashtype.go new file mode 100644 index 0000000..b4fd33d --- /dev/null +++ b/internal/controllers/trashtype.go @@ -0,0 +1,166 @@ +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 GetTrashCategories(c *fiber.Ctx) error { + trashCategories, err := services.GetTrashCategories() + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( + fiber.StatusInternalServerError, + "Failed to fetch trash categories", + nil, + )) + } + + var response []dto.TrashCategoryResponse + for _, category := range trashCategories { + + response = append(response, dto.NewTrashCategoryResponse( + category.ID, + category.Name, + utils.FormatDateToIndonesianFormat(category.CreatedAt), + utils.FormatDateToIndonesianFormat(category.UpdatedAt), + )) + } + + return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( + fiber.StatusOK, + "Trash categories fetched successfully", + response, + )) +} + +func GetTrashCategoryDetail(c *fiber.Ctx) error { + id := c.Params("id") + + trashCategoryDetail, err := services.GetTrashCategoryDetail(id) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( + fiber.StatusInternalServerError, + "Failed to fetch trash category detail", + nil, + )) + } + + detailResponse := dto.NewTrashCategoryResponse( + trashCategoryDetail.ID, + trashCategoryDetail.Name, + utils.FormatDateToIndonesianFormat(trashCategoryDetail.CreatedAt), + utils.FormatDateToIndonesianFormat(trashCategoryDetail.UpdatedAt), + ) + + var detailResponseList []dto.TrashDetailResponse + if trashCategoryDetail.Details != nil { + for _, detail := range trashCategoryDetail.Details { + detailResponseList = append(detailResponseList, dto.NewTrashDetailResponse( + detail.ID, + detail.Description, + detail.Price, + utils.FormatDateToIndonesianFormat(detail.CreatedAt), + utils.FormatDateToIndonesianFormat(detail.UpdatedAt), + )) + } + } + + return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( + fiber.StatusOK, + "Trash category detail fetched successfully", + struct { + Category dto.TrashCategoryResponse `json:"category"` + Details []dto.TrashDetailResponse `json:"details,omitempty"` + }{ + Category: detailResponse, + Details: detailResponseList, + }, + )) +} + +func CreateTrashCategory(c *fiber.Ctx) error { + var categoryInput dto.TrashCategoryDTO + + if err := c.BodyParser(&categoryInput); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( + fiber.StatusBadRequest, + "Invalid input data", + nil, + )) + } + + if err := categoryInput.Validate(); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( + fiber.StatusBadRequest, + "Validation failed: "+err.Error(), + nil, + )) + } + + newCategory, err := services.CreateTrashCategory(categoryInput.Name) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( + fiber.StatusInternalServerError, + "Failed to create trash category", + nil, + )) + } + + categoryResponse := map[string]interface{}{ + "id": newCategory.ID, + "name": newCategory.Name, + "createdAt": newCategory.CreatedAt, + "updatedAt": newCategory.UpdatedAt, + } + + return c.Status(fiber.StatusCreated).JSON(utils.FormatResponse( + fiber.StatusCreated, + "Trash category created successfully", + categoryResponse, + )) +} + +func CreateTrashDetail(c *fiber.Ctx) error { + var detailInput dto.TrashDetailDTO + + if err := c.BodyParser(&detailInput); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( + fiber.StatusBadRequest, + "Invalid input data", + nil, + )) + } + + if err := detailInput.Validate(); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( + fiber.StatusBadRequest, + "Validation failed: "+err.Error(), + nil, + )) + } + + newDetail, err := services.CreateTrashDetail(detailInput.CategoryID, detailInput.Description, detailInput.Price) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( + fiber.StatusInternalServerError, + "Failed to create trash detail", + nil, + )) + } + + detailResponse := map[string]interface{}{ + "id": newDetail.ID, + "description": newDetail.Description, + "price": newDetail.Price, + "createdAt": newDetail.CreatedAt, + "updatedAt": newDetail.UpdatedAt, + } + + return c.Status(fiber.StatusCreated).JSON(utils.FormatResponse( + fiber.StatusCreated, + "Trash detail created successfully", + detailResponse, + )) +} diff --git a/internal/controllers/userpin.go b/internal/controllers/userpin.go index 48612d1..32dba30 100644 --- a/internal/controllers/userpin.go +++ b/internal/controllers/userpin.go @@ -46,12 +46,10 @@ func CreatePin(c *fiber.Ctx) error { } formattedCreatedAt := utils.FormatDateToIndonesianFormat(pin.CreatedAt) - // formattedUpdatedAt := utils.FormatDateToIndonesianFormat(pin.UpdatedAt) pinResponse := dto.PinResponse{ - // ID: pin.ID, + CreatedAt: formattedCreatedAt, - // UpdatedAt: formattedUpdatedAt, } return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( diff --git a/internal/repositories/trashtype.go b/internal/repositories/trashtype.go new file mode 100644 index 0000000..68be9e5 --- /dev/null +++ b/internal/repositories/trashtype.go @@ -0,0 +1,37 @@ +package repositories + +import ( + "github.com/pahmiudahgede/senggoldong/config" + "github.com/pahmiudahgede/senggoldong/domain" +) + +func GetTrashCategories() ([]domain.TrashCategory, error) { + var categories []domain.TrashCategory + + if err := config.DB.Find(&categories).Error; err != nil { + return nil, err + } + return categories, nil +} + +func GetTrashCategoryDetail(id string) (domain.TrashCategory, error) { + var category domain.TrashCategory + if err := config.DB.Preload("Details").Where("id = ?", id).First(&category).Error; err != nil { + return category, err + } + return category, nil +} + +func CreateTrashCategory(category *domain.TrashCategory) error { + if err := config.DB.Create(category).Error; err != nil { + return err + } + return nil +} + +func CreateTrashDetail(detail *domain.TrashDetail) error { + if err := config.DB.Create(detail).Error; err != nil { + return err + } + return nil +} diff --git a/internal/services/trashtype.go b/internal/services/trashtype.go new file mode 100644 index 0000000..cacb1fa --- /dev/null +++ b/internal/services/trashtype.go @@ -0,0 +1,41 @@ +package services + +import ( + "github.com/pahmiudahgede/senggoldong/domain" + "github.com/pahmiudahgede/senggoldong/internal/repositories" +) + +func GetTrashCategories() ([]domain.TrashCategory, error) { + + return repositories.GetTrashCategories() +} + +func GetTrashCategoryDetail(id string) (domain.TrashCategory, error) { + return repositories.GetTrashCategoryDetail(id) +} + +func CreateTrashCategory(name string) (domain.TrashCategory, error) { + category := domain.TrashCategory{Name: name} + + err := repositories.CreateTrashCategory(&category) + if err != nil { + return category, err + } + + return category, nil +} + +func CreateTrashDetail(categoryID, description string, price int) (domain.TrashDetail, error) { + detail := domain.TrashDetail{ + CategoryID: categoryID, + Description: description, + Price: price, + } + + err := repositories.CreateTrashDetail(&detail) + if err != nil { + return detail, err + } + + return detail, nil +}