package todo import ( "encoding/json" "errors" "fmt" "os" "time" ) type item struct { Task string Done bool CreatedAt time.Time CompletedAt time.Time } type List []item // Add creates a new todo item and appends it to the list func (l *List) Add(task string) { t := item{ Task: task, Done: false, CreatedAt: time.Now(), CompletedAt: time.Time{}, } *l = append(*l, t) } // Complete method marks a todo item as completed by // setting the Done field to true and setting the CompletedAt to the current time func (l *List) Complete(i int) error { ls := *l if i <= 0 || i > len(ls) { return fmt.Errorf("item %d does not exist", i) } // Adjusting index for 0 base index ls[i-1].Done = true ls[i-1].CompletedAt = time.Now() return nil } // Delete method removes a todo item from the list func (l *List) Delete(i int) error { ls := *l if i <= 0 || i > len(ls) { return fmt.Errorf("item %d does not exist", i) } // Adjusting index for 0 base index *l = append(ls[:i-1], ls[i:]...) return nil } // Save method encodes the List as JSON and saves it // using the provided filename func (l *List) Save(filename string) error { js, err := json.Marshal(l) if err != nil { return err } return os.WriteFile(filename, js, 0644) } // Get method opens the provided file name, decodes // the JSON data and parses it into a List func (l *List) Get(filename string) error { file, err := os.ReadFile(filename) if err != nil { if errors.Is(err, os.ErrNotExist) { return nil } return err } return json.Unmarshal(file, l) } // String method returns a string representation of the List // Implementation of the fmt.Stringer interface func (l *List) String() string { formatted := "" for k, v := range *l { prefix := " " if v.Done { prefix = "X " } formatted += fmt.Sprintf("%s%d: %s\n", prefix, k+1, v.Task) } return formatted }