track.go

 1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
 2//
 3// SPDX-License-Identifier: AGPL-3.0-or-later
 4
 5package habit
 6
 7import (
 8	"errors"
 9	"fmt"
10
11	"git.secluded.site/go-lunatask"
12	"git.secluded.site/lune/internal/client"
13	"git.secluded.site/lune/internal/completion"
14	"git.secluded.site/lune/internal/config"
15	"git.secluded.site/lune/internal/dateutil"
16	"git.secluded.site/lune/internal/ui"
17	"github.com/spf13/cobra"
18)
19
20// ErrUnknownHabit indicates the specified habit key was not found in config.
21var ErrUnknownHabit = errors.New("unknown habit key")
22
23// TrackCmd tracks a habit activity. Exported for potential use by shortcuts.
24var TrackCmd = &cobra.Command{
25	Use:   "track KEY",
26	Short: "Track a habit",
27	Long: `Record that a habit was performed.
28
29KEY is the habit key from your config (not the raw Lunatask ID).
30Tracks for today by default. Use --date to specify another date
31using natural language (e.g., "yesterday", "2 days ago", "March 5").`,
32	Args:              cobra.ExactArgs(1),
33	ValidArgsFunction: completion.Habits,
34	RunE:              runTrack,
35}
36
37func init() {
38	TrackCmd.Flags().StringP("date", "d", "", "Date performed (default: today)")
39}
40
41func runTrack(cmd *cobra.Command, args []string) error {
42	habitKey := args[0]
43
44	cfg, err := config.Load()
45	if err != nil {
46		return err
47	}
48
49	habit := cfg.HabitByKey(habitKey)
50	if habit == nil {
51		return fmt.Errorf("%w: %s", ErrUnknownHabit, habitKey)
52	}
53
54	date, err := resolveDate(cmd)
55	if err != nil {
56		return err
57	}
58
59	apiClient, err := client.New()
60	if err != nil {
61		return err
62	}
63
64	req := &lunatask.TrackHabitActivityRequest{PerformedOn: date}
65
66	if err := ui.SpinVoid("Tracking habit…", func() error {
67		_, err := apiClient.TrackHabitActivity(cmd.Context(), habit.ID, req)
68
69		return err
70	}); err != nil {
71		return err
72	}
73
74	fmt.Fprintf(cmd.OutOrStdout(), "%s\n",
75		ui.Success.Render("Tracked "+habit.Name+" for "+date.String()))
76
77	return nil
78}
79
80func resolveDate(cmd *cobra.Command) (lunatask.Date, error) {
81	dateStr, _ := cmd.Flags().GetString("date")
82
83	return dateutil.Parse(dateStr)
84}