live seat availability: fetch from server webhook, orange/red styling when <10/0 seats, disable sold-out locations

This commit is contained in:
Oliver
2026-06-14 16:54:13 -03:00
parent ea58be1d97
commit 19183b42a8
5 changed files with 136 additions and 18 deletions
+49 -1
View File
@@ -299,6 +299,8 @@
}
.pricing-config-select:hover { border-color: var(--accent); }
.pricing-config-select:focus { border-color: var(--accent); }
.pricing-config-select.low-seats { border-color: var(--warning); box-shadow: 0 0 0 2px rgba(255, 170, 0, 0.2); }
.pricing-config-select.no-seats { border-color: var(--danger); box-shadow: 0 0 0 2px rgba(255, 59, 59, 0.2); }
.pricing-config-input {
background: var(--bg);
border: 1px solid var(--border);
@@ -363,7 +365,7 @@
<option value="yearly">Yearly</option>
</select>
<select class="pricing-config-select" id="pricing-location">
<option value="france">France</option>
<option value="">Loading locations...</option>
</select>
<input type="email" class="pricing-config-input" id="pricing-email" placeholder="Email" autocomplete="email" />
<input type="text" class="pricing-config-input" id="pricing-coupon" placeholder="Coupon code" />
@@ -539,6 +541,51 @@
<script>
// ── Signup Webhook URLs (matching app.derez.ai) ──────────
const ORDER_WEBHOOK = "https://n8n.derez.ai/webhook/payment";
const SERVER_WEBHOOK = "https://n8n.derez.ai/webhook/server";
async function initServerLocations() {
const sel = document.getElementById('pricing-location');
if (!sel) return;
try {
const res = await fetch(SERVER_WEBHOOK);
const data = await res.json();
const servers = Array.isArray(data) ? data : [data];
sel.innerHTML = '';
servers.forEach(function(s) {
const server = s.server || '';
const available = parseInt(s['Seats Available'], 10) || 0;
const label = server.charAt(0).toUpperCase() + server.slice(1);
const opt = document.createElement('option');
opt.value = server.toLowerCase().replace(/\s+/g, '-');
if (available <= 0) {
opt.textContent = label + ' (sold out)';
opt.disabled = true;
opt.style.color = '#ff4444';
opt.style.fontWeight = '600';
sel.classList.remove('low-seats');
sel.classList.add('no-seats');
} else if (available < 10) {
opt.textContent = label + ' (available ' + available + ')';
opt.style.color = '#ff9900';
opt.style.fontWeight = '600';
sel.classList.add('low-seats');
sel.classList.remove('no-seats');
} else {
opt.textContent = label + ' (available ' + available + ')';
opt.style.color = '';
opt.style.fontWeight = '';
sel.classList.remove('low-seats', 'no-seats');
}
sel.appendChild(opt);
});
for (var i = 0; i < sel.options.length; i++) {
if (!sel.options[i].disabled) { sel.selectedIndex = i; break; }
}
} catch (err) {
console.error('Failed to load server locations:', err);
sel.innerHTML = '<option value="france" style="color:#ff9900;font-weight:600">France (available ?)</option>';
}
}
/* ── Period / billing update ──────────────────────────── */
function updatePeriodDisplay() {
@@ -553,6 +600,7 @@
}
document.getElementById('pricing-period').addEventListener('change', updatePeriodDisplay);
updatePeriodDisplay();
initServerLocations();
/* ── Capture UTM params from URL ──────────────────────── */
(function () {