class AdminBilling extends HTMLElement {
constructor() {
super();
this.pricingConfig = [];
this.stats = null;
this.boundHandleClick = this.handleClick.bind(this);
this.loading = true;
this.error = null;
}
async connectedCallback() {
this.addEventListener('click', this.boundHandleClick);
await this.loadData();
this.render();
this.attachEventListeners();
}
disconnectedCallback() {
this.removeEventListener('click', this.boundHandleClick);
}
async loadData() {
this.loading = true;
this.error = null;
try {
const [pricing, stats] = await Promise.all([
this.fetchPricing(),
this.fetchStats()
]);
this.pricingConfig = pricing;
this.stats = stats;
this.loading = false;
} catch (error) {
console.error('Failed to load admin billing data:', error);
this.error = error.message || 'Failed to load admin billing data';
this.loading = false;
}
}
async fetchPricing() {
const response = await fetch('/api/admin/billing/pricing', {
headers: {'Authorization': `Bearer ${localStorage.getItem('token')}`}
});
return await response.json();
}
async fetchStats() {
const response = await fetch('/api/admin/billing/stats', {
headers: {'Authorization': `Bearer ${localStorage.getItem('token')}`}
});
return await response.json();
}
formatCurrency(amount) {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
}).format(amount);
}
render() {
if (this.loading) {
this.innerHTML = '
Loading admin billing data...
';
return;
}
if (this.error) {
this.innerHTML = ``;
return;
}
this.innerHTML = `
Billing Administration
Total Revenue
${this.formatCurrency(this.stats?.total_revenue || 0)}
Total Invoices
${this.stats?.total_invoices || 0}
Pending Invoices
${this.stats?.pending_invoices || 0}
Pricing Configuration
| Configuration |
Current Value |
Unit |
Actions |
${this.pricingConfig.map(config => `
| ${config.description || config.config_key} |
${config.config_value} |
${config.unit || '-'} |
|
`).join('')}
`;
}
handleClick(e) {
const target = e.target;
if (target.classList.contains('btn-edit')) {
const configId = target.dataset.configId;
this.editPricing(configId);
return;
}
if (target.id === 'generateInvoices') {
this.generateInvoices();
}
}
attachEventListeners() {
}
async editPricing(configId) {
const config = this.pricingConfig.find(c => c.id === parseInt(configId));
if (!config) return;
const newValue = prompt(`Enter new value for ${config.config_key}:`, config.config_value);
if (newValue === null) return;
try {
const response = await fetch(`/api/admin/billing/pricing/${configId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${localStorage.getItem('token')}`
},
body: JSON.stringify({
config_key: config.config_key,
config_value: parseFloat(newValue)
})
});
if (response.ok) {
alert('Pricing updated successfully');
await this.loadData();
this.render();
this.attachEventListeners();
} else {
alert('Failed to update pricing');
}
} catch (error) {
console.error('Error updating pricing:', error);
alert('Error updating pricing');
}
}
async generateInvoices() {
const year = parseInt(this.querySelector('#invoiceYear').value);
const month = parseInt(this.querySelector('#invoiceMonth').value);
if (!confirm(`Generate invoices for ${month}/${year}?`)) return;
try {
const response = await fetch(`/api/admin/billing/generate-invoices/${year}/${month}`, {
method: 'POST',
headers: {'Authorization': `Bearer ${localStorage.getItem('token')}`}
});
const result = await response.json();
alert(`Generated ${result.generated} invoices, skipped ${result.skipped} users`);
} catch (error) {
console.error('Error generating invoices:', error);
alert('Failed to generate invoices');
}
}
}
customElements.define('admin-billing', AdminBilling);
export default AdminBilling;