❤️ হৃদয় এর হিসাব নিকাশ
বর্তমান ব্যালেন্স (SAR)
SAR০.০০
মোট সঞ্চয়
SAR ০
বাকি ঋণ
SAR ০
পারিবারিক ট্রান্সফার
SAR ০
💰
এই মাসের আয়
SAR ০
💸
এই মাসের ব্যয়
SAR ০
🏦
মোট সঞ্চয়
SAR ০
📋
মোট ঋণ বাকি
SAR ০
📉 শেষ ৬ মাসের ট্রেন্ড (আয় বনাম ব্যয়)
⚡ দ্রুত লেনদেন যোগ করুন
🕐 সাম্প্রতিক লেনদেন
📭

কোনো লেনদেন নেই

📋 লেনদেনের ইতিহাস
🏦 সঞ্চয় ব্যবস্থাপনা
মোট সঞ্চয় ব্যালেন্স
SAR ০.০০
🏦
সঞ্চয় ইতিহাস
📋 ঋণ ব্যবস্থাপনা
মোট বাকি ঋণ
SAR ০.০০
📋
ঋণের তালিকা
📊 রিপোর্ট ও বিশ্লেষণ
📈 মাসিক আয় বনাম ব্যয়
🍩 ব্যয়ের বিভাগ
📅 মাসিক সারাংশ
মাসআয়ব্যয়সঞ্চয়
🌍 সারাজীবনের পরিসংখ্যান
💰
SAR ০
মোট আয়
💸
SAR ০
মোট ব্যয়
🏦
SAR ০
মোট সঞ্চয়
🏠
SAR ০
পারিবারিক
📥
SAR ০
ঋণ গ্রহণ
📤
SAR ০
ঋণ পরিশোধ
⚙️ সেটিংস
🌙
ডার্ক মোড
অন্ধকার থিম ব্যবহার করুন
🔒
পিন লক
অ্যাপ খোলার সময় ৪ ডিজিট পিন চাইবে
🎯 মাসিক বাজেট
📅 বার্ষিক সমাপ্তি

🔒 বর্তমান বছর বন্ধ করুন

এই বছরের সকল হিসাব চূড়ান্ত করুন এবং পরের বছরে নিয়ে যান।

