← back to Ventura Claw Leads
views/admin/billing.ejs
117 lines
<%- include('../partials/head', { title }) %>
<%- include('../partials/header') %>
<section class="long-form" style="max-width:1000px">
<p class="kicker">Billing</p>
<h1 class="display-sm">Pick a tier.</h1>
<p class="lede">Current tier: <strong><%= currentBusiness.tier === 'free' ? 'Free' : currentBusiness.tier.charAt(0).toUpperCase() + currentBusiness.tier.slice(1) %></strong> · status: <%= currentBusiness.subscription_status || 'inactive' %></p>
<% if (flash.upgraded) { %><p class="callout" style="background:#dcfce7;border-left:3px solid #16a34a;color:#166534;padding:12px 16px;margin:16px 0;border-radius:4px">Subscription updated to <strong><%= flash.upgraded %></strong>. The new tier may take ~30 seconds to reflect on your dashboard once Stripe confirms.</p><% } %>
<% if (flash.canceled) { %><p class="callout" style="background:var(--bg-alt);border-left:3px solid var(--brass);padding:12px 16px;margin:16px 0;border-radius:4px">Checkout canceled — no changes made.</p><% } %>
<% if (flash.error) { %><p class="callout" style="background:#fee2e2;border-left:3px solid #dc2626;padding:12px 16px;margin:16px 0;border-radius:4px">Error: <%= flash.error %></p><% } %>
<% if (flash.mock || flash['mock=portal']) { %><p class="callout" style="background:var(--bg-alt);border-left:3px solid var(--brass);padding:12px 16px;margin:16px 0;border-radius:4px">Stripe is in mock mode (no live keys). Real checkout requires a configured Stripe account.</p><% } %>
<% if (!stripeLive) { %>
<p class="muted" style="margin-top:24px">Billing is in mock mode in this environment — buttons below are clickable but won't actually charge.</p>
<% } %>
<div class="tiers" style="margin-top:32px">
<div class="tier-card">
<h3>Free</h3>
<p class="tier-price">$0<small> / forever</small></p>
<ul>
<li>Public directory profile</li>
<li>Customer messages forwarded</li>
<li>Standard search placement</li>
</ul>
<% if (currentBusiness.tier === 'free') { %>
<p class="muted" style="font-size:12px;margin-top:14px">Your current tier.</p>
<% } %>
</div>
<% Object.entries(tiers).forEach(function(entry){
var tierKey = entry[0]; var tierMeta = entry[1];
var isCurrent = currentBusiness.tier === tierKey;
var isFeatured = tierKey === 'standard';
%>
<div class="tier-card<%= isFeatured ? ' is-featured' : '' %>">
<h3><%= tierMeta.name %></h3>
<p class="tier-price"><%= tierMeta.label.split(' /')[0] %><small> / month</small></p>
<ul>
<% if (tierKey === 'starter') { %>
<li>Custom description & photos</li>
<li>"Claimed" badge in search</li>
<li>Priority over free listings</li>
<li>Monthly traffic report</li>
<% } else if (tierKey === 'standard') { %>
<li>Everything in Starter</li>
<li>"Standard" badge — above free listings</li>
<li>Featured in category sidebar</li>
<li>Sub-60s lead delivery</li>
<% } else { %>
<li>Everything in Standard</li>
<li>Home-page weekly rotation</li>
<li>Top placement in category</li>
<li>Quarterly co-marketing</li>
<% } %>
</ul>
<% if (isCurrent) { %>
<p class="muted" style="font-size:12px;margin-top:14px;color:#16a34a">Your current tier.</p>
<% } else { %>
<form method="post" action="/admin/billing/checkout" style="margin-top:14px">
<input type="hidden" name="_csrf" value="<%= csrfToken %>">
<input type="hidden" name="tier" value="<%= tierKey %>">
<button type="submit" class="btn btn-primary" style="width:100%">Upgrade to <%= tierMeta.name %></button>
</form>
<% } %>
</div>
<% }); %>
</div>
<% if (typeof events !== 'undefined' && events && events.length > 0) { %>
<h2 style="margin-top:48px">Recent activity</h2>
<p class="muted" style="margin:0 0 16px;font-size:13px">Stripe events for your subscription, newest first.</p>
<table style="width:100%;border-collapse:collapse;font-size:13px">
<thead>
<tr style="border-bottom:1px solid var(--border);text-align:left">
<th style="padding:8px;font-size:11px;letter-spacing:0.06em;text-transform:uppercase;color:var(--fg-muted);font-weight:500">When</th>
<th style="padding:8px;font-size:11px;letter-spacing:0.06em;text-transform:uppercase;color:var(--fg-muted);font-weight:500">Event</th>
<th style="padding:8px;font-size:11px;letter-spacing:0.06em;text-transform:uppercase;color:var(--fg-muted);font-weight:500">Detail</th>
</tr>
</thead>
<tbody>
<% events.forEach(function(ev){
var obj = (ev.payload && ev.payload.data && ev.payload.data.object) || {};
var detail = '';
if (obj.amount_paid != null) detail = '$' + (obj.amount_paid / 100).toFixed(2);
else if (obj.amount_due != null) detail = '$' + (obj.amount_due / 100).toFixed(2);
else if (obj.status) detail = obj.status;
%>
<tr style="border-bottom:1px solid var(--border)">
<td style="padding:10px 8px;color:var(--fg-muted);white-space:nowrap"><%= new Date(ev.created_at).toLocaleString('en-US',{ month:'short', day:'numeric', hour:'numeric', minute:'2-digit' }) %></td>
<td style="padding:10px 8px;font-family:var(--mono,monospace);font-size:12px"><%= ev.event_type %></td>
<td style="padding:10px 8px;color:<%= obj.status === 'active' ? '#16a34a' : 'var(--fg-muted)' %>"><%= detail || '—' %></td>
</tr>
<% }); %>
</tbody>
</table>
<% } %>
<% if (currentBusiness.stripe_customer_id) { %>
<h2 style="margin-top:48px">Manage subscription</h2>
<p>Update your payment method, see invoices, or cancel from the secure Stripe portal.</p>
<form method="post" action="/admin/billing/portal" style="margin-top:12px">
<input type="hidden" name="_csrf" value="<%= csrfToken %>">
<button type="submit" class="btn btn-ghost">Open billing portal →</button>
</form>
<% } %>
<h2 style="margin-top:48px">Sign out</h2>
<form method="post" action="/admin/logout" style="margin-top:8px">
<input type="hidden" name="_csrf" value="<%= csrfToken %>">
<button type="submit" class="btn btn-ghost btn-sm">Sign out</button>
</form>
</section>
<%- include('../partials/footer') %>