No upcoming filings.
`;
}
renderJurisdictionChart();
}
function renderJurisdictionChart() {
const ctx = document.getElementById('jurisdictionChart').getContext('2d');
const counts = state.jurisdictions.reduce((acc, j) => {
acc[j] = state.entities.filter(e => e.jurisdiction === j).length;
return acc;
}, {});
const chartData = {
labels: Object.keys(counts),
datasets: [{
label: 'Number of Entities',
data: Object.values(counts),
backgroundColor: 'rgba(59, 130, 246, 0.7)',
borderColor: 'rgba(59, 130, 246, 1)',
borderWidth: 1
}]
};
if (jurisdictionChart) {
jurisdictionChart.data = chartData;
jurisdictionChart.update();
} else {
jurisdictionChart = new Chart(ctx, {
type: 'bar',
data: chartData,
options: { scales: { y: { beginAtZero: true, ticks: { stepSize: 1 } } }, plugins: { legend: { display: false } } }
});
}
}
function renderEntityTable() {
const tableBody = document.getElementById('entity-table-body');
tableBody.innerHTML = '';
if(state.entities.length === 0) {
tableBody.innerHTML = `
| No entities found. |
`;
return;
}
state.entities.forEach(entity => {
tableBody.innerHTML += `
| ${entity.name} |
${entity.type} |
${entity.jurisdiction} |
${entity.status} |
|
`;
});
}
function renderConfigLists() {
const configMap = {type: state.types, jurisdiction: state.jurisdictions, filing: state.filings, status: state.statuses};
for (const [type, items] of Object.entries(configMap)) {
document.getElementById(`${type}-list`).innerHTML = items.map(item => `
${item}`).join('');
}
}
function updateSelectOptions() {
const selects = {'entity-type': state.types, 'entity-jurisdiction': state.jurisdictions, 'entity-status': state.statuses};
for (const [id, options] of Object.entries(selects)) {
document.getElementById(id).innerHTML = options.map(o => `
`).join('');
}
}
// --- EVENT HANDLERS ---
Object.keys({type:0, jurisdiction:0, filing:0, status:0}).forEach(type => {
document.getElementById(`${type}-form`).addEventListener('submit', (e) => handleConfigForm(e, `${type}s`));
});
function handleConfigForm(e, stateKey) {
e.preventDefault();
const input = e.target.querySelector('input');
if (input.value.trim() && !state[stateKey].includes(input.value.trim())) {
state[stateKey].push(input.value.trim());
saveState();
renderConfigLists();
updateSelectOptions();
input.value = '';
}
}
entityForm.addEventListener('submit', (e) => {
e.preventDefault();
const id = document.getElementById('entity-id').value;
const complianceFilings = Array.from(document.querySelectorAll('#filings-container .filing-row')).map((row, i) => ({
type: row.querySelector('.filing-type').value,
dueDate: row.querySelector('.filing-date').value,
fee: parseFloat(row.querySelector('.filing-fee').value) || 0,
id: Date.now() + i
}));
const data = {
name: document.getElementById('entity-name').value, type: document.getElementById('entity-type').value, jurisdiction: document.getElementById('entity-jurisdiction').value,
formationDate: document.getElementById('entity-formationDate').value, registeredAgent: document.getElementById('entity-registeredAgent').value, ein: document.getElementById('entity-ein').value,
status: document.getElementById('entity-status').value, complianceFilings
};
if (id) {
const index = state.entities.findIndex(p => p.id == id);
if (index > -1) state.entities[index] = { ...state.entities[index], ...data };
} else {
data.id = state.nextEntityId++;
state.entities.push(data);
}
saveState();
renderAll();
closeEntityModal();
});
// --- GLOBAL FUNCTIONS ---
const app = {
switchTab: (tabName) => {
state.currentTab = tabName;
document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active', 'border-blue-500', 'text-blue-600'));
document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
document.getElementById(`tab-btn-${tabName}`).classList.add('active', 'border-blue-500', 'text-blue-600');
document.getElementById(`tab-content-${tabName}`).classList.add('active');
},
navigateTabs: (dir) => {
const i = tabOrder.indexOf(state.currentTab);
const nextI = dir === 'next' ? (i + 1) % tabOrder.length : (i - 1 + tabOrder.length) % tabOrder.length;
app.switchTab(tabOrder[nextI]);
},
openEntityModal: (id = null) => {
entityForm.reset();
document.getElementById('entity-id').value = '';
document.getElementById('filings-container').innerHTML = '';
if (id) {
const entity = state.entities.find(p => p.id === id);
if(entity) {
document.getElementById('modal-title').textContent = 'Edit Entity';
Object.keys(entity).forEach(key => {
const el = document.getElementById(`entity-${key === 'id' ? 'id' : key}`);
if (el) el.value = entity[key];
});
entity.complianceFilings.forEach(f => window.app.addFilingRow(f));
}
} else {
document.getElementById('modal-title').textContent = 'Add New Entity';
window.app.addFilingRow();
}
entityModal.classList.remove('hidden');
},
closeEntityModal: () => entityModal.classList.add('hidden'),
editEntity: (id) => app.openEntityModal(id),
deleteEntity: (id) => {
if (confirm('Are you sure you want to delete this entity?')) {
state.entities = state.entities.filter(p => p.id !== id);
saveState();
renderAll();
}
},
deleteConfigItem: (type, value) => {
const keyMap = {type:'type', jurisdiction:'jurisdiction', filing:'complianceFilings', status:'status'};
const stateKey = `${type}s`;
if (type === 'filing') {
if (state.entities.some(e => e.complianceFilings.some(f => f.type === value))) { alert(`Cannot delete. This filing type is in use.`); return; }
} else if (state.entities.some(e => e[keyMap[type]] === value)) { alert(`Cannot delete. This ${type} is in use.`); return; }
state[stateKey] = state[stateKey].filter(item => item !== value);
saveState(); renderConfigLists(); updateSelectOptions();
},
addFilingRow: (filing = {}) => {
const container = document.getElementById('filings-container');
const div = document.createElement('div');
div.className = 'filing-row grid grid-cols-12 gap-2 items-center';
const filingOptions = state.filings.map(f => `
`).join('');
div.innerHTML = `
`;
container.appendChild(div);
},
generatePDF: () => {
const { jsPDF } = window.jspdf;
const doc = new jsPDF();
if (typeof doc.autoTable !== 'function') return;
doc.setFontSize(18); doc.text("Corporate Legal Entity Management Report", 14, 22);
doc.setFontSize(11); doc.text(`Generated: ${now.toLocaleDateString()}`, 14, 30);
doc.autoTable({
startY: 40, theme: 'striped',
body: [
['Total Entities', state.entities.length],
['Active Jurisdictions', [...new Set(state.entities.map(e => e.jurisdiction))].length],
['Filings Due (Next 30 Days)', document.getElementById('stat-upcoming-filings').textContent],
['Total Filing Fees Due (30 Days)', document.getElementById('stat-total-fees').textContent]
]
});
doc.autoTable({
startY: doc.lastAutoTable.finalY + 15, theme: 'grid',
head: [['Entity Name', 'Type', 'Jurisdiction', 'Formation Date', 'Status']],
body: state.entities.map(e => [e.name, e.type, e.jurisdiction, e.formationDate, e.status])
});
const allFilings = state.entities.flatMap(e => e.complianceFilings.map(f => ({...f, entityName: e.name})))
.filter(f => new Date(f.dueDate) >= now)
.sort((a,b) => new Date(a.dueDate) - new Date(b.dueDate));
doc.autoTable({
startY: doc.lastAutoTable.finalY + 15, theme: 'grid',
head: [['Entity Name', 'Filing Type', 'Due Date', 'Fee']],
body: allFilings.map(f => [f.entityName, f.type, f.dueDate, formatCurrency(f.fee)])
});
doc.save('Entity-Management-Report.pdf');
}
};
window.app = app;
// Initial Load
loadState(); renderAll(); app.switchTab(state.currentTab);
});
// --- Make functions callable from inline HTML ---
function switchTab(tabName) { window.app.switchTab(tabName); }
function navigateTabs(direction) { window.app.navigateTabs(direction); }
function openEntityModal(id = null) { window.app.openEntityModal(id); }
function closeEntityModal() { window.app.closeEntityModal(); }
function generatePDF() { window.app.generatePDF(); }
function addFilingRow(filing = {}) { window.app.addFilingRow(filing); }