document.addEventListener('DOMContentLoaded', function() { const claimForm = document.getElementById('claim-form'); const subdomainInput = document.getElementById('subdomain'); const availabilityStatus = document.getElementById('availability-status'); const claimBtn = document.getElementById('claim-btn'); const claimSection = document.getElementById('claim-section'); const successSection = document.getElementById('success-section'); const errorSection = document.getElementById('error-section'); const routerConfig = document.getElementById('router-config'); let checkTimeout = null; subdomainInput.addEventListener('input', function() { const value = this.value.toLowerCase().replace(/[^a-z0-9-]/g, ''); this.value = value; clearTimeout(checkTimeout); availabilityStatus.textContent = ''; availabilityStatus.className = 'status'; claimBtn.disabled = true; if (value.length >= 3) { checkTimeout = setTimeout(() => checkAvailability(value), 300); } }); async function checkAvailability(subdomain) { try { const response = await fetch(`/api/check?subdomain=${encodeURIComponent(subdomain)}`); const data = await response.json(); if (data.available) { availabilityStatus.textContent = '✓ Available'; availabilityStatus.className = 'status available'; claimBtn.disabled = false; } else { availabilityStatus.textContent = '✗ Already taken'; availabilityStatus.className = 'status taken'; claimBtn.disabled = true; } } catch (error) { console.error('Error checking availability:', error); } } claimForm.addEventListener('submit', async function(e) { e.preventDefault(); const subdomain = subdomainInput.value; claimBtn.disabled = true; claimBtn.textContent = 'Claiming...'; try { const response = await fetch('/api/claim', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ subdomain: subdomain }), }); const data = await response.json(); if (response.ok) { showSuccess(data); } else { showError(data.error || 'Failed to claim space'); } } catch (error) { showError('Network error. Please try again.'); } claimBtn.disabled = false; claimBtn.textContent = 'Claim Space'; }); function showSuccess(data) { claimSection.classList.add('hidden'); successSection.classList.remove('hidden'); routerConfig.classList.remove('hidden'); document.getElementById('token-value').textContent = data.token; document.getElementById('fqdn-value').textContent = data.fqdn; const updateUrl = `https://dyn.${data.fqdn.split('.').slice(-2).join('.')}/api/nic/update?hostname=%h&myip=%i`; document.getElementById('update-url').textContent = updateUrl; document.querySelectorAll('.hostname-placeholder').forEach(el => { el.textContent = data.fqdn; }); document.querySelectorAll('.update-url-placeholder').forEach(el => { el.textContent = updateUrl; }); const curlCmd = `curl -u "none:${data.token}" "https://dyn.${data.fqdn.split('.').slice(-2).join('.')}/api/nic/update?hostname=${data.fqdn}"`; document.getElementById('curl-example').textContent = curlCmd; document.getElementById('copy-token').addEventListener('click', function() { copyToClipboard(data.token); this.textContent = 'Copied!'; setTimeout(() => this.textContent = 'Copy Token', 2000); }); document.getElementById('copy-curl').addEventListener('click', function() { copyToClipboard(curlCmd); this.textContent = 'Copied!'; setTimeout(() => this.textContent = 'Copy', 2000); }); } function showError(message) { claimSection.classList.add('hidden'); errorSection.classList.remove('hidden'); document.getElementById('error-message').textContent = message; } document.getElementById('try-again').addEventListener('click', function() { errorSection.classList.add('hidden'); claimSection.classList.remove('hidden'); subdomainInput.value = ''; subdomainInput.focus(); }); function copyToClipboard(text) { navigator.clipboard.writeText(text).catch(function() { const textarea = document.createElement('textarea'); textarea.value = text; document.body.appendChild(textarea); textarea.select(); document.execCommand('copy'); document.body.removeChild(textarea); }); } });