diff --git a/constants/months.go b/constants/months.go
new file mode 100644
index 0000000..5939932
--- /dev/null
+++ b/constants/months.go
@@ -0,0 +1,16 @@
+package constants
+
+var Months = []string{
+ "January",
+ "February",
+ "March",
+ "April",
+ "May",
+ "June",
+ "July",
+ "August",
+ "September",
+ "October",
+ "November",
+ "December",
+}
diff --git a/constants/routes.go b/constants/routes.go
index 2f1b344..461c787 100644
--- a/constants/routes.go
+++ b/constants/routes.go
@@ -3,4 +3,5 @@ package constants
const (
RouteBooking = "/bookings"
RouteNewBooking = "/bookings/new"
+ RouteReports = "/reports"
)
diff --git a/internal/server/handlers.go b/internal/server/handlers.go
index 1a9956e..cfb653d 100644
--- a/internal/server/handlers.go
+++ b/internal/server/handlers.go
@@ -142,6 +142,60 @@ func (s Server) handleCreateItem() echo.HandlerFunc {
}
}
+func (s Server) handleReportsPage() echo.HandlerFunc {
+ return func(c echo.Context) error {
+ period := c.QueryParam("period")
+ if !u.Contains([]string{"month", "year"}, period) {
+ period = "month"
+ }
+
+ monthStr := c.QueryParam("month")
+ month, err := strconv.Atoi(monthStr)
+ if err != nil || month < 1 || month > 12 {
+ month = int(time.Now().Month())
+ }
+
+ yearStr := c.QueryParam("year")
+ _, err = strconv.Atoi(yearStr)
+ if err != nil {
+ yearStr = time.Now().Format("2006")
+ }
+ return s.renderTempl(c, http.StatusOK, views.Reports(constants.Months, yearStr))
+ }
+}
+
+func (s Server) handleComputeReport() echo.HandlerFunc {
+ return func(c echo.Context) error {
+ period := c.QueryParam("period")
+ if !u.Contains([]string{"month", "year"}, period) {
+ return &echo.HTTPError{
+ Code: http.StatusBadRequest,
+ Message: fmt.Sprintf("%q is not a valid period", period),
+ }
+ }
+
+ monthStr := c.QueryParam("month")
+ month, err := strconv.Atoi(monthStr)
+ if err != nil || month < 1 || month > 12 {
+ return &echo.HTTPError{
+ Code: http.StatusBadRequest,
+ Message: fmt.Sprintf("%q is not a valid month", month),
+ }
+ }
+
+ yearStr := c.QueryParam("year")
+ year, err := strconv.Atoi(yearStr)
+ if err != nil {
+ return &echo.HTTPError{
+ Code: http.StatusBadRequest,
+ Message: fmt.Sprintf("%q is not a valid year", year),
+ }
+ }
+ // TODO: compute report view model
+ return s.renderTempl(c, http.StatusOK, views.ReportSection())
+ }
+}
+
func (s Server) handleCreateInvoicePdf() echo.HandlerFunc {
return func(c echo.Context) error {
data := struct {
diff --git a/internal/server/routes.go b/internal/server/routes.go
index b6c6c54..53635e6 100644
--- a/internal/server/routes.go
+++ b/internal/server/routes.go
@@ -30,5 +30,7 @@ func (s Server) MountHandlers() {
s.Router.POST(constants.RouteNewBooking, s.handleCreateBooking())
s.Router.GET(fmt.Sprintf("%s/:id", constants.RouteBooking), s.handleBookingPage())
s.Router.POST(fmt.Sprintf("%s/:id/items", constants.RouteBooking), s.handleCreateItem())
+ s.Router.GET(constants.RouteReports, s.handleReportsPage())
+ s.Router.GET(fmt.Sprintf("%s/do", constants.RouteReports), s.handleComputeReport())
s.Router.GET("/pdf", s.handleCreateInvoicePdf())
}
diff --git a/internal/views/base.templ b/internal/views/base.templ
index 7661537..b29fbd5 100644
--- a/internal/views/base.templ
+++ b/internal/views/base.templ
@@ -20,6 +20,7 @@ templ BaseLayout() {
diff --git a/internal/views/report_section.templ b/internal/views/report_section.templ
new file mode 100644
index 0000000..ccc6269
--- /dev/null
+++ b/internal/views/report_section.templ
@@ -0,0 +1,38 @@
+package views
+
+templ ReportSection() {
+
+
Your report
+
+
+
+
+
+
+
+
+ | ID |
+ Name |
+ Total (€) |
+ From |
+ To |
+ Platform |
+
+
+
+
+ |
+
+ 12
+
+ |
+ joe |
+ |
+ fgsdkjf |
+ jjxlkvj |
+ jjxlkvj |
+
+
+
+
+}
diff --git a/internal/views/report_section_templ.go b/internal/views/report_section_templ.go
new file mode 100644
index 0000000..24c6ff8
--- /dev/null
+++ b/internal/views/report_section_templ.go
@@ -0,0 +1,35 @@
+// Code generated by templ - DO NOT EDIT.
+
+// templ: version: v0.2.543
+package views
+
+//lint:file-ignore SA4006 This context is only used if a nested component is present.
+
+import "github.com/a-h/templ"
+import "context"
+import "io"
+import "bytes"
+
+func ReportSection() templ.Component {
+ return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
+ if !templ_7745c5c3_IsBuffer {
+ templ_7745c5c3_Buffer = templ.GetBuffer()
+ defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var1 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var1 == nil {
+ templ_7745c5c3_Var1 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("| ID | Name | Total (€) | From | To | Platform |
| 12 | joe | | fgsdkjf | jjxlkvj | jjxlkvj |
|---|
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if !templ_7745c5c3_IsBuffer {
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
+ }
+ return templ_7745c5c3_Err
+ })
+}
diff --git a/internal/views/reports.templ b/internal/views/reports.templ
new file mode 100644
index 0000000..1db3dfb
--- /dev/null
+++ b/internal/views/reports.templ
@@ -0,0 +1,43 @@
+package views
+
+import (
+ "strconv"
+)
+
+templ Reports(months []string, year string) {
+ @BaseLayout() {
+
+ Reports
+ Generate monthly and yearly statements
+
+
+
+ }
+}
diff --git a/internal/views/reports_templ.go b/internal/views/reports_templ.go
new file mode 100644
index 0000000..78044a2
--- /dev/null
+++ b/internal/views/reports_templ.go
@@ -0,0 +1,93 @@
+// Code generated by templ - DO NOT EDIT.
+
+// templ: version: v0.2.543
+package views
+
+//lint:file-ignore SA4006 This context is only used if a nested component is present.
+
+import "github.com/a-h/templ"
+import "context"
+import "io"
+import "bytes"
+
+import (
+ "strconv"
+)
+
+func Reports(months []string, year string) templ.Component {
+ return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
+ if !templ_7745c5c3_IsBuffer {
+ templ_7745c5c3_Buffer = templ.GetBuffer()
+ defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var1 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var1 == nil {
+ templ_7745c5c3_Var1 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ templ_7745c5c3_Var2 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
+ if !templ_7745c5c3_IsBuffer {
+ templ_7745c5c3_Buffer = templ.GetBuffer()
+ defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("Reports
Generate monthly and yearly statements
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if !templ_7745c5c3_IsBuffer {
+ _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer)
+ }
+ return templ_7745c5c3_Err
+ })
+ templ_7745c5c3_Err = BaseLayout().Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if !templ_7745c5c3_IsBuffer {
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
+ }
+ return templ_7745c5c3_Err
+ })
+}