Error: The dashboard could not be initialized due to missing HTML elements. Please check the tool\'s code.
';
return; // Stop execution if essential elements are missing
}
const { jsPDF } = window.jspdf;
// STATE MANAGEMENT
let banks = JSON.parse(localStorage.getItem('brd_banksData')) || [];
// ELEMENT REFERENCES
const bankFormContainer = document.getElementById('brd-bank-form-container');
const bankForm = document.getElementById('brd-bank-form');
const itemFormContainer = document.getElementById('brd-item-form-container');
const itemForm = document.getElementById('brd-item-form');
const managementListContainer = document.getElementById('brd-management-list');
const bankCardsContainer = document.getElementById('brd-bank-cards-container');
const nextBtn = document.getElementById('brd-next-btn');
const prevBtn = document.getElementById('brd-prev-btn');
const tabButtons = document.querySelectorAll('.brd-tab-button');
const tabContents = document.querySelectorAll('.brd-tab-content');
// UTILITY FUNCTIONS
const formatCurrency = (amount) => {
return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(amount);
};
const generateId = () => '_' + Math.random().toString(36).substr(2, 9);
const saveState = () => {
localStorage.setItem('brd_banksData', JSON.stringify(banks));
};
// TAB NAVIGATION LOGIC
window.brd_changeTab = (event, tabId) => {
tabContents.forEach(content => content.classList.remove('active'));
tabButtons.forEach(button => button.classList.remove('active'));
document.getElementById(tabId).classList.add('active');
event.currentTarget.classList.add('active');
updateNavButtons();
};
const updateNavButtons = () => {
const activeTabIndex = [...tabButtons].findIndex(btn => btn.classList.contains('active'));
prevBtn.disabled = activeTabIndex === 0;
nextBtn.disabled = activeTabIndex === tabButtons.length - 1;
};
nextBtn.addEventListener('click', () => {
const activeTabIndex = [...tabButtons].findIndex(btn => btn.classList.contains('active'));
if (activeTabIndex < tabButtons.length - 1) {
tabButtons[activeTabIndex + 1].click();
}
});
prevBtn.addEventListener('click', () => {
const activeTabIndex = [...tabButtons].findIndex(btn => btn.classList.contains('active'));
if (activeTabIndex > 0) {
tabButtons[activeTabIndex - 1].click();
}
});
// RENDER FUNCTIONS
const renderAll = () => {
renderManagementList();
renderDashboard();
updateNavButtons();
};
const renderDashboard = () => {
bankCardsContainer.innerHTML = '';
let totalDeposits = 0;
let totalLiabilities = 0;
if (banks.length === 0) {
bankCardsContainer.innerHTML = `
No banks have been added yet. Go to the "Manage Banks & Accounts" tab to add your first bank.
`;
} else {
banks.forEach(bank => {
const accountsTotal = bank.accounts.reduce((sum, acc) => sum + parseFloat(acc.balance), 0);
const loansTotal = bank.loans.reduce((sum, loan) => sum + parseFloat(loan.balance), 0);
const cardsTotal = bank.creditCards.reduce((sum, card) => sum + parseFloat(card.balance), 0);
const bankDeposits = accountsTotal;
const bankLiabilities = loansTotal + cardsTotal;
totalDeposits += bankDeposits;
totalLiabilities += bankLiabilities;
const card = document.createElement('div');
card.className = 'brd-bank-card';
card.innerHTML = `
Accounts
Loans
Credit Cards
Contacts
- Person: ${bank.contactPerson || 'N/A'}
- Email: ${bank.contactEmail || 'N/A'}
- Phone: ${bank.contactPhone || 'N/A'}
`;
bankCardsContainer.appendChild(card);
const accountsList = card.querySelector(`#accounts-list-${bank.id}`);
if (bank.accounts.length > 0) {
bank.accounts.forEach(acc => accountsList.innerHTML += `
${acc.name} (${acc.type}) ${formatCurrency(acc.balance)}`);
} else {
accountsList.innerHTML = '
No accounts added.';
}
const loansList = card.querySelector(`#loans-list-${bank.id}`);
if (bank.loans.length > 0) {
bank.loans.forEach(loan => loansList.innerHTML += `
${loan.name} ${formatCurrency(loan.balance)}`);
} else {
loansList.innerHTML = '
No loans added.';
}
const cardsList = card.querySelector(`#cards-list-${bank.id}`);
if (bank.creditCards.length > 0) {
bank.creditCards.forEach(cc => cardsList.innerHTML += `
${cc.name} ${formatCurrency(cc.balance)}`);
} else {
cardsList.innerHTML = '
No credit cards added.';
}
});
}
const totalNetPosition = totalDeposits - totalLiabilities;
document.getElementById('brd-total-deposits').textContent = formatCurrency(totalDeposits);
document.getElementById('brd-total-liabilities').textContent = formatCurrency(totalLiabilities);
document.getElementById('brd-net-position').textContent = formatCurrency(totalNetPosition);
};
const renderManagementList = () => {
managementListContainer.innerHTML = '';
if (banks.length === 0) {
managementListContainer.innerHTML = `
Click "Add New Bank" to get started.
`;
return;
}
banks.forEach(bank => {
const section = document.createElement('div');
section.className = 'brd-manage-section';
section.dataset.bankId = bank.id;
section.innerHTML = `
${renderManagementSubSection('accounts', 'Accounts', bank)}
${renderManagementSubSection('loans', 'Loans', bank)}
${renderManagementSubSection('creditCards', 'Credit Cards', bank)}
`;
managementListContainer.appendChild(section);
});
};
const renderManagementSubSection = (type, title, bank) => {
let itemsHtml = bank[type].map(item => `
${item.name} - ${formatCurrency(item.balance)}
`).join('');
if (bank[type].length === 0) {
itemsHtml = '
No items added yet.
';
}
return `
${title}
${itemsHtml}
`;
};
// FORM HANDLING
const showBankForm = (bank = null) => {
bankForm.reset();
document.getElementById('brd-edit-bank-id').value = '';
if (bank) {
document.getElementById('brd-form-title').textContent = `Editing ${bank.name}`;
document.getElementById('brd-edit-bank-id').value = bank.id;
document.getElementById('brd-bank-name').value = bank.name;
document.getElementById('brd-contact-person').value = bank.contactPerson || '';
document.getElementById('brd-contact-email').value = bank.contactEmail || '';
document.getElementById('brd-contact-phone').value = bank.contactPhone || '';
} else {
document.getElementById('brd-form-title').textContent = 'Add a New Bank';
}
itemFormContainer.classList.add('brd-hidden');
bankFormContainer.classList.remove('brd-hidden');
};
const hideBankForm = () => {
bankFormContainer.classList.add('brd-hidden');
bankForm.reset();
};
const showItemForm = (type, bankId, item = null) => {
itemForm.reset();
document.getElementById('brd-item-bank-id').value = bankId;
document.getElementById('brd-item-type').value = type;
document.getElementById('brd-edit-item-id').value = '';
const fieldsContainer = document.getElementById('brd-item-form-fields');
let formTitle = 'Add';
let formFields = '';
switch (type) {
case 'accounts':
formTitle += ' Account';
formFields = `
`;
break;
case 'loans':
formTitle += ' Loan';
formFields = `
`;
break;
case 'creditCards':
formTitle += ' Credit Card';
formFields = `
`;
break;
}
fieldsContainer.innerHTML = formFields;
if (item) {
formTitle = `Editing ${item.name}`;
document.getElementById('brd-edit-item-id').value = item.id;
document.getElementById('brd-item-name').value = item.name;
document.getElementById('brd-item-balance').value = item.balance;
if (type === 'accounts' && document.getElementById('brd-item-type-select')) {
document.getElementById('brd-item-type-select').value = item.type;
}
}
document.getElementById('brd-item-form-title').textContent = formTitle;
bankFormContainer.classList.add('brd-hidden');
itemFormContainer.classList.remove('brd-hidden');
};
const hideItemForm = () => {
itemFormContainer.classList.add('brd-hidden');
itemForm.reset();
};
// EVENT LISTENERS
document.getElementById('brd-add-new-bank-btn').addEventListener('click', () => showBankForm());
document.getElementById('brd-cancel-bank-form').addEventListener('click', hideBankForm);
document.getElementById('brd-cancel-item-form').addEventListener('click', hideItemForm);
bankForm.addEventListener('submit', function (e) {
e.preventDefault();
const bankId = document.getElementById('brd-edit-bank-id').value;
const newBankData = {
name: document.getElementById('brd-bank-name').value.trim(),
contactPerson: document.getElementById('brd-contact-person').value.trim(),
contactEmail: document.getElementById('brd-contact-email').value.trim(),
contactPhone: document.getElementById('brd-contact-phone').value.trim()
};
if (bankId) { // Editing existing bank
const bank = banks.find(b => b.id === bankId);
if(bank) Object.assign(bank, newBankData);
} else { // Adding new bank
banks.push({
...newBankData,
id: generateId(),
accounts: [],
loans: [],
creditCards: []
});
}
saveState();
renderAll();
hideBankForm();
});
itemForm.addEventListener('submit', function(e) {
e.preventDefault();
const bankId = document.getElementById('brd-item-bank-id').value;
const type = document.getElementById('brd-item-type').value;
const itemId = document.getElementById('brd-edit-item-id').value;
const bank = banks.find(b => b.id === bankId);
if (!bank) return;
const newItemData = {
name: document.getElementById('brd-item-name').value.trim(),
balance: parseFloat(document.getElementById('brd-item-balance').value) || 0,
};
if (type === 'accounts') {
newItemData.type = document.getElementById('brd-item-type-select').value;
}
if (itemId) { // Editing
const item = bank[type].find(i => i.id === itemId);
if (item) Object.assign(item, newItemData);
} else { // Adding
newItemData.id = generateId();
bank[type].push(newItemData);
}
saveState();
renderAll();
hideItemForm();
});
managementListContainer.addEventListener('click', function(e) {
const target = e.target;
const action = target.dataset.action;
if (!action) return;
const bankSection = target.closest('.brd-manage-section');
const bankId = bankSection.dataset.bankId;
const bank = banks.find(b => b.id === bankId);
if(!bank) return;
const itemElement = target.closest('.brd-manage-item');
const subsection = target.closest('.brd-manage-subsection');
switch (action) {
case 'edit-bank':
showBankForm(bank);
break;
case 'delete-bank':
if (confirm(`Are you sure you want to delete ${bank.name} and all its data?`)) {
banks = banks.filter(b => b.id !== bankId);
saveState();
renderAll();
}
break;
case 'add-item':
showItemForm(subsection.dataset.type, bankId);
break;
case 'edit-item': {
const type = subsection.dataset.type;
const itemId = itemElement.dataset.itemId;
const item = bank[type].find(i => i.id === itemId);
if(item) showItemForm(type, bankId, item);
break;
}
case 'delete-item': {
const type = subsection.dataset.type;
const itemId = itemElement.dataset.itemId;
const item = bank[type].find(i => i.id === itemId);
if (item && confirm(`Are you sure you want to delete ${item.name}?`)) {
bank[type] = bank[type].filter(i => i.id !== itemId);
saveState();
renderAll();
}
break;
}
}
});
// PDF DOWNLOAD
document.getElementById('brd-download-pdf-btn').addEventListener('click', function () {
const pdfContent = document.getElementById('brd-pdf-content');
if (!pdfContent) {
console.error("PDF content area not found.");
alert("Could not generate PDF: content area is missing.");
return;
}
const downloadButton = this;
downloadButton.textContent = 'Generating...';
downloadButton.disabled = true;
html2canvas(pdfContent, {
scale: 2, // Improve resolution
useCORS: true,
backgroundColor: '#ffffff'
}).then(canvas => {
try {
const imgData = canvas.toDataURL('image/png');
const pdf = new jsPDF({
orientation: 'p',
unit: 'mm',
format: 'a4'
});
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = pdf.internal.pageSize.getHeight();
const canvasWidth = canvas.width;
const canvasHeight = canvas.height;
const ratio = canvasWidth / canvasHeight;
const imgWidth = pdfWidth - 20; // with margin
const imgHeight = imgWidth / ratio;
let position = 10; // top margin
pdf.addImage(imgData, 'PNG', 10, position, imgWidth, imgHeight);
pdf.save('Bank_Relationship_Summary.pdf');
} catch (error) {
console.error("Error generating PDF:", error);
alert("An error occurred while generating the PDF. Please try again.");
} finally {
downloadButton.textContent = 'Download Summary as PDF';
downloadButton.disabled = false;
}
}).catch(err => {
console.error("html2canvas failed:", err);
alert("An error occurred while capturing the page content for the PDF.");
downloadButton.textContent = 'Download Summary as PDF';
downloadButton.disabled = false;
});
});
// INITIALIZATION
renderAll();
});