diff options
author | T <t@tjp.lol> | 2025-08-06 16:56:46 -0600 |
---|---|---|
committer | T <t@tjp.lol> | 2025-08-07 08:33:49 -0600 |
commit | 4843deb9cfa6d91282c5124ec025c636137e9e94 (patch) | |
tree | 180dc226e7dcdbbba8ea6ecabba821f4bdb64949 /internal | |
parent | d75bd93385bf3b54ada84c3d45011d7f8efc1f80 (diff) |
Enhanced date range parsing with more flexible input formats
- Added support for 'this week' and 'this month' date ranges
- Added support for month names (e.g., 'february', 'july') with automatic year detection
- Added support for 'month year' format (e.g., 'july 2023', 'feb 2022')
- Enhanced help text and examples for all report commands
- Added comprehensive test coverage for date range parsing
- Fixed timezone handling in TUI history display
- Minor code style improvements
Diffstat (limited to 'internal')
-rw-r--r-- | internal/commands/report.go | 60 | ||||
-rw-r--r-- | internal/commands/status_test.go | 1 | ||||
-rw-r--r-- | internal/reports/daterange.go | 162 | ||||
-rw-r--r-- | internal/reports/daterange_test.go | 246 | ||||
-rw-r--r-- | internal/tui/app.go | 2 | ||||
-rw-r--r-- | internal/tui/history_box.go | 8 | ||||
-rw-r--r-- | internal/tui/projects_box.go | 5 |
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 |