fix: pagination underflow, remove |safe, move bar_height_pct to adapter

This commit is contained in:
2026-05-04 19:09:28 +02:00
parent 27be840faa
commit a4846f3bea
4 changed files with 27 additions and 16 deletions

View File

@@ -5,7 +5,7 @@ use application::ports::{
NewReviewPageData, ProfilePageData, RegisterPageData, UsersPageData, NewReviewPageData, ProfilePageData, RegisterPageData, UsersPageData,
}; };
use domain::models::{ use domain::models::{
DiaryEntry, FeedEntry, MonthActivity, UserStats, UserSummary, UserTrends, DiaryEntry, FeedEntry, MonthActivity, MonthlyRating, UserStats, UserSummary, UserTrends,
collections::Paginated, collections::Paginated,
}; };
@@ -57,6 +57,11 @@ struct UsersTemplate<'a> {
ctx: &'a HtmlPageContext, ctx: &'a HtmlPageContext,
} }
struct MonthlyRatingRow<'a> {
rating: &'a MonthlyRating,
bar_height_pct: i64,
}
#[derive(Template)] #[derive(Template)]
#[template(path = "profile.html")] #[template(path = "profile.html")]
struct ProfileTemplate<'a> { struct ProfileTemplate<'a> {
@@ -70,13 +75,14 @@ struct ProfileTemplate<'a> {
limit: u32, limit: u32,
history: Option<&'a Vec<MonthActivity>>, history: Option<&'a Vec<MonthActivity>>,
trends: Option<&'a UserTrends>, trends: Option<&'a UserTrends>,
monthly_rating_rows: Vec<MonthlyRatingRow<'a>>,
heatmap: Vec<HeatmapCell>, heatmap: Vec<HeatmapCell>,
} }
struct HeatmapCell { struct HeatmapCell {
month_label: String, month_label: String,
count: i64, count: i64,
bg_style: String, alpha: f64,
} }
#[allow(dead_code)] #[allow(dead_code)]
@@ -114,11 +120,15 @@ fn build_heatmap(history: &[MonthActivity]) -> Vec<HeatmapCell> {
HeatmapCell { HeatmapCell {
month_label: label.to_string(), month_label: label.to_string(),
count, count,
bg_style: format!("background: rgba(74, 158, 255, {:.2})", alpha), alpha,
} }
}).collect() }).collect()
} }
fn bar_height_pct(avg_rating: f64) -> i64 {
(avg_rating / 5.0 * 100.0) as i64
}
pub struct AskamaHtmlRenderer; pub struct AskamaHtmlRenderer;
impl AskamaHtmlRenderer { impl AskamaHtmlRenderer {
@@ -195,6 +205,12 @@ impl HtmlRenderer for AskamaHtmlRenderer {
.unwrap_or_default(); .unwrap_or_default();
let profile_display_name = data.profile_user_email let profile_display_name = data.profile_user_email
.split('@').next().unwrap_or(&data.profile_user_email).to_string(); .split('@').next().unwrap_or(&data.profile_user_email).to_string();
let monthly_rating_rows: Vec<MonthlyRatingRow<'_>> = data.trends.as_ref()
.map(|t| t.monthly_ratings.iter().map(|r| MonthlyRatingRow {
bar_height_pct: bar_height_pct(r.avg_rating),
rating: r,
}).collect())
.unwrap_or_default();
ProfileTemplate { ProfileTemplate {
ctx: &data.ctx, ctx: &data.ctx,
profile_display_name, profile_display_name,
@@ -206,6 +222,7 @@ impl HtmlRenderer for AskamaHtmlRenderer {
limit: data.limit, limit: data.limit,
history: data.history.as_ref(), history: data.history.as_ref(),
trends: data.trends.as_ref(), trends: data.trends.as_ref(),
monthly_rating_rows,
heatmap, heatmap,
} }
.render() .render()

View File

@@ -40,7 +40,7 @@
{% endfor %} {% endfor %}
</div> </div>
<nav class="pagination"> <nav class="pagination">
{% if current_offset > 0 %} {% if current_offset >= limit %}
<a href="/?offset={{ current_offset - limit }}">&larr; Prev</a> <a href="/?offset={{ current_offset - limit }}">&larr; Prev</a>
{% endif %} {% endif %}
{% if has_more %} {% if has_more %}

View File

@@ -37,7 +37,7 @@
<div class="heatmap-label">Movies watched this year</div> <div class="heatmap-label">Movies watched this year</div>
<div class="heatmap"> <div class="heatmap">
{% for cell in heatmap %} {% for cell in heatmap %}
<div class="heatmap-cell" style="{{ cell.bg_style|safe }}"> <div class="heatmap-cell" style="background: rgba(74, 158, 255, {{ cell.alpha }})">
<div class="heatmap-count">{{ cell.count }}</div> <div class="heatmap-count">{{ cell.count }}</div>
<div class="heatmap-month">{{ cell.month_label }}</div> <div class="heatmap-month">{{ cell.month_label }}</div>
</div> </div>
@@ -75,14 +75,14 @@
{% elif view == "trends" %} {% elif view == "trends" %}
{% if let Some(t) = trends %} {% if let Some(t) = trends %}
<div class="trends-section"> <div class="trends-section">
{% if !t.monthly_ratings.is_empty() %} {% if !monthly_rating_rows.is_empty() %}
<div class="chart-block"> <div class="chart-block">
<div class="chart-label">Average rating per month</div> <div class="chart-label">Average rating per month</div>
<div class="bar-chart"> <div class="bar-chart">
{% for m in t.monthly_ratings %} {% for row in monthly_rating_rows %}
<div class="bar-col"> <div class="bar-col">
<div class="bar-fill" style="height: {{ m.bar_height_pct() }}%"></div> <div class="bar-fill" style="height: {{ row.bar_height_pct }}%"></div>
<div class="bar-month">{{ m.month_label }}</div> <div class="bar-month">{{ row.rating.month_label }}</div>
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
@@ -150,7 +150,7 @@
{% endfor %} {% endfor %}
</div> </div>
<nav class="pagination"> <nav class="pagination">
{% if current_offset > 0 %} {% if current_offset >= limit %}
<a href="?view={{ view }}&offset={{ current_offset - limit }}">&larr; Prev</a> <a href="?view={{ view }}&offset={{ current_offset - limit }}">&larr; Prev</a>
{% endif %} {% endif %}
{% if has_more %} {% if has_more %}

View File

@@ -352,12 +352,6 @@ pub struct MonthlyRating {
pub count: i64, pub count: i64,
} }
impl MonthlyRating {
pub fn bar_height_pct(&self) -> i64 {
(self.avg_rating / 5.0 * 100.0) as i64
}
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct DirectorStat { pub struct DirectorStat {
pub director: String, pub director: String,