💾 ডেটা ব্যাকআপ
📤
ব্যাকআপ রপ্তানি করুন
JSON ফাইলে সব ডেটা সংরক্ষণ করুন
📥
ব্যাকআপ আমদানি করুন
JSON ফাইল থেকে ডেটা পুনরুদ্ধার করুন
📊
Excel রপ্তানি করুন
পেশাদার Excel ওয়ার্কবুক তৈরি করুন
📄
PDF রিপোর্ট
প্রিন্টযোগ্য আর্থিক রিপোর্ট
⚠️ বিপজ্জনক জোন
🗑️
এই বছরের ডেটা মুছুন
বর্তমান বছরের সব লেনদেন মুছে ফেলুন
❤️ হৃদয় এর হিসাব নিকাশ v1.0
SAR মুদ্রা | বাংলা ভাষা
`; const w = window.open('', '_blank'); w.document.write(html); w.document.close(); setTimeout(() => w.print(), 600); } // ───────────────────────────────────────────── // CLEAR YEAR DATA // ───────────────────────────────────────────── function clearYearData() { if (!confirm(`${currentYear} সালের সব ডেটা মুছে ফেলবেন? এটি পূর্বাবস্থায় ফেরানো যাবে না।`)) return; if (!confirm(`আবার নিশ্চিত করুন: ${currentYear} সালের সকল লেনদেন স্থায়ীভাবে মুছে যাবে। আগে ব্যাকআপ নেওয়া হয়েছে কি?`)) return; const d = getData(); delete d[currentYear]; if (!saveData(d)) return; showToast(`🗑️ ${currentYear} সালের ডেটা মুছে ফেলা হয়েছে`, 'success'); refreshAll(); } // ───────────────────────────────────────────── // THEME // ───────────────────────────────────────────── function toggleTheme() { const html = document.documentElement; const isDark = html.getAttribute('data-theme') === 'dark'; const newTheme = isDark ? 'light' : 'dark'; html.setAttribute('data-theme', newTheme); document.getElementById('darkModeToggle').className = 'toggle' + (isDark ? '' : ' on'); document.getElementById('themeIcon').textContent = isDark ? '☀️' : '🌙'; document.getElementById('themeToggleBtn').textContent = isDark ? '☀️' : '🌙'; localStorage.setItem('hidoy_theme', newTheme); // Refresh charts if on reports if (document.getElementById('page-reports').classList.contains('active')) { renderReports(); } if (document.getElementById('page-home').classList.contains('active')) { renderTrendChart(); } } // ───────────────────────────────────────────── // MODAL HELPERS // ───────────────────────────────────────────── function closeModal(id) { document.getElementById(id).classList.remove('open'); } // Close modal on overlay click document.querySelectorAll('.modal-overlay').forEach(overlay => { overlay.addEventListener('click', e => { if (e.target === overlay) overlay.classList.remove('open'); }); }); // Close modal on Escape key document.addEventListener('keydown', e => { if (e.key === 'Escape') { document.querySelectorAll('.modal-overlay.open').forEach(o => o.classList.remove('open')); } }); // ───────────────────────────────────────────── // TOAST // ───────────────────────────────────────────── function showToast(msg, type = '') { const el = document.createElement('div'); el.className = 'toast ' + type; el.textContent = msg; document.getElementById('toastContainer').appendChild(el); setTimeout(() => el.remove(), 2800); } // ───────────────────────────────────────────── // UTILS // ───────────────────────────────────────────── function todayStr() { return new Date().toISOString().split('T')[0]; } // ───────────────────────────────────────────── // PIN LOCK // ───────────────────────────────────────────── function getPin() { return localStorage.getItem('hidoy_pin') || ''; } function isPinEnabled() { return !!getPin(); } function togglePinSetting() { if (isPinEnabled()) { if (!confirm('পিন লক বন্ধ করবেন?')) return; localStorage.removeItem('hidoy_pin'); document.getElementById('pinToggle').className = 'toggle'; showToast('🔓 পিন লক বন্ধ করা হয়েছে', 'success'); return; } const pin = prompt('৪ ডিজিটের একটি পিন সেট করুন:'); if (pin === null) return; if (!/^\d{4}$/.test(pin)) { showToast('পিন ৪ ডিজিটের সংখ্যা হতে হবে', 'error'); return; } const confirmPin = prompt('পিন আবার লিখুন:'); if (confirmPin !== pin) { showToast('পিন মিলেনি', 'error'); return; } localStorage.setItem('hidoy_pin', pin); document.getElementById('pinToggle').className = 'toggle on'; showToast('🔒 পিন লক চালু করা হয়েছে', 'success'); } function buildLockKeypad() { const el = document.getElementById('lockKeypad'); el.innerHTML = ''; for (let i = 1; i <= 9; i++) { el.innerHTML += ``; } el.innerHTML += ``; el.innerHTML += ``; el.innerHTML += ``; } function renderLockDots() { const el = document.getElementById('lockDots'); el.innerHTML = ''; for (let i = 0; i < 4; i++) { el.innerHTML += `
`; } } function pinPress(d) { if (pinEntry.length >= 4) return; pinEntry += d; document.getElementById('lockError').textContent = ''; renderLockDots(); if (pinEntry.length === 4) { setTimeout(() => { if (pinEntry === getPin()) { document.getElementById('lockScreen').classList.add('hidden'); pinEntry = ''; } else { document.getElementById('lockError').textContent = 'ভুল পিন, আবার চেষ্টা করুন'; pinEntry = ''; renderLockDots(); } }, 150); } } function pinBackspace() { pinEntry = pinEntry.slice(0, -1); document.getElementById('lockError').textContent = ''; renderLockDots(); } function pinClear() { pinEntry = ''; document.getElementById('lockError').textContent = ''; renderLockDots(); } function checkPinLock() { if (!isPinEnabled()) return; document.getElementById('lockScreen').classList.remove('hidden'); buildLockKeypad(); renderLockDots(); } // ───────────────────────────────────────────── // BUDGET // ───────────────────────────────────────────── function getBudget() { const v = parseFloat(localStorage.getItem('hidoy_budget')); return isFinite(v) && v > 0 ? v : 0; } function saveBudget() { const v = parseFloat(document.getElementById('budgetInput').value); if (!v || v <= 0 || !isFinite(v)) { localStorage.removeItem('hidoy_budget'); showToast('বাজেট সরানো হয়েছে', 'success'); } else { localStorage.setItem('hidoy_budget', String(v)); showToast('🎯 বাজেট সংরক্ষিত হয়েছে', 'success'); } updateBudgetCard(); } function updateBudgetCard() { const budget = getBudget(); const card = document.getElementById('budgetCard'); if (!budget) { card.style.display = 'none'; return; } card.style.display = 'block'; const now = new Date(); const spent = monthSum(currentYear, now.getMonth(), 'expense'); const pct = Math.min(100, (spent / budget) * 100); const fill = document.getElementById('budgetBarFill'); fill.style.width = pct + '%'; fill.classList.toggle('over', spent > budget); document.getElementById('budgetSpentLbl').textContent = 'খরচ: ' + fmt(spent); document.getElementById('budgetTotalLbl').textContent = 'বাজেট: ' + fmt(budget); } // ───────────────────────────────────────────── // HOME TREND CHART (last 6 months) // ───────────────────────────────────────────── function renderTrendChart() { const canvas = document.getElementById('trendChart'); if (!canvas) return; const isDark = document.documentElement.getAttribute('data-theme') !== 'light'; const textColor = isDark ? '#9AAAC8' : '#5A6A8A'; const gridColor = isDark ? 'rgba(255,255,255,0.05)' : 'rgba(0,0,0,0.05)'; const now = new Date(); const labels = []; const incomeData = []; const expenseData = []; for (let i = 5; i >= 0; i--) { const d = new Date(now.getFullYear(), now.getMonth() - i, 1); const y = d.getFullYear(); const m = d.getMonth(); labels.push(MONTHS_BN[m].substring(0,3)); incomeData.push(monthSum(y, m, 'income')); expenseData.push(monthSum(y, m, 'expense')); } if (trendChart) trendChart.destroy(); trendChart = new Chart(canvas, { type: 'line', data: { labels, datasets: [ { label:'আয়', data: incomeData, borderColor:'#22C55E', backgroundColor:'rgba(34,197,94,0.15)', tension:0.35, fill:true, pointRadius:2 }, { label:'ব্যয়', data: expenseData, borderColor:'#EF4444', backgroundColor:'rgba(239,68,68,0.15)', tension:0.35, fill:true, pointRadius:2 } ] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { labels: { color: textColor, font: { family:'Hind Siliguri', size:10 }, boxWidth:10, padding:6 } } }, scales: { x: { ticks: { color: textColor, font: { family:'Hind Siliguri', size:9 } }, grid: { display:false } }, y: { ticks: { color: textColor, font: { family:'Hind Siliguri', size:9 } }, grid: { color: gridColor } } } } }); } // ───────────────────────────────────────────── // EDIT TRANSACTION // ───────────────────────────────────────────── function editTx() { if (!currentTxId) return; const yd = getYearData(currentYear); const t = yd.transactions.find(x => x.id === currentTxId); if (!t) return; editingTxId = t.id; const m = TYPE_META[t.type] || {}; const cats = CATEGORIES[t.type] || []; const catOptions = cats.map(c => ``).join(''); const extraOption = cats.includes(t.category) ? '' : ``; document.getElementById('txDetailTitle').textContent = '✏️ লেনদেন সম্পাদনা'; document.getElementById('txDetailContent').innerHTML = `
${esc(m.label)}
`; // Swap action buttons for save/cancel const actions = document.querySelector('#txDetailModal .modal-actions'); actions.innerHTML = ` `; } function cancelEditTx() { editingTxId = null; closeModal('txDetailModal'); } function saveEditTx() { if (!editingTxId) return; const amount = parseFloat(document.getElementById('editAmount').value); const date = document.getElementById('editDate').value; const category = document.getElementById('editCategory').value; const note = document.getElementById('editNote').value.trim(); if (!amount || amount <= 0 || !isFinite(amount)) { showToast('সঠিক পরিমাণ লিখুন', 'error'); return; } if (amount > 999999999) { showToast('পরিমাণ অনেক বেশি', 'error'); return; } if (!date) { showToast('তারিখ দিন', 'error'); return; } const yd = getYearData(currentYear); const t = yd.transactions.find(x => x.id === editingTxId); if (!t) return; t.amount = amount; t.date = date; t.category = category; t.note = note; if (!saveYearData(currentYear, yd)) return; editingTxId = null; closeModal('txDetailModal'); showToast('✅ পরিবর্তন সংরক্ষিত হয়েছে', 'success'); refreshAll(); } // ───────────────────────────────────────────── // HISTORY DATE RANGE // ───────────────────────────────────────────── function clearHistoryDateFilter() { document.getElementById('historyFrom').value = ''; document.getElementById('historyTo').value = ''; renderHistory(); } // ───────────────────────────────────────────── // INIT // ───────────────────────────────────────────── function init() { // PIN lock check (must happen first) checkPinLock(); // Restore theme const savedTheme = localStorage.getItem('hidoy_theme') || 'dark'; document.documentElement.setAttribute('data-theme', savedTheme); document.getElementById('darkModeToggle').className = 'toggle' + (savedTheme === 'dark' ? ' on' : ''); document.getElementById('themeIcon').textContent = savedTheme === 'dark' ? '🌙' : '☀️'; document.getElementById('themeToggleBtn').textContent = savedTheme === 'dark' ? '🌙' : '☀️'; // Restore PIN toggle state document.getElementById('pinToggle').className = 'toggle' + (isPinEnabled() ? ' on' : ''); // Restore budget input const budget = getBudget(); if (budget) document.getElementById('budgetInput').value = budget; // Set default date document.getElementById('entryDate').value = todayStr(); // Build year selector buildYearSelector(); // Init category dropdown updateCategoryDropdown(); // Build month filter buildMonthFilter(); // Refresh all views refreshAll(); } init();