import { api } from '../api.js'; import { showToast } from '../components/toast.js'; import { esc } from '../utils.js'; export async function render(container) { container.innerHTML = `

Loading...

`; try { const [subData, plans] = await Promise.all([ fetch('/api/subscription/me', { headers: { Authorization: `Bearer ${localStorage.getItem('token')}` }}).then(r => r.json()), fetch('/api/subscription/plans').then(r => r.json()) ]); const content = document.getElementById('billingContent'); content.innerHTML = `

Current Plan

${subData.plan.display_name}
${subData.self_hosted ? 'Self-Hosted' : ''} ${subData.trial?.active ? `Trial - ${subData.trial.days_left} days left` : ''}
${subData.trial?.active ? `
Your ${subData.trial.plan?.charAt(0).toUpperCase() + subData.trial.plan?.slice(1)} trial ends in ${subData.trial.days_left} days
After the trial, you'll be moved to the Free plan (1 device). Upgrade now to keep all your devices and features.
` : ''}
Devices
${subData.usage.devices} / ${subData.plan.max_devices === -1 ? 'Unlimited' : subData.plan.max_devices}
${subData.plan.max_devices > 0 ? `
` : ''}
Storage
${subData.usage.storage_mb} MB / ${subData.plan.max_storage_mb === -1 ? 'Unlimited' : subData.plan.max_storage_mb + ' MB'}
${subData.plan.max_storage_mb > 0 ? `
` : ''}
Features
${subData.plan.remote_control ? '
✓ Remote Control
' : '
✗ Remote Control
'} ${subData.plan.remote_url ? '
✓ Remote URLs
' : '
✗ Remote URLs
'} ${subData.plan.priority_support ? '
✓ Priority Support
' : '
✗ Priority Support
'}

Available Plans

${plans.map(p => `
${p.id === subData.plan.id ? '
Current
' : ''}
${p.display_name}
${p.price_monthly > 0 ? `$${p.price_monthly}/mo` : 'Free'}
${p.max_devices === -1 ? 'Unlimited' : p.max_devices} devices
${p.max_storage_mb === -1 ? 'Unlimited' : (p.max_storage_mb >= 1024 ? (p.max_storage_mb/1024) + ' GB' : p.max_storage_mb + ' MB')} storage
${p.remote_control ? '✓' : '✗'} Remote Control
${p.remote_url ? '✓' : '✗'} Remote URLs
${p.priority_support ? '✓' : '✗'} Priority Support
${p.price_yearly > 0 ? `
or $${p.price_yearly}/year (save ${Math.round((1 - p.price_yearly / (p.price_monthly * 12)) * 100)}%)
` : ''} ${!subData.self_hosted && p.price_monthly > 0 && p.id !== subData.plan.id ? `
${p.price_yearly > 0 ? `` : ''}
` : ''} ${!subData.self_hosted && p.id === subData.plan.id && subData.subscription?.stripe_subscription_id ? ` ` : ''}
`).join('')}
${subData.self_hosted ? '

Self-hosted mode: plans can be assigned by admins without billing.

' : ''}
`; // Checkout handler window._checkout = async (planId, interval) => { try { const res = await fetch('/api/stripe/checkout', { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${localStorage.getItem('token')}` }, body: JSON.stringify({ plan_id: planId, interval }) }); const data = await res.json(); if (data.error) { showToast(data.error, 'error'); return; } if (data.url) window.location.href = data.url; } catch (err) { showToast('Failed to start checkout: ' + err.message, 'error'); } }; // Manage subscription handler (Stripe Customer Portal) window._manageSubscription = async () => { try { const res = await fetch('/api/stripe/portal', { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${localStorage.getItem('token')}` }, }); const data = await res.json(); if (data.error) { showToast(data.error, 'error'); return; } if (data.url) window.location.href = data.url; } catch (err) { showToast('Failed to open billing portal: ' + err.message, 'error'); } }; // Check for payment success/cancel in URL if (window.location.hash.includes('payment=success')) { showToast('Payment successful! Your plan has been upgraded.', 'success'); window.location.hash = '#/billing'; } } catch (err) { document.getElementById('billingContent').innerHTML = `

Failed to load

${esc(err.message)}

`; } } export function cleanup() {}