summaryrefslogtreecommitdiff
path: root/internal/tui/form.go
diff options
context:
space:
mode:
authorT <t@tjp.lol>2025-08-13 15:25:23 -0600
committerT <t@tjp.lol>2025-08-13 16:02:05 -0600
commite9e6eb4e456ee53da5a6ef743251410d4d3d8381 (patch)
treed722145a5f7a3dd07623e96045078983b3a14e4c /internal/tui/form.go
parentd6781f3e5b431057c23b2deaa943f273699e37f5 (diff)
report generation modal
Diffstat (limited to 'internal/tui/form.go')
-rw-r--r--internal/tui/form.go77
1 files changed, 56 insertions, 21 deletions
diff --git a/internal/tui/form.go b/internal/tui/form.go
index 3a1e5f6..d70fb8b 100644
--- a/internal/tui/form.go
+++ b/internal/tui/form.go
@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"strconv"
+ "strings"
"time"
"punchcard/internal/reports"
@@ -19,6 +20,7 @@ const (
noSuggestions suggestionType = iota
suggestClients
suggestProjects
+ suggestReportType
)
type FormField struct {
@@ -100,6 +102,22 @@ func newDateRangeField(label string) FormField {
return f
}
+func newReportTypeField(label string) FormField {
+ f := FormField{
+ Model: textinput.New(),
+ label: label,
+ suggestions: suggestReportType,
+ }
+ f.Validate = func(s string) error {
+ switch strings.ToLower(s) {
+ case "invoice", "timesheet", "unified":
+ return nil
+ }
+ return errors.New("pick one of invoice, timesheet, or unified")
+ }
+ return f
+}
+
type Form struct {
fields []FormField
selIdx int
@@ -113,8 +131,8 @@ func NewForm(fields []FormField) Form {
return Form{fields: fields}
}
-func (ff Form) Error() error {
- for _, field := range ff.fields {
+func (f Form) Error() error {
+ for _, field := range f.fields {
if field.Err != nil {
return field.Err
}
@@ -169,44 +187,58 @@ func NewHistoryFilterForm() Form {
return form
}
-func (ff Form) Update(msg tea.Msg) (Form, tea.Cmd) {
+func NewGenerateReportForm() Form {
+ form := NewForm([]FormField{
+ newReportTypeField("Report Type"),
+ newDateRangeField("Date Range"),
+ {Model: textinput.New(), label: "Client", suggestions: suggestClients},
+ {Model: textinput.New(), label: "Project (optional)", suggestions: suggestProjects},
+ {Model: textinput.New(), label: "Output Path (optional)"},
+ {Model: textinput.New(), label: "Timezone (optional)"},
+ })
+ form.SelectedStyle = &modalFocusedInputStyle
+ form.UnselectedStyle = &modalBlurredInputStyle
+ return form
+}
+
+func (f Form) Update(msg tea.Msg) (Form, tea.Cmd) {
if msg, ok := msg.(tea.KeyMsg); ok {
switch msg.String() {
case "tab":
- ff.fields[ff.selIdx].Blur()
- ff.selIdx = (ff.selIdx + 1) % len(ff.fields)
- return ff, ff.fields[ff.selIdx].Focus()
+ f.fields[f.selIdx].Blur()
+ f.selIdx = (f.selIdx + 1) % len(f.fields)
+ return f, f.fields[f.selIdx].Focus()
case "shift+tab":
- ff.fields[ff.selIdx].Blur()
- ff.selIdx--
- if ff.selIdx < 0 {
- ff.selIdx += len(ff.fields)
+ f.fields[f.selIdx].Blur()
+ f.selIdx--
+ if f.selIdx < 0 {
+ f.selIdx += len(f.fields)
}
- return ff, ff.fields[ff.selIdx].Focus()
+ return f, f.fields[f.selIdx].Focus()
}
}
- field, cmd := ff.fields[ff.selIdx].Update(msg)
- ff.fields[ff.selIdx] = field
- return ff, cmd
+ field, cmd := f.fields[f.selIdx].Update(msg)
+ f.fields[f.selIdx] = field
+ return f, cmd
}
-func (ff Form) View() string {
+func (f Form) View() string {
content := ""
- if ff.err != nil {
- content += errorStyle.Render(ff.err.Error()) + "\n\n"
+ if f.err != nil {
+ content += errorStyle.Render(f.err.Error()) + "\n\n"
}
- for i, field := range ff.fields {
+ for i, field := range f.fields {
if i > 0 {
content += "\n\n"
}
content += field.label + ":\n"
- style := ff.UnselectedStyle
- if i == ff.selIdx {
- style = ff.SelectedStyle
+ style := f.UnselectedStyle
+ if i == f.selIdx {
+ style = f.SelectedStyle
}
if style != nil {
content += style.Render(field.View())
@@ -241,6 +273,9 @@ func (f *Form) SetSuggestions(m AppModel) {
}
ff.SetSuggestions(projNames)
ff.ShowSuggestions = true
+ case suggestReportType:
+ ff.SetSuggestions([]string{"Invoice", "Timesheet", "Unified"})
+ ff.ShowSuggestions = true
}
}
}