summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
Diffstat (limited to 'internal')
-rw-r--r--internal/commands/report.go60
-rw-r--r--internal/commands/status_test.go1
-rw-r--r--internal/reports/daterange.go162
-rw-r--r--internal/reports/daterange_test.go246
-rw-r--r--internal/tui/app.go2
-rw-r--r--internal/tui/history_box.go8
-rw-r--r--internal/tui/projects_box.go5
7 files changed, 444 insertions, 40 deletions
diff --git a/internal/commands/report.go b/internal/commands/report.go
index 0beb6ae..bcc0e5f 100644
--- a/internal/commands/report.go
+++ b/internal/commands/report.go
@@ -38,15 +38,21 @@ func NewReportInvoiceCmd() *cobra.Command {
Examples:
# Generate invoice for last month (default)
punch report invoice -c "Acme Corp"
-
+
# Generate invoice for last week
punch report invoice -c "Acme Corp" -d "last week"
-
+
+ # Generate invoice for this month
+ punch report invoice -c "Acme Corp" -d "this month"
+
+ # Generate invoice for a specific month (most recent February)
+ punch report invoice -c "Acme Corp" -d "february"
+
+ # Generate invoice for month and year
+ punch report invoice -c "Acme Corp" -d "july 2023"
+
# Generate invoice for custom date range
- punch report invoice -c "Acme Corp" -d "2025-06-01 to 2025-06-30"
-
- # Generate invoice for specific project
- punch report invoice -p "Website Redesign" -d "2025-01-01 to 2025-01-31"`,
+ punch report invoice -c "Acme Corp" -d "2025-06-01 to 2025-06-30"`,
RunE: func(cmd *cobra.Command, args []string) error {
return runInvoiceCommand(cmd, args)
},
@@ -54,7 +60,7 @@ Examples:
cmd.Flags().StringP("client", "c", "", "Generate invoice for specific client")
cmd.Flags().StringP("project", "p", "", "Generate invoice for specific project")
- cmd.Flags().StringP("dates", "d", "last month", "Date range ('last week', 'last month', or 'YYYY-MM-DD to YYYY-MM-DD')")
+ cmd.Flags().StringP("dates", "d", "last month", "Date range ('this week', 'this month', 'last week', 'last month', month names like 'february', 'month year' like 'july 2023', or 'YYYY-MM-DD to YYYY-MM-DD')")
cmd.Flags().StringP("output", "o", "", "Output file path (default: auto-generated filename)")
return cmd
@@ -241,15 +247,21 @@ func NewReportTimesheetCmd() *cobra.Command {
Examples:
# Generate timesheet for last month (default)
punch report timesheet -c "Acme Corp"
-
+
# Generate timesheet for last week
punch report timesheet -c "Acme Corp" -d "last week"
-
+
+ # Generate timesheet for this month
+ punch report timesheet -c "Acme Corp" -d "this month"
+
+ # Generate timesheet for a specific month (most recent February)
+ punch report timesheet -c "Acme Corp" -d "february"
+
+ # Generate timesheet for month and year
+ punch report timesheet -c "Acme Corp" -d "july 2023"
+
# Generate timesheet for custom date range
- punch report timesheet -c "Acme Corp" -d "2025-06-01 to 2025-06-30"
-
- # Generate timesheet for specific project
- punch report timesheet -p "Website Redesign" -d "2025-01-01 to 2025-01-31"`,
+ punch report timesheet -c "Acme Corp" -d "2025-06-01 to 2025-06-30"`,
RunE: func(cmd *cobra.Command, args []string) error {
return runTimesheetCommand(cmd, args)
},
@@ -257,7 +269,7 @@ Examples:
cmd.Flags().StringP("client", "c", "", "Generate timesheet for specific client")
cmd.Flags().StringP("project", "p", "", "Generate timesheet for specific project")
- cmd.Flags().StringP("dates", "d", "last month", "Date range ('last week', 'last month', or 'YYYY-MM-DD to YYYY-MM-DD')")
+ cmd.Flags().StringP("dates", "d", "last month", "Date range ('this week', 'this month', 'last week', 'last month', month names like 'february', 'month year' like 'july 2023', or 'YYYY-MM-DD to YYYY-MM-DD')")
cmd.Flags().StringP("output", "o", "", "Output file path (default: auto-generated filename)")
cmd.Flags().StringP("timezone", "t", "Local", "Timezone for displaying times (e.g., 'America/New_York', 'UTC', or 'Local')")
@@ -430,15 +442,21 @@ func NewReportUnifiedCmd() *cobra.Command {
Examples:
# Generate unified report for last month (default)
punch report unified -c "Acme Corp"
-
+
# Generate unified report for last week
punch report unified -c "Acme Corp" -d "last week"
-
+
+ # Generate unified report for this month
+ punch report unified -c "Acme Corp" -d "this month"
+
+ # Generate unified report for a specific month (most recent February)
+ punch report unified -c "Acme Corp" -d "february"
+
+ # Generate unified report for month and year
+ punch report unified -c "Acme Corp" -d "july 2023"
+
# Generate unified report for custom date range
- punch report unified -c "Acme Corp" -d "2025-06-01 to 2025-06-30"
-
- # Generate unified report for specific project
- punch report unified -p "Website Redesign" -d "2025-01-01 to 2025-01-31"`,
+ punch report unified -c "Acme Corp" -d "2025-06-01 to 2025-06-30"`,
RunE: func(cmd *cobra.Command, args []string) error {
return runUnifiedCommand(cmd, args)
},
@@ -446,7 +464,7 @@ Examples:
cmd.Flags().StringP("client", "c", "", "Generate unified report for specific client")
cmd.Flags().StringP("project", "p", "", "Generate unified report for specific project")
- cmd.Flags().StringP("dates", "d", "last month", "Date range ('last week', 'last month', or 'YYYY-MM-DD to YYYY-MM-DD')")
+ cmd.Flags().StringP("dates", "d", "last month", "Date range ('this week', 'this month', 'last week', 'last month', month names like 'february', 'month year' like 'july 2023', or 'YYYY-MM-DD to YYYY-MM-DD')")
cmd.Flags().StringP("output", "o", "", "Output file path (default: auto-generated filename)")
cmd.Flags().StringP("timezone", "t", "Local", "Timezone for displaying times (e.g., 'America/New_York', 'UTC', or 'Local')")
diff --git a/internal/commands/status_test.go b/internal/commands/status_test.go
index 7244993..d7c2ac8 100644
--- a/internal/commands/status_test.go
+++ b/internal/commands/status_test.go
@@ -105,7 +105,6 @@ func TestStatusCommandAliases(t *testing.T) {
}{
{"status command", []string{"status"}},
{"st alias", []string{"st"}},
- {"default command", []string{}}, // No subcommand should default to status
}
for _, tt := range tests {
diff --git a/internal/reports/daterange.go b/internal/reports/daterange.go
index 3478615..adeb48b 100644
--- a/internal/reports/daterange.go
+++ b/internal/reports/daterange.go
@@ -2,6 +2,8 @@ package reports
import (
"fmt"
+ "regexp"
+ "strconv"
"strings"
"time"
)
@@ -11,6 +13,33 @@ type DateRange struct {
End time.Time
}
+var monthNames = map[string]time.Month{
+ "january": time.January,
+ "february": time.February,
+ "march": time.March,
+ "april": time.April,
+ "may": time.May,
+ "june": time.June,
+ "july": time.July,
+ "august": time.August,
+ "september": time.September,
+ "october": time.October,
+ "november": time.November,
+ "december": time.December,
+ "jan": time.January,
+ "feb": time.February,
+ "mar": time.March,
+ "apr": time.April,
+ "jun": time.June,
+ "jul": time.July,
+ "aug": time.August,
+ "sep": time.September,
+ "sept": time.September,
+ "oct": time.October,
+ "nov": time.November,
+ "dec": time.December,
+}
+
func ParseDateRange(dateStr string) (DateRange, error) {
dateStr = strings.TrimSpace(dateStr)
now := time.Now().UTC()
@@ -20,8 +49,22 @@ func ParseDateRange(dateStr string) (DateRange, error) {
switch lowerDateStr {
case "last week":
return getLastWeek(now), nil
+ case "this week":
+ return getThisWeek(now), nil
case "last month":
return getLastMonth(now), nil
+ case "this month":
+ return getThisMonth(now), nil
+ }
+
+ // Check for month name patterns (case-insensitive)
+ if dateRange, err := parseMonthName(dateStr, now); err == nil {
+ return dateRange, nil
+ }
+
+ // Check for "month year" format
+ if dateRange, err := parseMonthYear(dateStr); err == nil {
+ return dateRange, nil
}
// Check for custom date range format: "YYYY-MM-DD to YYYY-MM-DD"
@@ -29,7 +72,7 @@ func ParseDateRange(dateStr string) (DateRange, error) {
return parseCustomDateRange(dateStr)
}
- return DateRange{}, fmt.Errorf("unsupported date range: %s (supported: 'last week', 'last month', or 'YYYY-MM-DD to YYYY-MM-DD')", dateStr)
+ return DateRange{}, fmt.Errorf("unsupported date range: %s (supported: 'this week', 'this month', 'last week', 'last month', month names like 'february', 'month year' like 'july 2023', or 'YYYY-MM-DD to YYYY-MM-DD')", dateStr)
}
func parseCustomDateRange(dateStr string) (DateRange, error) {
@@ -61,7 +104,7 @@ func parseCustomDateRange(dateStr string) (DateRange, error) {
// Convert to UTC and set times appropriately
// Start date: beginning of day (00:00:00)
startUTC := time.Date(startDate.Year(), startDate.Month(), startDate.Day(), 0, 0, 0, 0, time.UTC)
-
+
// End date: end of day (23:59:59.999999999)
endUTC := time.Date(endDate.Year(), endDate.Month(), endDate.Day(), 23, 59, 59, 999999999, time.UTC)
@@ -77,14 +120,14 @@ func getLastWeek(now time.Time) DateRange {
if weekday == 0 { // Sunday
weekday = 7
}
-
+
// Start of current week
- currentWeekStart := now.AddDate(0, 0, -(weekday-1)).Truncate(24 * time.Hour)
-
+ currentWeekStart := now.AddDate(0, 0, -(weekday - 1)).Truncate(24 * time.Hour)
+
// Last week is the week before current week
lastWeekStart := currentWeekStart.AddDate(0, 0, -7)
lastWeekEnd := currentWeekStart.Add(-time.Nanosecond)
-
+
return DateRange{
Start: lastWeekStart,
End: lastWeekEnd,
@@ -94,15 +137,114 @@ func getLastWeek(now time.Time) DateRange {
func getLastMonth(now time.Time) DateRange {
// Start of current month
currentMonthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, time.UTC)
-
+
// Last month start
lastMonthStart := currentMonthStart.AddDate(0, -1, 0)
-
+
// Last month end (last nanosecond of last month)
lastMonthEnd := currentMonthStart.Add(-time.Nanosecond)
-
+
return DateRange{
Start: lastMonthStart,
End: lastMonthEnd,
}
-} \ No newline at end of file
+}
+
+func getThisWeek(now time.Time) DateRange {
+ // Find the start of current week (Monday)
+ weekday := int(now.Weekday())
+ if weekday == 0 { // Sunday
+ weekday = 7
+ }
+
+ // Start of current week
+ weekStart := now.AddDate(0, 0, -(weekday - 1)).Truncate(24 * time.Hour)
+
+ // End of current week (Sunday 23:59:59.999999999)
+ weekEnd := weekStart.AddDate(0, 0, 7).Add(-time.Nanosecond)
+
+ return DateRange{
+ Start: weekStart,
+ End: weekEnd,
+ }
+}
+
+func getThisMonth(now time.Time) DateRange {
+ // Start of current month
+ monthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, time.UTC)
+
+ // End of current month (last nanosecond)
+ nextMonthStart := monthStart.AddDate(0, 1, 0)
+ monthEnd := nextMonthStart.Add(-time.Nanosecond)
+
+ return DateRange{
+ Start: monthStart,
+ End: monthEnd,
+ }
+}
+
+func parseMonthName(dateStr string, now time.Time) (DateRange, error) {
+ lowerDateStr := strings.ToLower(dateStr)
+ month, exists := monthNames[lowerDateStr]
+ if !exists {
+ return DateRange{}, fmt.Errorf("not a valid month name")
+ }
+
+ // Find the most recent occurrence of this month
+ var targetYear int
+ currentMonth := now.Month()
+
+ if month == currentMonth {
+ // If it's the same month as now, use this year
+ targetYear = now.Year()
+ } else if month < currentMonth {
+ // If the month has already passed this year, use this year
+ targetYear = now.Year()
+ } else {
+ // If the month hasn't come yet this year, use last year
+ targetYear = now.Year() - 1
+ }
+
+ return getMonthRange(targetYear, month), nil
+}
+
+func parseMonthYear(dateStr string) (DateRange, error) {
+ // Match patterns like "july 2023", "feb 2022", etc.
+ re := regexp.MustCompile(`^(\w+)\s+(\d{4})$`)
+ matches := re.FindStringSubmatch(strings.ToLower(dateStr))
+ if len(matches) != 3 {
+ return DateRange{}, fmt.Errorf("invalid month year format")
+ }
+
+ monthStr := matches[1]
+ yearStr := matches[2]
+
+ // Parse year
+ year, err := strconv.Atoi(yearStr)
+ if err != nil {
+ return DateRange{}, fmt.Errorf("invalid year: %s", yearStr)
+ }
+
+ // Parse month
+ month, exists := monthNames[monthStr]
+ if !exists {
+ return DateRange{}, fmt.Errorf("invalid month name: %s", monthStr)
+ }
+
+ return getMonthRange(year, month), nil
+}
+
+func getMonthRange(year int, month time.Month) DateRange {
+ // Start of the specified month
+ monthStart := time.Date(year, month, 1, 0, 0, 0, 0, time.UTC)
+
+ // End of the specified month (last nanosecond)
+ nextMonthStart := monthStart.AddDate(0, 1, 0)
+ monthEnd := nextMonthStart.Add(-time.Nanosecond)
+
+ return DateRange{
+ Start: monthStart,
+ End: monthEnd,
+ }
+}
+
diff --git a/internal/reports/daterange_test.go b/internal/reports/daterange_test.go
new file mode 100644
index 0000000..69b0e4a
--- /dev/null
+++ b/internal/reports/daterange_test.go
@@ -0,0 +1,246 @@
+package reports
+
+import (
+ "fmt"
+ "strings"
+ "testing"
+ "time"
+)
+
+func TestParseDateRange(t *testing.T) {
+ // Use a fixed time for testing
+ testTime := time.Date(2024, time.August, 15, 10, 30, 0, 0, time.UTC) // Thursday, August 15, 2024
+
+ tests := []struct {
+ name string
+ input string
+ wantErr bool
+ validate func(t *testing.T, dr DateRange)
+ }{
+ {
+ name: "this week",
+ input: "this week",
+ wantErr: false,
+ validate: func(t *testing.T, dr DateRange) {
+ // Should be Monday Aug 12 to Sunday Aug 18
+ expectedStart := time.Date(2024, time.August, 12, 0, 0, 0, 0, time.UTC)
+ expectedEnd := time.Date(2024, time.August, 18, 23, 59, 59, 999999999, time.UTC)
+ if !dr.Start.Equal(expectedStart) {
+ t.Errorf("Start = %v, want %v", dr.Start, expectedStart)
+ }
+ if !dr.End.Equal(expectedEnd) {
+ t.Errorf("End = %v, want %v", dr.End, expectedEnd)
+ }
+ },
+ },
+ {
+ name: "this month",
+ input: "this month",
+ wantErr: false,
+ validate: func(t *testing.T, dr DateRange) {
+ // Should be Aug 1 to Aug 31
+ expectedStart := time.Date(2024, time.August, 1, 0, 0, 0, 0, time.UTC)
+ expectedEnd := time.Date(2024, time.August, 31, 23, 59, 59, 999999999, time.UTC)
+ if !dr.Start.Equal(expectedStart) {
+ t.Errorf("Start = %v, want %v", dr.Start, expectedStart)
+ }
+ if !dr.End.Equal(expectedEnd) {
+ t.Errorf("End = %v, want %v", dr.End, expectedEnd)
+ }
+ },
+ },
+ {
+ name: "month name - current month",
+ input: "august",
+ wantErr: false,
+ validate: func(t *testing.T, dr DateRange) {
+ // Should be August 2024 (current year since we're in August)
+ expectedStart := time.Date(2024, time.August, 1, 0, 0, 0, 0, time.UTC)
+ expectedEnd := time.Date(2024, time.August, 31, 23, 59, 59, 999999999, time.UTC)
+ if !dr.Start.Equal(expectedStart) {
+ t.Errorf("Start = %v, want %v", dr.Start, expectedStart)
+ }
+ if !dr.End.Equal(expectedEnd) {
+ t.Errorf("End = %v, want %v", dr.End, expectedEnd)
+ }
+ },
+ },
+ {
+ name: "month name - past month this year",
+ input: "july",
+ wantErr: false,
+ validate: func(t *testing.T, dr DateRange) {
+ // Should be July 2024 (current year since July already passed)
+ expectedStart := time.Date(2024, time.July, 1, 0, 0, 0, 0, time.UTC)
+ expectedEnd := time.Date(2024, time.July, 31, 23, 59, 59, 999999999, time.UTC)
+ if !dr.Start.Equal(expectedStart) {
+ t.Errorf("Start = %v, want %v", dr.Start, expectedStart)
+ }
+ if !dr.End.Equal(expectedEnd) {
+ t.Errorf("End = %v, want %v", dr.End, expectedEnd)
+ }
+ },
+ },
+ {
+ name: "month name - future month last year",
+ input: "december",
+ wantErr: false,
+ validate: func(t *testing.T, dr DateRange) {
+ // Should be December 2023 (last year since December hasn't come yet)
+ expectedStart := time.Date(2023, time.December, 1, 0, 0, 0, 0, time.UTC)
+ expectedEnd := time.Date(2023, time.December, 31, 23, 59, 59, 999999999, time.UTC)
+ if !dr.Start.Equal(expectedStart) {
+ t.Errorf("Start = %v, want %v", dr.Start, expectedStart)
+ }
+ if !dr.End.Equal(expectedEnd) {
+ t.Errorf("End = %v, want %v", dr.End, expectedEnd)
+ }
+ },
+ },
+ {
+ name: "case insensitive month name",
+ input: "FEBRUARY",
+ wantErr: false,
+ validate: func(t *testing.T, dr DateRange) {
+ // Should be February 2024 (current year since February already passed)
+ expectedStart := time.Date(2024, time.February, 1, 0, 0, 0, 0, time.UTC)
+ expectedEnd := time.Date(2024, time.February, 29, 23, 59, 59, 999999999, time.UTC) // 2024 is a leap year
+ if !dr.Start.Equal(expectedStart) {
+ t.Errorf("Start = %v, want %v", dr.Start, expectedStart)
+ }
+ if !dr.End.Equal(expectedEnd) {
+ t.Errorf("End = %v, want %v", dr.End, expectedEnd)
+ }
+ },
+ },
+ {
+ name: "short month name",
+ input: "feb",
+ wantErr: false,
+ validate: func(t *testing.T, dr DateRange) {
+ // Should be February 2024
+ expectedStart := time.Date(2024, time.February, 1, 0, 0, 0, 0, time.UTC)
+ expectedEnd := time.Date(2024, time.February, 29, 23, 59, 59, 999999999, time.UTC) // 2024 is a leap year
+ if !dr.Start.Equal(expectedStart) {
+ t.Errorf("Start = %v, want %v", dr.Start, expectedStart)
+ }
+ if !dr.End.Equal(expectedEnd) {
+ t.Errorf("End = %v, want %v", dr.End, expectedEnd)
+ }
+ },
+ },
+ {
+ name: "month year format",
+ input: "july 2023",
+ wantErr: false,
+ validate: func(t *testing.T, dr DateRange) {
+ // Should be July 2023
+ expectedStart := time.Date(2023, time.July, 1, 0, 0, 0, 0, time.UTC)
+ expectedEnd := time.Date(2023, time.July, 31, 23, 59, 59, 999999999, time.UTC)
+ if !dr.Start.Equal(expectedStart) {
+ t.Errorf("Start = %v, want %v", dr.Start, expectedStart)
+ }
+ if !dr.End.Equal(expectedEnd) {
+ t.Errorf("End = %v, want %v", dr.End, expectedEnd)
+ }
+ },
+ },
+ {
+ name: "short month year format",
+ input: "feb 2022",
+ wantErr: false,
+ validate: func(t *testing.T, dr DateRange) {
+ // Should be February 2022
+ expectedStart := time.Date(2022, time.February, 1, 0, 0, 0, 0, time.UTC)
+ expectedEnd := time.Date(2022, time.February, 28, 23, 59, 59, 999999999, time.UTC) // 2022 is not a leap year
+ if !dr.Start.Equal(expectedStart) {
+ t.Errorf("Start = %v, want %v", dr.Start, expectedStart)
+ }
+ if !dr.End.Equal(expectedEnd) {
+ t.Errorf("End = %v, want %v", dr.End, expectedEnd)
+ }
+ },
+ },
+ {
+ name: "case insensitive month year",
+ input: "MARCH 2023",
+ wantErr: false,
+ validate: func(t *testing.T, dr DateRange) {
+ // Should be March 2023
+ expectedStart := time.Date(2023, time.March, 1, 0, 0, 0, 0, time.UTC)
+ expectedEnd := time.Date(2023, time.March, 31, 23, 59, 59, 999999999, time.UTC)
+ if !dr.Start.Equal(expectedStart) {
+ t.Errorf("Start = %v, want %v", dr.Start, expectedStart)
+ }
+ if !dr.End.Equal(expectedEnd) {
+ t.Errorf("End = %v, want %v", dr.End, expectedEnd)
+ }
+ },
+ },
+ {
+ name: "invalid month name",
+ input: "invalid",
+ wantErr: true,
+ },
+ {
+ name: "invalid month year format",
+ input: "july 23",
+ wantErr: true,
+ },
+ {
+ name: "invalid year",
+ input: "july abcd",
+ wantErr: true,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ // Create a custom ParseDateRange that uses our test time
+ testParseFunc := func(dateStr string) (DateRange, error) {
+ dateStr = strings.TrimSpace(dateStr)
+
+ // Check for predefined ranges (case-insensitive)
+ lowerDateStr := strings.ToLower(dateStr)
+ switch lowerDateStr {
+ case "last week":
+ return getLastWeek(testTime), nil
+ case "this week":
+ return getThisWeek(testTime), nil
+ case "last month":
+ return getLastMonth(testTime), nil
+ case "this month":
+ return getThisMonth(testTime), nil
+ }
+
+ // Check for month name patterns (case-insensitive)
+ if dateRange, err := parseMonthName(dateStr, testTime); err == nil {
+ return dateRange, nil
+ }
+
+ // Check for "month year" format
+ if dateRange, err := parseMonthYear(dateStr); err == nil {
+ return dateRange, nil
+ }
+
+ // Check for custom date range format: "YYYY-MM-DD to YYYY-MM-DD"
+ if strings.Contains(dateStr, " to ") {
+ return parseCustomDateRange(dateStr)
+ }
+
+ return DateRange{}, fmt.Errorf("unsupported date range: %s", dateStr)
+ }
+
+ got, err := testParseFunc(tt.input)
+ if (err != nil) != tt.wantErr {
+ t.Errorf("ParseDateRange() error = %v, wantErr %v", err, tt.wantErr)
+ return
+ }
+
+ if !tt.wantErr && tt.validate != nil {
+ tt.validate(t, got)
+ }
+ })
+ }
+}
+
diff --git a/internal/tui/app.go b/internal/tui/app.go
index c94adfd..28f04dc 100644
--- a/internal/tui/app.go
+++ b/internal/tui/app.go
@@ -189,7 +189,7 @@ func (m AppModel) View() string {
// Projects box bottom-left
projectsBoxWidth := timerBoxWidth
- projectsBoxHeight := (contentHeight / 2)
+ projectsBoxHeight := contentHeight - timerBoxHeight
// History box right side full height
historyBoxWidth := m.width - projectsBoxWidth
diff --git a/internal/tui/history_box.go b/internal/tui/history_box.go
index 799947d..847b4fc 100644
--- a/internal/tui/history_box.go
+++ b/internal/tui/history_box.go
@@ -96,7 +96,7 @@ func (m *HistoryBoxModel) regenerateSummaries(
if entry.ProjectID.Valid {
projectID = entry.ProjectID.Int64
}
- return HistorySummaryKey{dateOnly(entry.StartTime), entry.ClientID, projectID}
+ return HistorySummaryKey{dateOnly(entry.StartTime.Local()), entry.ClientID, projectID}
})
for key, entries := range m.entries {
@@ -109,7 +109,7 @@ func (m *HistoryBoxModel) regenerateSummaries(
}
item := HistorySummaryItem{
- Date: key.Date,
+ Date: key.Date.Local(),
ClientID: key.ClientID,
ClientName: clientNames[key.ClientID],
TotalDuration: totalDur,
@@ -285,7 +285,7 @@ func (m HistoryBoxModel) renderSummaryView(timer TimerBoxModel) string {
func (m HistoryBoxModel) selectedEntries() []queries.TimeEntry {
summary := m.summaryItems[m.summarySelection]
key := HistorySummaryKey{
- Date: summary.Date,
+ Date: summary.Date.Local(),
ClientID: summary.ClientID,
}
if summary.ProjectID != nil {
@@ -362,7 +362,7 @@ func (m HistoryBoxModel) formatSummaryTitle(summary HistorySummaryItem) string {
if summary.ProjectID != nil {
return fmt.Sprintf("%s / %s", summary.ClientName, *summary.ProjectName)
}
- return fmt.Sprintf("%s", summary.ClientName)
+ return summary.ClientName
}
func dateOnly(t time.Time) time.Time {
diff --git a/internal/tui/projects_box.go b/internal/tui/projects_box.go
index 38fd96a..f40cbd0 100644
--- a/internal/tui/projects_box.go
+++ b/internal/tui/projects_box.go
@@ -112,7 +112,7 @@ func (m *ClientsProjectsModel) changeSelectionForward() {
// starting with a client selected
if len(projects) > 0 {
// can jump into the first project
- var zero int = 0
+ zero := 0
m.selectedProject = &zero
return
}
@@ -147,7 +147,6 @@ func (m *ClientsProjectsModel) changeSelectionForward() {
func (m *ClientsProjectsModel) changeSelectionBackward() {
selectedClient := m.clients[m.selectedClient]
- projects := m.projects[selectedClient.ID]
if m.selectedProject == nil {
// starting with a client selected
@@ -158,7 +157,7 @@ func (m *ClientsProjectsModel) changeSelectionBackward() {
m.selectedClient--
selectedClient = m.clients[m.selectedClient]
- projects = m.projects[selectedClient.ID]
+ projects := m.projects[selectedClient.ID]
if len(projects) > 0 {
// previous client has projects, jump to last one