// Package form holds the shared huh entry-form builders used by both the // day list view and the grid view. Pure builders only — each view keeps its // own edit state machine (coupled to the Bubble Tea value-copy pointer fix). package form import ( "fmt" "strings" "time" "github.com/charmbracelet/huh" "ticktock/internal/store" ) // Values holds the raw string fields the huh form edits. type Values struct { Start, End, Project, Desc, Tags, Note string } // SplitTags splits a comma-separated tag string, trimming blanks. func SplitTags(s string) []string { var out []string for _, p := range strings.Split(s, ",") { if p = strings.TrimSpace(p); p != "" { out = append(out, p) } } return out } // BuildEntry turns form Values into an Entry on date (HH:MM times). The // returned Entry has no Key; the caller decides Add vs SafeReplace. func BuildEntry(date string, base store.Entry, v Values) (store.Entry, error) { st, err := time.ParseInLocation("2006-01-02 15:04", date+" "+v.Start, time.Local) if err != nil { return store.Entry{}, fmt.Errorf("start time %q: %w", v.Start, err) } et, err := time.ParseInLocation("2006-01-02 15:04", date+" "+v.End, time.Local) if err != nil { return store.Entry{}, fmt.Errorf("end time %q: %w", v.End, err) } return store.Entry{ Start: st, End: et, Project: v.Project, Description: v.Desc, Tags: SplitTags(v.Tags), Notes: v.Note, }, nil } // Suggest carries autocomplete candidates for the form's inputs. type Suggest struct { Projects, Descriptions, Tags []string } // New prefills *v from e and returns the edit form bound to v, with history // suggestions attached to project/description/tags. func New(e store.Entry, v *Values, sug Suggest) *huh.Form { v.Start = e.Start.Format("15:04") if e.Running() { v.End = "" } else { v.End = e.End.Format("15:04") } v.Project, v.Desc = e.Project, e.Description v.Tags, v.Note = strings.Join(e.Tags, ", "), e.Notes return huh.NewForm(huh.NewGroup( huh.NewInput().Title("start (HH:MM)").Value(&v.Start), huh.NewInput().Title("end (HH:MM)").Value(&v.End), huh.NewInput().Title("project").Value(&v.Project).Suggestions(sug.Projects), huh.NewInput().Title("description").Value(&v.Desc).Suggestions(sug.Descriptions), huh.NewInput().Title("tags (comma-sep)").Value(&v.Tags).Suggestions(sug.Tags), huh.NewInput().Title("note").Value(&v.Note), )) } // AddForm builds a form for a new entry whose start/end are already fixed by a // grid selection. Start/end are prefilled and placed last so the cursor lands // on project, yet the times remain editable if the selection needs tweaking. func AddForm(start, end, project string, v *Values, sug Suggest) *huh.Form { *v = Values{Start: start, End: end, Project: project} return huh.NewForm(huh.NewGroup( huh.NewInput().Title("project").Value(&v.Project).Suggestions(sug.Projects), huh.NewInput().Title("description").Value(&v.Desc).Suggestions(sug.Descriptions), huh.NewInput().Title("tags (comma-sep)").Value(&v.Tags).Suggestions(sug.Tags), huh.NewInput().Title("note").Value(&v.Note), huh.NewInput().Title("start (HH:MM)").Value(&v.Start), huh.NewInput().Title("end (HH:MM)").Value(&v.End), )) }