Add Total Followers (month end) tile to Reports tab and PDF

Month Start and New Followers already existed, but neither answers
"how many followers do we actually have as of this month" without
the reader doing the addition themselves. Adds a third tile, Total
Followers (month end) = Month Start + New Followers, placed between
them so the row reads Start -> New -> End as one story. Pinned to
that specific reporting period like Month Start already is, so it
never drifts with "today" the way the tile removed earlier did.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
beantownbabeandClaude Sonnet 5 committed 2026-09-30 11:48:24 +02:00
1 parent 36933c2c31
commit 1718a56ea6
2 files changed
+21 -3

No files matched your search

+5
View File
@@ -4271,6 +4271,11 @@ def _render_reports_tab(month_value):
label_style=_reports_centered_label, value_style=_reports_big_centered_value,
card_style=_reports_card_style, body_style=_reports_kpi_body_style),
style={"flex": "1", "minWidth": "0"}),
html.Div(kpi("Total Followers", f"{stats['end_of_month_followers']:,}" if stats["end_of_month_followers"] is not None else "—",
"month end", color=_REPORTS_ACCENT,
label_style=_reports_centered_label, value_style=_reports_big_centered_value,
card_style=_reports_card_style, body_style=_reports_kpi_body_style),
style={"flex": "1", "minWidth": "0"}),
html.Div(kpi("Posts Published", f"{stats['posts_published']:,}", color=_REPORTS_ACCENT,
label_style=_reports_centered_label, value_style=_reports_big_centered_value,
card_style=_reports_card_style, body_style=_reports_kpi_body_style),
+16 -3
View File
@@ -120,12 +120,22 @@ def compute_period_stats(ctx, timeframe_value="all"):
if start_of_month_followers:
monthly_growth_rate = (new_followers / start_of_month_followers) * 100
# Total Followers, pinned to the end of this specific reporting period (start +
# this period's own new followers) — not the live/global current_total_followers,
# so a report read weeks later still shows that month's own total rather than
# whatever the count has drifted to by the time someone opens it. None whenever
# start_of_month_followers is None (same "all"/year-level cases).
end_of_month_followers = (
start_of_month_followers + new_followers if start_of_month_followers is not None else None
)
return {
"fts_f": fts_f, "posts_f": posts_f, "cts_f": cts_f, "vts_f": vts_f,
"new_followers": new_followers, "total_impressions": total_impressions,
"total_page_views": total_page_views, "posts_published": posts_published,
"best_eng": best_eng, "avg_eng": avg_eng,
"start_of_month_followers": start_of_month_followers,
"end_of_month_followers": end_of_month_followers,
"monthly_growth_rate": monthly_growth_rate,
"period_label": _period_label(timeframe_value),
}
@@ -199,6 +209,7 @@ def build_report_pdf(ctx, timeframe_value="all"):
avg_eng = period["avg_eng"]
monthly_growth_rate = period["monthly_growth_rate"]
start_of_month_followers = period["start_of_month_followers"]
end_of_month_followers = period["end_of_month_followers"]
period_label = period["period_label"]
styles = getSampleStyleSheet()
@@ -226,16 +237,18 @@ def build_report_pdf(ctx, timeframe_value="all"):
# --- KPI summary table ---
story.append(Paragraph("Key Metrics", h2_style))
kpi_data = [
["Month Start", "New Followers", "Posts Published",
["Month Start", "New Followers", "Total Followers\n(month end)", "Posts Published",
"Total Impressions", "Total Page Views", "Best Post Real Eng.", "Avg. Eng. Rate", "Monthly Growth Rate"],
[f"{start_of_month_followers:,}" if start_of_month_followers is not None else "—",
f"{new_followers:,}", f"{posts_published:,}",
f"{new_followers:,}",
f"{end_of_month_followers:,}" if end_of_month_followers is not None else "—",
f"{posts_published:,}",
f"{total_impressions:,}", f"{total_page_views:,}",
f"{best_eng:.1f}%" if best_eng is not None else "Pending audit",
f"{avg_eng:.2f}%" if avg_eng else "—",
f"{monthly_growth_rate:+.1f}%" if monthly_growth_rate is not None else "—"],
]
kpi_table = Table(kpi_data, colWidths=[2 * cm] * 8)
kpi_table = Table(kpi_data, colWidths=[2 * cm] * 9)
kpi_table.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, 0), LIGHT_GRAY),
("TEXTCOLOR", (0, 0), (-1, 0), TEXT_GRAY),