Add dedicated-IP tier: IPRoyal DC/ISP reseller API, location picker, auto-provisioning
This commit is contained in:
@@ -17,7 +17,8 @@
|
||||
<a class="logo" href="/">CLEAN<span class="dot">.</span>PROXYS</a>
|
||||
<div class="nav-links">
|
||||
<a href="/">Home</a>
|
||||
<a href="/plans">Plans</a>
|
||||
<a href="/plans">Residential</a>
|
||||
<a href="/dedicated">Dedicated IPs</a>
|
||||
{% if user %}<a href="/dashboard">Dashboard</a><a href="/logout">Logout</a>
|
||||
{% else %}<a href="/login">Login</a><a class="cta" href="/signup">Sign up</a>{% endif %}
|
||||
</div>
|
||||
|
||||
@@ -52,6 +52,35 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if dedicated %}
|
||||
<div class="card" style="margin-top:18px">
|
||||
<h3>Dedicated IPs</h3>
|
||||
{% for d in dedicated %}
|
||||
<div style="border:1px solid var(--border);border-radius:8px;padding:12px;margin:10px 0">
|
||||
<div style="display:flex;justify-content:space-between">
|
||||
<strong style="color:var(--text)">{{ d.product_name }} · {{ d.location_name }}</strong>
|
||||
<span style="color:{{ {'active':'var(--ok)','provisioning':'var(--warn)','pending_payment':'var(--warn)','failed':'var(--danger)','expired':'var(--muted)'}.get(d.status,'var(--muted)') }}">{{ d.status }}</span>
|
||||
</div>
|
||||
{% if d.status == 'active' %}
|
||||
<div class="copy" style="margin-top:8px">
|
||||
<input type="text" readonly value="{{ d.proxy_host }}:{{ d.proxy_port }}" onclick="this.select()">
|
||||
<button onclick="copy(this.previousElementSibling)">Copy</button>
|
||||
</div>
|
||||
<div class="copy" style="margin-top:6px">
|
||||
<input type="text" readonly value="{{ d.proxy_user }}:{{ d.proxy_pass }}" onclick="this.select()">
|
||||
<button onclick="copy(this.previousElementSibling)">Copy</button>
|
||||
</div>
|
||||
{% elif d.status in ('provisioning','pending_payment') %}
|
||||
<p class="muted" style="font-size:12px;margin:6px 0 0">Provisioning — refresh shortly for your IP.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
<p class="muted" style="font-size:12px;margin:0"><a href="/dedicated">Order another dedicated IP →</a></p>
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="muted" style="margin-top:18px">No dedicated IPs yet — <a href="/dedicated">order one</a>.</p>
|
||||
{% endif %}
|
||||
|
||||
<script>
|
||||
function copy(el){ el.select(); document.execCommand('copy'); }
|
||||
</script>
|
||||
|
||||
77
templates/dedicated.html
Normal file
77
templates/dedicated.html
Normal file
@@ -0,0 +1,77 @@
|
||||
{% extends "base.html" %}
|
||||
{% block body %}
|
||||
<div class="hero" style="padding-bottom:20px">
|
||||
<h1>Dedicated <span class="glow">IPs</span>.</h1>
|
||||
<p class="lede">One clean IP, yours alone. Static datacenter or premium residential-ISP. Provisioned automatically from a global pool.</p>
|
||||
</div>
|
||||
|
||||
<div class="dash-grid">
|
||||
<div class="card">
|
||||
<h3>Configure your IP</h3>
|
||||
<form method="post" action="/dedicated/buy" onsubmit="document.getElementById('loc_name').value=document.getElementById('loc').selectedOptions[0].textContent">
|
||||
<label>Type</label>
|
||||
<div class="grid" style="grid-template-columns:1fr 1fr">
|
||||
{% for pid, p in products.items() %}
|
||||
<label class="switch" style="cursor:pointer">
|
||||
<input type="radio" name="product" value="{{ pid }}" {% if loop.first %}checked{% endif %} style="width:auto">
|
||||
<span>{{ p.name }}</span>
|
||||
</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<label>Duration</label>
|
||||
<div class="grid" style="grid-template-columns:1fr 1fr 1fr">
|
||||
{% for days in [30, 60, 90] %}
|
||||
<label class="switch" style="cursor:pointer">
|
||||
<input type="radio" name="days" value="{{ days }}" {% if days == 30 %}checked{% endif %} style="width:auto">
|
||||
<span>{{ days }}d</span>
|
||||
</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<label>Location</label>
|
||||
<select id="loc" name="location_id"></select>
|
||||
<input type="hidden" name="location_name" id="loc_name" value="">
|
||||
|
||||
<input type="submit" value="Order dedicated IP">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="card">
|
||||
<h3>Pricing</h3>
|
||||
{% for pid, p in products.items() %}
|
||||
<p class="muted" style="margin:0 0 6px"><strong style="color:var(--text)">{{ p.name }}</strong> — {{ p.desc }}</p>
|
||||
{% for days, (_, sats) in p.plans.items() %}
|
||||
<div class="copy" style="margin-bottom:4px">
|
||||
<span class="mono" style="flex:1">{{ days }} days</span>
|
||||
<span class="mono" style="color:var(--neon)">{{ sats }} sats</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<hr style="border-color:var(--border);margin:12px 0">
|
||||
{% endfor %}
|
||||
<p class="muted" style="font-size:12px">IPs provision automatically after payment (usually minutes). You get the host:port + credentials in your dashboard once live.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const locs = {
|
||||
3: {{ dc_locs | tojson }},
|
||||
9: {{ isp_locs | tojson }}
|
||||
};
|
||||
function updateLocs() {
|
||||
const pid = document.querySelector('input[name=product]:checked').value;
|
||||
const sel = document.getElementById('loc');
|
||||
sel.innerHTML = '';
|
||||
(locs[pid] || []).forEach(([id, name, stock]) => {
|
||||
const o = document.createElement('option');
|
||||
o.value = id; o.textContent = name + (stock ? '' : ' — out of stock');
|
||||
if (!stock) o.disabled = true;
|
||||
sel.appendChild(o);
|
||||
});
|
||||
}
|
||||
document.querySelectorAll('input[name=product]').forEach(r => r.onchange = updateLocs);
|
||||
updateLocs();
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user