Skip to content

Commit

Permalink
Merge pull request #7 from drewstinnett/feature-edit-entry
Browse files Browse the repository at this point in the history
Feature: Edit Form
  • Loading branch information
drewstinnett authored Feb 7, 2024
2 parents c8a9796 + a87bd35 commit 8972038
Show file tree
Hide file tree
Showing 10 changed files with 287 additions and 117 deletions.
1 change: 1 addition & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ linters-settings:
- '$gostd'
- "github.com/stretchr/testify/require"
- "github.com/stretchr/testify/assert"
- "github.com/charmbracelet/huh"
# depguard:
# list-type: blacklist
# include-go-root: false
Expand Down
64 changes: 64 additions & 0 deletions cmd/letseat/cmd/edit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package cmd

import (
"fmt"
"sort"

"github.com/charmbracelet/huh"
letseat "github.com/drewstinnett/letseat/pkg"
"github.com/spf13/cobra"
)

func newEditCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "edit",
Short: "edit entries",
RunE: runEdit,
}
return cmd
}

func editEntryOpts(e letseat.Entries) []huh.Option[string] {
sort.Slice(e, func(i, j int) bool {
return e[i].Date.After(*e[j].Date)
})
ret := make([]huh.Option[string], len(e))
for idx, entry := range e {
ret[idx] = huh.NewOption(fmt.Sprintf("%v - %v", entry.Date.Format("2006-01-02"), entry.Place), entry.Key())
}
return ret
}

func runEdit(cmd *cobra.Command, args []string) error {
diary := letseat.New(
letseat.WithDBFilename(mustGetCmd[string](*cmd, "data")),
)
defer dclose(diary)

var editID string
form := huh.NewForm(
huh.NewGroup(
huh.NewSelect[string]().
Title("Which entry would you like to edit?").
Options(
editEntryOpts(diary.Entries())...,
).
Value(&editID),
),
)
if err := form.Run(); err != nil {
return err
}

e, err := diary.Get(editID)
if err != nil {
return err
}

editForm := newEntryForm(e)
if err := editForm.NewForm(diary.Entries()).Run(); err != nil {
return err
}

return nil
}
2 changes: 1 addition & 1 deletion cmd/letseat/cmd/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ func runExport(cmd *cobra.Command, args []string) error {
diary := letseat.New(
letseat.WithDBFilename(mustGetCmd[string](*cmd, "data")),
)
defer dclose(diary)
out, err := diary.Export()
if err != nil {
return err
}
defer dclose(diary)
fmt.Fprint(cmd.OutOrStdout(), string(out))
return nil
}
149 changes: 149 additions & 0 deletions cmd/letseat/cmd/form.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package cmd

import (
"fmt"
"strconv"
"time"

"github.com/charmbracelet/huh"
letseat "github.com/drewstinnett/letseat/pkg"
)

func (e entryForm) Entry() letseat.Entry {
d, err := time.Parse("2006-01-02", e.date)
panicIfErr(err)

cost, err := strconv.Atoi(e.cost)
panicIfErr(err)

ret := letseat.Entry{
Place: e.place,
Date: &d,
IsTakeout: e.takeout,
Ratings: make(map[string]int, len(e.ratings)),
Cost: cost,
}

if e.newPlace != "" {
ret.Place = e.newPlace
}
for person, rating := range e.ratings {
ret.Ratings[person] = *rating
}
return ret
}

func (e *entryForm) NewForm(entries letseat.Entries) *huh.Form {
placeOpts := newPlaceOpts(entries.UniquePlaceNames())

groups := []*huh.Group{
huh.NewGroup(
huh.NewInput().
Title("Date").
Description("When did you go?").
Validate(validateDate).
Value(&e.date),
huh.NewSelect[string]().
Title("Place").
Description("What's this place called?").
Options(placeOpts...).
Value(&e.place),
huh.NewInput().
Title("Cost").
Description("Use 0 for unknown cost").
Placeholder("0").
Validate(validateNumber).
Prompt("$ ").
Value(&e.cost),
huh.NewConfirm().
Title("Take Out?").
Value(&e.takeout),
),
huh.NewGroup(
huh.NewInput().
Title("Name").
Description("What's this new place called??").
Validate(validatePlace).
Value(&e.newPlace),
).WithHideFunc(func() bool {
return e.place != ""
}),
}
ri := e.newRatingInputs(entries.PeopleEnhanced())
if len(ri) > 0 {
groups = append(groups, huh.NewGroup(ri...))
}
return huh.NewForm(groups...)
}

var ratingOptions []*huh.Option[int] = []*huh.Option[int]{
{Key: "🚫 No Rating", Value: 0},
{Key: "⭐️⭐️⭐️⭐️⭐️", Value: 5},
{Key: "⭐️⭐️⭐️⭐️", Value: 4},
{Key: "⭐️⭐️⭐️", Value: 3},
{Key: "⭐️⭐️", Value: 2},
{Key: "⭐️", Value: 1},
}

func ratingOptionsWithSelected(s int) []huh.Option[int] {
var ret []huh.Option[int]
for _, item := range ratingOptions {
if item.Value == s {
ret = append(ret, item.Selected(true))
} else {
ret = append(ret, *item)
}
}
return ret
}

func newPlaceOpts(places []string) []huh.Option[string] {
placeOpts := make([]huh.Option[string], len(places)+1)
placeOpts[0] = huh.Option[string]{
Key: "Someplace New!",
Value: "",
}
for idx, item := range places {
placeOpts[idx+1] = huh.Option[string]{
Key: item,
Value: item,
}
}
return placeOpts
}

