Compare commits

...

2 commits

Author SHA1 Message Date
5adaca65a2 added delete and edit tui 2025-07-27 16:40:08 -04:00
abb85650c8 added edit and delete event functions 2025-07-27 16:18:54 -04:00
5 changed files with 232 additions and 51 deletions

View file

@ -119,3 +119,76 @@ func GetEventsForDay(year,month,day int32) ([]*calendar.Event,error) {
})
return events,err
}
func EditEvent(originalYear, originalMonth, originalDay, originalStartHour int32, updated EventInput) error {
if db == nil {
err := fmt.Errorf("badger DB is not initialized")
logger.Log.Error(err)
return err
}
// Reject changes to key-defining fields
if updated.Year != originalYear ||
updated.Month != originalMonth ||
updated.Day != originalDay ||
updated.StartHour != originalStartHour {
err := fmt.Errorf("editing key-defining fields (year, month, day, startHour) is not allowed; delete and recreate instead")
logger.Log.Error(err)
return err
}
key := fmt.Appendf(nil, "events/%04d-%02d-%02d/%02d", originalYear, originalMonth, originalDay, originalStartHour)
event := &calendar.Event{
Title: updated.Title,
Description: updated.Description,
Year: originalYear,
Month: originalMonth,
Day: originalDay,
StartHour: originalStartHour,
EndHour: updated.EndHour,
Color: updated.Color,
}
data, err := proto.Marshal(event)
if err != nil {
err = fmt.Errorf("failed to marshal updated event: %w", err)
logger.Log.Error(err)
return err
}
err = db.Update(func(txn *badger.Txn) error {
return txn.Set(key, data)
})
if err != nil {
err = fmt.Errorf("failed to update event in DB: %w", err)
logger.Log.Error(err)
return err
}
return nil
}
func DeleteEvent(year, month, day, startHour int32) error {
if db == nil {
err := fmt.Errorf("badger DB is not initialized")
logger.Log.Error(err)
return err
}
key := fmt.Appendf(nil, "events/%04d-%02d-%02d/%02d", year, month, day, startHour)
err := db.Update(func(txn *badger.Txn) error {
return txn.Delete(key)
})
if err != nil {
err = fmt.Errorf("failed to delete event from DB: %w", err)
logger.Log.Error(err)
return err
}
return nil
}

116
tui/forms.go Normal file
View file

@ -0,0 +1,116 @@
package tui
import (
"fmt"
"strconv"
"git.skdevstudios.com/SK-Development-Studios/go-cal-tui/internal/storage"
"github.com/charmbracelet/huh"
)
// showEventForm prompts user for new event data and calls onSubmit with the result.
func showEventForm(onSubmit func(storage.EventInput)) error {
var title, description, year, month, day, startHour, endHour, color string
form := huh.NewForm(
huh.NewGroup(
huh.NewInput().Title("Title").Value(&title),
huh.NewInput().Title("Description").Value(&description),
huh.NewInput().Title("Year").Value(&year),
huh.NewInput().Title("Month").Value(&month),
huh.NewInput().Title("Day").Value(&day),
huh.NewInput().Title("Start Hour (023)").Value(&startHour),
huh.NewInput().Title("End Hour (023)").Value(&endHour),
huh.NewInput().Title("Color (e.g. 99 or #ff5733)").Value(&color),
),
)
if err := form.Run(); err != nil {
return err
}
yr, _ := strconv.Atoi(year)
mo, _ := strconv.Atoi(month)
da, _ := strconv.Atoi(day)
sh, _ := strconv.Atoi(startHour)
eh, _ := strconv.Atoi(endHour)
onSubmit(storage.EventInput{
Title: title,
Description: description,
Year: int32(yr),
Month: int32(mo),
Day: int32(da),
StartHour: int32(sh),
EndHour: int32(eh),
Color: color,
})
return nil
}
// showEditForm allows editing of mutable fields in an existing event.
func showEditForm(evt *storage.EventInput, onSubmit func(storage.EventInput)) error {
// Convert to string for input
endHourStr := strconv.Itoa(int(evt.EndHour))
colorStr := evt.Color
titleStr := evt.Title
descStr := evt.Description
form := huh.NewForm(
huh.NewGroup(
huh.NewInput().Title("Title").Value(&titleStr),
huh.NewInput().Title("Description").Value(&descStr),
huh.NewInput().Title("End Hour (023)").Value(&endHourStr),
huh.NewInput().Title("Color (e.g. 99 or #ff5733)").Value(&colorStr),
),
)
if err := form.Run(); err != nil {
return err
}
endHour, err := strconv.Atoi(endHourStr)
if err != nil {
return err
}
onSubmit(storage.EventInput{
Title: titleStr,
Description: descStr,
Year: evt.Year,
Month: evt.Month,
Day: evt.Day,
StartHour: evt.StartHour,
EndHour: int32(endHour),
Color: colorStr,
})
return nil
}
// showDeleteConfirm prompts for confirmation before deleting an event.
func showDeleteConfirm(evt *storage.EventInput, onConfirm func()) error {
var confirm bool
form := huh.NewForm(
huh.NewGroup(
huh.NewConfirm().
Title(fmt.Sprintf("Delete event '%s' on %04d-%02d-%02d at %02d:00?", evt.Title, evt.Year, evt.Month, evt.Day, evt.StartHour)).
Affirmative("Yes").
Negative("No").
Value(&confirm),
),
)
if err := form.Run(); err != nil {
return err
}
if confirm {
onConfirm()
}
return nil
}

