Files
ersteller/starter/todos/todos.go
T

169 lines
5.0 KiB
Go

package todos
import (
"context"
"fmt"
"strconv"
"strings"
. "ersteller-lib"
"git.gorlug.de/code/golang/ersteller-lib/starter/ent"
"git.gorlug.de/code/golang/ersteller-lib/starter/ent/todo"
. "maragu.dev/gomponents"
. "maragu.dev/gomponents/html"
)
const TodosPath = "/todos"
const TodosPathDe = "/todos"
// i18n texts
var texts *Texts
type Texts struct {
PageTitle I18nText
PageDescription I18nText
HeroTitle I18nText
AddPlaceholder I18nText
AddButton I18nText
DeleteButton I18nText
SaveButton I18nText
}
type Page struct {
createPage CreateHtmxPageFunc
db *ent.Client
ViewRoute HtmxRoute
AddRoute HtmxRoute
UpdateRoute HtmxRoute
DeleteRoute HtmxRoute
}
func NewPage(createPage CreateHtmxPageFunc, server HtmxServer, path *ActivePath, db *ent.Client) *Page {
if texts == nil {
createTexts()
}
p := &Page{createPage: createPage, db: db}
p.ViewRoute = NewHtmxGetRoute(p.View, LanguagePaths{En: TodosPath, De: TodosPathDe}).SetActivePath(path)
p.ViewRoute.Add(server)
p.AddRoute = NewHtmxPostRoute(p.Add, LanguagePaths{En: TodosPath + "/add", De: TodosPathDe + "/add"})
p.AddRoute.Add(server)
p.UpdateRoute = NewHtmxPostRoute(p.Update, LanguagePaths{En: TodosPath + "/update", De: TodosPathDe + "/update"})
p.UpdateRoute.Add(server)
p.DeleteRoute = NewHtmxPostRoute(p.Delete, LanguagePaths{En: TodosPath + "/delete", De: TodosPathDe + "/delete"})
p.DeleteRoute.Add(server)
return p
}
func createTexts() {
texts = &Texts{
PageTitle: NewI18nText(map[Language]string{En: "Todos", De: "Todos"}),
PageDescription: NewI18nText(map[Language]string{En: "Manage your todos", De: "Verwalte deine Todos"}),
HeroTitle: NewI18nText(map[Language]string{En: "Todos", De: "Todos"}),
AddPlaceholder: NewI18nText(map[Language]string{En: "New todo title", De: "Neuer Todo-Titel"}),
AddButton: NewI18nText(map[Language]string{En: "Add", De: "Hinzufügen"}),
DeleteButton: NewI18nText(map[Language]string{En: "Delete", De: "Löschen"}),
SaveButton: NewI18nText(map[Language]string{En: "Save", De: "Speichern"}),
}
}
func (p *Page) getMetaData() PageWebsiteMetaData {
return PageWebsiteMetaData{
Title: texts.PageTitle,
Lang: En,
Description: texts.PageDescription,
}
}
func (p *Page) View(c HtmxContext) {
language := c.GetLanguage()
todos, _ := p.db.Todo.Query().Order(ent.Asc(todo.FieldCreatedAt)).All(context.Background())
content := Group{
Div(Class("hero-section"),
H1(Class("hero-title"), Text(texts.HeroTitle.FromLang(language))),
),
Div(Class("content-section"),
p.addForm(c),
Div(ID("todos-list"), p.todosList(c, todos)),
),
}
p.createPage(c, p.getMetaData(), content)
}
func (p *Page) addForm(c HtmxContext) Node {
lang := c.GetLanguage()
return Form(Action(p.AddRoute.ToUrlFromContext(c, lang)), Method("post"),
Div(Class("form-row"),
Input(Type("text"), Name("title"), Placeholder(texts.AddPlaceholder.FromLang(lang))),
Button(Type("submit"), Text(texts.AddButton.FromLang(lang))),
),
)
}
func (p *Page) todosList(c HtmxContext, list []*ent.Todo) Node {
lang := c.GetLanguage()
items := make([]Node, 0, len(list))
for _, t := range list {
items = append(items, p.todoItem(c, lang, t))
}
return Ul(Class("todo-list"), Group(items))
}
func (p *Page) todoItem(c HtmxContext, lang Language, t *ent.Todo) Node {
// Simple inline edit form per item
return Li(ID(p.itemDomID(t.ID)),
Form(Action(p.UpdateRoute.ToUrlFromContext(c, lang)), Method("post"),
Input(Type("hidden"), Name("id"), Value(fmt.Sprintf("%d", t.ID))),
Input(Type("checkbox"), Name("completed"), If(t.Completed, Attr("checked", "checked"))),
Input(Type("text"), Name("title"), Value(t.Title)),
Button(Type("submit"), Text(texts.SaveButton.FromLang(lang))),
),
Form(Action(p.DeleteRoute.ToUrlFromContext(c, lang)), Method("post"),
Input(Type("hidden"), Name("id"), Value(fmt.Sprintf("%d", t.ID))),
Button(Type("submit"), Class("danger"), Text(texts.DeleteButton.FromLang(lang))),
),
)
}
func (p *Page) itemDomID(id int) string { return fmt.Sprintf("todo-%d", id) }
// Handlers
func (p *Page) Add(c HtmxContext) {
title := strings.TrimSpace(c.GetFormValue("title"))
if title == "" {
p.renderList(c)
return
}
_, _ = p.db.Todo.Create().SetTitle(title).Save(context.Background())
p.renderList(c)
}
func (p *Page) Update(c HtmxContext) {
idStr := c.GetFormValue("id")
id, _ := strconv.Atoi(idStr)
if id == 0 {
p.renderList(c)
return
}
title := strings.TrimSpace(c.GetFormValue("title"))
completed := c.GetFormValue("completed") == "on"
_ = p.db.Todo.UpdateOneID(id).SetTitle(title).SetCompleted(completed).Exec(context.Background())
p.renderList(c)
}
func (p *Page) Delete(c HtmxContext) {
idStr := c.GetFormValue("id")
id, _ := strconv.Atoi(idStr)
if id != 0 {
_ = p.db.Todo.DeleteOneID(id).Exec(context.Background())
}
p.renderList(c)
}
func (p *Page) renderList(c HtmxContext) {
todos, _ := p.db.Todo.Query().Order(ent.Asc(todo.FieldCreatedAt)).All(context.Background())
c.Render(Div(ID("todos-list"), p.todosList(c, todos)))
}