mirror of
https://github.com/rjNemo/rentease.git
synced 2026-06-06 02:36:49 +00:00
reports page
This commit is contained in:
parent
9f4af72c85
commit
172c5037b4
9 changed files with 283 additions and 0 deletions
16
constants/months.go
Normal file
16
constants/months.go
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
package constants
|
||||
|
||||
var Months = []string{
|
||||
"January",
|
||||
"February",
|
||||
"March",
|
||||
"April",
|
||||
"May",
|
||||
"June",
|
||||
"July",
|
||||
"August",
|
||||
"September",
|
||||
"October",
|
||||
"November",
|
||||
"December",
|
||||
}
|
||||
|
|
@ -3,4 +3,5 @@ package constants
|
|||
const (
|
||||
RouteBooking = "/bookings"
|
||||
RouteNewBooking = "/bookings/new"
|
||||
RouteReports = "/reports"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
38
internal/views/report_section.templ
Normal file
38
internal/views/report_section.templ
Normal 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>
|
||||
}
|
||||
35
internal/views/report_section_templ.go
Normal file
35
internal/views/report_section_templ.go
Normal 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
|
||||
})
|
||||
}
|
||||
43
internal/views/reports.templ
Normal file
43
internal/views/reports.templ
Normal 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>
|
||||
}
|
||||
}
|
||||
93
internal/views/reports_templ.go
Normal file
93
internal/views/reports_templ.go
Normal 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
|
||||
})
|
||||
}
|
||||
Loading…
Reference in a new issue