fix: post-flatten dev scripts, lead form validation, copy improvements
- Fix dev_run.sh and dev_setup.sh cd path (../.. after repo flatten) - Quote form: re-render step 9 inline on validation error instead of flash + redirect to step 1; phone/email errors now show field-level - Supplier FAQ: move differentiation Q to top, fix Q10 email to hello@ (was leads@), rename Q1 to "How do I get listed?" - Replace Innenhalle → Indoorhalle throughout DE locale and seed script Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -273,31 +273,38 @@ async def quote_request():
|
||||
form = await request.form
|
||||
services = form.getlist("services_needed")
|
||||
|
||||
# Validate mandatory fields
|
||||
errors = []
|
||||
# Validate mandatory fields — collect field names for inline error display
|
||||
field_errors = []
|
||||
if not form.get("country"):
|
||||
errors.append("Country is required")
|
||||
field_errors.append("country")
|
||||
if not form.get("timeline"):
|
||||
errors.append("Timeline is required")
|
||||
field_errors.append("timeline")
|
||||
if not form.get("stakeholder_type"):
|
||||
errors.append("Stakeholder type is required")
|
||||
field_errors.append("stakeholder_type")
|
||||
if not form.get("contact_name", "").strip():
|
||||
errors.append("Full name is required")
|
||||
if not form.get("contact_email", "").strip():
|
||||
errors.append("Email is required")
|
||||
if not form.get("contact_phone", "").strip():
|
||||
errors.append("Phone number is required")
|
||||
field_errors.append("contact_name")
|
||||
contact_email_raw = form.get("contact_email", "").strip()
|
||||
if contact_email_raw and is_disposable_email(contact_email_raw):
|
||||
errors.append("Please use a permanent email address, not a temporary one.")
|
||||
if not contact_email_raw:
|
||||
field_errors.append("contact_email")
|
||||
elif is_disposable_email(contact_email_raw):
|
||||
field_errors.append("contact_email")
|
||||
contact_phone_raw = form.get("contact_phone", "").strip()
|
||||
if contact_phone_raw and not is_plausible_phone(contact_phone_raw):
|
||||
errors.append("Please enter a valid phone number.")
|
||||
if errors:
|
||||
if not contact_phone_raw:
|
||||
field_errors.append("contact_phone")
|
||||
elif not is_plausible_phone(contact_phone_raw):
|
||||
field_errors.append("contact_phone")
|
||||
if field_errors:
|
||||
if is_json:
|
||||
return jsonify({"ok": False, "errors": errors}), 422
|
||||
await flash("; ".join(errors), "error")
|
||||
return redirect(url_for("leads.quote_request"))
|
||||
return jsonify({"ok": False, "errors": field_errors}), 422
|
||||
form_data = {k: v for k, v in form.items() if not k.startswith("_") and k != "csrf_token"}
|
||||
form_data["services_needed"] = services
|
||||
return await render_template(
|
||||
"quote_request.html",
|
||||
data=form_data,
|
||||
step=9,
|
||||
steps=_get_quote_steps(lang),
|
||||
errors=field_errors,
|
||||
)
|
||||
|
||||
heat = calculate_heat_score(form)
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
"landing_roi_monthly_cf": "Monatlicher Cashflow",
|
||||
"landing_roi_payback": "Amortisationszeit",
|
||||
"landing_roi_annual_roi": "Jährlicher ROI",
|
||||
"landing_roi_note": "Annahmen: Innenhalle Mietmodell, 8 €/m² Miete, Personalkosten, 5 % Zinsen, 10-jähriges Darlehen. Amortisation und ROI basieren auf der Gesamtinvestition.",
|
||||
"landing_roi_note": "Annahmen: Indoorhalle Mietmodell, 8 €/m² Miete, Personalkosten, 5 % Zinsen, 10-jähriges Darlehen. Amortisation und ROI basieren auf der Gesamtinvestition.",
|
||||
"landing_roi_cta": "Jetzt planen →",
|
||||
"landing_journey_title": "Deine Reise",
|
||||
"landing_journey_01": "Analysieren",
|
||||
@@ -792,7 +792,7 @@
|
||||
"label_build_buy": "Kauf/Bau",
|
||||
"label_rent": "Miete",
|
||||
"label_courts": "Plätze",
|
||||
"label_indoor_hall": "Innenhalle",
|
||||
"label_indoor_hall": "Indoorhalle",
|
||||
"label_outdoor_land": "Außenfläche",
|
||||
"label_playing_surface": "Spielfläche",
|
||||
"wiz_capex": "CAPEX",
|
||||
@@ -1017,7 +1017,7 @@
|
||||
"sup_proof_q2": "Endlich eine Plattform, die den Padel-Baumarkt versteht. Wir kennen das Budget, den Zeitplan und den Standorttyp, bevor wir überhaupt Erstkontakt aufnehmen.",
|
||||
"sup_proof_cite2": "— Padel-Court-Installationsunternehmen, Skandinavien",
|
||||
"sup_faq_h2": "Anbieter-FAQ",
|
||||
"sup_faq_q1": "Wie beanspruche ich mein Inserat?",
|
||||
"sup_faq_q1": "Wie werde ich gelistet?",
|
||||
"sup_faq_a1_pre": "Finde dein Unternehmen in unserem",
|
||||
"sup_faq_a1_post": "und klicke auf „Ist das dein Unternehmen?“ Wir überprüfen deine Identität und geben dir Zugang, um einen Plan auszuwählen und dein Profil zu aktualisieren.",
|
||||
"sup_faq_dir_link": "Verzeichnis",
|
||||
@@ -1160,7 +1160,7 @@
|
||||
"features_meta_desc": "60+ anpassbare Variablen, 6 Analyse-Tabs, Sensitivitätsanalyse und professionelle Finanzprojektionen für deine Padelplatz-Investition.",
|
||||
"features_card_1_body": "Jede Annahme ist anpassbar: Platzbaukosten, Miete, Stundensätze, Auslastungskurven, Finanzierungskonditionen, Exit-Multiplikatoren. Nichts ist fest vorgegeben — Dein Modell spiegelt deine Realität wider.",
|
||||
"features_card_2_body": "Annahmen, Investition (CAPEX), Betriebsmodell, Cashflow, Renditen & Exit sowie Kennzahlen. Jeder Tab mit interaktiven Diagrammen, die sich in Echtzeit aktualisieren, wenn du Eingaben anpasst.",
|
||||
"features_card_3_body": "Innenhallenmodelle (Anmietung eines Bestandsgebäudes oder Neubau) und Außenanlagen mit Saisonalitätsanpassungen. Szenarien direkt nebeneinander vergleichen, um den besten Ansatz für deinen Markt zu finden.",
|
||||
"features_card_3_body": "Indoorhallenmodelle (Anmietung eines Bestandsgebäudes oder Neubau) und Außenanlagen mit Saisonalitätsanpassungen. Szenarien direkt nebeneinander vergleichen, um den besten Ansatz für deinen Markt zu finden.",
|
||||
"features_card_4_body": "Sieh dir an, wie sich deine IRR und Cash-Rendite bei unterschiedlichen Auslastungsraten und Preisen verändern. Ermittle deinen Break-even-Punkt sofort mit der integrierten Sensitivitätsmatrix.",
|
||||
"features_card_5_body": "IRR, MOIC, DSCR, Cash-on-Cash-Rendite, Break-even-Auslastung, RevPAH, Schuldenrendite — die Kennzahlen, die Banken und Investoren in einem Padelplatz-Businessplan sehen möchten.",
|
||||
"features_card_6_body": "Unbegrenzte Szenarien speichern. Verschiedene Standorte, Platzzahlen, Finanzierungsstrukturen und Preisstrategien testen. Laden und vergleichen, um den optimalen Plan für deine Investition zu finden.",
|
||||
@@ -1179,7 +1179,7 @@
|
||||
"landing_journey_05_desc": "Launch-Playbook, Performance-Benchmarks und Wachstumsanalysen für deinen Betrieb.",
|
||||
"landing_feature_1_body": "Jede Annahme ist anpassbar: Platzbaukosten, Miete, Preisgestaltung, Auslastung, Finanzierungskonditionen, Exit-Szenarien. Nichts ist fest vorgegeben.",
|
||||
"landing_feature_2_body": "Annahmen, Investition (CAPEX), Betriebsmodell, Cashflow, Renditen & Exit sowie Kennzahlen — jeder Tab mit interaktiven Diagrammen.",
|
||||
"landing_feature_3_body": "Innenhallenmodelle (Miete oder Neubau) und Außenanlagen mit Saisonalität. Szenarien direkt nebeneinander vergleichen.",
|
||||
"landing_feature_3_body": "Indoorhallenmodelle (Miete oder Neubau) und Außenanlagen mit Saisonalität. Szenarien direkt nebeneinander vergleichen.",
|
||||
"landing_feature_4_body": "Sieh dir an, wie sich deine Renditen bei unterschiedlichen Auslastungsraten und Preisen verändern. Break-even-Punkt sofort ermitteln.",
|
||||
"landing_feature_5_body": "IRR, MOIC, DSCR, Cash-on-Cash-Rendite, Break-even-Auslastung, RevPAH, Schuldenrendite — die Kennzahlen, die Banken und Investoren sehen möchten.",
|
||||
"landing_feature_6_body": "Unbegrenzte Szenarien speichern. Verschiedene Standorte, Platzzahlen und Finanzierungsstrukturen testen. Den optimalen Plan finden.",
|
||||
@@ -1192,7 +1192,7 @@
|
||||
"landing_faq_a3": "Wenn du über den Planer Angebote anforderst, teilen wir deine Projektdetails (Anlagentyp, Platzzahl, Glas, Beleuchtung, Land, Budget, Zeitplan) mit passenden Anbietern aus unserem Verzeichnis. Diese kontaktieren dich direkt mit ihren Angeboten.",
|
||||
"landing_faq_a4": "Das Durchsuchen des Verzeichnisses ist für alle kostenlos. Anbieter erhalten standardmäßig einen Basiseintrag. Kostenpflichtige Pläne (Basic ab 39 €/Monat, Growth ab 199 €/Monat, Pro ab 499 €/Monat) schalten Anfrageformulare, vollständige Beschreibungen, Logos, verifizierte Badges und Prioritätsplatzierung frei.",
|
||||
"landing_faq_a5": "Das Modell verwendet reale Standardwerte auf Basis europäischer Marktdaten. Jede Annahme ist anpassbar, sodass du deine lokalen Gegebenheiten abbilden kannst. Die Sensitivitätsanalyse zeigt, wie sich die Ergebnisse in verschiedenen Szenarien verändern, und hilft dir, die Bandbreite möglicher Ergebnisse zu verstehen.",
|
||||
"landing_seo_p1": "Padel ist der am schnellsten wachsende Sport in Europa — die Nachfrage nach Plätzen übersteigt das Angebot in Deutschland, Österreich, der Schweiz und darüber hinaus bei weitem. Eine Paddelhalle zu eröffnen kann eine attraktive Investition sein, aber die Zahlen müssen stimmen. Eine typische Innenhalle mit 6–8 Plätzen erfordert zwischen 300.000 € (Anmietung eines Bestandsgebäudes) und 2–3 Mio. € (Neubau), mit Amortisationszeiten von 3–5 Jahren für gut gelegene Anlagen.",
|
||||
"landing_seo_p1": "Padel ist der am schnellsten wachsende Sport in Europa — die Nachfrage nach Plätzen übersteigt das Angebot in Deutschland, Österreich, der Schweiz und darüber hinaus bei weitem. Eine Paddelhalle zu eröffnen kann eine attraktive Investition sein, aber die Zahlen müssen stimmen. Eine typische Indoorhalle mit 6–8 Plätzen erfordert zwischen 300.000 € (Anmietung eines Bestandsgebäudes) und 2–3 Mio. € (Neubau), mit Amortisationszeiten von 3–5 Jahren für gut gelegene Anlagen.",
|
||||
"landing_seo_p2": "Die entscheidenden Faktoren für den Erfolg sind Standort (treibt die Auslastung), Baukosten (CAPEX), Miet- oder Grundstückskosten sowie die Preisstrategie. Unser Finanzplaner ermöglicht es dir, alle diese Variablen interaktiv zu modellieren und die Auswirkungen auf IRR, MOIC, Cashflow und Schuldendienstdeckungsgrad in Echtzeit zu sehen. Ob du als Unternehmer deine erste Anlage prüfst, als Immobilienentwickler Padel in ein Mixed-Use-Projekt integrierst oder als Investor eine bestehende Paddelhalle bewertest — Padelnomics gibt dir die finanzielle Klarheit für fundierte Entscheidungen.",
|
||||
"landing_final_cta_sub": "Modelliere deine Investition und lass dich mit verifizierten Platz-Anbietern aus {total_countries} Ländern zusammenbringen.",
|
||||
"landing_jsonld_org_desc": "Professionelle Planungsplattform für Padelplatz-Investitionen. Finanzplaner, Anbieterverzeichnis und Marktinformationen für Padel-Unternehmer.",
|
||||
|
||||
@@ -1017,7 +1017,7 @@
|
||||
"sup_proof_q2": "Finally a platform that understands the padel construction market. We know the budget, the timeline, and the venue type before we even make first contact.",
|
||||
"sup_proof_cite2": "— Padel court installation company, Scandinavia",
|
||||
"sup_faq_h2": "Supplier FAQ",
|
||||
"sup_faq_q1": "How do I claim my listing?",
|
||||
"sup_faq_q1": "How do I get listed?",
|
||||
"sup_faq_a1_pre": "Find your company in our",
|
||||
"sup_faq_a1_post": "and click “Is this your company?” We’ll verify your identity and give you access to choose a plan and upgrade your profile.",
|
||||
"sup_faq_dir_link": "directory",
|
||||
|
||||
@@ -632,6 +632,10 @@
|
||||
<section class="sup-section">
|
||||
<h2>{{ t.sup_faq_h2 }}</h2>
|
||||
<div class="sup-faq">
|
||||
<details>
|
||||
<summary>{{ t.sup_faq_q3 }}</summary>
|
||||
<p>{{ t.sup_faq_a3 }}</p>
|
||||
</details>
|
||||
<details>
|
||||
<summary>{{ t.sup_faq_q1 }}</summary>
|
||||
<p>{{ t.sup_faq_a1_pre }} <a href="{{ url_for('directory.index') }}">{{ t.sup_faq_dir_link }}</a> {{ t.sup_faq_a1_post }}</p>
|
||||
@@ -640,10 +644,6 @@
|
||||
<summary>{{ t.sup_faq_q2 }}</summary>
|
||||
<p>{{ t.sup_faq_a2 }}</p>
|
||||
</details>
|
||||
<details>
|
||||
<summary>{{ t.sup_faq_q3 }}</summary>
|
||||
<p>{{ t.sup_faq_a3 }}</p>
|
||||
</details>
|
||||
<details>
|
||||
<summary>{{ t.sup_faq_q4 }}</summary>
|
||||
<p>{{ t.sup_faq_a4 }}</p>
|
||||
@@ -670,7 +670,7 @@
|
||||
</details>
|
||||
<details>
|
||||
<summary>{{ t.sup_faq_q10 }}</summary>
|
||||
<p>{{ t.sup_faq_a10_pre }} {{ config.LEADS_EMAIL }} {{ t.sup_faq_a10_post }}</p>
|
||||
<p>{{ t.sup_faq_a10_pre }} {{ config.EMAIL_FROM }} {{ t.sup_faq_a10_post }}</p>
|
||||
</details>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -123,7 +123,7 @@ pricing, rent, financing terms, and see how the numbers change in real time.\
|
||||
_DE_BODY = """\
|
||||
{{ padel_context }}
|
||||
|
||||
Diese Analyse modelliert eine **{{ dblCourts }} Doppel- + {{ sglCourts }} Einzelcourt-Innenhalle** \
|
||||
Diese Analyse modelliert eine **{{ dblCourts }} Doppel- + {{ sglCourts }} Einzelcourt-Indoorhalle** \
|
||||
auf Basis lokaler Marktdaten für {{ city }}, {{ country_name }}.
|
||||
{% if currency_note %}
|
||||
> **Hinweis:** {{ currency_note }}
|
||||
@@ -200,7 +200,7 @@ TEMPLATES = [
|
||||
"meta_description_pattern": (
|
||||
"Was kostet es, eine Padelhalle in {{ city }} zu eröffnen? "
|
||||
"Vollständige Investitionsanalyse: CAPEX, Umsatzmodell und Rendite "
|
||||
"für eine {{ dblCourts }}+{{ sglCourts }} Court Innenhalle."
|
||||
"für eine {{ dblCourts }}+{{ sglCourts }} Court Indoorhalle."
|
||||
),
|
||||
"body_template": _DE_BODY,
|
||||
},
|
||||
@@ -588,7 +588,7 @@ CITIES = [
|
||||
"padel_context_de": (
|
||||
"Chicagos große hispanische Gemeinschaft und etablierte Schlägertsportkultur "
|
||||
"machen es zu einem natürlichen Padelmarkt. Die harten Winter treiben die "
|
||||
"Nachfrage nach Innenhallen und reduzieren den Outdoor-Wettbewerb, "
|
||||
"Nachfrage nach Indoorhallen und reduzieren den Outdoor-Wettbewerb, "
|
||||
"der wärmere Märkte beeinflusst."
|
||||
),
|
||||
"currency_note_en": _EUR_NOTE_EN,
|
||||
|
||||
Reference in New Issue
Block a user