package main import ( "errors" "os" "strconv" "time" "github.com/aquasecurity/table" ) type Todo struct { Title string Status bool CreatedAt time.Time StatusAt *time.Time } type Todos []Todo func (todos *Todos) add(title string) { todo := Todo{ Title: title, Status: false, StatusAt: nil, CreatedAt: time.Now(), } *todos = append(*todos, todo) } func (todos *Todos) validateIndex(index int) error { if index < 0 || index >= len(*todos) { err := errors.New("invalid index") return err } return nil } func (todos *Todos) delete(index int) error { t := *todos if err := t.validateIndex(index); err != nil { return err } *todos = append(t[:index], t[index+1:]...) return nil } func (todos *Todos) toggle(index int) error { t := *todos if err := t.validateIndex(index); err != nil { return err } isCompeleted := t[index].Status if !isCompeleted { completionTime := time.Now() t[index].StatusAt = &completionTime } t[index].Status = !isCompeleted return nil } func (todos *Todos) edit(index int, newTitle string) error { t := *todos if err := t.validateIndex(index); err != nil { return err } t[index].Title = newTitle return nil } func (todos *Todos) print() { table := table.New(os.Stdout) table.SetRowLines(false) table.SetHeaders("Index", "Title", "Status", "Created at", "Status at") for index, t := range *todos { completed := "❌" completedAt := "" if t.Status { completed = "✅" if t.StatusAt != nil { completedAt = t.StatusAt.Format(time.RFC1123) } } table.AddRow(strconv.Itoa(index), t.Title, completed, t.CreatedAt.Format(time.RFC1123), completedAt) } table.Render() }