diff --git a/components/mostWatchedPerson.templ b/components/mostWatchedPerson.templ index 2b3f089..4b8e61d 100644 --- a/components/mostWatchedPerson.templ +++ b/components/mostWatchedPerson.templ @@ -1,11 +1,15 @@ package components -import "fmt" +import ( + "fmt" + "strconv" +) type MostWatchedPersonProps struct { Data []ListItem Job string Title string + Total int Year string Years []string } @@ -16,6 +20,9 @@ templ MostWatchedPerson(props MostWatchedPersonProps) { @Dropdown(DropdownProps{Route: fmt.Sprintf("/stats/most-watched-person/%s", props.Job), Options: props.Years, Value: props.Year}) } @OrderedList(props.Data, "person") +
+ { strconv.Itoa( props.Total ) } people total +
} } diff --git a/components/mostWatchedPerson_templ.go b/components/mostWatchedPerson_templ.go index 27a7305..1812284 100644 --- a/components/mostWatchedPerson_templ.go +++ b/components/mostWatchedPerson_templ.go @@ -1,6 +1,6 @@ // Code generated by templ - DO NOT EDIT. -// templ: version: v0.2.771 +// templ: version: v0.2.778 package components //lint:file-ignore SA4006 This context is only used if a nested component is present. @@ -8,12 +8,16 @@ package components import "github.com/a-h/templ" import templruntime "github.com/a-h/templ/runtime" -import "fmt" +import ( + "fmt" + "strconv" +) type MostWatchedPersonProps struct { Data []ListItem Job string Title string + Total int Year string Years []string } @@ -21,6 +25,9 @@ type MostWatchedPersonProps struct { func MostWatchedPerson(props MostWatchedPersonProps) templ.Component { return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) if !templ_7745c5c3_IsBuffer { defer func() { @@ -78,6 +85,23 @@ func MostWatchedPerson(props MostWatchedPersonProps) templ.Component { 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_Var4 string + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(props.Total)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/mostWatchedPerson.templ`, Line: 24, Col: 32} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" people total
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } return templ_7745c5c3_Err }) templ_7745c5c3_Err = Section("", 0).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) @@ -91,6 +115,9 @@ func MostWatchedPerson(props MostWatchedPersonProps) templ.Component { func MostWatchedGenres(data []ListItem) templ.Component { return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) if !templ_7745c5c3_IsBuffer { defer func() { @@ -101,12 +128,12 @@ func MostWatchedGenres(data []ListItem) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var4 := templ.GetChildren(ctx) - if templ_7745c5c3_Var4 == nil { - templ_7745c5c3_Var4 = templ.NopComponent + templ_7745c5c3_Var5 := templ.GetChildren(ctx) + if templ_7745c5c3_Var5 == nil { + templ_7745c5c3_Var5 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Var5 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_Var6 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) if !templ_7745c5c3_IsBuffer { @@ -124,7 +151,7 @@ func MostWatchedGenres(data []ListItem) templ.Component { } return templ_7745c5c3_Err }) - templ_7745c5c3_Err = Section("Most watched genre", 0).Render(templ.WithChildren(ctx, templ_7745c5c3_Var5), templ_7745c5c3_Buffer) + templ_7745c5c3_Err = Section("Most watched genre", 0).Render(templ.WithChildren(ctx, templ_7745c5c3_Var6), templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/db/queries.sql b/db/queries.sql index 5d2acb8..fc32fa5 100644 --- a/db/queries.sql +++ b/db/queries.sql @@ -260,6 +260,18 @@ ORDER BY count DESC LIMIT 10; +-- name: total-watched-by-job-and-year +SELECT + COUNT(*) AS count +FROM + seen s + INNER JOIN movie_person mp ON mp.movie_id = s.movie_id +WHERE + user_id = $1 + AND mp.job = $2 + AND ($3 = 'All' + OR EXTRACT(YEAR FROM date) = $3::int); + -- name: stats-watched-by-year SELECT EXTRACT(YEAR FROM date) AS label, diff --git a/handlers/stats.go b/handlers/stats.go index 727f23e..fb2c05d 100644 --- a/handlers/stats.go +++ b/handlers/stats.go @@ -37,9 +37,11 @@ func HandleGetStats(c *fiber.Ctx) error { var movies []components.ListItem var shortestAndLongest types.Movies var wilhelms []int + var totals []components.ListItem userId := c.Locals("UserId").(string) now := time.Now() + year := now.Format("2006") currentYear := now.Format("2006-01-02 15:04:05") err := db.Dot.Select(db.Client, &movies, "stats-most-watched-movies", userId) @@ -56,6 +58,12 @@ func HandleGetStats(c *fiber.Ctx) error { return err } + err = db.Dot.Select(db.Client, &totals, "total-watched-by-job-and-year", userId, "cast", year) + + if err != nil { + return err + } + err = db.Dot.Get(db.Client, &stats, "stats-data", userId) if err != nil { @@ -128,7 +136,11 @@ func HandleGetStats(c *fiber.Ctx) error { } } - year := now.Format("2006") + totalCast := 0 + + if len(totals) > 0 { + totalCast = totals[0].Count + } return utils.TemplRender(c, views.Stats( views.StatsProps{ @@ -141,6 +153,7 @@ func HandleGetStats(c *fiber.Ctx) error { Ratings: ratings, SeenThisYear: seenThisYearByMonth, Stats: stats, + TotalCast: totalCast, WatchedByYear: watchedByYear, Year: year, YearRatings: yearRatings, @@ -152,6 +165,7 @@ func HandleGetStats(c *fiber.Ctx) error { func HandleGetMostWatchedByJob(c *fiber.Ctx) error { var persons []components.ListItem + var totals []components.ListItem job := c.Params("job") year := c.Query("year", "All") @@ -165,14 +179,27 @@ func HandleGetMostWatchedByJob(c *fiber.Ctx) error { return err } - return utils.TemplRender(c, components.MostWatchedPerson(components.MostWatchedPersonProps{ - Data: persons, - Job: job, - Title: cases.Title(language.English).String(job), - Year: year, - Years: years, - }, - )) + err = db.Dot.Select(db.Client, &totals, "total-watched-by-job-and-year", userId, job, year) + + if err != nil { + return err + } + + totalJob := 0 + + if len(totals) > 0 { + totalJob = totals[0].Count + } + + return utils.TemplRender(c, components.MostWatchedPerson( + components.MostWatchedPersonProps{ + Data: persons, + Job: job, + Title: cases.Title(language.English).String(job), + Total: totalJob, + Year: year, + Years: years, + })) } func getGraphWithQuery(query string, userId string) ([]types.Bar, error) { diff --git a/public/styles.323df8.css b/public/styles.5709e2.css similarity index 99% rename from public/styles.323df8.css rename to public/styles.5709e2.css index 52b5ff4..fa50df8 100644 --- a/public/styles.323df8.css +++ b/public/styles.5709e2.css @@ -913,6 +913,10 @@ video { text-align: center; } +.text-right { + text-align: right; +} + .text-base { font-size: 1rem; line-height: 1.5rem; diff --git a/public/styles.css b/public/styles.css index 7d30656..7e995d8 100644 --- a/public/styles.css +++ b/public/styles.css @@ -923,6 +923,10 @@ video { text-align: center; } +.text-right { + text-align: right; +} + .text-base { font-size: 1rem; line-height: 1.5rem; diff --git a/views/stats.templ b/views/stats.templ index ff3ae56..fe71560 100644 --- a/views/stats.templ +++ b/views/stats.templ @@ -27,6 +27,7 @@ type StatsProps struct { SeenThisYear []types.Bar ShortestAndLongestMovie types.Movies Stats types.Stats + TotalCast int WatchedByYear []types.Bar WilhelmScreams int Year string @@ -174,6 +175,7 @@ templ Stats(props StatsProps) { Job: "cast", Title: "Cast", Data: props.MostWatchedCast, + Total: props.TotalCast, Year: "All", Years: append([]string{"All"}, props.Years...), }) diff --git a/views/stats_templ.go b/views/stats_templ.go index 845aa9a..9a08586 100644 --- a/views/stats_templ.go +++ b/views/stats_templ.go @@ -1,6 +1,6 @@ // Code generated by templ - DO NOT EDIT. -// templ: version: v0.2.771 +// templ: version: v0.2.778 package views //lint:file-ignore SA4006 This context is only used if a nested component is present. @@ -19,6 +19,9 @@ import ( func statsSection(job string) templ.Component { return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) if !templ_7745c5c3_IsBuffer { defer func() { @@ -66,6 +69,7 @@ type StatsProps struct { SeenThisYear []types.Bar ShortestAndLongestMovie types.Movies Stats types.Stats + TotalCast int WatchedByYear []types.Bar WilhelmScreams int Year string @@ -76,6 +80,9 @@ type StatsProps struct { func Stats(props StatsProps) templ.Component { return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) if !templ_7745c5c3_IsBuffer { defer func() { @@ -172,7 +179,7 @@ func Stats(props StatsProps) templ.Component { var templ_7745c5c3_Var9 string templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(props.Stats.UniqueMovies)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/stats.templ`, Line: 55, Col: 48} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/stats.templ`, Line: 56, Col: 48} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) if templ_7745c5c3_Err != nil { @@ -206,7 +213,7 @@ func Stats(props StatsProps) templ.Component { var templ_7745c5c3_Var11 string templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(props.Stats.SeenWithRewatches)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/stats.templ`, Line: 61, Col: 53} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/stats.templ`, Line: 62, Col: 53} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) if templ_7745c5c3_Err != nil { @@ -240,7 +247,7 @@ func Stats(props StatsProps) templ.Component { var templ_7745c5c3_Var13 string templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(props.FormattedTotalRuntime) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/stats.templ`, Line: 67, Col: 37} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/stats.templ`, Line: 68, Col: 37} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) if templ_7745c5c3_Err != nil { @@ -275,7 +282,7 @@ func Stats(props StatsProps) templ.Component { var templ_7745c5c3_Var15 string templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(props.WilhelmScreams)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/stats.templ`, Line: 74, Col: 45} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/stats.templ`, Line: 75, Col: 45} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15)) if templ_7745c5c3_Err != nil { @@ -323,7 +330,7 @@ func Stats(props StatsProps) templ.Component { var templ_7745c5c3_Var18 string templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(props.Stats.TopImdbTitle) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/stats.templ`, Line: 84, Col: 35} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/stats.templ`, Line: 85, Col: 35} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18)) if templ_7745c5c3_Err != nil { @@ -336,7 +343,7 @@ func Stats(props StatsProps) templ.Component { var templ_7745c5c3_Var19 string templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.FormatFloat(props.Stats.TopImdbRating, 'f', 1, 64)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/stats.templ`, Line: 87, Col: 70} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/stats.templ`, Line: 88, Col: 70} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19)) if templ_7745c5c3_Err != nil { @@ -386,7 +393,7 @@ func Stats(props StatsProps) templ.Component { var templ_7745c5c3_Var22 string templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(props.BestOfTheYear.Title) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/stats.templ`, Line: 95, Col: 37} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/stats.templ`, Line: 96, Col: 37} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22)) if templ_7745c5c3_Err != nil { @@ -410,7 +417,7 @@ func Stats(props StatsProps) templ.Component { var templ_7745c5c3_Var23 string templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.FormatInt(props.BestOfTheYear.Rating.Int64, 10)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/stats.templ`, Line: 99, Col: 69} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/stats.templ`, Line: 100, Col: 69} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23)) if templ_7745c5c3_Err != nil { @@ -462,7 +469,7 @@ func Stats(props StatsProps) templ.Component { var templ_7745c5c3_Var26 string templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.JoinStringErrs(props.ShortestAndLongestMovie[0].Title) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/stats.templ`, Line: 109, Col: 50} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/stats.templ`, Line: 110, Col: 50} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var26)) if templ_7745c5c3_Err != nil { @@ -481,7 +488,7 @@ func Stats(props StatsProps) templ.Component { var templ_7745c5c3_Var27 string templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(utils.FormatRuntime(props.ShortestAndLongestMovie[0].Runtime)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/stats.templ`, Line: 112, Col: 74} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/stats.templ`, Line: 113, Col: 74} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27)) if templ_7745c5c3_Err != nil { @@ -530,7 +537,7 @@ func Stats(props StatsProps) templ.Component { var templ_7745c5c3_Var30 string templ_7745c5c3_Var30, templ_7745c5c3_Err = templ.JoinStringErrs(props.ShortestAndLongestMovie[1].Title) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/stats.templ`, Line: 119, Col: 50} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/stats.templ`, Line: 120, Col: 50} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var30)) if templ_7745c5c3_Err != nil { @@ -549,7 +556,7 @@ func Stats(props StatsProps) templ.Component { var templ_7745c5c3_Var31 string templ_7745c5c3_Var31, templ_7745c5c3_Err = templ.JoinStringErrs(utils.FormatRuntime(props.ShortestAndLongestMovie[1].Runtime)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/stats.templ`, Line: 122, Col: 74} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/stats.templ`, Line: 123, Col: 74} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var31)) if templ_7745c5c3_Err != nil { @@ -660,7 +667,7 @@ func Stats(props StatsProps) templ.Component { var templ_7745c5c3_Var36 string templ_7745c5c3_Var36, templ_7745c5c3_Err = templ.JoinStringErrs(year.Label) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/stats.templ`, Line: 155, Col: 22} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/stats.templ`, Line: 156, Col: 22} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var36)) if templ_7745c5c3_Err != nil { @@ -700,7 +707,7 @@ func Stats(props StatsProps) templ.Component { var templ_7745c5c3_Var39 string templ_7745c5c3_Var39, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(year.Value)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/stats.templ`, Line: 162, Col: 36} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/stats.templ`, Line: 163, Col: 36} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var39)) if templ_7745c5c3_Err != nil { @@ -751,6 +758,7 @@ func Stats(props StatsProps) templ.Component { Job: "cast", Title: "Cast", Data: props.MostWatchedCast, + Total: props.TotalCast, Year: "All", Years: append([]string{"All"}, props.Years...), }).Render(ctx, templ_7745c5c3_Buffer)