// return a new EntryForm using a given entry as a template
func newEntryForm(t *letseat.Entry) entryForm {
if t == nil {
return entryForm{
date: time.Now().Format("2006-01-02"),
cost: "0",
ratings: map[string]*int{},
}
}
ratings := map[string]*int{}
for k, v := range t.Ratings {
v := v
ratings[k] = &v
}
return entryForm{
date: t.Date.Format("2006-01-02"),
cost: fmt.Sprint(t.Cost),
ratings: ratings,
place: t.Place,
takeout: t.IsTakeout,
}
}

func (e *entryForm) newRatingInputs(people []letseat.Person) []huh.Field {
ratingInputs := make([]huh.Field, len(people))
for idx, item := range people {
e.ratings[item.Name] = toPTR(0)
ro := ratingOptionsWithSelected(*e.ratings[item.Name])
ratingInputs[idx] = huh.NewSelect[int]().
Title(fmt.Sprintf("%v's Rating (%v)", item.Name, *e.ratings[item.Name])).
Options(ro...).
Value(e.ratings[item.Name])
}
return ratingInputs
}
21 changes: 21 additions & 0 deletions cmd/letseat/cmd/form_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package cmd

import (
"testing"

"github.com/charmbracelet/huh"
"github.com/stretchr/testify/require"
)

func TestNewPlaceOpts(t *testing.T) {
var target string
got := huh.NewForm(huh.NewGroup(
huh.NewSelect[string]().
Title("Place").
Options(newPlaceOpts([]string{"Taco Tuesday"})...).
Value(&target),
)).View()

require.Contains(t, got, "> Someplace New!", "Make sure the default is something new")
require.Contains(t, got, "Taco Tuesday", "Make sure we still have Taco Tuesday")
}
117 changes: 1 addition & 116 deletions cmd/letseat/cmd/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ package cmd

import (
"errors"
"fmt"
"log/slog"
"strconv"
"time"

"github.com/charmbracelet/huh"
"github.com/drewstinnett/gout/v2"
Expand All @@ -32,124 +29,12 @@ type entryForm struct {
ratings map[string]*int
}

func (e entryForm) Entry() letseat.Entry {
d, err := time.Parse("2006-01-02", e.date)
panicIfErr(err)

cost, err := strconv.Atoi(e.cost)
panicIfErr(err)

ret := letseat.Entry{
Place: e.place,
Date: &d,
IsTakeout: e.takeout,
Ratings: make(map[string]int, len(e.ratings)),
Cost: cost,
}

if e.newPlace != "" {
ret.Place = e.newPlace
}
for person, rating := range e.ratings {
ret.Ratings[person] = *rating
}
return ret
}

func (e *entryForm) NewForm(entries letseat.Entries) *huh.Form {
placeOpts := newPlaceOpts(entries.UniquePlaceNames())

groups := []*huh.Group{
huh.NewGroup(
huh.NewInput().
Title("Date").
Description("When did you go?").
Validate(validateDate).
Value(&e.date),
huh.NewSelect[string]().
Title("Place").
Description("What's this place called?").
Options(placeOpts...).
Value(&e.place),
huh.NewInput().
Title("Cost").
Description("Use 0 for unknown cost").
Placeholder("0").
Validate(validateNumber).
Prompt("$ ").
Value(&e.cost),
huh.NewConfirm().
Title("Take Out?").
Value(&e.takeout),
),
huh.NewGroup(
huh.NewInput().
Title("Name").
Description("What's this new place called??").
Validate(validatePlace).
Value(&e.newPlace),
).WithHideFunc(func() bool {
return e.place != ""
}),
}
ri := newRatingInputs(entries.PeopleEnhanced(), *e)
if len(ri) > 0 {
groups = append(groups, huh.NewGroup(ri...))
}
return huh.NewForm(groups...)
}

var ratingOptions []huh.Option[int] = []huh.Option[int]{
{Key: "🚫 No Rating", Value: 0},
{Key: "⭐️⭐️⭐️⭐️⭐️", Value: 5},
{Key: "⭐️⭐️⭐️⭐️", Value: 4},
{Key: "⭐️⭐️⭐️", Value: 3},
{Key: "⭐️⭐️", Value: 2},
{Key: "⭐️", Value: 1},
}

func newPlaceOpts(places []string) []huh.Option[string] {
placeOpts := make([]huh.Option[string], len(places)+1)
placeOpts[0] = huh.Option[string]{
Key: "Someplace New!",
Value: "",
}
for idx, item := range places {
placeOpts[idx+1] = huh.Option[string]{
Key: item,
Value: item,
}
}
return placeOpts
}

func newEntryForm() entryForm {
e := entryForm{
date: time.Now().Format("2006-01-02"),
cost: "0",
ratings: map[string]*int{},
}
return e
}

func newRatingInputs(people []letseat.Person, e entryForm) []huh.Field {
ratingInputs := make([]huh.Field, len(people))
for idx, item := range people {
e.ratings[item.Name] = toPTR(0)
ratingInputs[idx] = huh.NewSelect[int]().
Title(fmt.Sprintf("%v's Rating", item.Name)).
Options(ratingOptions...).
Value(e.ratings[item.Name])
}
return ratingInputs
}

func runLog(cmd *cobra.Command, args []string) error {
diary := letseat.New(
letseat.WithFilter(*mustNewEntryFilterWithCmd(cmd)),
letseat.WithDBFilename(mustGetCmd[string](*cmd, "data")),
)
e := newEntryForm()
e := newEntryForm(nil)

if err := e.NewForm(diary.Entries()).Run(); err != nil {
return err
Expand Down
1 change: 1 addition & 0 deletions cmd/letseat/cmd/log_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package cmd
Loading

0 comments on commit 8972038

Please sign in to comment.