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

${t('common.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 = `

${t('billing.current_plan')}

${subData.plan.display_name}
${subData.self_hosted ? `${t('billing.self_hosted')}` : ''} ${subData.trial?.active ? `${t('billing.trial_days_left', { n: subData.trial.days_left })}` : ''}
${subData.trial?.active ? `
${t('billing.trial_ends', { plan: (subData.trial.plan?.charAt(0).toUpperCase() + subData.trial.plan?.slice(1)) || '', n: subData.trial.days_left })}
${t('billing.trial_after')}
` : ''}
${t('billing.devices')}
${subData.usage.devices} / ${subData.plan.max_devices === -1 ? t('billing.unlimited') : subData.plan.max_devices}
${subData.plan.max_devices > 0 ? `
` : ''}
${t('billing.storage')}
${subData.usage.storage_mb} MB / ${subData.plan.max_storage_mb === -1 ? t('billing.unlimited') : subData.plan.max_storage_mb + ' MB'}
${subData.plan.max_storage_mb > 0 ? `
` : ''}
${t('billing.features')}
${subData.plan.remote_control ? `
✓ ${t('billing.feat.remote_control')}
` : `
✗ ${t('billing.feat.remote_control')}
`} ${subData.plan.remote_url ? `
✓ ${t('billing.feat.remote_urls')}
` : `
✗ ${t('billing.feat.remote_urls')}
`} ${subData.plan.priority_support ? `
✓ ${t('billing.feat.priority_support')}
` : `
✗ ${t('billing.feat.priority_support')}
`}

${t('billing.available_plans')}

${plans.map(p => `
${p.id === subData.plan.id ? `
${t('billing.current')}
` : ''}
${p.display_name}
${p.price_monthly > 0 ? `$${p.price_monthly}${t('billing.per_month')}` : t('billing.free')}
${p.max_devices === -1 ? t('billing.unlimited') : p.max_devices} ${t('billing.devices_lc')}
${p.max_storage_mb === -1 ? t('billing.unlimited') : (p.max_storage_mb >= 1024 ? (p.max_storage_mb/1024) + ' GB' : p.max_storage_mb + ' MB')} ${t('billing.storage_lc')}
${p.remote_control ? '✓' : '✗'} ${t('billing.feat.remote_control')}
${p.remote_url ? '✓' : '✗'} ${t('billing.feat.remote_urls')}
${p.priority_support ? '✓' : '✗'} ${t('billing.feat.priority_support')}
${p.price_yearly > 0 ? `
${t('billing.yearly_save', { price: p.price_yearly, pct: 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 ? `

${t('billing.self_hosted_note')}

` : ''}
`; 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(t('billing.toast.checkout_failed', { error: err.message }), 'error'); } }; 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(t('billing.toast.portal_failed', { error: err.message }), 'error'); } }; if (window.location.hash.includes('payment=success')) { showToast(t('billing.toast.payment_success'), 'success'); window.location.hash = '#/billing'; } } catch (err) { document.getElementById('billingContent').innerHTML = `

${t('billing.failed_to_load')}

${esc(err.message)}

`; } } export function cleanup() {}