Skip to main content

max / makenotwork

5.1 KB · 108 lines History Blame Raw
1 <div class="tab-docs"><a href="/docs/pricing">Docs: Pricing &rarr;</a></div>
2
3 <div class="data-section">
4 <h2 class="subsection-title">Membership Tiers</h2>
5 <p class="section-lead mb-5">
6 Create recurring membership tiers for your project. Members get access to all paid content.
7 </p>
8
9 {% if !stripe_connected %}
10 <div class="info-box subs-connect-info">
11 <h3 class="mb-2">Connect Stripe First</h3>
12 <p class="text-sm">You need to connect your Stripe account before creating subscription tiers. Go to <strong>Account Details</strong> in your dashboard to connect.</p>
13 </div>
14 {% else %}
15
16 <details class="form-section subs-new-tier">
17 <summary><h2 class="subsection-title">New Tier</h2></summary>
18 <form id="new-tier-form"
19 hx-post="/api/projects/{{ project_id }}/tiers"
20 hx-swap="none"
21 hx-on::after-request="if(event.detail.successful) { this.reset(); htmx.ajax('GET', '/dashboard/project/{{ project_slug }}/tabs/subscriptions', '#tab-content'); }">
22 <div class="form-group">
23 <label for="tier-name">Name</label>
24 <input type="text" id="tier-name" name="name" placeholder="e.g. Supporter, Premium" required maxlength="100">
25 </div>
26 <div class="form-group">
27 <label for="tier-description">Description</label>
28 <textarea id="tier-description" name="description" placeholder="What members get..." maxlength="2000"></textarea>
29 </div>
30 <div class="form-group">
31 <label for="tier-price-dollars">Monthly Price ($)</label>
32 <input type="number" id="tier-price-dollars" step="0.01" min="1.00" placeholder="5.00" required>
33 <input type="hidden" id="tier-price-cents" name="price_cents">
34 <span class="text-sm dimmed">Minimum $1.00.</span>
35 </div>
36 <script>
37 (function() {
38 var dollars = document.getElementById('tier-price-dollars');
39 var cents = document.getElementById('tier-price-cents');
40 dollars.addEventListener('input', function() {
41 cents.value = Math.round(parseFloat(this.value || 0) * 100);
42 });
43 })();
44 </script>
45 <button class="btn-primary" type="submit">Create Tier</button>
46 </form>
47 </details>
48
49 <div id="tiers-list">
50 {% if tiers.is_empty() %}
51 <p class="dimmed">No membership tiers yet. Create one above.</p>
52 {% else %}
53 <table class="data-table">
54 <thead>
55 <tr>
56 <th>Name</th>
57 <th>Price</th>
58 <th>Status</th>
59 <th>Actions</th>
60 </tr>
61 </thead>
62 <tbody>
63 {% for tier in tiers %}
64 <tr id="tier-row-{{ tier.id }}">
65 <td>
66 <strong>{{ tier.name }}</strong>
67 {% if !tier.description.is_empty() %}
68 <div class="tier-row-desc">{{ tier.description }}</div>
69 {% endif %}
70 </td>
71 <td>{{ tier.price }}</td>
72 <td>
73 {% if tier.is_active %}
74 <span class="badge active">Active</span>
75 {% else %}
76 <span class="badge inactive">Inactive</span>
77 {% endif %}
78 </td>
79 <td>
80 {% if tier.is_active %}
81 <button class="btn-secondary tier-action-btn"
82 hx-delete="/api/tiers/{{ tier.id }}"
83 hx-swap="none"
84 hx-on::after-request="if(event.detail.successful) htmx.ajax('GET', '/dashboard/project/{{ project_slug }}/tabs/subscriptions', '#tab-content');"
85 hx-confirm="Deactivate this tier? Existing subscribers will not be affected.">Deactivate</button>
86 {% endif %}
87 </td>
88 </tr>
89 {% endfor %}
90 </tbody>
91 </table>
92 {% endif %}
93 </div>
94
95 <div class="subs-members-bar">
96 <div>
97 <h3>Members</h3>
98 <p class="muted m-0">{{ subscriber_count }} active member{% if subscriber_count != 1 %}s{% endif %}</p>
99 </div>
100 {% if subscriber_count > 0 %}
101 <button class="btn-secondary text-sm"
102 onclick="this.textContent='Exporting...'; this.disabled=true; var btn=this; fetch('/api/export/subscriptions', {method:'POST', headers: csrfHeaders()}).then(function(r){return r.blob()}).then(function(b){var a=document.createElement('a'); a.href=URL.createObjectURL(b); a.download='members.csv'; a.click(); btn.textContent='Export CSV'; btn.disabled=false;}).catch(function(){btn.textContent='Export CSV'; btn.disabled=false; showToast('Export failed')});">Export CSV</button>
103 {% endif %}
104 </div>
105
106 {% endif %}
107 </div>
108