refactor(platform): make base template fully CMS-driven and platform-aware
Some checks failed
Some checks failed
Remove all hardcoded OMS-specific content from platform base template: nav links, contact info, brand name, and footer columns. Everything is now dynamic via platform model and CMS page queries. Wire up legal_pages context (privacy/terms) from database instead of hardcoded fallback. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -45,6 +45,7 @@ def _get_platform_context(request: Any, db: Any, platform: Any) -> dict[str, Any
|
|||||||
|
|
||||||
header_pages = []
|
header_pages = []
|
||||||
footer_pages = []
|
footer_pages = []
|
||||||
|
legal_pages = []
|
||||||
|
|
||||||
try:
|
try:
|
||||||
header_pages = content_page_service.list_platform_pages(
|
header_pages = content_page_service.list_platform_pages(
|
||||||
@@ -53,8 +54,11 @@ def _get_platform_context(request: Any, db: Any, platform: Any) -> dict[str, Any
|
|||||||
footer_pages = content_page_service.list_platform_pages(
|
footer_pages = content_page_service.list_platform_pages(
|
||||||
db, platform_id=platform_id, footer_only=True, include_unpublished=False
|
db, platform_id=platform_id, footer_only=True, include_unpublished=False
|
||||||
)
|
)
|
||||||
|
legal_pages = content_page_service.list_platform_pages(
|
||||||
|
db, platform_id=platform_id, legal_only=True, include_unpublished=False
|
||||||
|
)
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"[CMS] Platform context: {len(header_pages)} header, {len(footer_pages)} footer pages"
|
f"[CMS] Platform context: {len(header_pages)} header, {len(footer_pages)} footer, {len(legal_pages)} legal pages"
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"[CMS] Failed to load platform navigation pages: {e}")
|
logger.warning(f"[CMS] Failed to load platform navigation pages: {e}")
|
||||||
@@ -62,7 +66,7 @@ def _get_platform_context(request: Any, db: Any, platform: Any) -> dict[str, Any
|
|||||||
return {
|
return {
|
||||||
"header_pages": header_pages,
|
"header_pages": header_pages,
|
||||||
"footer_pages": footer_pages,
|
"footer_pages": footer_pages,
|
||||||
"legal_pages": [], # TODO: Add legal pages support if needed
|
"legal_pages": legal_pages,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -282,6 +282,7 @@ class ContentPageService:
|
|||||||
include_unpublished: bool = False,
|
include_unpublished: bool = False,
|
||||||
footer_only: bool = False,
|
footer_only: bool = False,
|
||||||
header_only: bool = False,
|
header_only: bool = False,
|
||||||
|
legal_only: bool = False,
|
||||||
) -> list[ContentPage]:
|
) -> list[ContentPage]:
|
||||||
"""
|
"""
|
||||||
List platform marketing pages.
|
List platform marketing pages.
|
||||||
@@ -292,6 +293,7 @@ class ContentPageService:
|
|||||||
include_unpublished: Include draft pages
|
include_unpublished: Include draft pages
|
||||||
footer_only: Only pages marked for footer display
|
footer_only: Only pages marked for footer display
|
||||||
header_only: Only pages marked for header display
|
header_only: Only pages marked for header display
|
||||||
|
legal_only: Only legal pages (privacy, terms) — not in header or footer nav
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List of platform marketing ContentPage objects
|
List of platform marketing ContentPage objects
|
||||||
@@ -311,6 +313,9 @@ class ContentPageService:
|
|||||||
if header_only:
|
if header_only:
|
||||||
filters.append(ContentPage.show_in_header == True)
|
filters.append(ContentPage.show_in_header == True)
|
||||||
|
|
||||||
|
if legal_only:
|
||||||
|
filters.append(ContentPage.slug.in_(["privacy", "terms"]))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
db.query(ContentPage)
|
db.query(ContentPage)
|
||||||
.filter(and_(*filters))
|
.filter(and_(*filters))
|
||||||
|
|||||||
@@ -7,10 +7,10 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
{# Dynamic page title #}
|
{# Dynamic page title #}
|
||||||
<title>{% block title %}Orion - Order Management for Letzshop Sellers{% endblock %}</title>
|
<title>{% block title %}{{ platform.name if platform else 'Wizard' }}{% endblock %}</title>
|
||||||
|
|
||||||
{# SEO Meta Tags #}
|
{# SEO Meta Tags #}
|
||||||
<meta name="description" content="{% block meta_description %}Lightweight OMS for Letzshop stores in Luxembourg. Order management, inventory, and invoicing made simple.{% endblock %}">
|
<meta name="description" content="{% block meta_description %}{{ platform.description if platform else '' }}{% endblock %}">
|
||||||
<meta name="keywords" content="{% block meta_keywords %}letzshop, order management, oms, luxembourg, e-commerce, invoicing, inventory{% endblock %}">
|
<meta name="keywords" content="{% block meta_keywords %}letzshop, order management, oms, luxembourg, e-commerce, invoicing, inventory{% endblock %}">
|
||||||
|
|
||||||
{# Favicon #}
|
{# Favicon #}
|
||||||
@@ -61,28 +61,16 @@
|
|||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<a href="/" class="flex items-center space-x-3">
|
<a href="/" class="flex items-center space-x-3">
|
||||||
<div class="w-8 h-8 rounded-lg bg-gradient-to-r from-indigo-600 to-purple-600 flex items-center justify-center">
|
<div class="w-8 h-8 rounded-lg bg-gradient-to-r from-indigo-600 to-purple-600 flex items-center justify-center">
|
||||||
<span class="text-white font-bold text-xl">W</span>
|
<span class="text-white font-bold text-xl">{{ (platform.name or 'W')[0] }}</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="text-xl font-bold text-gray-900 dark:text-white">
|
<span class="text-xl font-bold text-gray-900 dark:text-white">
|
||||||
Orion
|
{{ platform.name if platform else 'Wizard' }}
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# Desktop Navigation #}
|
{# Desktop Navigation (CMS-driven) #}
|
||||||
<div class="hidden md:flex items-center space-x-8">
|
<div class="hidden md:flex items-center space-x-8">
|
||||||
{# Main Navigation #}
|
|
||||||
<a href="/pricing" class="text-gray-700 dark:text-gray-300 hover:text-indigo-600 dark:hover:text-indigo-400 font-medium transition-colors">
|
|
||||||
{{ _("cms.platform.nav.pricing") }}
|
|
||||||
</a>
|
|
||||||
<a href="/find-shop" class="text-gray-700 dark:text-gray-300 hover:text-indigo-600 dark:hover:text-indigo-400 font-medium transition-colors">
|
|
||||||
{{ _("cms.platform.nav.find_shop") }}
|
|
||||||
</a>
|
|
||||||
<a href="/signup" class="px-4 py-2 bg-indigo-600 hover:bg-indigo-700 text-white font-medium rounded-lg transition-colors">
|
|
||||||
{{ _("cms.platform.nav.start_trial") }}
|
|
||||||
</a>
|
|
||||||
|
|
||||||
{# Dynamic header navigation from CMS #}
|
|
||||||
{% if header_pages %}
|
{% if header_pages %}
|
||||||
{% for page in header_pages %}
|
{% for page in header_pages %}
|
||||||
<a href="/{{ page.slug }}"
|
<a href="/{{ page.slug }}"
|
||||||
@@ -184,71 +172,43 @@
|
|||||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-8">
|
<div class="grid grid-cols-1 md:grid-cols-4 gap-8">
|
||||||
|
|
||||||
{# Brand Column #}
|
{# Brand Column #}
|
||||||
<div class="col-span-1">
|
<div class="col-span-1 md:col-span-2">
|
||||||
<div class="flex items-center space-x-3 mb-4">
|
<div class="flex items-center space-x-3 mb-4">
|
||||||
<div class="w-8 h-8 rounded-lg bg-gradient-to-r from-indigo-600 to-purple-600 flex items-center justify-center">
|
<div class="w-8 h-8 rounded-lg bg-gradient-to-r from-indigo-600 to-purple-600 flex items-center justify-center">
|
||||||
<span class="text-white font-bold text-xl">W</span>
|
<span class="text-white font-bold text-xl">{{ (platform.name or 'W')[0] }}</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="text-xl font-bold text-gray-900 dark:text-white">
|
<span class="text-xl font-bold text-gray-900 dark:text-white">
|
||||||
Orion
|
{{ platform.name if platform else 'Wizard' }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-gray-600 dark:text-gray-400 text-sm">
|
<p class="text-gray-600 dark:text-gray-400 text-sm max-w-md">
|
||||||
{{ _("cms.platform.footer.tagline") }}
|
{{ platform.description if platform else '' }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# Quick Links #}
|
{# Quick Links (from CMS footer pages) #}
|
||||||
|
{% if footer_pages %}
|
||||||
<div>
|
<div>
|
||||||
<h4 class="font-semibold text-gray-900 dark:text-white mb-4">{{ _("cms.platform.footer.quick_links") }}</h4>
|
<h4 class="font-semibold text-gray-900 dark:text-white mb-4">{{ _("cms.platform.footer.quick_links") }}</h4>
|
||||||
<ul class="space-y-2">
|
<ul class="space-y-2">
|
||||||
{% if footer_pages %}
|
{% for page in footer_pages %}
|
||||||
{% for page in footer_pages %}
|
|
||||||
<li>
|
|
||||||
<a href="/{{ page.slug }}"
|
|
||||||
class="text-gray-600 dark:text-gray-400 hover:text-primary dark:hover:text-primary transition-colors">
|
|
||||||
{{ page.title }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{# Platform Links #}
|
|
||||||
<div>
|
|
||||||
<h4 class="font-semibold text-gray-900 dark:text-white mb-4">{{ _("cms.platform.footer.platform") }}</h4>
|
|
||||||
<ul class="space-y-2">
|
|
||||||
<li>
|
<li>
|
||||||
<a href="/admin/login" class="text-gray-600 dark:text-gray-400 hover:text-primary transition-colors">
|
<a href="/{{ page.slug }}"
|
||||||
{{ _("cms.platform.nav.admin_login") }}
|
class="text-gray-600 dark:text-gray-400 hover:text-primary dark:hover:text-primary transition-colors">
|
||||||
</a>
|
{{ page.title }}
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="/store/orion/login" class="text-gray-600 dark:text-gray-400 hover:text-primary transition-colors">
|
|
||||||
{{ _("cms.platform.nav.store_login") }}
|
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
{# Contact Info #}
|
|
||||||
<div>
|
|
||||||
<h4 class="font-semibold text-gray-900 dark:text-white mb-4">{{ _("cms.platform.footer.contact") }}</h4>
|
|
||||||
<ul class="space-y-2 text-gray-600 dark:text-gray-400 text-sm">
|
|
||||||
<li>support@marketplace.com</li>
|
|
||||||
<li>+1 (555) 123-4567</li>
|
|
||||||
<li>123 Business St, Suite 100</li>
|
|
||||||
<li>San Francisco, CA 94102</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# Bottom Bar #}
|
{# Bottom Bar #}
|
||||||
<div class="mt-12 pt-8 border-t border-gray-200 dark:border-gray-700">
|
<div class="mt-12 pt-8 border-t border-gray-200 dark:border-gray-700">
|
||||||
<div class="flex flex-col md:flex-row justify-between items-center">
|
<div class="flex flex-col md:flex-row justify-between items-center">
|
||||||
<p class="text-gray-600 dark:text-gray-400 text-sm">
|
<p class="text-gray-600 dark:text-gray-400 text-sm">
|
||||||
{{ _("cms.platform.footer.copyright", year=2025) }}
|
© {{ current_year }} {{ platform.name if platform else 'Wizard' }}. All rights reserved.
|
||||||
</p>
|
</p>
|
||||||
<div class="flex space-x-6 mt-4 md:mt-0">
|
<div class="flex space-x-6 mt-4 md:mt-0">
|
||||||
{% if legal_pages %}
|
{% if legal_pages %}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ Module templates should use namespace prefix to avoid collisions:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from fastapi.templating import Jinja2Templates
|
from fastapi.templating import Jinja2Templates
|
||||||
@@ -92,3 +93,4 @@ templates.env.globals["SUPPORTED_LANGUAGES"] = SUPPORTED_LANGUAGES
|
|||||||
templates.env.globals["DEFAULT_LANGUAGE"] = DEFAULT_LANGUAGE
|
templates.env.globals["DEFAULT_LANGUAGE"] = DEFAULT_LANGUAGE
|
||||||
templates.env.globals["LANGUAGE_NAMES"] = LANGUAGE_NAMES
|
templates.env.globals["LANGUAGE_NAMES"] = LANGUAGE_NAMES
|
||||||
templates.env.globals["LANGUAGE_FLAGS"] = LANGUAGE_FLAGS
|
templates.env.globals["LANGUAGE_FLAGS"] = LANGUAGE_FLAGS
|
||||||
|
templates.env.globals["current_year"] = datetime.now().year
|
||||||
|
|||||||
Reference in New Issue
Block a user