diff --git a/mite/mite.go b/mite/mite.go index f555ec2..3ad792c 100644 --- a/mite/mite.go +++ b/mite/mite.go @@ -51,7 +51,7 @@ func (p Project) String() string { return fmt.Sprintf("%d: %s (%s)", p.ID, p.Name, p.CustomerName) } func (p Project) GetID() int { return p.ID } -func (p Project) GetName() string { return p.Name } +func (p Project) GetName() string { return p.Name + " (" + p.CustomerName + ")" } func (a APIClient) GetProjects() (Projects, error) { // GET /projects.json @@ -231,8 +231,8 @@ type requestAddTimeEntry struct { RequestTimeEntryHolder struct { DateAt string `json:"date_at"` Minutes int `json:"minutes"` - ProjectID int `json:"project_id,omit_empty"` - ServiceID int `json:"service_id,omit_empty"` + ProjectID int `json:"project_id,omitempty"` + ServiceID int `json:"service_id,omitempty"` Note string `json:"note"` } `json:"time_entry"` } diff --git a/model.go b/model.go index 20d7075..1be44ce 100644 --- a/model.go +++ b/model.go @@ -4,7 +4,7 @@ import ( "charmcal/mite" "errors" "fmt" - "strconv" + "slices" "strings" "time" @@ -54,6 +54,7 @@ type model struct { } statusBarMessage string windowWidth int + windowHeight int } func initialModel(miteDomain, miteApiKey string) model { @@ -92,86 +93,6 @@ func initialModel(miteDomain, miteApiKey string) model { return m } -func (m model) buildForm() *huh.Form { - - clOptions := []huh.Option[string]{} - for _, cust := range m.formData.customers { - op := miteToHuhOption(cust) - clOptions = append(clOptions, op) - } - - svcOptions := []huh.Option[string]{} - for _, svc := range m.formData.services { - op := miteToHuhOption(svc) - svcOptions = append(svcOptions, op) - } - - cl := huh.NewSelect[string](). - Key("client"). - Options(clOptions...). - Title("Client").Height(5).Value(&m.formData.selected.customer) - - sl := huh.NewSelect[string](). - Key("service"). - Options(svcOptions...). - Title("Service").Height(5) - - pl := huh.NewSelect[string](). - Key("project"). - Title("Project").Height(3). - OptionsFunc(func() []huh.Option[string] { - out := []huh.Option[string]{} - for _, proj := range m.formData.projects { - if fmt.Sprint(proj.CustomerID) == m.formData.selected.customer { - out = append(out, miteToHuhOption(proj)) - } - } - return out - }, &m.formData.selected.customer) - - form := huh.NewForm( - huh.NewGroup( - cl, - sl, - pl, - ), - huh.NewGroup( - huh.NewText(). - Key("description"). - Title("description"). - Validate(func(s string) error { - if s == "" { - return errors.New("must enter a description") - } - return nil - }), - huh.NewInput(). - Key("minutes"). - CharLimit(5). - Validate( - func(s string) error { - h, err := strconv.ParseInt(s, 10, 64) - if err != nil { - return err - } - if h < 0 { - return errors.New("must be positive") - } - return err - }). - Title("Minutes"), - ), - ) - return form -} - -func miteToHuhOption[T mite.APIObject](i T) huh.Option[string] { - return huh.Option[string]{ - Key: i.GetName(), - Value: fmt.Sprint(i.GetID()), - } -} - func (m model) Init() tea.Cmd { return m.fetchMiteData() } @@ -195,6 +116,10 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.formData.projects = msg.Projects m.fetchedData = true + slices.SortFunc(m.formData.customers, func(a, b mite.Customer) int { return strings.Compare(a.GetName(), b.GetName()) }) + slices.SortFunc(m.formData.services, func(a, b mite.Service) int { return strings.Compare(a.GetName(), b.GetName()) }) + slices.SortFunc(m.formData.projects, func(a, b mite.Project) int { return strings.Compare(a.GetName(), b.GetName()) }) + // just in case there is data for the currently focused day m.timeData.table.SetRows(m.tableDataForDate(m.dest.Time)) } @@ -275,6 +200,7 @@ func (m model) updateCal(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case tea.WindowSizeMsg: m.windowWidth = msg.Width + m.windowHeight = msg.Height // Is it a key press? case tea.KeyMsg: @@ -473,7 +399,7 @@ func (m model) View() string { sofar := lipgloss.Height(out) statusMsg := strings.ReplaceAll(m.statusBarMessage, "\n", " ") - out += styleStatusBar.MarginTop(19 - sofar).Width(m.windowWidth).Render(statusMsg) + out += styleStatusBar.MarginTop(m.windowHeight - sofar).Width(m.windowWidth).Render(statusMsg) return out } diff --git a/model_form.go b/model_form.go index 49e276b..a83aee9 100644 --- a/model_form.go +++ b/model_form.go @@ -1,7 +1,9 @@ package main import ( + "charmcal/mite" "errors" + "fmt" "strconv" "time" @@ -43,7 +45,7 @@ func (m model) updateForm(msg tea.Msg) (tea.Model, tea.Cmd) { err := m.miteAPI.AddTimeEntry(m.dest.Format(time.DateOnly), int(minutesInt), description, int(projectIDInt), int(serviceIDInt)) if err != nil { - m.statusBarMessage = errors.Join(err1, err2, err3).Error() + m.statusBarMessage = err.Error() m.tuiMode = MODE_CAL } else { m.statusBarMessage = "Successfully logged time" @@ -56,3 +58,87 @@ func (m model) updateForm(msg tea.Msg) (tea.Model, tea.Cmd) { return m, formCmd } + +func (m model) buildForm() *huh.Form { + + clOptions := []huh.Option[string]{} + for _, cust := range m.formData.customers { + op := miteToHuhOption(cust) + clOptions = append(clOptions, op) + } + + svcOptions := []huh.Option[string]{} + for _, svc := range m.formData.services { + op := miteToHuhOption(svc) + svcOptions = append(svcOptions, op) + } + + projOptions := []huh.Option[string]{ + { + Key: "[no project]", + Value: "0", + }, + } + for _, proj := range m.formData.projects { + op := miteToHuhOption(proj) + projOptions = append(projOptions, op) + } + + // cl := huh.NewSelect[string](). + // Key("client"). + // Options(clOptions...). + // Title("Client").Height(5).Value(&m.formData.selected.customer) + + sl := huh.NewSelect[string](). + Key("service"). + Options(svcOptions...). + Title("Service"). + Height(6) + + pl := huh.NewSelect[string](). + Key("project"). + Title("Project"). + Options(projOptions...). + Height(10) + + form := huh.NewForm( + huh.NewGroup( + pl, + sl, + ), + huh.NewGroup( + huh.NewText(). + Key("description"). + Title("description"). + Validate(func(s string) error { + if s == "" { + return errors.New("must enter a description") + } + return nil + }), + huh.NewInput(). + Key("minutes"). + CharLimit(5). + Validate( + func(s string) error { + h, err := strconv.ParseInt(s, 10, 64) + if err != nil { + return err + } + if h < 0 { + return errors.New("must be positive") + } + return err + }). + Title("Minutes"), + ), + ) + return form +} + +func miteToHuhOption[T mite.APIObject](i T) huh.Option[string] { + return huh.Option[string]{ + Key: i.GetName(), + Value: fmt.Sprint(i.GetID()), + } +}