Files
classifieds/app/templates/listings/detail.html
T
2026-06-18 09:29:33 -04:00

141 lines
6.5 KiB
HTML

{% extends "base.html" %}
{% block title %}{{ listing.title }} — Classifieds{% endblock %}
{% block meta_description %}<meta name="description" content="{{ (listing.body[:155] | replace('"', '&quot;') | replace('\n', ' ')) }}...">{% endblock %}
{% block og_title %}{{ listing.title }}{% endblock %}
{% block og_description %}{{ listing.body[:200] | replace('\n', ' ') }}{% endblock %}
{% block og_type %}product{% endblock %}
{% block og_image %}
{% if listing.images %}
<meta property="og:image" content="{{ request.host_url }}{{ url_for('listings.media', rel=listing.images[0].path)[1:] }}">
{% endif %}
{% endblock %}
{% block head %}
<script type="application/ld+json">
{
"@context": "https://schema.org/",
"@type": "Product",
"name": {{ listing.title | tojson }},
"description": {{ (listing.body[:500] | replace('\n', ' ')) | tojson }},
{% if listing.images %}"image": "{{ request.host_url }}{{ url_for('listings.media', rel=listing.images[0].path)[1:] }}",{% endif %}
{% if listing.price_cents %}"offers": {"@type": "Offer", "price": "{{ '%.2f'|format(listing.price_cents/100) }}", "priceCurrency": "USD"},{% endif %}
"seller": {"@type": "Person", "name": {{ listing.user.display_name | tojson }}}
}
</script>
{% endblock %}
{% block content %}
<article class="detail">
<div class="detail-main card">
<h1>{{ listing.title }}</h1>
<div class="detail-meta">
{% if listing.price_display %}<span class="price big">{{ listing.price_display }}</span>{% endif %}
<span class="badge cat">{{ listing.category.name }}</span>
{% if not listing.is_live %}<span class="badge warn">{{ listing.status.value }}</span>{% endif %}
</div>
<p class="muted small">
{% if listing.city %}{{ listing.city }}, {{ listing.state }} {{ listing.zip }}{% endif %}
· {{ _('%(n)s views', n=listing.view_count) }}
</p>
{% if listing.images %}
<div class="gallery">
{% for img in listing.images %}
<img src="{{ url_for('listings.media', rel=img.path) }}" alt="{{ listing.title }}" loading="{{ 'eager' if loop.first else 'lazy' }}">
{% endfor %}
</div>
{% endif %}
<div class="body">{{ listing.body | replace('\n','<br>') | safe }}</div>
{% if listing.attributes %}
<table class="attrs">
{% for f in listing.category.fields() %}
{% if listing.attributes.get(f.name) is not none %}
<tr><th>{{ f.label }}</th><td>{{ listing.attributes.get(f.name) }}</td></tr>
{% endif %}
{% endfor %}
</table>
{% endif %}
</div>
<aside class="detail-side card">
<div class="seller">
<strong>{{ listing.user.display_name }}</strong>
{% if listing.user.verified %}<span class="badge ok">{{ _('Verified') }}</span>{% endif %}
{% if listing_rating and listing_rating.avg %}
<div class="review-stars" style="font-size:14px">
{{ '★' * (listing_rating.avg | round | int) }}{{ '☆' * (5 - (listing_rating.avg | round | int)) }}
<span class="muted" style="font-size:12px">({{ listing_rating.count }})</span>
</div>
{% endif %}
</div>
{% if is_owner %}
<a class="btn" href="{{ url_for('listings.edit', listing_id=listing.id) }}">{{ _('Edit') }}</a>
<a class="btn ghost" href="{{ url_for('payments.boost_listing', listing_id=listing.id) }}">{{ _('⚡ Boost') }}</a>
{% if listing.status.value == 'active' %}
<form method="post" action="{{ url_for('listings.mark_sold', listing_id=listing.id) }}">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"><button class="btn ghost" type="submit">{{ _('Mark sold') }}</button>
</form>
{% endif %}
<form method="post" action="{{ url_for('listings.delete', listing_id=listing.id) }}"
onsubmit="return confirm('{{ _('Delete this listing?') }}')">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"><button class="btn danger" type="submit">{{ _('Delete') }}</button>
</form>
{% else %}
{% if current_user.is_authenticated %}
<a class="btn" href="{{ url_for('messaging.start_conversation', listing_id=listing.id) }}">
{{ _('Contact seller') }}
</a>
<form method="post"
action="{{ url_for('messaging.toggle_favorite', listing_id=listing.id) }}">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<button class="btn ghost" type="submit">{{ _('♥ Save listing') }}</button>
</form>
<form method="post" class="report-form"
action="{{ url_for('listings.report', listing_id=listing.id) }}">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<select class="input" name="reason">
{% for r in ['spam', 'scam', 'offensive', 'duplicate', 'miscategorized', 'other'] %}
<option value="{{ r }}">{{ r }}</option>
{% endfor %}
</select>
<input class="input" name="note" placeholder="{{ _('Optional note') }}">
<button class="btn ghost tiny" type="submit">{{ _('Report listing') }}</button>
</form>
{% else %}
<a class="btn" href="{{ url_for('auth.login') }}?next={{ request.path }}">
{{ _('Sign in to contact') }}
</a>
{% endif %}
{# Leave-review button for sold listings when viewer had a conversation #}
{% if current_user.is_authenticated and listing.status.value == 'sold'
and not is_owner and can_review %}
<a class="btn ghost" href="{{ url_for('listings.leave_review', listing_id=listing.id) }}">
{{ _('Leave a review') }}
</a>
{% endif %}
{% endif %}
</aside>
</article>
{# Reviews section #}
{% if listing.reviews.count() %}
<section class="card" style="margin-top:16px">
<h3>{{ _('Reviews') }} ({{ listing.reviews.count() }})</h3>
{% set rating_info = listing_rating %}
{% if rating_info and rating_info.avg %}
<div class="rating-summary">
<span class="review-stars">{{ '★' * (rating_info.avg | round | int) }}{{ '☆' * (5 - (rating_info.avg | round | int)) }}</span>
{{ '%.1f'|format(rating_info.avg) }} / 5 &nbsp;<span class="muted small">({{ rating_info.count }})</span>
</div>
{% endif %}
{% for review in listing.reviews.order_by(none).all() %}
<div class="review-block">
<div class="review-stars">{{ '★' * review.rating }}{{ '☆' * (5 - review.rating) }}</div>
<div class="muted small">{{ review.author.display_name }} · {{ review.created_at.strftime('%Y-%m-%d') }}</div>
{% if review.body %}<p>{{ review.body }}</p>{% endif %}
</div>
{% endfor %}
</section>
{% endif %}
{% endblock %}