merge: affiliate live preview fix
This commit is contained in:
@@ -3373,6 +3373,31 @@ async def affiliate_results():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/affiliate/preview", methods=["POST"])
|
||||||
|
@role_required("admin")
|
||||||
|
@csrf_protect
|
||||||
|
async def affiliate_preview():
|
||||||
|
"""Render a product card fragment from form data — used by live preview HTMX."""
|
||||||
|
from ..content.routes import _bake_env
|
||||||
|
from ..i18n import get_translations
|
||||||
|
|
||||||
|
form = await request.form
|
||||||
|
data = _form_to_product(form)
|
||||||
|
lang = data["language"] or "de"
|
||||||
|
|
||||||
|
# Convert JSON-string pros/cons to lists for the template
|
||||||
|
product = dict(data)
|
||||||
|
product["pros"] = json.loads(product["pros"]) if product["pros"] else []
|
||||||
|
product["cons"] = json.loads(product["cons"]) if product["cons"] else []
|
||||||
|
|
||||||
|
if not product["name"]:
|
||||||
|
return "<p style='color:#94A3B8;font-size:.875rem;padding:.5rem 0'>Fill in the form to see a preview.</p>"
|
||||||
|
|
||||||
|
tmpl = _bake_env.get_template("partials/product_card.html")
|
||||||
|
html = tmpl.render(product=product, t=get_translations(lang), lang=lang)
|
||||||
|
return html
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/affiliate/new", methods=["GET", "POST"])
|
@bp.route("/affiliate/new", methods=["GET", "POST"])
|
||||||
@role_required("admin")
|
@role_required("admin")
|
||||||
@csrf_protect
|
@csrf_protect
|
||||||
|
|||||||
@@ -39,11 +39,15 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
<div style="display:grid;grid-template-columns:1fr 380px;gap:2rem;align-items:start" class="affiliate-form-grid">
|
<div style="display:grid;grid-template-columns:1fr 380px;gap:2rem;align-items:start" class="affiliate-form-grid">
|
||||||
|
|
||||||
{# ── Left: form ── #}
|
{# ── Left: form ── #}
|
||||||
|
{# Invisible trigger: fires preview on any input change, includes the whole form #}
|
||||||
|
<div hx-post="{{ url_for('admin.affiliate_preview') }}"
|
||||||
|
hx-target="#product-preview"
|
||||||
|
hx-trigger="input from:#affiliate-form delay:600ms"
|
||||||
|
hx-include="#affiliate-form"
|
||||||
|
hx-push-url="false">
|
||||||
|
</div>
|
||||||
<form method="post" id="affiliate-form"
|
<form method="post" id="affiliate-form"
|
||||||
hx-post="{% if editing %}{{ url_for('admin.affiliate_edit', product_id=product_id) }}{% else %}{{ url_for('admin.affiliate_new') }}{% endif %}"
|
action="{% if editing %}{{ url_for('admin.affiliate_edit', product_id=product_id) }}{% else %}{{ url_for('admin.affiliate_new') }}{% endif %}">
|
||||||
hx-target="#product-preview"
|
|
||||||
hx-trigger="input delay:600ms"
|
|
||||||
hx-push-url="false">
|
|
||||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||||
|
|
||||||
<div class="card" style="padding:1.5rem;display:flex;flex-direction:column;gap:1.25rem;">
|
<div class="card" style="padding:1.5rem;display:flex;flex-direction:column;gap:1.25rem;">
|
||||||
|
|||||||
Reference in New Issue
Block a user