View file

@ -1,50 +0,0 @@
package tui
import (
"strconv"
"git.skdevstudios.com/SK-Development-Studios/go-cal-tui/internal/storage"
"github.com/charmbracelet/huh"
)
func showEventForm(onSubmit func(storage.EventInput)) error {
var title, description, year, month, day, startHour, endHour, color string
form := huh.NewForm(
huh.NewGroup(
huh.NewInput().Title("Title").Value(&title),
huh.NewInput().Title("Description").Value(&description),
huh.NewInput().Title("Year").Value(&year),
huh.NewInput().Title("Month").Value(&month),
huh.NewInput().Title("Day").Value(&day),
huh.NewInput().Title("Start Hour (023)").Value(&startHour),
huh.NewInput().Title("End Hour (023)").Value(&endHour),
huh.NewInput().Title("Color (e.g. 99 or #ff5733)").Value(&color),
),
)
if err := form.Run(); err != nil {
return err
}
yr, _ := strconv.Atoi(year)
mo, _ := strconv.Atoi(month)
da, _ := strconv.Atoi(day)
sh, _ := strconv.Atoi(startHour)
eh, _ := strconv.Atoi(endHour)
onSubmit(storage.EventInput{
Title: title,
Description: description,
Year: int32(yr),
Month: int32(mo),
Day: int32(da),
StartHour: int32(sh),
EndHour: int32(eh),
Color: color,
})
return nil
}

View file

@ -88,6 +88,48 @@ func (m model) updateHourlyView(msg tea.Msg) (tea.Model, tea.Cmd) {
showEventForm(func(e storage.EventInput) {
_ = storage.SaveEvent(e)
})
case "e":
event, err := storage.GetEvent(int32(m.year), int32(m.monthIndex+1), int32(m.selectedDay), int32(m.hourCursor))
if err != nil || event == nil {
break // No event to edit at this hour
}
// Create editable input struct
input := storage.EventInput{
Title: event.Title,
Description: event.Description,
Year: event.Year,
Month: event.Month,
Day: event.Day,
StartHour: event.StartHour,
EndHour: event.EndHour,
Color: event.Color,
}
showEditForm(&input, func(updated storage.EventInput) {
_ = storage.EditEvent(event.Year, event.Month, event.Day, event.StartHour, updated)
})
case "x": // or "delete"
event, err := storage.GetEvent(int32(m.year), int32(m.monthIndex+1), int32(m.selectedDay), int32(m.hourCursor))
if err != nil || event == nil {
break // No event to delete
}
input := storage.EventInput{
Title: event.Title,
Description: event.Description,
Year: event.Year,
Month: event.Month,
Day: event.Day,
StartHour: event.StartHour,
EndHour: event.EndHour,
Color: event.Color,
}
showDeleteConfirm(&input, func() {
_ = storage.DeleteEvent(event.Year, event.Month, event.Day, event.StartHour)
})
case "esc":
m.mode = monthView
return m, nil

View file

@ -134,7 +134,7 @@ func (m model) viewHourly() string {
b.WriteString(label + "\n")
}
b.WriteString("[n] to add event, [up]/[down] keys to move, [Esc] to go back to month view, [q] to quit.")
b.WriteString("[n] to add event,[e] to edit event,[x] to delete an event, [up]/[down] keys to move, [Esc] to go back to month view, [q] to quit.")
return b.String()
}