chore: update recurring events ui

This commit is contained in:
juancwu 2026-05-22 13:02:57 +00:00
commit f444a074bc
2 changed files with 219 additions and 30 deletions

View file

@ -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 ""
}

View file

@ -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
}
<select id="kind" name="kind" class="flex h-9 w-full items-center rounded-sm border border-input bg-transparent px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring" required>
<option value={ string(model.RecurringEventKindBill) } selected?={ props.Kind == string(model.RecurringEventKindBill) }>Bill (withdrawal)</option>
<option value={ string(model.RecurringEventKindFund) } selected?={ props.Kind == string(model.RecurringEventKindFund) }>Fund (deposit)</option>
</select>
@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
}
<select id="source_account" name="source_account" class="flex h-9 w-full items-center rounded-sm border border-input bg-transparent px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring" required>
<option value="" selected?={ props.SourceAccountID == "" }>Select an account…</option>
for _, a := range props.Accounts {
<option value={ a.ID } selected?={ props.SourceAccountID == a.ID }>{ a.Name }</option>
@selectbox.SelectBox() {
@selectbox.Trigger(selectbox.TriggerProps{
ID: "source_account",
Name: "source_account",
HasError: props.SourceErr != "",
}) {
@selectbox.Value(selectbox.ValueProps{Placeholder: "Select an account…"}) {
{ accountLabel(props.Accounts, props.SourceAccountID) }
}
}
</select>
@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
}
<select id="frequency" name="frequency" class="flex h-9 w-full items-center rounded-sm border border-input bg-transparent px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring" required>
<option value={ string(model.RecurringFrequencyDaily) } selected?={ props.Frequency == string(model.RecurringFrequencyDaily) }>Daily</option>
<option value={ string(model.RecurringFrequencyWeekly) } selected?={ props.Frequency == string(model.RecurringFrequencyWeekly) }>Weekly</option>
<option value={ string(model.RecurringFrequencyMonthly) } selected?={ props.Frequency == string(model.RecurringFrequencyMonthly) }>Monthly</option>
<option value={ string(model.RecurringFrequencyYearly) } selected?={ props.Frequency == string(model.RecurringFrequencyYearly) }>Yearly</option>
</select>
@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
}
<select id="day_of_week" name="day_of_week" class="flex h-9 w-full items-center rounded-sm border border-input bg-transparent px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring">
<option value="">—</option>
for i, name := range weekdayNames {
<option value={ intToStr(i) } selected?={ props.DayOfWeek == intToStr(i) }>{ name }</option>
@selectbox.SelectBox() {
@selectbox.Trigger(selectbox.TriggerProps{
ID: "day_of_week",
Name: "day_of_week",
HasError: props.DayOfWeekErr != "",
}) {
@selectbox.Value(selectbox.ValueProps{Placeholder: "—"}) {
{ weekdayLabel(props.DayOfWeek) }
}
}
</select>
@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
}
<select id="month_of_year" name="month_of_year" class="flex h-9 w-full items-center rounded-sm border border-input bg-transparent px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring">
<option value="">—</option>
for i, name := range monthNames {
<option value={ intToStr(i + 1) } selected?={ props.MonthOfYear == intToStr(i + 1) }>{ name }</option>
@selectbox.SelectBox() {
@selectbox.Trigger(selectbox.TriggerProps{
ID: "month_of_year",
Name: "month_of_year",
HasError: props.MonthOfYearErr != "",
}) {
@selectbox.Value(selectbox.ValueProps{Placeholder: "—"}) {
{ monthLabel(props.MonthOfYear) }
}
}
</select>
@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
}
<select id="timezone" name="timezone" class="flex h-9 w-full items-center rounded-sm border border-input bg-transparent px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring" required>
for _, tz := range props.Timezones {
<option value={ tz.Value } selected?={ props.Timezone == tz.Value }>{ tz.Label }</option>
@selectbox.SelectBox() {
@selectbox.Trigger(selectbox.TriggerProps{
ID: "timezone",
Name: "timezone",
HasError: props.TimezoneErr != "",
}) {
@selectbox.Value(selectbox.ValueProps{Placeholder: "Select a timezone…"}) {
{ timezoneLabel(props.Timezones, props.Timezone) }
}
}
</select>
@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 }