Add Team tab with per-member submenu (data starts Dec 2026)
New tab for analyzing each team member's own personal LinkedIn export data (separate from the Page-level Content/Followers/Visitors exports), starting December 2026 per Mckinley. Submenu dropdown lists Peter Gaal, Daniel Schmidt, Niklas Meidow, Aleksandra Kotenko, Mckinley Black. Same "starts empty" pattern as the Engagement Response tab: a hand- maintained team_exports.py module (empty for now) backs the tab, and each person shows a clean placeholder until their real export data gets added - no other code changes needed at that point. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ad2f8698f7
commit
436e52254a
2 files changed
+66
No files matched your search
@@ -17,6 +17,7 @@ import follower_directory_data
|
||||
import engagement_audit
|
||||
import theme_tracker
|
||||
import conversation_tracker
|
||||
import team_exports
|
||||
|
||||
# Overridable via env var so the same code runs unmodified in Docker/internal deployments —
|
||||
# defaults to this machine's path for local dev.
|
||||
@@ -2330,6 +2331,23 @@ def _build_engagement_response_tab():
|
||||
return dbc.Container([theme_card, convo_card], fluid=True, className="pb-3")
|
||||
|
||||
|
||||
_TEAM_MEMBER_OPTIONS = [{"label": name, "value": name} for name in team_exports.TEAM_MEMBERS]
|
||||
_TEAM_DEFAULT_MEMBER = team_exports.TEAM_MEMBERS[0]
|
||||
|
||||
team_tab = dbc.Container([
|
||||
html.Div([
|
||||
html.Label("Team member", style={"fontSize": "0.75rem", "fontWeight": "600",
|
||||
"marginBottom": "4px", "display": "block"}),
|
||||
dcc.Dropdown(
|
||||
id="team-member-select",
|
||||
options=_TEAM_MEMBER_OPTIONS, value=_TEAM_DEFAULT_MEMBER,
|
||||
clearable=False, searchable=False, style={"width": "280px"},
|
||||
),
|
||||
], style={"marginBottom": "1.25rem"}),
|
||||
html.Div(id="team-content-area"),
|
||||
], fluid=True, className="pb-3")
|
||||
|
||||
|
||||
refresh_data()
|
||||
engagement_response_tab = _build_engagement_response_tab()
|
||||
|
||||
@@ -2351,6 +2369,7 @@ NAV_ITEMS = [
|
||||
("growth", "Growth", growth_tab),
|
||||
("reports", "Reports", reports_tab),
|
||||
("engagement-response", "Engagement Response", engagement_response_tab),
|
||||
("team", "Team", team_tab),
|
||||
]
|
||||
TAB_CONTENT_MAP = {key: content for key, _, content in NAV_ITEMS}
|
||||
|
||||
@@ -2363,6 +2382,7 @@ TAB_HERO = {
|
||||
"growth": ("Growth", "Historical follower growth, tracked weekly against your own rolling best."),
|
||||
"reports": ("Reports", "Monthly progress reports for LinkedIn, combining the dashboard data with the Follower Directory."),
|
||||
"engagement-response": ("Engagement Response", "Theme performance across the whole campaign and a tracker for every real conversation, so none get left open."),
|
||||
"team": ("Team", "Each team member's own personal LinkedIn export data, starting December 2026."),
|
||||
"roadmap-insights": ("Campaign Roadmap — Insights", ""),
|
||||
"all-posts-insights": ("All Posts — Insights", "The Content tab's own post list and format/activity charts, mirrored here for the selected month."),
|
||||
"follower-growth-insights": ("Follower Growth — Insights", "The Overview and Growth tabs' own follower charts, mirrored here for the selected month."),
|
||||
@@ -2662,6 +2682,25 @@ def _switch_to_insights_page(pathname, selected_month):
|
||||
return classes + [content, hero_title, _hero_subtitle_children(active), _hero_actions(active, month_value)]
|
||||
|
||||
|
||||
@app.callback(
|
||||
Output("team-content-area", "children"),
|
||||
Input("team-member-select", "value"),
|
||||
)
|
||||
def _render_team_tab(name):
|
||||
"""Starts empty for everyone - personal-profile exports begin December 2026 (see
|
||||
team_exports.py). Shows the same clean "nothing yet" treatment as the Engagement
|
||||
Response tab's theme/conversation cards until a person's real data lands."""
|
||||
data = team_exports.exports_for(name)
|
||||
if not data:
|
||||
return dbc.Alert(
|
||||
f"No personal LinkedIn export data for {name} yet - this starts December 2026. "
|
||||
"Add an entry to team_exports.TEAM_EXPORTS as each person's export data comes in, "
|
||||
"no other code changes needed for it to show up here.",
|
||||
color="info",
|
||||
)
|
||||
return html.Div(f"Export data for {name}: {data}")
|
||||
|
||||
|
||||
@app.callback(
|
||||
Output("fb-expanded", "data", allow_duplicate=True),
|
||||
Input("fb-expand-btn", "n_clicks"),
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
"""Per-team-member personal LinkedIn export data, starting December 2026. The Page-level
|
||||
exports (Content/Followers/Visitors/Competitors) only cover the TXproducts Company Page -
|
||||
this is for each team member's own personal profile activity (their own post performance,
|
||||
follower growth, etc.), tracked separately starting when that analysis begins.
|
||||
|
||||
Empty until December 2026 - add each person's export data here as it starts coming in,
|
||||
no other code changes needed for it to show up in the Team tab. The exact per-person
|
||||
schema isn't fixed yet (personal-profile exports aren't the same shape as the Page's own
|
||||
exports), so this starts as a simple hand-maintained dict keyed by name; replace a
|
||||
person's entry with whatever structure their real export data turns out to need.
|
||||
"""
|
||||
|
||||
TEAM_MEMBERS = [
|
||||
"Peter Gaal",
|
||||
"Daniel Schmidt",
|
||||
"Niklas Meidow",
|
||||
"Aleksandra Kotenko",
|
||||
"Mckinley Black",
|
||||
]
|
||||
|
||||
# "Peter Gaal": {"exports": [...], "notes": "..."},
|
||||
TEAM_EXPORTS = {
|
||||
}
|
||||
|
||||
|
||||
def exports_for(name):
|
||||
return TEAM_EXPORTS.get(name)
|
||||
Reference in new issue
Block a user