diff options
-rw-r--r-- | db.go | 31 | ||||
-rw-r--r-- | model.go | 23 | ||||
-rw-r--r-- | page.go | 46 | ||||
-rw-r--r-- | templates/index.html | 6 | ||||
-rw-r--r-- | templates/parts/entry.html | 6 | ||||
-rw-r--r-- | templates/parts/entryRows.html | 2 | ||||
-rw-r--r-- | tidsreg.go | 100 |
7 files changed, 156 insertions, 58 deletions
@@ -8,7 +8,7 @@ import ( type Database interface { GetTracking() (*Entry, error) GetEntries() ([]*Entry, error) - QueryEntry(id *int) ([]*Entry, error) + QueryEntry(id *int, date *Date) ([]*Entry, error) StartNewEntry(now time.Time, task *Entry) (*Entry, error) StopEntry(now time.Time) error SaveEntry(task *Entry) (*Entry, error) @@ -49,12 +49,16 @@ func (db *InMemDb) GetEntries() ([]*Entry, error) { return res, nil } -func (db *InMemDb) QueryEntry(id *int) ([]*Entry, error) { +func (db *InMemDb) QueryEntry(id *int, date *Date) ([]*Entry, error) { res := make([]*Entry, 0, 1) for _, entry := range db.entries { - if id != nil && entry.Id == *id { - res = append(res, entry) + if id != nil && entry.Id != *id { + continue + } + if date != nil && entry.Date != *date { + continue } + res = append(res, entry) } return res, nil @@ -65,6 +69,7 @@ func (db *InMemDb) StartNewEntry(now time.Time, task *Entry) (*Entry, error) { Id: len(db.entries), From: task.From, To: nil, + Date: DateFromStd(now), Tag: task.Tag, Comment: task.Comment, } @@ -77,6 +82,7 @@ func (db *InMemDb) StartNewEntry(now time.Time, task *Entry) (*Entry, error) { db.entries = append(db.entries, newTask) db.StopEntry(now) db.current = newTask + return newTask, nil } @@ -91,20 +97,21 @@ func (db *InMemDb) StopEntry(now time.Time) error { return nil } -func (db *InMemDb) SaveEntry(task *Entry) (*Entry, error) { - if task.Id < 0 || task.Id >= len(db.entries) { - copyTask := *task +func (db *InMemDb) SaveEntry(entry *Entry) (*Entry, error) { + if entry.Id < 0 || entry.Id >= len(db.entries) { + copyTask := *entry copyTask.Id = len(db.entries) db.entries = append(db.entries, ©Task) return ©Task, nil } - existent := db.entries[task.Id] - existent.Comment = task.Comment - existent.Tag = task.Tag - existent.From = task.From - existent.To = task.To + existent := db.entries[entry.Id] + existent.Comment = entry.Comment + existent.Tag = entry.Tag + existent.From = entry.From + existent.To = entry.To + existent.Date = entry.Date return existent, nil } @@ -2,13 +2,14 @@ package main import ( "errors" + "log" "regexp" "time" ) type Entry struct { Id int - Date time.Time + Date Date From *Time To *Time Tag *string @@ -34,6 +35,18 @@ var ( ErrInvalidDate = errors.New("Invalid date string") ) +func NewEntry(date Date) *Entry { + return &Entry{ + Id: -1, + From: nil, + Date: date, + To: nil, + Tag: nil, + Comment: "", + } + +} + func TimeFromStd(time time.Time) Time { return Time(time.Format("15:04")) } @@ -67,3 +80,11 @@ func DateFromString(str string) (*Date, error) { date := Date(str) return &date, nil } + +func (d Date) ToStd() time.Time { + t, err := time.Parse("2006-01-02", string(d)) + if err != nil { + log.Fatal(err) + } + return t +} @@ -1,24 +1,29 @@ package main +import "time" + type Service struct { Db Database } type DateInfo struct { - Date string - Tomorrow string - Yesterday string + Date Date + Tomorrow Date + Yesterday Date + IsToday bool } type EntryPage struct { Entry *Entry Detached bool Tracking *Entry + DateInfo DateInfo } type RootPage struct { - Entry *EntryPage - Entries []*Entry + DateInfo DateInfo + Entry *EntryPage + Entries []*Entry } type TasksPage struct { @@ -31,6 +36,15 @@ func NewService(db Database) *Service { } } +func NewDateInfo(t time.Time) DateInfo { + return DateInfo{ + Date: DateFromStd(t), + Tomorrow: DateFromStd(t.Add(24 * time.Hour)), + Yesterday: DateFromStd(t.Add(-24 * time.Hour)), + IsToday: DateFromStd(time.Now()) == DateFromStd(t), + } +} + func (srv *Service) GetTasksPage() (*TasksPage, error) { tasks, err := srv.Db.GetTasks() if err != nil { @@ -40,16 +54,16 @@ func (srv *Service) GetTasksPage() (*TasksPage, error) { Tasks: tasks, }, nil } -func (srv *Service) GetEntryPage(detached *Entry) (*EntryPage, error) { +func (srv *Service) GetEntryPage(detached *Entry, dt DateInfo) (*EntryPage, error) { tracking, err := srv.Db.GetTracking() if err != nil { return nil, err } - page := &EntryPage{ Entry: tracking, Detached: false, Tracking: tracking, + DateInfo: dt, } if detached != nil { @@ -60,18 +74,26 @@ func (srv *Service) GetEntryPage(detached *Entry) (*EntryPage, error) { return page, nil } -func (srv *Service) GetRootPage() (*RootPage, error) { - entry, err := srv.GetEntryPage(nil) +func (srv *Service) GetRootPage(date Date) (*RootPage, error) { + var entry *Entry = nil + + if string(date) != time.Now().Format("2006-01-02") { + // If not today detach + entry = NewEntry(date) + } + + entryPage, err := srv.GetEntryPage(entry, NewDateInfo(date.ToStd())) if err != nil { return nil, err } - entries, err := srv.Db.GetEntries() + entries, err := srv.Db.QueryEntry(nil, &date) if err != nil { return nil, err } return &RootPage{ - Entry: entry, - Entries: entries, + DateInfo: entryPage.DateInfo, + Entry: entryPage, + Entries: entries, }, nil } diff --git a/templates/index.html b/templates/index.html index eecf879..b2dc6b0 100644 --- a/templates/index.html +++ b/templates/index.html @@ -55,9 +55,9 @@ </head> <body> <div id="controls-bar"> - <button>I går</button> - <input type="date" /> - <button>I morgen</button> + <button hx-get="/" hx-replace-url="true" hx-params="date" hx-vals='{"date": "{{.DateInfo.Yesterday}}"}' hx-target="body">I går</button> + <input type="date" hx-get="/" hx-replace-url="true" hx-params="date" hx-vals='js:{date: event.target.value}' autocomplete="off" hx-target="body" hx-trigger="change" value="{{.DateInfo.Date}}" /> + <button hx-get="/" hx-replace-url="true" hx-params="date" hx-vals='{"date": "{{.DateInfo.Tomorrow}}"}' hx-target="body">I morgen</button> </div> <div class="flex"> <div> diff --git a/templates/parts/entry.html b/templates/parts/entry.html index 9f05ffa..300f543 100644 --- a/templates/parts/entry.html +++ b/templates/parts/entry.html @@ -48,13 +48,15 @@ >Gem </button> {{end}} - {{ if .Detached }} + {{ if .Detached}} + {{ if .DateInfo.IsToday }} <button hx-get="/tracking" hx-trigger="click" hx-target="#entry-bar" hx-swap="outerHTML" >Tilbage</button> + {{ end }} {{ else }} {{ if .Entry }} <button @@ -77,5 +79,5 @@ hx-target="#entry-bar" hx-swap="outerHTML" >Manuel</button> - {{ end }} + {{ end }}<input readonly type="text" name="date" {{if .Entry}}value="{{ .Entry.Date }}"{{end}} /> </form> diff --git a/templates/parts/entryRows.html b/templates/parts/entryRows.html index fd14608..9e9c0eb 100644 --- a/templates/parts/entryRows.html +++ b/templates/parts/entryRows.html @@ -1,4 +1,4 @@ -<tbody hx-swap="outerHTML" hx-trigger="changedEntries from:body" hx-get="/entryRows"> +<tbody hx-swap="outerHTML" hx-trigger="changedEntries from:body" hx-get="/entryRows" hx-params="date" hx-vals='{"date": "{{.DateInfo.Date}}"}'> {{ range $entry := .Entries }} <tr> <td>{{ $entry.Id }}</td> @@ -1,9 +1,11 @@ package main import ( + "errors" "fmt" "log" "net/http" + "net/url" "strconv" "text/template" "time" @@ -13,15 +15,29 @@ import ( type Server struct { template *template.Template - srv *Service + srv *Service } -func parseTaskFromForm(r *http.Request) (*Entry, error) { +func parseTaskFromForm(r *http.Request, useToday bool) (*Entry, error) { err := r.ParseForm() if err != nil { return nil, err } + var date Date + dateP, err := DateFromString(r.PostFormValue("date")) + if err != nil { + return nil, err + } + if dateP != nil { + date = *dateP + } else { + if useToday { + date = DateFromStd(time.Now()) + } else { + return nil, errors.New("date missing from post") + } + } from, err := TimeFromString(r.PostFormValue("from")) if err != nil { return nil, err @@ -40,10 +56,11 @@ func parseTaskFromForm(r *http.Request) (*Entry, error) { } } - task := &Entry { - Id: int(id), - From: from, - To: to, + task := &Entry{ + Id: int(id), + From: from, + Date: date, + To: to, Comment: r.PostFormValue("comment"), } return task, nil @@ -69,6 +86,22 @@ func writeError(w http.ResponseWriter, err string, code int) { return } +func parseDateFromUrl(url *url.URL, allowToday bool) (Date, error) { + date, err := DateFromString(url.Query().Get("date")) + if err != nil { + return "", nil + } + if date == nil { + if allowToday { + return DateFromStd(time.Now()), nil + } else { + return "", errors.New("date query param empty") + } + } + + return *date, nil +} + func (s *Server) rootHandle(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/" { w.WriteHeader(http.StatusNotFound) @@ -76,7 +109,13 @@ func (s *Server) rootHandle(w http.ResponseWriter, r *http.Request) { return } - page, err := s.srv.GetRootPage() + date, err := parseDateFromUrl(r.URL, true) + if err != nil { + writeError(w, err.Error(), http.StatusBadRequest) + return + } + + page, err := s.srv.GetRootPage(date) if err != nil { writeError(w, err.Error(), http.StatusInternalServerError) return @@ -85,11 +124,10 @@ func (s *Server) rootHandle(w http.ResponseWriter, r *http.Request) { s.renderTemplate(w, "index.html", page) } - func (s *Server) postStart(w http.ResponseWriter, r *http.Request) { now := time.Now() - task, err := parseTaskFromForm(r) + task, err := parseTaskFromForm(r, true) if err != nil { writeError(w, err.Error(), http.StatusBadRequest) return @@ -100,7 +138,7 @@ func (s *Server) postStart(w http.ResponseWriter, r *http.Request) { writeError(w, err.Error(), http.StatusInternalServerError) return } - page, err := s.srv.GetEntryPage(nil) + page, err := s.srv.GetEntryPage(nil, NewDateInfo(now)) if err != nil { writeError(w, err.Error(), http.StatusInternalServerError) return @@ -112,7 +150,7 @@ func (s *Server) postStart(w http.ResponseWriter, r *http.Request) { func (s *Server) postStop(w http.ResponseWriter, r *http.Request) { now := time.Now() - task, err := parseTaskFromForm(r) + task, err := parseTaskFromForm(r, true) if err != nil { writeError(w, err.Error(), http.StatusBadRequest) return @@ -134,7 +172,8 @@ func (s *Server) postStop(w http.ResponseWriter, r *http.Request) { } func (s *Server) getTracking(w http.ResponseWriter, _ *http.Request) { - page, err := s.srv.GetEntryPage(nil) + nowDt := NewDateInfo(time.Now()) + page, err := s.srv.GetEntryPage(nil, nowDt) if err != nil { writeError(w, err.Error(), http.StatusInternalServerError) return @@ -144,7 +183,7 @@ func (s *Server) getTracking(w http.ResponseWriter, _ *http.Request) { } func (s *Server) putSave(w http.ResponseWriter, r *http.Request) { - task, err := parseTaskFromForm(r) + task, err := parseTaskFromForm(r, false) if err != nil { writeError(w, err.Error(), http.StatusBadRequest) return @@ -161,7 +200,7 @@ func (s *Server) putSave(w http.ResponseWriter, r *http.Request) { detached = task } - page, err := s.srv.GetEntryPage(detached) + page, err := s.srv.GetEntryPage(detached, NewDateInfo(task.Date.ToStd())) if err != nil { writeError(w, err.Error(), http.StatusInternalServerError) return @@ -172,16 +211,16 @@ func (s *Server) putSave(w http.ResponseWriter, r *http.Request) { s.renderTemplate(w, "entry.html", page) } -func (s *Server) getNew(w http.ResponseWriter, _ *http.Request) { - task := &Entry { - Id: -1, - From: nil, - To: nil, - Tag: nil, - Comment: "", +func (s *Server) getNew(w http.ResponseWriter, r *http.Request) { + date, err := parseDateFromUrl(r.URL, true) + if err != nil { + writeError(w, err.Error(), http.StatusBadRequest) + return } - page, err := s.srv.GetEntryPage(task) + task := NewEntry(date) + + page, err := s.srv.GetEntryPage(task, NewDateInfo(date.ToStd())) if err != nil { writeError(w, err.Error(), http.StatusInternalServerError) return @@ -198,7 +237,7 @@ func (s *Server) getEdit(w http.ResponseWriter, r *http.Request) { } id := int(idLarge) - entries, err := s.srv.Db.QueryEntry(&id) + entries, err := s.srv.Db.QueryEntry(&id, nil) if err != nil { writeError(w, err.Error(), http.StatusInternalServerError) return @@ -208,7 +247,8 @@ func (s *Server) getEdit(w http.ResponseWriter, r *http.Request) { return } - page, err := s.srv.GetEntryPage(entries[0]) + page, err := s.srv.GetEntryPage(entries[0], + NewDateInfo(entries[0].Date.ToStd())) if err != nil { writeError(w, err.Error(), http.StatusInternalServerError) return @@ -217,8 +257,14 @@ func (s *Server) getEdit(w http.ResponseWriter, r *http.Request) { s.renderTemplate(w, "entry.html", page) } -func (s *Server) getEntries(w http.ResponseWriter, _ *http.Request) { - page, err := s.srv.GetRootPage() +func (s *Server) getEntries(w http.ResponseWriter, r *http.Request) { + date, err := parseDateFromUrl(r.URL, true) + if err != nil { + writeError(w, err.Error(), http.StatusBadRequest) + return + } + + page, err := s.srv.GetRootPage(date) if err != nil { writeError(w, err.Error(), http.StatusInternalServerError) return @@ -242,7 +288,7 @@ func main() { s := Server{ template: nil, - srv: NewService(NewInMemDb()), + srv: NewService(NewInMemDb()), } r := mux.NewRouter() |