diff options
Diffstat (limited to 'internal/tui/modal.go')
-rw-r--r-- | internal/tui/modal.go | 128 |
1 files changed, 106 insertions, 22 deletions
diff --git a/internal/tui/modal.go b/internal/tui/modal.go index 88b2861..167b659 100644 --- a/internal/tui/modal.go +++ b/internal/tui/modal.go @@ -17,15 +17,23 @@ import ( type ModalType int const ( - ModalTypeSearch ModalType = iota - ModalTypeClient + ModalTypeClient ModalType = iota ModalTypeProject ModalTypeDeleteConfirmation ModalTypeEntry ) func (mt ModalType) newForm() Form { - return NewEntryEditorForm() + switch mt { + case ModalTypeEntry: + return NewEntryEditorForm() + case ModalTypeClient: + return NewClientForm() + case ModalTypeProject: + return NewProjectForm() + } + + return Form{} } type ModalBoxModel struct { @@ -69,41 +77,64 @@ func (m ModalBoxModel) RenderCenteredOver(mainContent string, app AppModel) stri func (m ModalBoxModel) Render() string { switch m.Type { - case ModalTypeSearch: - return modalTitleStyle.Render("SEARCH BOX") case ModalTypeEntry: - return m.RenderEntryEditor() + return m.RenderFormModal("⏰ Time Entry") case ModalTypeDeleteConfirmation: return m.RenderDeleteConfirmation() + case ModalTypeClient: + return m.RenderFormModal("👤 Client") + case ModalTypeProject: + return m.RenderFormModal("📂 Project") default: // REMOVE ME return "DEFAULT CONTENT" } } -func (m ModalBoxModel) RenderEntryEditor() string { - return fmt.Sprintf("%s\n\n%s", modalTitleStyle.Render("✏️ Edit Time Entry"), m.form.View()) +func (m ModalBoxModel) RenderFormModal(title string) string { + return fmt.Sprintf( + "%s\n\n%s\n\n%s Delete %s Cancel", + modalTitleStyle.Render(title), + m.form.View(), + boldStyle.Render("[Enter]"), + boldStyle.Render("[Esc]"), + ) } func (m ModalBoxModel) RenderDeleteConfirmation() string { - title := modalTitleStyle.Render("🗑️ Delete Time Entry") - content := "Are you sure you want to delete this time entry?\nThis action cannot be undone.\n\n[Enter] Delete [Esc] Cancel" - return fmt.Sprintf("%s\n\n%s", title, content) + return fmt.Sprintf( + "%s\n\nAre you sure you want to delete this time entry?\nThis action cannot be undone.\n\n%s Delete %s Cancel", + modalTitleStyle.Render("🗑️ Delete Time Entry"), + boldStyle.Render("[Enter]"), + boldStyle.Render("[Esc]"), + ) +} + +func (m *ModalBoxModel) activateCreateProjectModal(am AppModel) { + m.activate(ModalTypeProject, 0) + if am.selectedBox == ProjectsBox && len(am.projectsBox.clients) > 0 { + client := am.projectsBox.clients[am.projectsBox.selectedClient] + m.form.fields[1].SetValue(client.Name) + } + m.form.fields[0].Focus() } -func (m *ModalBoxModel) activate(t ModalType) { +func (m *ModalBoxModel) activate(t ModalType, editedID int64) { m.Active = true m.Type = t m.form = t.newForm() + m.editedID = editedID } func (m *ModalBoxModel) deactivate() { m.Active = false } -var modalTitleStyle = lipgloss.NewStyle(). - Bold(true) +var ( + boldStyle = lipgloss.NewStyle().Bold(true) + modalTitleStyle = boldStyle +) -func (m ModalBoxModel) SubmitForm(am AppModel) tea.Cmd { +func (m *ModalBoxModel) SubmitForm(am AppModel) tea.Cmd { switch m.Type { case ModalTypeDeleteConfirmation: err := am.queries.RemoveTimeEntry(context.Background(), m.editedID) @@ -117,27 +148,80 @@ func (m ModalBoxModel) SubmitForm(am AppModel) tea.Cmd { return reOpenModal() } - // Extract and validate form data - params, hasErrors := m.validateAndParseForm(am) + params, hasErrors := m.validateAndParseEntryForm(am) if hasErrors { return reOpenModal() } - // Perform the edit err := am.queries.EditTimeEntry(context.Background(), params) if err != nil { - // TODO: Handle edit error (could set form error) + m.form.err = err + return reOpenModal() + } + + msg := am.refreshCmd() + return func() tea.Msg { return msg } + case ModalTypeClient: + if err := m.form.Error(); err != nil { + return reOpenModal() + } + + var rate *float64 + if value := m.form.fields[2].Value(); value != "" { + r, _ := strconv.ParseFloat(value, 64) + rate = &r + } + + if m.editedID != 0 { + panic("editing a client not yet implemented") + } + + if _, err := actions.New(am.queries).CreateClient( + context.Background(), + m.form.fields[0].Value(), + m.form.fields[1].Value(), + rate, + ); err != nil { + m.form.err = err + return reOpenModal() + } + + msg := am.refreshCmd() + return func() tea.Msg { return msg } + + case ModalTypeProject: + if err := m.form.Error(); err != nil { + return reOpenModal() + } + + var rate *float64 + if value := m.form.fields[2].Value(); value != "" { + r, _ := strconv.ParseFloat(value, 64) + rate = &r + } + + if m.editedID != 0 { + panic("editing a project not yet implemented") + } + + if _, err := actions.New(am.queries).CreateProject( + context.Background(), + m.form.fields[0].Value(), + m.form.fields[1].Value(), + rate, + ); err != nil { + m.form.err = err return reOpenModal() } - // Success - close modal and refresh data - return func() tea.Msg { return am.refreshCmd() } + msg := am.refreshCmd() + return func() tea.Msg { return msg } } return nil } -func (m *ModalBoxModel) validateAndParseForm(am AppModel) (queries.EditTimeEntryParams, bool) { +func (m *ModalBoxModel) validateAndParseEntryForm(am AppModel) (queries.EditTimeEntryParams, bool) { var params queries.EditTimeEntryParams var hasErrors bool |