diff options
Diffstat (limited to 'internal')
-rw-r--r-- | internal/database/queries.sql | 2 | ||||
-rw-r--r-- | internal/queries/queries.sql.go | 2 | ||||
-rw-r--r-- | internal/tui/app.go | 45 | ||||
-rw-r--r-- | internal/tui/commands.go | 5 | ||||
-rw-r--r-- | internal/tui/form.go | 11 | ||||
-rw-r--r-- | internal/tui/keys.go | 5 | ||||
-rw-r--r-- | internal/tui/modal.go | 26 | ||||
-rw-r--r-- | internal/tui/shared.go | 19 |
8 files changed, 100 insertions, 15 deletions
diff --git a/internal/database/queries.sql b/internal/database/queries.sql index 1ab9f44..4ed5578 100644 --- a/internal/database/queries.sql +++ b/internal/database/queries.sql @@ -203,7 +203,7 @@ returning *; -- name: UpdateContractor :one update contractor set name = @name, label = @label, email = @email -where id = (select id from contractor order by id limit 1) +where id = (select id from contractor limit 1) returning *; -- name: UpdateClient :one diff --git a/internal/queries/queries.sql.go b/internal/queries/queries.sql.go index 0408942..4ae940c 100644 --- a/internal/queries/queries.sql.go +++ b/internal/queries/queries.sql.go @@ -1172,7 +1172,7 @@ func (q *Queries) UpdateClient(ctx context.Context, arg UpdateClientParams) (Cli const updateContractor = `-- name: UpdateContractor :one update contractor set name = ?1, label = ?2, email = ?3 -where id = (select id from contractor order by id limit 1) +where id = (select id from contractor limit 1) returning id, name, label, email, created_at ` diff --git a/internal/tui/app.go b/internal/tui/app.go index f434034..0b67933 100644 --- a/internal/tui/app.go +++ b/internal/tui/app.go @@ -67,6 +67,7 @@ type AppModel struct { projectsBox ClientsProjectsModel historyBox HistoryBoxModel modalBox ModalBoxModel + contractor ContractorInfo width int height int @@ -81,6 +82,12 @@ type TimeStats struct { WeekTotal time.Duration } +type ContractorInfo struct { + name string + label string + email string +} + // NewApp creates a new TUI application func NewApp(ctx context.Context, q *queries.Queries) *AppModel { return &AppModel{ @@ -129,6 +136,7 @@ func (m AppModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { cmds = append(cmds, doTick()) case dataUpdatedMsg: + m.contractor = msg.contractor m.timerBox.timerInfo = msg.timerInfo m.timerBox.timerInfo.setNames(msg.clients, msg.projects) m.timeStats = msg.stats @@ -177,6 +185,9 @@ func (m AppModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.openEntryEditor() } + case openContractorEditor: + m.openContractorEditor() + case openModalUnchanged: m.modalBox.Active = true @@ -246,6 +257,12 @@ func (m *AppModel) openEntryEditor() { } } +func (m *AppModel) openContractorEditor() { + m.modalBox.activate(ModalTypeContractor, 0, *m) + m.modalBox.populateContractorFields(m.contractor) + m.modalBox.form.fields[0].Focus() +} + func (m *AppModel) openHistoryFilterModal() { m.modalBox.activate(ModalTypeHistoryFilter, 0, *m) m.modalBox.form.fields[0].Focus() @@ -369,17 +386,18 @@ func (m AppModel) View() string { // dataUpdatedMsg is sent when data is updated from the database type dataUpdatedMsg struct { - timerInfo TimerInfo - stats TimeStats - clients []queries.Client - projects map[int64][]queries.Project - entries []queries.TimeEntry - err error + contractor ContractorInfo + timerInfo TimerInfo + stats TimeStats + clients []queries.Client + projects map[int64][]queries.Project + entries []queries.TimeEntry + err error } // refreshCmd is a command to update all app data func (m AppModel) refreshCmd() tea.Msg { - timerInfo, stats, clients, projects, entries, err := getAppData(m.ctx, m.queries, m.historyBox.filter) + contractor, timerInfo, stats, clients, projects, entries, err := getAppData(m.ctx, m.queries, m.historyBox.filter) if err != nil { msg := dataUpdatedMsg{} msg.err = err @@ -387,12 +405,13 @@ func (m AppModel) refreshCmd() tea.Msg { } return dataUpdatedMsg{ - timerInfo: timerInfo, - stats: stats, - clients: clients, - projects: projects, - entries: entries, - err: nil, + contractor: contractor, + timerInfo: timerInfo, + stats: stats, + clients: clients, + projects: projects, + entries: entries, + err: nil, } } diff --git a/internal/tui/commands.go b/internal/tui/commands.go index 657b3f5..363b570 100644 --- a/internal/tui/commands.go +++ b/internal/tui/commands.go @@ -21,6 +21,7 @@ type ( drillUpMsg struct{} modalClosed struct{} openTimeEntryEditor struct{} + openContractorEditor struct{} openModalUnchanged struct{} openDeleteConfirmation struct{} recheckBounds struct{} @@ -100,6 +101,10 @@ func editCurrentEntry() tea.Cmd { return func() tea.Msg { return openTimeEntryEditor{} } } +func editContractor() tea.Cmd { + return func() tea.Msg { return openContractorEditor{} } +} + func reOpenModal() tea.Cmd { return func() tea.Msg { return openModalUnchanged{} } } diff --git a/internal/tui/form.go b/internal/tui/form.go index 09db989..d0a2025 100644 --- a/internal/tui/form.go +++ b/internal/tui/form.go @@ -201,6 +201,17 @@ func NewGenerateReportForm() Form { return form } +func NewContractorForm() Form { + form := NewForm([]FormField{ + {Model: textinput.New(), label: "Your Name"}, + {Model: textinput.New(), label: "Label for your work"}, + {Model: textinput.New(), label: "Your Email"}, + }) + form.SelectedStyle = &modalFocusedInputStyle + form.UnselectedStyle = &modalBlurredInputStyle + return form +} + func (f Form) Update(msg tea.Msg) (Form, tea.Cmd) { if msg, ok := msg.(tea.KeyMsg); ok { switch msg.String() { diff --git a/internal/tui/keys.go b/internal/tui/keys.go index 05e1a05..52e15f6 100644 --- a/internal/tui/keys.go +++ b/internal/tui/keys.go @@ -57,6 +57,11 @@ var Bindings map[KeyBindingScope]map[string]KeyBinding = map[KeyBindingScope]map Description: func(am AppModel) string { return "Refresh" }, Result: func(am *AppModel) tea.Cmd { return am.refreshCmd }, }, + "c": KeyBinding{ + Key: "c", + Description: func(am AppModel) string { return "Edit Contractor" }, + Result: func(am *AppModel) tea.Cmd { return editContractor() }, + }, "q": KeyBinding{ Key: "q", Description: func(am AppModel) string { return "Quit" }, diff --git a/internal/tui/modal.go b/internal/tui/modal.go index 77b3fa9..51ac384 100644 --- a/internal/tui/modal.go +++ b/internal/tui/modal.go @@ -24,6 +24,7 @@ const ( ModalTypeEntry ModalTypeHistoryFilter ModalTypeGenerateReport + ModalTypeContractor ) func (mt ModalType) newForm() Form { @@ -38,6 +39,8 @@ func (mt ModalType) newForm() Form { return NewHistoryFilterForm() case ModalTypeGenerateReport: return NewGenerateReportForm() + case ModalTypeContractor: + return NewContractorForm() } return Form{} @@ -96,6 +99,8 @@ func (m ModalBoxModel) Render() string { return m.RenderFormModal("🔍 History Filter") case ModalTypeGenerateReport: return m.RenderFormModal("📄 Generate Report") + case ModalTypeContractor: + return m.RenderFormModal("👤 Contractor") default: // REMOVE ME return "DEFAULT CONTENT" } @@ -141,6 +146,12 @@ func (m *ModalBoxModel) deactivate() { m.Active = false } +func (m *ModalBoxModel) populateContractorFields(contractor ContractorInfo) { + m.form.fields[0].SetValue(contractor.name) + m.form.fields[1].SetValue(contractor.label) + m.form.fields[2].SetValue(contractor.email) +} + var ( boldStyle = lipgloss.NewStyle().Bold(true) modalTitleStyle = boldStyle @@ -287,6 +298,21 @@ func (m *ModalBoxModel) SubmitForm(am AppModel) tea.Cmd { return generateReport(m, am) + case ModalTypeContractor: + if err := m.form.Error(); err != nil { + return reOpenModal() + } + + if _, err := am.queries.UpdateContractor(context.Background(), queries.UpdateContractorParams{ + Name: m.form.fields[0].Value(), + Label: m.form.fields[1].Value(), + Email: m.form.fields[2].Value(), + }); err != nil { + m.form.err = err + return reOpenModal() + } + + return am.refreshCmd } return nil diff --git a/internal/tui/shared.go b/internal/tui/shared.go index c79560a..c81827a 100644 --- a/internal/tui/shared.go +++ b/internal/tui/shared.go @@ -59,6 +59,19 @@ func FormatDuration(d time.Duration) string { return fmt.Sprintf("%ds", seconds) } +func getContractorInfo(ctx context.Context, q *queries.Queries) (ContractorInfo, error) { + c, err := q.GetContractor(ctx) + if err != nil { + return ContractorInfo{}, err + } + + return ContractorInfo{ + name: c.Name, + label: c.Label, + email: c.Email, + }, nil +} + func getTimerInfo(ctx context.Context, q *queries.Queries) (TimerInfo, error) { var info TimerInfo @@ -193,6 +206,7 @@ func getAppData( q *queries.Queries, filter HistoryFilter, ) ( + contractor ContractorInfo, info TimerInfo, stats TimeStats, clients []queries.Client, @@ -200,6 +214,11 @@ func getAppData( entries []queries.TimeEntry, err error, ) { + contractor, err = getContractorInfo(ctx, q) + if err != nil { + return + } + info, err = getTimerInfo(ctx, q) if err != nil { return |