96 lines
7.5 KiB
HTML
96 lines
7.5 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<meta name="theme-color" content="#050506">
|
||
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'><rect width='64' height='64' rx='14' fill='%23050506'/><circle cx='32' cy='32' r='20' fill='none' stroke='%23c6ff4d' stroke-width='3' stroke-dasharray='4 6'/><circle cx='32' cy='32' r='7' fill='%23c6ff4d'/></svg>">
|
||
<title>Your workspace — Shkor Labs</title>
|
||
<meta name="robots" content="noindex">
|
||
<meta name="referrer" content="no-referrer">
|
||
<link rel="stylesheet" href="../../styles.css">
|
||
<link rel="stylesheet" href="../../apply/apply.css">
|
||
<style>.creds{margin-top:16px;padding:16px 18px;border-radius:12px;background:rgba(255,255,255,.035);box-shadow:inset 0 0 0 1px var(--line-2);font:14px/1.9 var(--mono);color:var(--fg-2)}.creds b{display:inline;font:inherit;color:var(--fg)}</style>
|
||
</head>
|
||
<body>
|
||
<header class="nav">
|
||
<div class="wrap nav-in">
|
||
<a class="brand" href="../../" aria-label="Shkor Labs — home">
|
||
<svg viewBox="0 0 32 32" aria-hidden="true"><circle cx="16" cy="16" r="12" fill="none" stroke="currentColor" stroke-width="2" stroke-dasharray="3 4"/><circle cx="16" cy="16" r="4.5" fill="currentColor"/></svg>
|
||
<span>Shkor<b>Labs</b></span>
|
||
</a>
|
||
</div>
|
||
</header>
|
||
<main id="main" class="apply">
|
||
<div class="grid-bg" aria-hidden="true"></div>
|
||
<div class="wrap status-in">
|
||
<p class="kicker">Autopilot · $99/month</p>
|
||
<h1 id="title">Loading…</h1>
|
||
<p class="lead" id="sub"></p>
|
||
<ol class="timeline" id="tl" aria-live="polite"></ol>
|
||
<div class="bookmark">
|
||
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 3h12v18l-6-4-6 4V3Z" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round"/></svg>
|
||
<p><b>Bookmark this page.</b> It's your private link: come back any time to finish a step or find your workspace login. Don't share it.</p>
|
||
</div>
|
||
</div>
|
||
</main>
|
||
<script>
|
||
(function () {
|
||
var q = new URLSearchParams(location.search), t = q.get('t') || '';
|
||
try { if (!t) t = localStorage.getItem('shkor_ap') || ''; } catch (x) {}
|
||
var tl = document.getElementById('tl'), title = document.getElementById('title'), sub = document.getElementById('sub'), busy = false;
|
||
var ARROW = '<svg viewBox="0 0 20 20" aria-hidden="true"><path d="M4 10h11M11 5l5 5-5 5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>';
|
||
var KYC = { 'Not Started': 'Not started', 'In Progress': 'In progress', 'In Review': 'Under review', 'Approved': 'Verified', 'Declined': 'Not approved', 'Abandoned': 'Abandoned', 'Expired': 'Link expired' };
|
||
function esc(s) { return String(s || '').replace(/[&<>"]/g, function (c) { return { '&': '&', '<': '<', '>': '>', '"': '"' }[c]; }); }
|
||
function item(state, head, body, action) { return '<li class="tl ' + state + '"><span class="tl-dot" aria-hidden="true"></span><div><b>' + head + '</b><p>' + body + '</p>' + (action || '') + '</div></li>'; }
|
||
function pill(state, text) { return ' <span class="pill ' + state + '">' + esc(text) + '</span>'; }
|
||
function render(d) {
|
||
var first = (d.name || '').split(' ')[0], s = d.stage, h = '';
|
||
var kycState = s === 'kyc' ? 'wip' : s === 'declined' ? 'bad' : 'ok';
|
||
h += item(kycState, 'Identity verification' + pill(kycState, KYC[d.kyc] || d.kyc),
|
||
s === 'declined' ? 'We couldn’t verify your identity, so we can’t open a workspace. If you think this is a mistake, write to hello@shkor.com.' : 'ID document and a selfie, handled by Didit. About 2 minutes.',
|
||
d.kyc_url ? '<a class="btn" href="' + esc(d.kyc_url) + '"><span>' + (d.kyc === 'Not Started' ? 'Verify now' : 'Continue verification') + '</span>' + ARROW + '</a>' : '');
|
||
var payState = s === 'pay' ? 'wip' : (s === 'deploying' || s === 'ready') ? 'ok' : 'todo';
|
||
var cancelled = q.get('cancelled') && s === 'pay';
|
||
h += item(payState, 'Payment · $99/month' + (payState === 'ok' ? pill('ok', 'Paid') : ''),
|
||
s === 'pay' ? (q.get('paid') ? 'Confirming your payment…' : cancelled ? 'Payment was cancelled — you can try again.' : 'Secure card payment by Stripe. Monthly, cancel any time.') : payState === 'ok' ? 'Subscription active. Receipts go to ' + esc(d.email) + '.' : 'Opens after verification.',
|
||
s === 'pay' && !q.get('paid') ? '<button class="btn" id="pay" type="button"><span>Pay $99 and deploy</span>' + ARROW + '</button><p class="form-err" id="payerr"></p>' : '');
|
||
var depState = s === 'deploying' ? 'wip' : s === 'ready' ? 'ok' : 'todo';
|
||
var dep = 'Your own server, web panel with Claude Code and OpenCode, and a Simbiot agent.';
|
||
var act = '';
|
||
if (s === 'deploying') dep = 'Creating your server and installing the tools. This usually takes 15–40 minutes — this page updates by itself, and you can close it.';
|
||
if (s === 'ready' && d.panel) {
|
||
dep = 'Your workspace is live. Sign in to the panel, then pick Claude Code (sign in with your own Claude account) or OpenCode (works right away).';
|
||
act = '<div class="creds">Panel: <b><a href="' + esc(d.panel.url) + '" target="_blank" rel="noopener">' + esc(d.panel.url) + '</a></b><br>Login: <b>' + esc(d.panel.user) + '</b><br>Password: <b>' + esc(d.panel.password) + '</b></div>'
|
||
+ '<a class="btn" href="' + esc(d.panel.url) + '" target="_blank" rel="noopener"><span>Open my workspace</span>' + ARROW + '</a>';
|
||
}
|
||
h += item(depState, 'Your workspace' + (s === 'ready' ? pill('ok', 'Live') : s === 'deploying' ? pill('wip', 'Deploying') : ''), dep, act);
|
||
tl.innerHTML = h;
|
||
title.textContent = s === 'ready' ? 'Welcome aboard, ' + first + '.' : s === 'deploying' ? 'Deploying your workspace…' : s === 'declined' ? 'Verification not approved' : s === 'pay' ? 'Verified. One step left.' : 'Hi ' + first + ', let’s verify you.';
|
||
sub.textContent = s === 'kyc' ? 'Payment opens as soon as your identity is verified. If you’ve just finished, the result usually arrives within a minute.' : '';
|
||
var pay = document.getElementById('pay');
|
||
if (pay) pay.addEventListener('click', function () {
|
||
pay.disabled = true; pay.querySelector('span').textContent = 'Opening Stripe…';
|
||
fetch('/api/autopilot/checkout', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ t: t }) })
|
||
.then(function (r) { return r.json().then(function (j) { return { ok: r.ok, j: j }; }); })
|
||
.then(function (res) { if (!res.ok || !res.j.url) throw new Error(res.j.error || 'Couldn’t open the payment page.'); location.href = res.j.url; })
|
||
.catch(function (x) { document.getElementById('payerr').textContent = x.message; pay.disabled = false; pay.querySelector('span').textContent = 'Pay $99 and deploy'; });
|
||
});
|
||
}
|
||
function load() {
|
||
if (busy) return; busy = true;
|
||
fetch('/api/autopilot/status?t=' + encodeURIComponent(t), { cache: 'no-store' })
|
||
.then(function (r) { return r.json().then(function (j) { return { ok: r.ok, j: j }; }); })
|
||
.then(function (res) {
|
||
if (!res.ok) { title.textContent = 'Order not found'; sub.innerHTML = esc(res.j.error || 'Check your link.') + ' <a href="../">Start again</a>.'; return; }
|
||
render(res.j);
|
||
})
|
||
.catch(function () { title.textContent = 'Can’t load right now'; sub.textContent = 'Please refresh in a moment.'; })
|
||
.then(function () { busy = false; });
|
||
}
|
||
load();
|
||
setInterval(function () { if (!document.hidden && !document.getElementById('pay')) load(); }, 15000);
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|