feat(budget): further implementation with modal for editing
Some checks failed
Build and Push Docker Image / Build-And-Push-Docker-Image (push) Failing after 1m9s

This commit is contained in:
2026-01-03 16:33:56 +01:00
parent 43e4334201
commit cee01c9a29
5 changed files with 106 additions and 26 deletions

View File

@@ -33,7 +33,7 @@ func NewHandler(s Service, r *core.Render) Handler {
func (h HandlerImpl) Handle(r *http.ServeMux) { func (h HandlerImpl) Handle(r *http.ServeMux) {
r.Handle("GET /budget", h.handlePage()) r.Handle("GET /budget", h.handlePage())
// r.Handle("GET /budget/{id}", h.handleTransactionItemComp()) r.Handle("GET /budget/{id}", h.handleEdit())
r.Handle("POST /budget/{id}", h.handlePost()) r.Handle("POST /budget/{id}", h.handlePost())
// r.Handle("DELETE /budget/{id}", h.handleDelete()) // r.Handle("DELETE /budget/{id}", h.handleDelete())
} }
@@ -48,14 +48,43 @@ func (h HandlerImpl) handlePage() http.HandlerFunc {
return return
} }
// transactions, err := h.s.GetAll(r.Context(), user) budgets, err := h.s.GetAll(r.Context(), user)
if err != nil {
core.HandleError(w, r, err)
return
}
comp := page(budgets)
h.r.RenderLayout(r, w, comp, user)
}
}
func (h HandlerImpl) handleEdit() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
core.UpdateSpan(r)
user := core.GetUser(r)
if user == nil {
core.DoRedirect(w, r, "/auth/signin")
return
}
var (
// id uuid.UUID
// err error
)
idStr := r.PathValue("id")
if idStr != "new" {
// id, err = uuid.Parse(idStr)
// if err != nil { // if err != nil {
// core.HandleError(w, r, err) // core.HandleError(w, r, fmt.Errorf("could not parse Id: %w", core.ErrBadRequest))
// return // return
// } // }
}
comp := page() comp := editNew()
h.r.RenderLayout(r, w, comp, user) h.r.Render(r, w, comp)
} }
} }

View File

