From f444a074bcc3a68864f9997737c65f64455adcf0 Mon Sep 17 00:00:00 2001 From: juancwu Date: Fri, 22 May 2026 13:02:57 +0000 Subject: [PATCH] chore: update recurring events ui --- internal/ui/forms/helpers.go | 65 ++++++++- internal/ui/forms/recurring_event.templ | 184 ++++++++++++++++++++---- 2 files changed, 219 insertions(+), 30 deletions(-) diff --git a/internal/ui/forms/helpers.go b/internal/ui/forms/helpers.go index 28e9a6d..fc8f0cb 100644 --- a/internal/ui/forms/helpers.go +++ b/internal/ui/forms/helpers.go @@ -1,5 +1,68 @@ package forms -import "strconv" +import ( + "strconv" + + "git.juancwu.dev/juancwu/budgit/internal/misc/timezone" + "git.juancwu.dev/juancwu/budgit/internal/model" +) func intToStr(n int) string { return strconv.Itoa(n) } + +func kindLabel(v string) string { + switch v { + case string(model.RecurringEventKindBill): + return "Bill (withdrawal)" + case string(model.RecurringEventKindFund): + return "Fund (deposit)" + } + return "" +} + +func frequencyLabel(v string) string { + switch v { + case string(model.RecurringFrequencyDaily): + return "Daily" + case string(model.RecurringFrequencyWeekly): + return "Weekly" + case string(model.RecurringFrequencyMonthly): + return "Monthly" + case string(model.RecurringFrequencyYearly): + return "Yearly" + } + return "" +} + +func weekdayLabel(v string) string { + i, err := strconv.Atoi(v) + if err != nil || i < 0 || i >= len(weekdayNames) { + return "" + } + return weekdayNames[i] +} + +func monthLabel(v string) string { + i, err := strconv.Atoi(v) + if err != nil || i < 1 || i > len(monthNames) { + return "" + } + return monthNames[i-1] +} + +func accountLabel(accounts []*model.Account, id string) string { + for _, a := range accounts { + if a.ID == id { + return a.Name + } + } + return "" +} + +func timezoneLabel(tzs []timezone.TimezoneOption, v string) string { + for _, tz := range tzs { + if tz.Value == v { + return tz.Label + } + } + return "" +} diff --git a/internal/ui/forms/recurring_event.templ b/internal/ui/forms/recurring_event.templ index dd37e6a..826ecac 100644 --- a/internal/ui/forms/recurring_event.templ +++ b/internal/ui/forms/recurring_event.templ @@ -7,6 +7,7 @@ import "git.juancwu.dev/juancwu/budgit/internal/ui/components/card" import "git.juancwu.dev/juancwu/budgit/internal/ui/components/checkbox" import "git.juancwu.dev/juancwu/budgit/internal/ui/components/form" import "git.juancwu.dev/juancwu/budgit/internal/ui/components/input" +import "git.juancwu.dev/juancwu/budgit/internal/ui/components/selectbox" import "git.juancwu.dev/juancwu/budgit/internal/ui/components/textarea" type RecurringEventFormProps struct { @@ -91,10 +92,31 @@ templ RecurringEventForm(props RecurringEventFormProps) { @form.Label(form.LabelProps{For: "kind"}) { Kind } - + @selectbox.SelectBox() { + @selectbox.Trigger(selectbox.TriggerProps{ + ID: "kind", + Name: "kind", + HasError: props.KindErr != "", + }) { + @selectbox.Value(selectbox.ValueProps{Placeholder: "Select a kind…"}) { + { kindLabel(props.Kind) } + } + } + @selectbox.Content(selectbox.ContentProps{NoSearch: true}) { + @selectbox.Item(selectbox.ItemProps{ + Value: string(model.RecurringEventKindBill), + Selected: props.Kind == string(model.RecurringEventKindBill), + }) { + Bill (withdrawal) + } + @selectbox.Item(selectbox.ItemProps{ + Value: string(model.RecurringEventKindFund), + Selected: props.Kind == string(model.RecurringEventKindFund), + }) { + Fund (deposit) + } + } + } if props.KindErr != "" { @form.Message(form.MessageProps{Variant: form.MessageVariantError}) { { props.KindErr } @@ -105,12 +127,27 @@ templ RecurringEventForm(props RecurringEventFormProps) { @form.Label(form.LabelProps{For: "source_account"}) { Account } - + @selectbox.Content(selectbox.ContentProps{SearchPlaceholder: "Search accounts…"}) { + for _, a := range props.Accounts { + @selectbox.Item(selectbox.ItemProps{ + Value: a.ID, + Selected: props.SourceAccountID == a.ID, + }) { + { a.Name } + } + } + } + } if props.SourceErr != "" { @form.Message(form.MessageProps{Variant: form.MessageVariantError}) { { props.SourceErr } @@ -147,12 +184,43 @@ templ RecurringEventForm(props RecurringEventFormProps) { @form.Label(form.LabelProps{For: "frequency"}) { Frequency } - + @selectbox.SelectBox() { + @selectbox.Trigger(selectbox.TriggerProps{ + ID: "frequency", + Name: "frequency", + HasError: props.FrequencyErr != "", + }) { + @selectbox.Value(selectbox.ValueProps{Placeholder: "Select a frequency…"}) { + { frequencyLabel(props.Frequency) } + } + } + @selectbox.Content(selectbox.ContentProps{NoSearch: true}) { + @selectbox.Item(selectbox.ItemProps{ + Value: string(model.RecurringFrequencyDaily), + Selected: props.Frequency == string(model.RecurringFrequencyDaily), + }) { + Daily + } + @selectbox.Item(selectbox.ItemProps{ + Value: string(model.RecurringFrequencyWeekly), + Selected: props.Frequency == string(model.RecurringFrequencyWeekly), + }) { + Weekly + } + @selectbox.Item(selectbox.ItemProps{ + Value: string(model.RecurringFrequencyMonthly), + Selected: props.Frequency == string(model.RecurringFrequencyMonthly), + }) { + Monthly + } + @selectbox.Item(selectbox.ItemProps{ + Value: string(model.RecurringFrequencyYearly), + Selected: props.Frequency == string(model.RecurringFrequencyYearly), + }) { + Yearly + } + } + } if props.FrequencyErr != "" { @form.Message(form.MessageProps{Variant: form.MessageVariantError}) { { props.FrequencyErr } @@ -191,12 +259,33 @@ templ RecurringEventForm(props RecurringEventFormProps) { @form.Label(form.LabelProps{For: "day_of_week"}) { Day of week } - + @selectbox.Content(selectbox.ContentProps{NoSearch: true}) { + @selectbox.Item(selectbox.ItemProps{ + Value: "", + Selected: props.DayOfWeek == "", + }) { + — + } + for i, name := range weekdayNames { + @selectbox.Item(selectbox.ItemProps{ + Value: intToStr(i), + Selected: props.DayOfWeek == intToStr(i), + }) { + { name } + } + } + } + } @form.Description() { Used for weekly events. } @@ -235,12 +324,33 @@ templ RecurringEventForm(props RecurringEventFormProps) { @form.Label(form.LabelProps{For: "month_of_year"}) { Month } - + @selectbox.Content(selectbox.ContentProps{NoSearch: true}) { + @selectbox.Item(selectbox.ItemProps{ + Value: "", + Selected: props.MonthOfYear == "", + }) { + — + } + for i, name := range monthNames { + @selectbox.Item(selectbox.ItemProps{ + Value: intToStr(i + 1), + Selected: props.MonthOfYear == intToStr(i + 1), + }) { + { name } + } + } + } + } @form.Description() { Used for yearly events. } @@ -275,11 +385,27 @@ templ RecurringEventForm(props RecurringEventFormProps) { @form.Label(form.LabelProps{For: "timezone"}) { Timezone } - + @selectbox.Content(selectbox.ContentProps{SearchPlaceholder: "Search timezones…"}) { + for _, tz := range props.Timezones { + @selectbox.Item(selectbox.ItemProps{ + Value: tz.Value, + Selected: props.Timezone == tz.Value, + }) { + { tz.Label } + } + } + } + } if props.TimezoneErr != "" { @form.Message(form.MessageProps{Variant: form.MessageVariantError}) { { props.TimezoneErr }