Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cmd/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,9 @@ var logCmd = &cobra.Command{
duration := entry.Duration()
totalDuration += duration

timeRange := entry.StartTime.Format("3:04 PM")
timeRange := entry.StartTime.Format("03:04 PM")
if entry.EndTime != nil {
timeRange += " - " + entry.EndTime.Format("3:04 PM")
timeRange += " - " + entry.EndTime.Format("03:04 PM")
} else {
timeRange += " - (running)"
}
Expand Down
20 changes: 13 additions & 7 deletions cmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ var startCmd = &cobra.Command{
}

if running != nil {
fmt.Fprintf(os.Stderr, "Error: Already tracking time for `%s\n", running.ProjectName)
fmt.Fprintf(os.Stderr, "Error: Already tracking time for `%s`\n", running.ProjectName)
fmt.Println("Use 'tmpo stop' to stop the current session first.")

os.Exit(1)
Expand All @@ -41,16 +41,22 @@ var startCmd = &cobra.Command{
projectName, err := DetectProjectName()
if err != nil {
fmt.Fprintf(os.Stderr, "Error detecting project: %v\n", err)

os.Exit(1)
}

description := ""
if len(args) > 0 {
description = args[0]
}

entry, err := db.CreateEntry(projectName, description)
// Load config to get hourly rate if available
var hourlyRate *float64
if cfg, _, err := config.FindAndLoad(); err == nil && cfg != nil && cfg.HourlyRate > 0 {
hourlyRate = &cfg.HourlyRate
}

entry, err := db.CreateEntry(projectName, description, hourlyRate)
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)

Expand All @@ -60,11 +66,11 @@ var startCmd = &cobra.Command{
fmt.Printf("[tmpo] Started tracking time for '%s'\n", entry.ProjectName)

if cfg, _, err := config.FindAndLoad(); err == nil && cfg != nil {
fmt.Println(" Source: .tmporc")
fmt.Println(" Config Source: .tmporc")
} else if project.IsInGitRepo() {
fmt.Println(" Source: git repository")
fmt.Println(" Config Source: git repository")
} else {
fmt.Println(" Source: directory name")
fmt.Println(" Config Source: directory name")
}

if description != "" {
Expand Down
51 changes: 41 additions & 10 deletions cmd/stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"os"
"time"

"github.com/DylanDevelops/tmpo/internal/config"
"github.com/DylanDevelops/tmpo/internal/storage"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -45,7 +44,7 @@ var statsCmd = &cobra.Command{

start = now.AddDate(0, 0, -weekday+1).Truncate(24 * time.Hour)
end = start.AddDate(0, 0, 7)
periodName = "This week"
periodName = "This Week"
} else {
entries, err := db.GetEntries(0)
if err != nil {
Expand Down Expand Up @@ -94,28 +93,41 @@ func ShowPeriodStats(entries []*storage.TimeEntry, periodName string) {
}

projectStats := make(map[string]time.Duration)
projectEarnings := make(map[string]float64)
var totalDuration time.Duration
var totalEarnings float64
hasAnyEarnings := false

for _, entry := range entries {
duration := entry.Duration()
projectStats[entry.ProjectName] += duration
totalDuration += duration

if entry.HourlyRate != nil {
earnings := duration.Hours() * *entry.HourlyRate
projectEarnings[entry.ProjectName] += earnings
totalEarnings += earnings
hasAnyEarnings = true
}
}

fmt.Printf("\n[tmpo] Stats for %s\n\n", periodName)
fmt.Printf(" Total Time: %s (%.2f hours)\n", formatDuration(totalDuration), totalDuration.Hours())
fmt.Printf(" Total Entries: %d\n\n", len(entries))
fmt.Printf(" Total Entries: %d\n", len(entries))

if hasAnyEarnings {
fmt.Printf(" Total Estimated Earnings: $%.2f\n", totalEarnings)
}

fmt.Println()
fmt.Println(" By Project:")
for project, duration := range projectStats {
percentage := (duration.Seconds() / totalDuration.Seconds()) * 100
fmt.Printf(" %-20s %s (%.1f%%)\n", project, formatDuration(duration), percentage)
}

cfg, _, _ := config.FindAndLoad()
if cfg != nil && cfg.HourlyRate > 0 {
earnings := totalDuration.Hours() * cfg.HourlyRate
fmt.Printf("\n Estimated Earnings: $%.2f (at $%.2f/hr)\n", earnings, cfg.HourlyRate)
if earnings, ok := projectEarnings[project]; ok && earnings > 0 {
fmt.Printf(" └─ Estimated Earnings: $%.2f\n", earnings)
}
}
}

Expand All @@ -137,30 +149,49 @@ func ShowPeriodStats(entries []*storage.TimeEntry, periodName string) {
func ShowAllTimeStats(entries []*storage.TimeEntry, db *storage.Database) {
if len(entries) == 0 {
fmt.Println("No entries found.")

return
}

projectStats := make(map[string]time.Duration)
projectEarnings := make(map[string]float64)
var totalDuration time.Duration
var totalEarnings float64
hasAnyEarnings := false

for _, entry := range entries {
duration := entry.Duration()
projectStats[entry.ProjectName] += duration
totalDuration += duration

if entry.HourlyRate != nil {
earnings := duration.Hours() * *entry.HourlyRate
projectEarnings[entry.ProjectName] += earnings
totalEarnings += earnings
hasAnyEarnings = true
}
}

projects, _ := db.GetAllProjects()

fmt.Printf("\n[tmpo] All-Time Statistics\n")
fmt.Printf(" Total Time: %s (%.2f hours)\n", formatDuration(totalDuration), totalDuration.Hours())
fmt.Printf(" Total Entries: %d\n", len(entries))
fmt.Printf(" Projects Tracked: %d\n\n", len(projects))
fmt.Printf(" Projects Tracked: %d\n", len(projects))

if hasAnyEarnings {
fmt.Printf(" Total Estimated Earnings: $%.2f\n", totalEarnings)
}

fmt.Println()
fmt.Println(" By Project:")
for project, duration := range projectStats {
percentage := (duration.Seconds() / totalDuration.Seconds()) * 100
fmt.Printf(" %-20s %s (%.1f%%)\n", project, formatDuration(duration), percentage)

if earnings, ok := projectEarnings[project]; ok && earnings > 0 {
fmt.Printf(" └─ Estimated Earnings: $%.2f\n", earnings)
}
}
}

Expand Down
Loading
Loading