hrender-examples/htmx-alpine-pt2/main.go
2025-12-12 03:37:19 +01:00

239 lines
5.6 KiB
Go

package main
import (
"fmt"
"log"
"net/http"
"os"
"sort"
"strconv"
"time"
"github.com/alexedwards/flow"
"github.com/zepyrshut/hrender"
"github.com/zepyrshut/hrender/ui"
)
type TodoList struct {
ID int
Name string
Completed bool
Error string
ui.CRUDActions
}
var todoList = []TodoList{
{
ID: 1,
Name: "Sacar a la perra",
Completed: true,
},
{
ID: 2,
Name: "Limpiar la casa",
Completed: false,
},
{
ID: 3,
Name: "Ir al supermercado",
Completed: false,
},
}
func (t *TodoList) GetID() string {
return strconv.Itoa(t.ID)
}
func (t *TodoList) SetCRUDActions(actions ui.CRUDActions) {
t.CRUDActions = actions
}
func main() {
templatesFS := os.DirFS("./templates")
h := hrender.NewHTMLRender(templatesFS, false)
mux := flow.New()
mux.Use(func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Printf("sleeping 0.5 second, path %s, method %s", r.URL.Path, r.Method)
time.Sleep(200 * time.Millisecond)
next.ServeHTTP(w, r)
})
})
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set(hrender.ContentType, hrender.ContentTextHTMLUTF8)
err := h.RenderW(w, "pages/index", hrender.H{}, "layouts/base")
if err != nil {
http.Error(w, fmt.Sprintf("error loading template, err: %v", err), http.StatusInternalServerError)
}
}, "GET")
mux.HandleFunc("/todo", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set(hrender.ContentType, hrender.ContentTextHTMLUTF8)
sort.Slice(todoList, func(i, j int) bool {
return todoList[i].ID > todoList[j].ID
})
err := h.RenderW(w, "fragments/todo-widget", hrender.H{
"Todo": todoList,
})
if err != nil {
http.Error(w, fmt.Sprintf("error loading template, err: %v", err), http.StatusInternalServerError)
}
}, "GET")
mux.HandleFunc("/todo", func(w http.ResponseWriter, r *http.Request) {
err := r.ParseForm()
if err != nil {
http.Error(w, fmt.Sprintf("error loading template, err: %v", err), http.StatusInternalServerError)
return
}
w.Header().Set(hrender.ContentType, hrender.ContentTextHTMLUTF8)
name := r.FormValue("name")
if name == "" {
w.Header().Set("HX-Retarget", "#create-todo-form")
w.Header().Set("HX-Reswap", "outerHTML")
err := h.RenderW(w, "fragments/todo-new-form", hrender.H{
"Name": name,
"Error": "El nombre es obligatorio",
})
if err != nil {
http.Error(w, fmt.Sprintf("error loading template, err: %v", err), http.StatusInternalServerError)
}
return
}
newID := 0
sort.Slice(todoList, func(i, j int) bool {
return todoList[i].ID > todoList[j].ID
})
if len(todoList) > 0 {
newID = todoList[0].ID + 1
} else {
newID = 1
}
newItem := TodoList{
ID: newID,
Name: name,
Completed: false,
}
todoList = append(todoList, newItem)
err = h.RenderW(w, "fragments/todo-row", hrender.H{
"ID": newID,
"Name": newItem.Name,
"Completed": false,
})
if err != nil {
http.Error(w, fmt.Sprintf("error loading template, err: %v", err), http.StatusInternalServerError)
}
}, "POST")
mux.HandleFunc("/todo/:id/completed", func(w http.ResponseWriter, r *http.Request) {
idStr := r.PathValue("id")
id, err := strconv.Atoi(idStr)
if err != nil {
http.Error(w, fmt.Sprintf("error loading template, err: %v", err), http.StatusInternalServerError)
return
}
var foundItem *TodoList
for i := range todoList {
if todoList[i].ID == id {
todoList[i].Completed = !todoList[i].Completed
foundItem = &todoList[i]
break
}
}
if foundItem == nil {
http.Error(w, fmt.Sprintf("error loading template, err: %v", err), http.StatusInternalServerError)
return
}
w.Header().Set(hrender.ContentType, hrender.ContentTextHTMLUTF8)
err = h.RenderW(w, "fragments/todo-row", hrender.H{
"ID": foundItem.ID,
"Name": foundItem.Name,
"Completed": foundItem.Completed,
})
if err != nil {
http.Error(w, "error loading template", http.StatusInternalServerError)
}
}, "PATCH")
mux.HandleFunc("/todo/:id", func(w http.ResponseWriter, r *http.Request) {
idStr := r.PathValue("id")
id, err := strconv.Atoi(idStr)
if err != nil {
http.Error(w, "invalid id", http.StatusBadRequest)
return
}
if err := r.ParseForm(); err != nil {
http.Error(w, "bad request", http.StatusBadRequest)
return
}
newName := r.FormValue("name")
if newName == "" {
w.Header().Set("HX-Retarget", fmt.Sprintf("#todo-edit-form-%d", id))
w.Header().Set("HX-Reswap", "outerHTML")
err := h.RenderW(w, "fragments/todo-edit-form", hrender.H{
"ID": id,
"Name": newName,
"Error": "El nombre es obligatorio",
})
if err != nil {
http.Error(w, "error loading template", http.StatusInternalServerError)
}
return
}
if newName == "some error" {
log.Println("error triggered")
http.Error(w, "bad request", http.StatusBadRequest)
return
}
var foundItem *TodoList
for i := range todoList {
if todoList[i].ID == id {
todoList[i].Name = newName
foundItem = &todoList[i]
break
}
}
if foundItem == nil {
http.Error(w, "item not found", http.StatusNotFound)
return
}
w.Header().Set(hrender.ContentType, hrender.ContentTextHTMLUTF8)
err = h.RenderW(w, "fragments/todo-row", hrender.H{
"ID": foundItem.ID,
"Name": foundItem.Name,
"Completed": foundItem.Completed,
})
if err != nil {
http.Error(w, "error loading template", http.StatusInternalServerError)
}
}, "PUT")
log.Println("server started on port 8080")
err := http.ListenAndServe(":8080", mux)
if err != nil {
panic("server cannot start")
}
}