@@ -2,39 +2,75 @@ package budget
import "spend-sparrow/internal/template/svg" import "spend-sparrow/internal/template/svg"
templ page() { templ page(budgets []Budget) {
<!-- for _,name:=range([]string{"Lebensmittel", "Tanken", "Drogerie", "Milch", "Parken"}) { -->
<div class="flex flex-wrap gap-20 text-xl mt-10 justify-center"> <div class="flex flex-wrap gap-20 text-xl mt-10 justify-center">
@newItem() @newItem()
for i:=range(10) { for _,budget:=range(budgets ) {
@item(i) @item(budget)
} }
</div> </div>
} }
templ Items() { templ editNew() {
<div></div> <dialog id="newBudget" class="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-lg openDialogModal">
} <form
hx-post={ "/transaction/new" }
templ Edit() { class="flex justify-end gap-4 items-center "
<div></div> >
<div class="grid grid-cols-[auto_auto] items-center gap-4 mr-auto">
<label for="timestamp" class="text-sm text-gray-500">Name</label>
<input
autofocus
name="name"
type="text"
class="bg-white input datetime"
/>
<label for="value" class="text-sm text-gray-500">Value</label>
<input
name="value"
type="number"
class="mr-auto bg-white input"
/>
</div>
<button type="submit" class="button button-neglect px-1 flex items-center gap-2">
@svg.Save()
<span>
Save
</span>
</button>
<button commandfor="newBudget" command="close" class="button button-neglect px-1 flex items-center gap-2">
<span class="h-4 w-4">
@svg.Cancel()
</span>
<span>
Cancel
</span>
</button>
</form>
</dialog>
} }
templ newItem() { templ newItem() {
<section class="p-5 flex gap-4 active:bg-gray-200 flex-col justify-center items-center hover:bg-gray-100 transition-all cursor-pointer w-44 h-44 rounded-lg bg-gray-50 border-1 border-gray-300"> <button
hx-get="/budget/new"
hx-target="#dialogContainer"
class="p-5 w-64 h-64 flex gap-10 active:bg-gray-200 flex-col justify-center items-center hover:bg-gray-100 transition-all cursor-pointer rounded-lg bg-gray-50 border-1 border-gray-300"
>
New Budget New Budget
<div class="w-10"> <div class="w-10">
@svg.Plus() @svg.Plus()
</div> </div>
</section> </button>
} }
templ item(i int) { templ item(budget Budget) {
<section class="flex flex-col w-44 h-44 p-5 rounded-lg bg-gray-50 border-1 border-gray-300 "> <section class="flex flex-col w-64 h-64 p-5 rounded-lg bg-gray-50 border-1 border-gray-300 ">
<span> <span>
Budget { i } { budget.Description }
</span> </span>
<span> <span>
{ 200 + i }€ { 200 }€
</span> </span>
</section> </section>
} }

View File

@@ -37,6 +37,7 @@ templ Layout(slot templ.Component, user templ.Component, loggedIn bool, path str
<script src="/static/js/dashboard.js" defer></script> <script src="/static/js/dashboard.js" defer></script>
</head> </head>
<body hx-headers='{"Csrf-Token": "CSRF_TOKEN"}'> <body hx-headers='{"Csrf-Token": "CSRF_TOKEN"}'>
<div id="dialogContainer"></div>
<div class="flex flex-col min-h-screen"> <div class="flex flex-col min-h-screen">
<header class="sticky top-0 z-50 bg-white flex items-center gap-6 p-4 border-b-1 border-gray-200"> <header class="sticky top-0 z-50 bg-white flex items-center gap-6 p-4 border-b-1 border-gray-200">
<button id="menuButton" class="w-10 h-10 block xl:hidden"> <button id="menuButton" class="w-10 h-10 block xl:hidden">

View File

@@ -1,11 +1,25 @@
document.addEventListener("DOMContentLoaded", () => { document.addEventListener("DOMContentLoaded", () => {
menuButton.addEventListener("click", function (e) { menuButton.addEventListener("click", function() {
menu.showModal(); menu.showModal();
}); });
menuButtonClose.addEventListener("click", function (e) { menuButtonClose.addEventListener("click", function() {
menu.close(); menu.close();
}); });
}) })
htmx.on("htmx:afterSwap", () => {
dialogs = dialogContainer.getElementsByClassName("openDialogModal");
Array.from(dialogs).forEach((dialog) => {
dialog.showModal()
// buttons = dialog.getElementsByClassName("closeModalDialog");
// Array.from(buttons).forEach((button) => button.addEventListener("click", closeModalDialog))
})
});
// function closeModalDialog(e) {
// e.preventDefault();
// console.log(e)
// e.target.close()
// }

View File

@@ -11,7 +11,7 @@ function updateTime() {
document.querySelectorAll(".datetime").forEach((el) => { document.querySelectorAll(".datetime").forEach((el) => {
if (el.textContent !== "") { if (el.textContent !== "") {
el.textContent = el.textContent.includes("UTC") ? new Date(el.textContent).toLocaleString([], { day: 'numeric', month: 'short', year: 'numeric' }) : el.textContent; el.textContent = el.textContent.includes("UTC") ? new Date(el.textContent).toLocaleString([], { day: 'numeric', month: 'short', year: 'numeric' }) : el.textContent;
} else if (el.attributes['value'] !== "") { } else if (el.attributes['value'] && el.attributes['value'] !== "") {
const value = el.attributes['value'].value; const value = el.attributes['value'].value;
const newDate = value.includes("UTC") ? new Date(value) : value; const newDate = value.includes("UTC") ? new Date(value) : value;
el.valueAsDate = newDate; el.valueAsDate = newDate;