From 6e936dbb95d1ff1acb4666d4930f6420f3a29425 Mon Sep 17 00:00:00 2001 From: Deeman Date: Wed, 4 Mar 2026 15:32:56 +0100 Subject: [PATCH] =?UTF-8?q?feat(maps):=20Phase=205=20=E2=80=94=20standalon?= =?UTF-8?q?e=20opportunity=20map=20page?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New route GET //opportunity-map renders a full-width Leaflet map with a country selector. On country change, fetches /api/opportunity/{slug}.json and renders opportunity circles (color-coded by score, sized by population) plus existing-venue gray reference dots from /api/markets/{country}/cities.json. Co-Authored-By: Claude Opus 4.6 --- web/src/padelnomics/public/routes.py | 12 ++ .../public/templates/opportunity_map.html | 127 ++++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100644 web/src/padelnomics/public/templates/opportunity_map.html diff --git a/web/src/padelnomics/public/routes.py b/web/src/padelnomics/public/routes.py index 99aeb1c..9bf0248 100644 --- a/web/src/padelnomics/public/routes.py +++ b/web/src/padelnomics/public/routes.py @@ -5,6 +5,7 @@ from pathlib import Path from quart import Blueprint, g, render_template, request, session +from ..analytics import fetch_analytics from ..core import check_rate_limit, count_where, csrf_protect, execute, fetch_all, fetch_one from ..i18n import get_translations @@ -71,6 +72,17 @@ async def market_score(): return await render_template("market_score.html") +@bp.route("/opportunity-map") +async def opportunity_map(): + """Interactive padel opportunity map — country selector + location dots.""" + countries = await fetch_analytics(""" + SELECT DISTINCT country_slug, country_name_en + FROM serving.city_market_profile + ORDER BY country_name_en + """) + return await render_template("opportunity_map.html", countries=countries) + + @bp.route("/imprint") async def imprint(): lang = g.get("lang", "en") diff --git a/web/src/padelnomics/public/templates/opportunity_map.html b/web/src/padelnomics/public/templates/opportunity_map.html new file mode 100644 index 0000000..7eea4a3 --- /dev/null +++ b/web/src/padelnomics/public/templates/opportunity_map.html @@ -0,0 +1,127 @@ +{% extends "base.html" %} + +{% block title %}Padel Opportunity Map — {{ config.APP_NAME }}{% endblock %} + +{% block head %} + + + +{% endblock %} + +{% block content %} +
+
+

Padel Opportunity Map

+

Locations ranked by investment potential — population, supply gap, sports culture, and catchment reach.

+
+ +
+ + +
+ +
+ +
+ Circle size: population  |  + Color: + High (≥70)   + Mid (40–70)   + Low (<40) +
+
+{% endblock %} + +{% block scripts %} + + +{% endblock %}