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:
1 parent
36933c2c31
commit
1718a56ea6
2 files changed
+21
-3
No files matched your search
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
Reference in new issue
Block a user