From b9ee8d8895fb4e54083c52b2947ae942cd8ba512 Mon Sep 17 00:00:00 2001 From: Henrique Miranda Date: Sun, 17 Nov 2024 17:40:22 -0300 Subject: [PATCH] edit client procedures --- go.mod | 2 +- go.sum | 2 + static/css/input.css | 20 +++++ web/db/client_procedures_store.go | 65 +++++++++++++- web/handlers/client_handler.go | 33 +++++++ web/services/client_procedure_service.go | 19 ++++ web/types/client_procedure.go | 2 + web/view/pages/client_detail_page.templ | 106 +++++++++++++++++++++-- web/view/ui/modal.templ | 8 +- web/web.go | 1 + 10 files changed, 244 insertions(+), 14 deletions(-) diff --git a/go.mod b/go.mod index 1ec7431..bfdce06 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/henriquepw/imperium-tattoo go 1.23.1 require ( - github.com/a-h/templ v0.2.771 + github.com/a-h/templ v0.2.793 github.com/go-playground/validator/v10 v10.22.0 github.com/joho/godotenv v1.5.1 github.com/matoous/go-nanoid/v2 v2.1.0 diff --git a/go.sum b/go.sum index a8e2b92..36e67d8 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ github.com/a-h/templ v0.2.771 h1:4KH5ykNigYGGpCe0fRJ7/hzwz72k3qFqIiiLLJskbSo= github.com/a-h/templ v0.2.771/go.mod h1:lq48JXoUvuQrU0VThrK31yFwdRjTCnIE5bcPCM9IP1w= +github.com/a-h/templ v0.2.793 h1:Io+/ocnfGWYO4VHdR0zBbf39PQlnzVCVVD+wEEs6/qY= +github.com/a-h/templ v0.2.793/go.mod h1:lq48JXoUvuQrU0VThrK31yFwdRjTCnIE5bcPCM9IP1w= github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo= diff --git a/static/css/input.css b/static/css/input.css index b0b0dfe..ca751cd 100644 --- a/static/css/input.css +++ b/static/css/input.css @@ -3,6 +3,26 @@ @tailwind utilities; @layer components { + *::selection { + @apply bg-accent-8 text-white; + } + + ::-webkit-scrollbar { + width: 8px; + } + + ::-webkit-scrollbar-track { + @apply bg-gray-1; + } + + ::-webkit-scrollbar-thumb { + @apply bg-accent-8; + } + + ::-webkit-scrollbar-thumb:hover { + @apply bg-accent-10; + } + .card { @apply bg-gray-2 backdrop-blur border border-gray-7 rounded-lg p-4 } diff --git a/web/db/client_procedures_store.go b/web/db/client_procedures_store.go index 4fbcef2..3017596 100644 --- a/web/db/client_procedures_store.go +++ b/web/db/client_procedures_store.go @@ -11,8 +11,9 @@ import ( type ClientProcedureStore interface { Insert(ctx context.Context, item types.ClientProcedure) error - Update(ctx context.Context, id string, dto types.ClientProcedureUpdateDTO) error + Update(ctx context.Context, dto types.ClientProcedureUpdateDTO) error List(ctx context.Context, clientID string) ([]types.ClientProcedure, error) + Get(ctx context.Context, procedureID string) (*types.ClientProcedure, error) } type clientProcedureStore struct { @@ -55,6 +56,7 @@ func (s *clientProcedureStore) List(ctx context.Context, clientID string) ([]typ cp.id, cp.description, cp.done_at, + cp.procedure_id, p.name FROM client_procedure cp @@ -77,6 +79,7 @@ func (s *clientProcedureStore) List(ctx context.Context, clientID string) ([]typ &i.ID, &i.Description, &doneAt, + &i.ProcedureID, &i.Procedure, ) if err != nil { @@ -94,6 +97,62 @@ func (s *clientProcedureStore) List(ctx context.Context, clientID string) ([]typ return items, nil } -func (s *clientProcedureStore) Update(ctx context.Context, clientID string, dto types.ClientProcedureUpdateDTO) error { - return nil +func (s *clientProcedureStore) Get(ctx context.Context, procedureID string) (*types.ClientProcedure, error) { + query := ` + SELECT + cp.id, + cp.description, + cp.done_at, + cp.procedure_id, + p.name + FROM + client_procedure cp + LEFT JOIN procedure p ON cp.procedure_id = p.id + WHERE + cp.id = ? + ` + row := s.db.QueryRowContext(ctx, query, procedureID) + + var procedure types.ClientProcedure + doneAt := "" + err := row.Scan( + &procedure.ID, + &procedure.Description, + &doneAt, + &procedure.ProcedureID, + &procedure.Procedure, + ) + if err != nil { + return nil, err + } + + procedure.DoneAt, err = time.Parse(time.RFC3339, doneAt) + if err != nil { + return nil, err + } + + return &procedure, nil +} + +func (s *clientProcedureStore) Update(ctx context.Context, dto types.ClientProcedureUpdateDTO) error { + query := ` + UPDATE client_procedure + SET + procedure_id = ?, + description = ?, + done_at = ?, + updated_at = ? + WHERE + id = ? + ` + _, error := s.db.ExecContext( + ctx, query, + dto.ProcedureID, + dto.Description, + date.FormatToISO(dto.DoneAt), + date.FormatToISO(time.Now()), + dto.ID, + ) + + return error } diff --git a/web/handlers/client_handler.go b/web/handlers/client_handler.go index 3c3eb2a..3ee9b2b 100644 --- a/web/handlers/client_handler.go +++ b/web/handlers/client_handler.go @@ -1,8 +1,10 @@ package handlers import ( + "fmt" "log" "net/http" + "time" "github.com/a-h/templ" "github.com/henriquepw/imperium-tattoo/pkg/date" @@ -71,6 +73,37 @@ func (h *ClientHandler) CreateClientAction(w http.ResponseWriter, r *http.Reques ) } +func (h *ClientHandler) EditClientProcedureAction(w http.ResponseWriter, r *http.Request) { + r.ParseForm() + doneAt, err := time.Parse(time.DateOnly, r.Form.Get("doneAt")) + if err != nil { + fmt.Print(err) + httputil.Render(w, r, http.StatusBadRequest, pages.ClientProcessEditForm(map[string]string{"doneAt": "Data inválida"})) + return + } + + payload := types.ClientProcedureUpdateDTO{ + ID: r.PathValue("procedureId"), + Description: r.Form.Get("description"), + ProcedureID: r.Form.Get("procedureId"), + DoneAt: doneAt, + } + + p, err := h.clientProcedureSVC.EditClientProcedure(r.Context(), payload) + if err != nil { + httputil.RenderError(w, r, err, func(e errors.ServerError) templ.Component { + return pages.ClientProcessEditForm(e.Errors) + }) + return + } + + httputil.Render( + w, r, http.StatusOK, + pages.ClientProcessEditForm(nil), + pages.OobUpdateClientProcedure(*p), + ) +} + func (h *ClientHandler) ClientDetailPage(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") diff --git a/web/services/client_procedure_service.go b/web/services/client_procedure_service.go index 545be9e..71ad92d 100644 --- a/web/services/client_procedure_service.go +++ b/web/services/client_procedure_service.go @@ -15,6 +15,7 @@ import ( type ClientProcedureService interface { CreateClientProcedure(ctx context.Context, dto types.ClientProcedureCreateDTO) (*types.ClientProcedure, error) + EditClientProcedure(ctx context.Context, dto types.ClientProcedureUpdateDTO) (*types.ClientProcedure, error) ListClientProcedures(ctx context.Context, clientID string) ([]types.ClientProcedure, error) } @@ -73,3 +74,21 @@ func (s *clientProcedureService) ListClientProcedures(ctx context.Context, clien return procedures, nil } + +func (s *clientProcedureService) EditClientProcedure(ctx context.Context, dto types.ClientProcedureUpdateDTO) (*types.ClientProcedure, error) { + if err := validate.CheckPayload(dto); err != nil { + return nil, err + } + + err := s.store.Update(ctx, dto) + if err != nil { + return nil, errors.Internal("Não foi possível editar o procedimento") + } + + p, err := s.store.Get(ctx, dto.ID) + if err != nil { + return nil, errors.Internal("Não foi possível editar o procedimento") + } + + return p, nil +} diff --git a/web/types/client_procedure.go b/web/types/client_procedure.go index 6bfefdf..1879895 100644 --- a/web/types/client_procedure.go +++ b/web/types/client_procedure.go @@ -21,6 +21,8 @@ type ClientProcedureCreateDTO struct { } type ClientProcedureUpdateDTO struct { + ID string `validate:"required,id,len=18"` DoneAt time.Time `validate:"required"` Description string `validate:"required,min=5"` + ProcedureID string `validate:"required,id,len=18"` } diff --git a/web/view/pages/client_detail_page.templ b/web/view/pages/client_detail_page.templ index 165d32a..66145cf 100644 --- a/web/view/pages/client_detail_page.templ +++ b/web/view/pages/client_detail_page.templ @@ -67,7 +67,7 @@ templ ClientDetailPage( clientProcedures []types.ClientProcedure, ) { @layout.Dashbaord(client.Name, boosted) { -
+
@layout.PageHeader(client.Name, []ui.BreadcrumbItem{ {Label: "Clientes", Href: "/clients"}, {Label: "Detalhe", Href: "/clients/" + client.ID}, @@ -241,11 +241,18 @@ func parseProcedures(items []types.Procedure) string { } templ ClientProcessSection(id string, procedures []types.Procedure, clientProcedures []types.ClientProcedure) { -
+

Procedimentos

@ClientProcedureList(clientProcedures) + @ui.Modal("!!procedure", "procedure=undefined", "Editar Procedimento") { + @ClientProcessEditForm(nil) + } @ui.Modal("newProcedureOpen", "newProcedureOpen=false", "Registrar Procedimento") { @ClientProcessCreateForm(id, types.ClientProcedureCreateDTO{}, nil) } @@ -259,9 +266,46 @@ templ ClientProcessSection(id string, procedures []types.Procedure, clientProced
} +templ OobUpdateClientProcedure(p types.ClientProcedure) { +
  • + + + { p.Procedure } + + { p.Description } +
  • +} + templ clientProcedureItem(p types.ClientProcedure) { -
  • - +
  • + { p.Procedure } @@ -269,6 +313,56 @@ templ clientProcedureItem(p types.ClientProcedure) {
  • } +templ ClientProcessEditForm(errors map[string]string) { +
    +
    + @ui.FormField("procedureID", "Procedimento", errors["procedureId"], true) { + + } + @ui.TextInput(ui.TextInputOps{ + Required: true, + Label: "Data de Realização", + Name: "doneAt", + Type: "date", + XValue: "procedure?.doneAt", + Error: errors["doneAt"], + }) +
    + @ui.TextArea(ui.TextAreaOps{ + Required: true, + Label: "Descrição", + Name: "description", + Placeholder: "Descreva como foi o procedimento, quais matérias foram usados, etc", + XValue: "procedure?.description", + Error: errors["description"], + }) + @ui.SubmitBtn("save", "Salvando...", "ml-auto") { + Salvar + } +
    +} + templ ClientProcedureList(procedures []types.ClientProcedure) { if len(procedures) == 0 {
    @@ -305,7 +399,7 @@ templ ClientProcessCreateForm(id string, values types.ClientProcedureCreateDTO, @ui.FormField("procedureID", "Procedimento", errors["procedureId"], true) {