summaryrefslogtreecommitdiff
path: root/internal/tui/commands.go
diff options
context:
space:
mode:
authorT <t@tjp.lol>2025-09-29 15:04:44 -0600
committerT <t@tjp.lol>2025-09-30 11:40:45 -0600
commit7ba68d333bc20b5795ccfd3870546a05eee60470 (patch)
tree12dc4b017803b7d01844fd42b9e3be281cbbd986 /internal/tui/commands.go
parentbce8dbb58165e443902d9dae3909225ef42630c4 (diff)
Support for archiving clients and projects.HEADmain
Diffstat (limited to 'internal/tui/commands.go')
-rw-r--r--internal/tui/commands.go141
1 files changed, 96 insertions, 45 deletions
diff --git a/internal/tui/commands.go b/internal/tui/commands.go
index 4fdd9e0..90bc05f 100644
--- a/internal/tui/commands.go
+++ b/internal/tui/commands.go
@@ -2,9 +2,7 @@ package tui
import (
"context"
- "fmt"
- "strings"
- "time"
+ "errors"
"git.tjp.lol/punchcard/internal/actions"
"git.tjp.lol/punchcard/internal/queries"
@@ -32,6 +30,26 @@ type (
openHistoryFilterModal struct{}
openReportModal struct{}
updateHistoryFilter HistoryFilter
+ archiveSelectedMsg struct {
+ clientID int64
+ projectID *int64
+ restoreClientID int64
+ restoreProjectID *int64
+ }
+ unarchiveSelectedMsg struct {
+ clientID int64
+ projectID *int64
+ restoreClientID int64
+ restoreProjectID *int64
+ }
+ toggleShowArchivedMsg struct {
+ restoreClientID int64
+ restoreProjectID *int64
+ }
+ restoreSelectionMsg struct{ clientID int64; projectID *int64 }
+ showArchivedWarningMsg struct{ params *ArchivedPunchInParams }
+ reportGenerationSucceeded struct{}
+ reportGenerationFailed struct{ err error }
)
func navigate(forward bool) tea.Cmd {
@@ -40,8 +58,25 @@ func navigate(forward bool) tea.Cmd {
func punchIn(m AppModel) tea.Cmd {
return func() tea.Msg {
- _, _ = actions.New(m.queries).PunchInMostRecent(context.Background(), "", nil)
- // TODO: use the returned TimerSession instead of re-querying everything
+ a := actions.New(m.queries)
+ _, err := a.PunchInMostRecent(context.Background(), "", nil, false)
+ // Handle archived errors by showing modal
+ if err != nil {
+ if errors.Is(err, actions.ErrArchivedClient) {
+ return showArchivedWarningMsg{
+ params: &ArchivedPunchInParams{
+ EntityType: "client",
+ },
+ }
+ } else if errors.Is(err, actions.ErrArchivedProject) {
+ return showArchivedWarningMsg{
+ params: &ArchivedPunchInParams{
+ EntityType: "project",
+ },
+ }
+ }
+ }
+
return m.refreshCmd()
}
}
@@ -69,8 +104,33 @@ func punchInOnSelection(m AppModel) tea.Cmd {
return nil
}
- _, _ = actions.New(m.queries).PunchIn(context.Background(), clientID, projectID, description, entryRate)
- // TODO: use the returned TimerSession instead of re-querying everything
+ a := actions.New(m.queries)
+ _, err := a.PunchIn(context.Background(), clientID, projectID, description, entryRate, false)
+ // Handle archived errors by showing modal
+ if err != nil {
+ if errors.Is(err, actions.ErrArchivedClient) {
+ return showArchivedWarningMsg{
+ params: &ArchivedPunchInParams{
+ ClientID: clientID,
+ ProjectID: projectID,
+ Description: description,
+ Rate: entryRate,
+ EntityType: "client",
+ },
+ }
+ } else if errors.Is(err, actions.ErrArchivedProject) {
+ return showArchivedWarningMsg{
+ params: &ArchivedPunchInParams{
+ ClientID: clientID,
+ ProjectID: projectID,
+ Description: description,
+ Rate: entryRate,
+ EntityType: "project",
+ },
+ }
+ }
+ }
+
return m.refreshCmd()
}
}
@@ -139,51 +199,42 @@ func createReportModal() tea.Cmd {
return func() tea.Msg { return openReportModal{} }
}
-func generateReport(m *ModalBoxModel, am AppModel) tea.Cmd {
+func generateReport(am AppModel, genFunc func(context.Context, *queries.Queries, reports.ReportParams) (*reports.ReportResult, error), params reports.ReportParams) tea.Cmd {
return func() tea.Msg {
- form := &m.form
-
- dateRange, err := reports.ParseDateRange(form.fields[1].Value())
- if err != nil {
- form.fields[1].Err = fmt.Errorf("invalid date range: %v", err)
- return reOpenModal()
+ if _, err := genFunc(context.Background(), am.queries, params); err != nil {
+ return reportGenerationFailed{err: err}
}
+ return reportGenerationSucceeded{}
+ }
+}
- var tz *time.Location
- tzstr := form.fields[5].Value()
- if tzstr == "" {
- tz = time.Local
- } else {
- zone, err := time.LoadLocation(tzstr)
- if err != nil {
- form.fields[5].Err = err
- return reOpenModal()
- }
- tz = zone
+func archiveClientOrProject(clientID int64, projectID *int64) tea.Cmd {
+ return func() tea.Msg {
+ return archiveSelectedMsg{
+ clientID: clientID,
+ projectID: projectID,
+ restoreClientID: clientID,
+ restoreProjectID: projectID,
}
+ }
+}
- var genFunc func(context.Context, *queries.Queries, reports.ReportParams) (*reports.ReportResult, error)
- switch strings.ToLower(form.fields[0].Value()) {
- case "invoice":
- genFunc = reports.GenerateInvoice
- case "timesheet":
- genFunc = reports.GenerateTimesheet
- case "unified":
- genFunc = reports.GenerateUnifiedReport
+func unarchiveClientOrProject(clientID int64, projectID *int64) tea.Cmd {
+ return func() tea.Msg {
+ return unarchiveSelectedMsg{
+ clientID: clientID,
+ projectID: projectID,
+ restoreClientID: clientID,
+ restoreProjectID: projectID,
}
+ }
+}
- params := reports.ReportParams{
- ClientName: form.fields[2].Value(),
- ProjectName: form.fields[3].Value(),
- DateRange: dateRange,
- OutputPath: form.fields[4].Value(),
- Timezone: tz,
- }
- if _, err := genFunc(context.Background(), am.queries, params); err != nil {
- form.err = err
- return reOpenModal()
+func toggleShowArchived(clientID int64, projectID *int64) tea.Cmd {
+ return func() tea.Msg {
+ return toggleShowArchivedMsg{
+ restoreClientID: clientID,
+ restoreProjectID: projectID,
}
-
- return nil
}
}