Template
Add shop, POS sync, event ticketing, and shipping catalog apps.
Clients can run in-house retail without Shopify while keeping the same Docker/Django/Postgres stack and data-ownership promise. Closes #5.
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Tickets · {{ event.title }}{% endblock %}
|
||||
{% block content %}
|
||||
<section class="section section-lg">
|
||||
<div class="container">
|
||||
<h1>Tickets · {{ event.title }}</h1>
|
||||
<p>{{ event.price }} {{ event.currency|upper }} each{% if event.seats_remaining is not None %} · {{ event.seats_remaining }} left{% endif %}</p>
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<p><label>Email <input name="email" type="email" required></label></p>
|
||||
<p><label>Name <input name="customer_name"></label></p>
|
||||
<p><label>Quantity <input name="quantity" type="number" min="1" value="1"></label></p>
|
||||
<button class="button button-primary" type="submit">Pay with Stripe</button>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,8 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Checkout cancelled{% endblock %}
|
||||
{% block content %}
|
||||
<section class="section section-lg"><div class="container">
|
||||
<h1>Checkout cancelled</h1>
|
||||
<p>No charge for {{ order.event.title }}. <a href="{% url 'events:buy' order.event.slug %}">Try again</a>.</p>
|
||||
</div></section>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,18 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}{{ event.title }} · {{ SITE_NAME }}{% endblock %}
|
||||
{% block content %}
|
||||
<section class="section section-lg">
|
||||
<div class="container">
|
||||
<p><a href="{% url 'events:list' %}">← Events</a></p>
|
||||
<h1>{{ event.title }}</h1>
|
||||
<p class="muted">{{ event.starts_at|date:"F j, Y g:i A" }}{% if event.venue %} · {{ event.venue }}{% endif %}</p>
|
||||
<div>{{ event.description|linebreaks }}</div>
|
||||
<p>{{ event.price }} {{ event.currency|upper }}</p>
|
||||
{% if event.seats_remaining == 0 %}
|
||||
<p>Sold out.</p>
|
||||
{% else %}
|
||||
<p><a class="button button-primary" href="{% url 'events:buy' event.slug %}">Buy tickets</a></p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,18 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Events · {{ SITE_NAME }}{% endblock %}
|
||||
{% block content %}
|
||||
<section class="section section-lg">
|
||||
<div class="container">
|
||||
<h1 class="text-uppercase">Events</h1>
|
||||
{% for event in events %}
|
||||
<article style="margin:0 0 32px">
|
||||
<h2><a href="{{ event.get_absolute_url }}">{{ event.title }}</a></h2>
|
||||
<p class="muted">{{ event.starts_at|date:"F j, Y g:i A" }}{% if event.venue %} · {{ event.venue }}{% endif %}</p>
|
||||
<p>{{ event.price }} {{ event.currency|upper }}{% if event.seats_remaining is not None %} · {{ event.seats_remaining }} seats left{% endif %}</p>
|
||||
</article>
|
||||
{% empty %}
|
||||
<p>No upcoming events.</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,23 @@
|
||||
{% extends "portal_base.html" %}
|
||||
{% block title %}{{ event.title }} · Portal{% endblock %}
|
||||
{% block topbar_title %}{{ event.title }}{% endblock %}
|
||||
{% block portal_content %}
|
||||
<p><a class="btn btn-ghost" href="{% url 'events_portal:event_edit' event.pk %}">Edit</a></p>
|
||||
<p>{{ event.starts_at }} · {{ event.tickets_sold }} / {{ event.capacity|default:"∞" }} seats · {{ event.price }} {{ event.currency|upper }}</p>
|
||||
<table class="table">
|
||||
<thead><tr><th>Order</th><th>Email</th><th>Qty</th><th>Status</th><th>Codes</th></tr></thead>
|
||||
<tbody>
|
||||
{% for order in orders %}
|
||||
<tr>
|
||||
<td>{{ order.number }}</td>
|
||||
<td>{{ order.email }}</td>
|
||||
<td>{{ order.quantity }}</td>
|
||||
<td>{{ order.get_status_display }}</td>
|
||||
<td>{% for ticket in order.tickets.all %}{{ ticket.code }}{% if not forloop.last %}, {% endif %}{% endfor %}</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr><td colspan="5" class="empty-state">No ticket orders yet.</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,17 @@
|
||||
{% extends "portal_base.html" %}
|
||||
{% block title %}{% if event %}Edit{% else %}New{% endif %} event · Portal{% endblock %}
|
||||
{% block topbar_title %}{% if event %}Edit event{% else %}New event{% endif %}{% endblock %}
|
||||
{% block portal_content %}
|
||||
<form method="post" class="form-grid">
|
||||
{% csrf_token %}
|
||||
<div class="field"><label>Title</label><input name="title" required value="{{ event.title|default:'' }}"></div>
|
||||
<div class="field"><label>Slug</label><input name="slug" value="{{ event.slug|default:'' }}" placeholder="auto from title"></div>
|
||||
<div class="field"><label>Starts</label><input name="starts_at" type="datetime-local" required value="{% if event %}{{ event.starts_at|date:'Y-m-d\\TH:i' }}{% endif %}"></div>
|
||||
<div class="field"><label>Venue</label><input name="venue" value="{{ event.venue|default:'' }}"></div>
|
||||
<div class="field"><label>Capacity</label><input name="capacity" type="number" min="0" value="{{ event.capacity|default:0 }}"></div>
|
||||
<div class="field"><label>Price</label><input name="price" type="number" step="0.01" min="0" required value="{{ event.price|default:'0' }}"></div>
|
||||
<div class="field"><label>Description</label><textarea name="description" style="min-height:120px">{{ event.description|default:'' }}</textarea></div>
|
||||
<label><input type="checkbox" name="is_published" {% if event.is_published %}checked{% endif %}> Published</label>
|
||||
<button class="btn btn-primary" type="submit">Save</button>
|
||||
</form>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,21 @@
|
||||
{% extends "portal_base.html" %}
|
||||
{% block title %}Events · Portal{% endblock %}
|
||||
{% block topbar_title %}Events{% endblock %}
|
||||
{% block portal_content %}
|
||||
<p><a class="btn btn-primary" href="{% url 'events_portal:event_new' %}">New event</a></p>
|
||||
<table class="table">
|
||||
<thead><tr><th>Title</th><th>When</th><th>Capacity</th><th>Status</th></tr></thead>
|
||||
<tbody>
|
||||
{% for event in events %}
|
||||
<tr>
|
||||
<td><a href="{% url 'events_portal:event_detail' event.pk %}">{{ event.title }}</a></td>
|
||||
<td>{{ event.starts_at }}</td>
|
||||
<td>{{ event.tickets_sold }} / {{ event.capacity|default:"∞" }}</td>
|
||||
<td>{% if event.is_published %}Published{% else %}Draft{% endif %}</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr><td colspan="4" class="empty-state">No events yet.</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,9 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Tickets {{ order.number }}{% endblock %}
|
||||
{% block content %}
|
||||
<section class="section section-lg"><div class="container">
|
||||
<h1>You're in</h1>
|
||||
<p>Order {{ order.number }} for {{ order.event.title }} is {{ order.get_status_display|lower }}.</p>
|
||||
<p>Ticket codes will be emailed to {{ order.email }}.</p>
|
||||
</div></section>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user