`;
container.appendChild(card);
});
lucide.createIcons();
} catch (e) {
container.textContent = "Failed to load plans.";
}
}
async function initPayment(planId) {
if (!tg) return alert("Open in Telegram");
// Simple loader on button
const btn = event.target;
const oldText = btn.innerText;
btn.innerText = 'Creating..';
btn.disabled = true;
try {
const body = {
user_id: currentState.user.id,
plan_id: planId
};
if (currentState.promoCode) {
body.promo_code = currentState.promoCode;
// Reset after use or keep active? Bot usually resets. Let's keep it until refresh.
}
const res = await fetch(`${API_BASE}/create-invoice`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body)
});
const data = await res.json();
if (data.invoice_link) {
tg.openInvoice(data.invoice_link, (status) => {
if (status === 'paid') {
tg.showAlert('Successful Payment!');
router('dashboard');
}
});
} else {
tg.showAlert('Error: ' + (data.error || 'Unknown'));
}
} catch (e) {
tg.showAlert('Network error');
} finally {
btn.innerText = oldText;
btn.disabled = false;
}
}
async function loadSubscription() {
const linkEl = document.getElementById('config-link');
const fetchBtn = document.querySelector('.btn-secondary');
// If we don't have URL, try to fetch it again via user stats
if (!currentState.subUrl) {
try {
const res = await fetch(`${API_BASE}/user/${currentState.user.id}`);
const data = await res.json();
currentState.subUrl = data.subscription_url;
} catch (e) { }
}
const url = currentState.subUrl;
if (url) {
linkEl.textContent = url;
// Gen QR
const qrContainer = document.getElementById('qrcode-container');
qrContainer.innerHTML = '';
new QRCode(qrContainer, {
text: url,
width: 160,
height: 160,
colorDark: "#000000",
colorLight: "#ffffff",
correctLevel: QRCode.CorrectLevel.M
});
} else {
linkEl.textContent = "No active subscription found";
document.getElementById('qrcode-container').innerHTML = '';
}
}
function copyConfig() {
if (currentState.subUrl) {
navigator.clipboard.writeText(currentState.subUrl);
if (tg) tg.showAlert("Link copied to clipboard!");
else alert("Copied!");
} else {
if (tg) tg.showAlert("No subscription to copy.");
}
}
function toggleAcc(header) {
const body = header.nextElementSibling;
body.classList.toggle('open');
const icon = header.querySelector('svg');
// Simple rotation logic if needed, or just rely on CSS
}
async function loadProfile() {
document.getElementById('profile-name').textContent = currentState.user.first_name;
document.getElementById('profile-id').textContent = `ID: ${currentState.user.id}`;
const avatar = document.getElementById('profile-avatar');
avatar.textContent = (currentState.user.first_name || 'U')[0].toUpperCase();
}
async function checkPromo() {
const input = document.getElementById('promo-input');
const resDiv = document.getElementById('promo-result');
const code = input.value.trim();
if (!code) return;
try {
const res = await fetch(`${API_BASE}/check-promo`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ code })
});
if (res.ok) {
const data = await res.json();
resDiv.innerHTML = `
✅ ${data.description}. Apply at checkout!
`;
currentState.promoCode = data.code; // Save for checkout
tg.showAlert(`Promo valid! Discount: ${data.discount}%. Go to Shop to buy.`);
} else {
resDiv.innerHTML = `
❌ Invalid Code
`;
}
} catch (e) {
resDiv.textContent = "Error checking promo";
}
}
function openHelp() {
// Simple alert or modal. Using routing for now logic would be better if we had a help page.
alert("Support: @hoshimach1");
}
// Material Ripple Init
document.addEventListener('click', function (e) {
const target = e.target.closest('button, .action-card, .plan-card'); // Select ripple targets
if (target) {
const circle = document.createElement('span');
const diameter = Math.max(target.clientWidth, target.clientHeight);
const radius = diameter / 2;
const rect = target.getBoundingClientRect();
circle.style.width = circle.style.height = `${diameter}px`;
circle.style.left = `${e.clientX - rect.left - radius}px`;
circle.style.top = `${e.clientY - rect.top - radius}px`;
circle.classList.add('ripple');
// Remove existing ripples to be clean or append? Append allows rapid clicks.
const ripple = target.getElementsByClassName('ripple')[0];
if (ripple) {
ripple.remove();
}
target.appendChild(circle);
}
});
// Start
document.addEventListener('DOMContentLoaded', () => {
router('dashboard');
});