reports page

This commit is contained in:
Ruidy 2024-02-10 21:10:33 +01:00
parent 9f4af72c85
commit 172c5037b4
No known key found for this signature in database
GPG key ID: E00F51288CB857CC
9 changed files with 283 additions and 0 deletions

16
constants/months.go Normal file
View file

@ -0,0 +1,16 @@
package constants
var Months = []string{
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
}

View file

@ -3,4 +3,5 @@ package constants
const (
RouteBooking = "/bookings"
RouteNewBooking = "/bookings/new"
RouteReports = "/reports"
)

View file

@ -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 {

View file

@ -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())
}

View file

@ -20,6 +20,7 @@ templ BaseLayout() {
</ul>
<ul>
<li><a href="/bookings">Bookings</a></li>
<li><a href="/reports">Reports</a></li>
<li><a href="/bookings/new" role="button">New Booking</a></li>
</ul>
</nav>

View file

@ -0,0 +1,38 @@
package views
templ ReportSection() {
<div class="grid">
<h2>Your report </h2>
<div>
<button class="outline">Create PDF</button>
</div>
</div>
<figure>
<table role="grid">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">Name</th>
<th scope="col">Total (€)</th>
<th scope="col">From</th>
<th scope="col">To</th>
<th scope="col">Platform</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">
<a href="fjkslafj">
12
</a>
</th>
<td>joe</td>
<td></td>
<td>fgsdkjf</td>
<td>jjxlkvj</td>
<td>jjxlkvj</td>
</tr>
</tbody>
</table>
</figure>
}

View file

@ -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("<div class=\"grid\"><h2>Your report </h2><div><button class=\"outline\">Create PDF</button></div></div><figure><table role=\"grid\"><thead><tr><th scope=\"col\">ID</th><th scope=\"col\">Name</th><th scope=\"col\">Total (€)</th><th scope=\"col\">From</th><th scope=\"col\">To</th><th scope=\"col\">Platform</th></tr></thead> <tbody><tr><th scope=\"row\"><a href=\"fjkslafj\">12</a></th><td>joe</td><td></td><td>fgsdkjf</td><td>jjxlkvj</td><td>jjxlkvj</td></tr></tbody></table></figure>")
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
})
}

View file

@ -0,0 +1,43 @@
package views
import (
"strconv"
)
templ Reports(months []string, year string) {
@BaseLayout() {
<hgroup>
<h1>Reports</h1>
<h2>Generate monthly and yearly statements</h2>
</hgroup>
<form hx-get="/reports/do" hx-target="#report">
<fieldset>
<legend>Period</legend>
<label for="month">
<input type="radio" id="month" name="period" value="month" checked/>
Monthly
</label>
<label for="year">
<input type="radio" id="year" name="period" value="year"/>
Yearly
</label>
</fieldset>
<label for="year">
Year
<input type="number" id="year" name="year" value={ year }/>
</label>
<label for="month">
Month
<select name="month" id="month" autofocus>
for i, month := range months {
<option value={ strconv.Itoa(i + 1) }>{ month } </option>
}
</select>
</label>
<button>
Submit
</button>
</form>
<section id="report"></section>
}
}

View file

@ -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("<hgroup><h1>Reports</h1><h2>Generate monthly and yearly statements</h2></hgroup><form hx-get=\"/reports/do\" hx-target=\"#report\"><fieldset><legend>Period</legend> <label for=\"month\"><input type=\"radio\" id=\"month\" name=\"period\" value=\"month\" checked> Monthly</label> <label for=\"year\"><input type=\"radio\" id=\"year\" name=\"period\" value=\"year\"> Yearly</label></fieldset><label for=\"year\">Year <input type=\"number\" id=\"year\" name=\"year\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(year))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"></label> <label for=\"month\">Month <select name=\"month\" id=\"month\" autofocus>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
for i, month := range months {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<option value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(strconv.Itoa(i + 1)))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(month)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/views/reports.templ`, Line: 32, Col: 51}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</option>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</select></label> <button>Submit</button></form><section id=\"report\"></section>")
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
})
}