class AdminBilling extends HTMLElement {
constructor() {
super();
this.pricingConfig = [];
this.stats = null;
this.boundHandleClick = this.handleClick.bind(this);
}
async connectedCallback() {
this.addEventListener('click', this.boundHandleClick);
await this.loadData();
this.render();
this.attachEventListeners();
}
disconnectedCallback() {
this.removeEventListener('click', this.boundHandleClick);
}
async loadData() {
try {
const [pricing, stats] = await Promise.all([
this.fetchPricing(),
this.fetchStats()
]);
this.pricingConfig = pricing;
this.stats = stats;
} catch (error) {
console.error('Failed to load admin billing data:', error);
}
}
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() {
this.innerHTML = `
<div class="admin-billing">
<h2>Billing Administration</h2>
<div class="stats-cards">
<div class="stat-card">
<h3>Total Revenue</h3>
<div class="stat-value">${this.formatCurrency(this.stats?.total_revenue || 0)}</div>
</div>
<div class="stat-card">
<h3>Total Invoices</h3>
<div class="stat-value">${this.stats?.total_invoices || 0}</div>
</div>
<div class="stat-card">
<h3>Pending Invoices</h3>
<div class="stat-value">${this.stats?.pending_invoices || 0}</div>
</div>
</div>
<div class="pricing-config-section">
<h3>Pricing Configuration</h3>
<table class="pricing-table">
<thead>
<tr>
<th>Configuration</th>
<th>Current Value</th>
<th>Unit</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
${this.pricingConfig.map(config => `
<tr data-config-id="${config.id}">
<td>${config.description || config.config_key}</td>
<td class="config-value">${config.config_value}</td>
<td>${config.unit || '-'}</td>
<td>
<button class="btn-edit" data-config-id="${config.id}">Edit</button>
</td>
</tr>
`).join('')}
</tbody>
</table>
</div>
<div class="invoice-generation-section">
<h3>Generate Invoices</h3>
<div class="invoice-gen-form">
<label>
Year:
<input type="number" id="invoiceYear" value="${new Date().getFullYear()}" min="2020">
</label>
<label>
Month:
<input type="number" id="invoiceMonth" value="${new Date().getMonth() + 1}" min="1" max="12">
</label>
<button class="btn-primary" id="generateInvoices">Generate All Invoices</button>
</div>
</div>
</div>
`;
}
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;