Add shopper accounts, reviews, tracking, and seed_demo (#9)

Closes #9. Shop-gated buyer accounts, purchase reviews, Stripe customer ids, shipment tracking, slim public contact form, and a template-neutral seed_demo command.
This commit is contained in:
2026-09-07 08:35:55 -05:00
parent 9cdce7a897
commit 5b11cc18c7
66 changed files with 3051 additions and 285 deletions
+41
View File
@@ -15,6 +15,47 @@
<label>Qty <input name="quantity" type="number" min="1" value="1"></label>
<button class="button button-primary" type="submit">Add to cart</button>
</form>
<h2>Reviews</h2>
{% if review_count %}
<p>{{ review_avg|floatformat:1 }} / 5 · {{ review_count }} review{{ review_count|pluralize }}</p>
{% else %}
<p>No reviews yet.</p>
{% endif %}
{% if can_review %}
<form method="post" action="{% url 'shop:review' product.slug %}">
{% csrf_token %}
<p>
<label for="review-rating">Rating</label>
<select id="review-rating" name="rating" required>
<option value="">Choose 15</option>
<option value="5">5 — Excellent</option>
<option value="4">4 — Good</option>
<option value="3">3 — Okay</option>
<option value="2">2 — Fair</option>
<option value="1">1 — Poor</option>
</select>
</p>
<p><label>Title (optional) <input name="title" maxlength="120"></label></p>
<p><label>Review (optional) <textarea name="body" rows="4"></textarea></label></p>
<button class="button button-primary" type="submit">Submit review</button>
</form>
{% elif already_reviewed %}
<p>You already reviewed this product.</p>
{% elif user.is_authenticated %}
<p>Buy this product to leave a review.</p>
{% else %}
<p><a href="{% url 'account:login' %}?next={{ request.path }}">Sign in</a> after a purchase to leave a review.</p>
{% endif %}
<ul>
{% for review in reviews %}
<li>
<strong>{{ review.rating }}/5</strong>
{% if review.title %} · {{ review.title }}{% endif %}
<span> — {{ review.user.first_name|default:review.user.email }}</span>
{% if review.body %}<p>{{ review.body|linebreaks }}</p>{% endif %}
</li>
{% endfor %}
</ul>
</div>
</section>
{% endblock %}