diff --git a/Domains/Frontend/MiniProjects/FinanceManager/analytics.css b/Domains/Frontend/MiniProjects/FinanceManager/analytics.css new file mode 100644 index 00000000..c8d40a0b --- /dev/null +++ b/Domains/Frontend/MiniProjects/FinanceManager/analytics.css @@ -0,0 +1,170 @@ +/* analytics.css */ +.analytics-content { + max-width: var(--max-width); + margin: 0 auto; + padding: 90px 40px var(--spacing-2xl) 40px; +} + +/* Time Selector */ +.time-selector-card { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: var(--spacing-xl); +} + +.tabs-container { + display: flex; + gap: var(--spacing-md); +} + +.tab-btn { + color: var(--color-text-secondary); + padding: 10px 15px; + font-weight: 500; + transition: var(--transition-normal); + border-bottom: 2px solid transparent; +} + +.tab-btn.active, .tab-btn:hover { + color: var(--color-primary); + border-bottom: 2px solid var(--color-primary); +} + +.download-btn { + padding: 10px 20px; +} + +/* Statistics Grid */ +.statistics-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: var(--spacing-lg); + margin-bottom: var(--spacing-xl); +} + +.stat-card { + text-align: center; +} + +.stat-card .label { + color: var(--color-text-secondary); + margin-bottom: 5px; +} + +.stat-card .stat-value { + font-size: 2em; + margin: 0; +} + +/* Charts Grid */ +.charts-grid { + display: grid; + grid-template-columns: 2fr 1fr; /* Two main columns */ + gap: var(--spacing-lg); +} + +.chart-card.full-width { + grid-column: 1 / -1; /* Spans all columns */ +} + +.chart-card { + min-height: 350px; +} + +.chart-placeholder { + height: 300px; + margin-top: var(--spacing-lg); + background-color: var(--color-bg-hover); + border-radius: var(--radius-md); + display: flex; + justify-content: center; + align-items: center; + color: var(--color-text-secondary); + font-size: 1.1em; + border: 1px dashed var(--color-border); + position: relative; +} + +/* Mock Bar Chart Styling (for Income vs Expense) */ +.bar-chart-mock { + display: flex; + justify-content: space-around; + align-items: flex-end; + padding: var(--spacing-lg); + height: 300px; + gap: var(--spacing-md); +} + +.bar-set { + display: flex; + flex-direction: column; + align-items: center; + width: 60px; + height: 100%; + position: relative; +} + +.income-bar, .expense-bar { + width: 25px; + border-radius: 4px 4px 0 0; + transition: height 0.5s; +} + +.income-bar { + background-color: var(--color-success); + margin-bottom: 2px; +} + +.expense-bar { + background-color: var(--color-danger); + margin-bottom: 2px; +} + +.bar-set .label { + position: absolute; + bottom: -20px; + color: var(--color-text-secondary); + font-size: 0.9em; +} + +/* Mock Pie/Line Chart Legend Dots */ +.pie-chart-mock .legend-dot, .line-chart-mock .legend-dot { + display: inline-block; + width: 10px; + height: 10px; + border-radius: 50%; + margin-right: 5px; +} + +/* Mobile Responsiveness */ +@media (max-width: 1024px) { + .time-selector-card { + flex-direction: column; + align-items: stretch; + gap: var(--spacing-md); + } + .tabs-container { + justify-content: space-around; + width: 100%; + margin-bottom: var(--spacing-md); + } + .download-btn { + width: 100%; + } + .statistics-grid { + grid-template-columns: repeat(2, 1fr); + } + .charts-grid { + grid-template-columns: 1fr; /* Stack charts on mobile */ + } + .chart-card { + min-height: 300px; + } +} + +@media (max-width: 600px) { + .statistics-grid { + grid-template-columns: 1fr; + } +} \ No newline at end of file diff --git a/Domains/Frontend/MiniProjects/FinanceManager/analytics.html b/Domains/Frontend/MiniProjects/FinanceManager/analytics.html new file mode 100644 index 00000000..4898229e --- /dev/null +++ b/Domains/Frontend/MiniProjects/FinanceManager/analytics.html @@ -0,0 +1,111 @@ + + + + + + MONEYFY - Analytics + + + + + + + + + +
+

Financial Analytics & Reports

+ +
+ + +
+ +
+
+

Avg. Daily Spending

+

$68.15

+
+
+

Highest Spending Category

+

Bills

+
+
+

Savings Goal Progress

+

62%

+
+
+ +
+
+

Income vs. Expense Comparison

+
+
+
+
+ Jan +
+
+
+
+ Feb +
+
+
+
+ Mar +
+
+
+ +
+

Spending by Category

+
+ [Pie Chart Placeholder] +
Bills +
Food +
+
+ +
+

Net Income Over Time

+
+ [Line Chart Placeholder] +
+
+ +
+

Savings Rate Trend

+
+ [Savings Line Chart Placeholder] +
+
+ +
+
+ + + + \ No newline at end of file diff --git a/Domains/Frontend/MiniProjects/FinanceManager/budgets.css b/Domains/Frontend/MiniProjects/FinanceManager/budgets.css new file mode 100644 index 00000000..dd098409 --- /dev/null +++ b/Domains/Frontend/MiniProjects/FinanceManager/budgets.css @@ -0,0 +1,151 @@ +/* budgets.css */ +.budgets-content { + max-width: var(--max-width); + margin: 0 auto; + padding: 90px 40px var(--spacing-2xl) 40px; +} + +/* Budget Summary Header */ +.budget-summary-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: var(--spacing-xl); + margin-bottom: var(--spacing-xl); +} + +.summary-details .label { + color: var(--color-text-secondary); +} + +.summary-details .value { + font-size: 2.2em; + font-weight: 700; + color: var(--color-primary); + margin: 5px 0; +} +.summary-details .spent-value { + color: var(--color-text-primary); +} +.remaining-value { + font-weight: 500; +} + +.overall-progress { + width: 40%; +} + +.progress-bar { + background-color: var(--color-bg-hover); + height: 12px; + border-radius: 6px; + overflow: hidden; + margin-bottom: 5px; +} + +.progress-fill { + height: 100%; + background-color: var(--color-primary); + transition: width 0.5s ease-out; +} + +.progress-label { + text-align: right; + color: var(--color-text-secondary); +} + +.add-budget-btn { + min-width: 150px; +} + +/* Budget Cards Grid */ +.budget-cards-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: var(--spacing-lg); + margin-bottom: var(--spacing-xl); +} + +.budget-card { + padding: var(--spacing-lg); + position: relative; +} + +.card-header { + display: flex; + align-items: center; + margin-bottom: var(--spacing-md); +} + +.budget-icon { + font-size: 1.5em; + color: var(--color-primary); + margin-right: 15px; +} + +.budget-card h3 { + margin: 0; + font-size: 1.5em; + color: var(--color-text-primary); +} + +.budget-amounts { + margin: var(--spacing-md) 0; +} + +.spent-limit { + color: var(--color-text-secondary); + font-size: 0.9em; +} + +.primary-fill { background-color: var(--color-primary); } +.warning-fill { background-color: var(--color-warning); } +.danger-fill { background-color: var(--color-danger); } + +.primary-text { color: var(--color-primary); } +.warning-text { color: var(--color-warning); } +.success-text { color: var(--color-success); } +.danger-text { color: var(--color-danger); } + +.percentage { + font-weight: 700; + margin-top: 5px; +} + +.card-actions { + position: absolute; + top: var(--spacing-lg); + right: var(--spacing-lg); +} + +/* Budget Card Hover Effect */ +.budget-card:hover { + transform: scale(1.03); + border-color: var(--color-primary); + box-shadow: 0 10px 30px rgba(0, 217, 255, 0.2); +} + +/* Mobile Responsiveness */ +@media (max-width: 1024px) { + .budget-summary-header { + flex-direction: column; + align-items: flex-start; + gap: var(--spacing-lg); + } + .overall-progress { + width: 100%; + order: 3; + } + .add-budget-btn { + width: 100%; + } + .budget-cards-grid { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (max-width: 600px) { + .budget-cards-grid { + grid-template-columns: 1fr; + } +} \ No newline at end of file diff --git a/Domains/Frontend/MiniProjects/FinanceManager/budgets.html b/Domains/Frontend/MiniProjects/FinanceManager/budgets.html new file mode 100644 index 00000000..7f39096e --- /dev/null +++ b/Domains/Frontend/MiniProjects/FinanceManager/budgets.html @@ -0,0 +1,145 @@ + + + + + + MONEYFY - Budgets + + + + + + + + + +
+

Monthly Budgets

+ +
+
+

Total Budget vs. Spent (Oct)

+

$2,800.00 / $2,112.55

+

Remaining: $687.45

+
+
+
+
+
+

75.45% Utilized

+
+ +
+ +
+ +
+
+ +

Bills

+
+
+

$950.00 spent of $1,000.00 limit

+
+
+
+
+

95% Used

+

Remaining: $50.00

+ +
+ + +
+
+ +
+
+ +

Food & Dining

+
+
+

$580.00 spent of $800.00 limit

+
+
+
+
+

72.5% Used

+

Remaining: $220.00

+ +
+ + +
+
+ +
+
+ +

Leisure & Fun

+
+
+

$462.55 spent of $400.00 limit

+
+
+
+
+

115.6% Used

+

OVERSPENT: $62.55

+ +
+ + +
+
+ +
+ +
+

Budget Insights

+

Mini-chart trends and recommendations will appear here.

+
+
+ + + + + + \ No newline at end of file diff --git a/Domains/Frontend/MiniProjects/FinanceManager/dashboard.css b/Domains/Frontend/MiniProjects/FinanceManager/dashboard.css new file mode 100644 index 00000000..54227da9 --- /dev/null +++ b/Domains/Frontend/MiniProjects/FinanceManager/dashboard.css @@ -0,0 +1,296 @@ +/* dashboard.css */ + +/* --- Layout Grid (Section 2) --- */ +.dashboard-content { + max-width: var(--max-width); + margin: 0 auto; + padding: 90px 40px var(--spacing-2xl) 40px; /* 90px top padding to clear fixed header */ +} + +/* Header/Navbar Styling (Section 3) */ +.navbar { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 70px; + background-color: var(--color-bg-tertiary); + border-bottom: 1px solid var(--color-border); + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 40px; + z-index: 1000; +} + +.logo { + font-size: 1.8em; + font-weight: 900; +} + +.desktop-nav a { + margin: 0 15px; + color: var(--color-text-secondary); + font-weight: 500; + padding: 5px 0; + transition: var(--transition-normal); +} + +.desktop-nav a.active, .desktop-nav a:hover { + color: var(--color-primary); + border-bottom: 2px solid var(--color-primary); +} + +.user-actions { + display: flex; + align-items: center; +} + +.search-input { + background-color: var(--color-bg-quaternary); + border: 1px solid var(--color-border); + border-radius: var(--radius-md); + padding: 8px 12px; + color: var(--color-text-primary); + width: 150px; + transition: width var(--transition-normal), border-color var(--transition-normal); +} + +.search-input:focus { + width: 200px; + border-color: var(--color-primary); + outline: none; +} + +.icon-btn { + color: var(--color-text-secondary); + font-size: 1.2em; + margin-left: var(--spacing-lg); + cursor: pointer; + transition: color var(--transition-normal); +} + +.icon-btn:hover { + color: var(--color-primary); +} + +.mobile-menu-toggle { + display: none; /* Hidden on desktop */ +} + +/* Welcome Section */ +.welcome-section { + padding: var(--spacing-xl) 0; + margin-bottom: var(--spacing-xl); + background: linear-gradient(90deg, var(--color-bg-primary) 0%, var(--color-bg-quaternary) 100%); + border-radius: var(--radius-lg); +} + +.welcome-section h1 { + font-size: 2.5em; + margin-bottom: 5px; +} + +.status-message { + color: var(--color-text-secondary); +} + +/* Summary Cards Grid */ +.summary-cards-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: var(--spacing-lg); + margin-bottom: var(--spacing-2xl); +} + +.summary-card { + padding: var(--spacing-lg); + display: flex; + flex-direction: column; + justify-content: space-between; + position: relative; + overflow: hidden; +} + +.summary-card.primary-accent { border-left: 5px solid var(--color-primary); } +.summary-card.success-accent { border-left: 5px solid var(--color-success); } +.summary-card.danger-accent { border-left: 5px solid var(--color-danger); } + +.summary-card .label { + color: var(--color-text-secondary); + font-size: 0.9em; + margin-top: 10px; +} + +.summary-card h2.value { + font-size: 2.2em; + font-weight: 700; + color: var(--color-text-primary); + margin-top: 5px; + margin-bottom: 0; +} + +.summary-card .icon-large { + font-size: 1.8em; + position: absolute; + top: var(--spacing-lg); + right: var(--spacing-lg); + opacity: 0.5; +} + +.summary-card:hover { + box-shadow: 0 8px 32px rgba(0, 217, 255, 0.1); +} + +/* Savings Rate Progress Circle (Placeholder Styling) */ +.savings-rate-display { + display: flex; + justify-content: center; + align-items: center; + height: 80px; +} +.progress-circle { + /* Purely illustrative: in a real app, this is SVG/Canvas/CSS conical gradient */ + width: 60px; + height: 60px; + border-radius: 50%; + background-color: var(--color-bg-hover); + border: 5px solid var(--color-primary); + display: flex; + align-items: center; + justify-content: center; + font-weight: 700; + color: var(--color-primary); +} + + +/* Dashboard Widgets Grid */ +.dashboard-widgets-grid { + display: grid; + grid-template-columns: 2fr 1fr; /* Chart takes 2/3, Transactions takes 1/3 */ + gap: var(--spacing-lg); + margin-bottom: var(--spacing-2xl); +} + +.chart-section { + min-height: 400px; + display: flex; + flex-direction: column; +} + +.chart-placeholder { + flex-grow: 1; + display: flex; + justify-content: center; + align-items: center; + color: var(--color-text-secondary); + background-color: var(--color-bg-hover); + border-radius: var(--radius-md); + margin-bottom: var(--spacing-lg); +} + +.chart-legend { + display: flex; + flex-wrap: wrap; + gap: var(--spacing-lg); + font-size: 0.9em; + color: var(--color-text-secondary); +} + +.legend-dot { + display: inline-block; + width: 10px; + height: 10px; + border-radius: 50%; + margin-right: 5px; +} + +/* Recent Transactions List */ +.transaction-list { + margin-top: var(--spacing-lg); +} + +.transaction-row { + display: grid; + grid-template-columns: 2fr 1fr 1fr; + padding: 12px 0; + border-bottom: 1px solid var(--color-border); + transition: background-color var(--transition-normal); +} + +.transaction-row:hover { + background-color: var(--color-bg-hover); + border-left: 4px solid var(--color-primary); + padding-left: 4px; +} + +.transaction-row .desc { + font-weight: 500; +} +.transaction-row .cat { + color: var(--color-text-secondary); + font-size: 0.9em; + text-align: center; +} +.transaction-row .amount { + font-weight: 600; + text-align: right; +} + +.tertiary-link { + display: block; + margin-top: var(--spacing-md); + text-align: right; + color: var(--color-primary); + font-size: 0.9em; +} + +/* Quick Action Buttons */ +.quick-actions { + display: flex; + gap: var(--spacing-lg); + padding: var(--spacing-lg) 0; + justify-content: center; +} + +/* --- Mobile Responsiveness (Section 5) --- */ +@media (max-width: 1024px) { + .navbar { + padding: 0 20px; + } + .desktop-nav, .search-input, .icon-btn { + display: none; + } + .mobile-menu-toggle { + display: block; /* Show hamburger on mobile */ + font-size: 1.5em; + color: var(--color-primary); + } + .dashboard-content { + padding: 90px 20px var(--spacing-xl) 20px; + } + .summary-cards-grid { + grid-template-columns: repeat(2, 1fr); /* 2 columns on tablet */ + } + .dashboard-widgets-grid { + grid-template-columns: 1fr; /* Stack on tablet/mobile */ + } + .quick-actions { + flex-direction: column; + } + .quick-actions button { + width: 100%; + } +} + +@media (max-width: 600px) { + .summary-cards-grid { + grid-template-columns: 1fr; /* 1 column on phone */ + } + .welcome-section h1 { + font-size: 1.8em; + } + .transaction-row { + grid-template-columns: 1.5fr 1fr 1fr; + } +} \ No newline at end of file diff --git a/Domains/Frontend/MiniProjects/FinanceManager/index.html b/Domains/Frontend/MiniProjects/FinanceManager/index.html new file mode 100644 index 00000000..83043e42 --- /dev/null +++ b/Domains/Frontend/MiniProjects/FinanceManager/index.html @@ -0,0 +1,108 @@ + + + + + + MONEYFY - Dashboard + + + + + + + + +
+ +
+

Welcome back, John!

+

Current Date: October 22, 2025 | "Control your money, or it will control you."

+
+ +
+ +
+ +

Total Balance

+

$14,580.92

+
+ +
+ +

Total Income (Oct)

+

$4,250.00

+
+ +
+ +

Total Expenses (Oct)

+

$2,112.55

+
+ +
+ +

Savings Rate

+
+
38%
+
+
+
+ +
+
+

Expense Distribution

+
[Doughnut Chart Placeholder]
+
+

Bills: $950

+

Food: $580

+

Transport: $120

+

Leisure: $462

+
+
+ +
+

Recent Transactions

+
+
+ Salary Deposit + Income + +$3,500.00 +
+
+ Grocery Shopping + Food + -$125.75 +
+
+ View All Transactions +
+
+ +
+ + + +
+ +
+ + + + \ No newline at end of file diff --git a/Domains/Frontend/MiniProjects/FinanceManager/scripts/budgets.js b/Domains/Frontend/MiniProjects/FinanceManager/scripts/budgets.js new file mode 100644 index 00000000..c8b70084 --- /dev/null +++ b/Domains/Frontend/MiniProjects/FinanceManager/scripts/budgets.js @@ -0,0 +1,129 @@ +// scripts/budgets.js +import { STORAGE_KEYS, loadData, saveData, calculateTotal, getSpendingByCategory } from './utils.js'; + +document.addEventListener('DOMContentLoaded', () => { + const budgetGrid = document.querySelector('.budget-cards-grid'); + const addBudgetBtn = document.querySelector('.add-budget-btn'); + const modal = document.getElementById('budget-modal'); + const closeBtn = modal.querySelector('.close-btn'); + const budgetForm = modal.querySelector('form'); + + // Load initial data + let budgets = loadData(STORAGE_KEYS.BUDGETS); + const transactions = loadData(STORAGE_KEYS.EXPENSES); + const spendingByCategory = getSpendingByCategory(transactions); + + // --- Core UI Rendering Function --- + function renderBudgets(budgetData) { + if (!budgetGrid) return; + budgetGrid.innerHTML = ''; + + const totalBudget = budgetData.reduce((sum, b) => sum + b.limit, 0); + const totalSpent = budgetData.reduce((sum, b) => sum + b.spent, 0); + + // 1. Update Overall Summary + updateOverallSummary(totalBudget, totalSpent); + + // 2. Render Cards + budgetData.forEach(budget => { + // Ensure spent is calculated correctly, matching mock data + const spent = spendingByCategory[budget.category] || budget.spent; // Use real data if available, else mock data + const limit = budget.limit; + const percentage = Math.round((spent / limit) * 100); + const remaining = limit - spent; + + let fillClass = 'primary-fill'; + let textClass = 'primary-text'; + let remainingText = `Remaining: $${Math.max(0, remaining).toFixed(2)}`; + + if (percentage >= 100) { + fillClass = 'danger-fill'; + textClass = 'danger-text'; + remainingText = `OVERSPENT: $${Math.abs(remaining).toFixed(2)}`; + } else if (percentage >= 75) { + fillClass = 'warning-fill'; + textClass = 'warning-text'; + } + + const card = document.createElement('div'); + card.classList.add('card', 'budget-card', `${textClass.split('-')[0]}-accent`); // e.g., 'danger-accent' + card.innerHTML = ` +
+ +

${budget.category}

+
+
+

$${spent.toFixed(2)} spent of $${limit.toFixed(2)} limit

+
+
+
+
+

${percentage}% Used

+

${remainingText}

+ +
+ + +
+ `; + budgetGrid.appendChild(card); + }); + } + + // --- Overall Summary Update --- + function updateOverallSummary(totalBudget, totalSpent) { + const utilization = totalBudget > 0 ? (totalSpent / totalBudget) * 100 : 0; + const remaining = totalBudget - totalSpent; + + document.querySelector('.summary-details .value').innerHTML = + `$${totalBudget.toFixed(2)} / $${totalSpent.toFixed(2)}`; + + const remainingEl = document.querySelector('.remaining-value'); + remainingEl.textContent = `Remaining: $${remaining.toFixed(2)}`; + remainingEl.classList.toggle('danger-text', remaining < 0); + remainingEl.classList.toggle('success-text', remaining >= 0); + + document.querySelector('.progress-fill').style.width = `${Math.min(100, utilization).toFixed(2)}%`; + document.querySelector('.progress-label').textContent = `${utilization.toFixed(2)}% Utilized`; + } + + // --- Modal/Form Handling --- + addBudgetBtn.addEventListener('click', () => { + budgetForm.reset(); + modal.classList.remove('hidden'); + }); + + closeBtn.addEventListener('click', () => { + modal.classList.add('hidden'); + }); + + window.addEventListener('click', (event) => { + if (event.target === modal) { + modal.classList.add('hidden'); + } + }); + + budgetForm.addEventListener('submit', (event) => { + event.preventDefault(); + + // Simplified form data extraction and ID assignment + const newId = Date.now(); + const newBudget = { + id: newId, + category: budgetForm.elements['budget-category'].value, + limit: parseFloat(budgetForm.elements['budget-limit'].value), + spent: 0.00, // Starts at 0 + startDate: new Date().toISOString().slice(0, 10), + endDate: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10), + }; + + budgets.push(newBudget); + saveData(STORAGE_KEYS.BUDGETS, budgets); + renderBudgets(budgets); + modal.classList.add('hidden'); + }); + + + // Initial render + renderBudgets(budgets); +}); \ No newline at end of file diff --git a/Domains/Frontend/MiniProjects/FinanceManager/scripts/dashboard.js b/Domains/Frontend/MiniProjects/FinanceManager/scripts/dashboard.js new file mode 100644 index 00000000..b26f47b4 --- /dev/null +++ b/Domains/Frontend/MiniProjects/FinanceManager/scripts/dashboard.js @@ -0,0 +1,66 @@ +// scripts/dashboard.js +import { loadData, calculateTotal, getSpendingByCategory } from './utils.js'; + +document.addEventListener('DOMContentLoaded', () => { + // 1. Load Data + const transactions = loadData('moneyfy_expenses'); + + // 2. Perform Calculations + const totalIncome = calculateTotal(transactions, 'income'); + const totalExpense = calculateTotal(transactions, 'expense'); + const totalBalance = totalIncome - totalExpense; + const spendingByCategory = getSpendingByCategory(transactions); + + // Example: Calculate Savings Rate + const savingsRate = totalIncome > 0 ? ((totalIncome - totalExpense) / totalIncome) * 100 : 0; + + // 3. Update DOM Elements (Dashboard) + + // Update Total Balance Card + const balanceElement = document.querySelector('.summary-card.primary-accent h2.value'); + if (balanceElement) { + balanceElement.innerHTML = `$${totalBalance.toFixed(2)}`; + } + + // Update Income Card + const incomeElement = document.querySelector('.summary-card.success-accent h2.value'); + if (incomeElement) { + incomeElement.innerHTML = `$${totalIncome.toFixed(2)}`; + } + + // Update Expense Card + const expenseElement = document.querySelector('.summary-card.danger-accent h2.value'); + if (expenseElement) { + expenseElement.innerHTML = `$${totalExpense.toFixed(2)}`; + } + + // Update Savings Rate Card + const rateElement = document.querySelector('.progress-circle'); + if (rateElement) { + const rate = Math.max(0, savingsRate.toFixed(0)); // Cannot be negative for display + rateElement.textContent = `${rate}%`; + rateElement.style.setProperty('--percent', rate); + } + + // 4. Populate Recent Transactions (Simplified Example) + const recentList = document.querySelector('.transaction-list'); + if (recentList) { + recentList.innerHTML = ''; // Clear existing placeholders + const recentTxs = transactions.slice(-5).reverse(); // Get last 5 + recentTxs.forEach(tx => { + const amountClass = tx.type === 'income' ? 'success' : 'danger'; + const sign = tx.type === 'income' ? '+' : '-'; + + const row = document.createElement('div'); + row.classList.add('transaction-row', `${amountClass}-row`); + row.innerHTML = ` + ${tx.description} + ${tx.category} + ${sign}$${tx.amount.toFixed(2)} + `; + recentList.appendChild(row); + }); + } + + // Note: Chart rendering logic (using Chart.js) would go here, utilizing spendingByCategory +}); \ No newline at end of file diff --git a/Domains/Frontend/MiniProjects/FinanceManager/scripts/transactions.js b/Domains/Frontend/MiniProjects/FinanceManager/scripts/transactions.js new file mode 100644 index 00000000..5301270e --- /dev/null +++ b/Domains/Frontend/MiniProjects/FinanceManager/scripts/transactions.js @@ -0,0 +1,100 @@ +// scripts/transactions.js +import { STORAGE_KEYS, loadData, saveData } from './utils.js'; + +document.addEventListener('DOMContentLoaded', () => { + const transactionTableBody = document.querySelector('.transaction-table-container tbody'); + const addTransactionBtn = document.getElementById('add-transaction-btn'); + const modal = document.getElementById('transaction-modal'); + const closeBtn = modal.querySelector('.close-btn'); + const transactionForm = modal.querySelector('form'); + + // Load initial data + let transactions = loadData(STORAGE_KEYS.EXPENSES); + + // --- Core UI Rendering Function --- + function renderTransactions(data) { + if (!transactionTableBody) return; + transactionTableBody.innerHTML = ''; // Clear current rows + + data.forEach(tx => { + const isIncome = tx.type === 'income'; + const amountClass = isIncome ? 'income' : 'expense'; + const sign = isIncome ? '+' : '-'; + const categoryIcon = isIncome ? 'fa-briefcase' : 'fa-house-crack'; // Simplified Icon Logic + + const row = document.createElement('tr'); + row.classList.add('transaction-row-data'); + row.innerHTML = ` + ${tx.date} + ${tx.description} + ${tx.category} + ${sign}$${tx.amount.toFixed(2)} + + + + + `; + transactionTableBody.appendChild(row); + }); + } + + // --- Modal/Form Handling --- + + addTransactionBtn.addEventListener('click', () => { + // Reset form for adding new transaction + transactionForm.reset(); + modal.classList.remove('hidden'); + }); + + closeBtn.addEventListener('click', () => { + modal.classList.add('hidden'); + }); + + window.addEventListener('click', (event) => { + if (event.target === modal) { + modal.classList.add('hidden'); + } + }); + + transactionForm.addEventListener('submit', (event) => { + event.preventDefault(); + + // Simplified form data extraction and ID assignment + const newId = Date.now(); + const newTx = { + id: newId, + date: new Date().toISOString().slice(0, 10), // Mock today's date + description: 'New User Entry', // Replace with real form value + category: 'Uncategorized', // Replace with real form value + amount: 50.00, // Replace with real form value + type: transactionForm.elements.type.value, + }; + + transactions.unshift(newTx); // Add to the start of the array + saveData(STORAGE_KEYS.EXPENSES, transactions); + renderTransactions(transactions); // Re-render the list + modal.classList.add('hidden'); + }); + + // --- Action Listeners (Edit/Delete) --- + transactionTableBody.addEventListener('click', (event) => { + const target = event.target; + const id = parseInt(target.dataset.id); + + if (target.classList.contains('delete-icon')) { + // Mock deletion + if (confirm('Are you sure you want to delete this transaction?')) { + transactions = transactions.filter(tx => tx.id !== id); + saveData(STORAGE_KEYS.EXPENSES, transactions); + renderTransactions(transactions); + } + } else if (target.classList.contains('edit-icon')) { + // Mock edit - in a real app, this would populate the modal + alert(`Editing transaction ID: ${id}. Modal population logic needed here.`); + modal.classList.remove('hidden'); + } + }); + + // Initial render + renderTransactions(transactions); +}); \ No newline at end of file diff --git a/Domains/Frontend/MiniProjects/FinanceManager/scripts/utils.js b/Domains/Frontend/MiniProjects/FinanceManager/scripts/utils.js new file mode 100644 index 00000000..8326fe7c --- /dev/null +++ b/Domains/Frontend/MiniProjects/FinanceManager/scripts/utils.js @@ -0,0 +1,99 @@ +// scripts/utils.js + +// --- 1. Constants and Data Keys --- +const STORAGE_KEYS = { + EXPENSES: 'moneyfy_expenses', + BUDGETS: 'moneyfy_budgets' +}; + +// --- 2. Mock Data Definitions --- +// In a real application, this data would come from a secure API. +let mockData = { + expenses: [ + { id: 1, date: '2025-10-20', description: 'Salary Deposit', category: 'Income', amount: 4250.00, type: 'income' }, + { id: 2, date: '2025-10-21', description: 'Electricity Bill', category: 'Bills', amount: 98.50, type: 'expense' }, + { id: 3, date: '2025-10-21', description: 'Grocery Shopping', category: 'Food & Dining', amount: 125.75, type: 'expense' }, + { id: 4, date: '2025-10-22', description: 'Netflix Subscription', category: 'Subscriptions', amount: 15.99, type: 'expense' }, + { id: 5, date: '2025-10-22', description: 'Dinner Out', category: 'Food & Dining', amount: 75.00, type: 'expense' }, + ], + budgets: [ + { id: 101, category: 'Bills', limit: 1000.00, spent: 950.00, startDate: '2025-10-01', endDate: '2025-10-31' }, + { id: 102, category: 'Food & Dining', limit: 800.00, spent: 580.00, startDate: '2025-10-01', endDate: '2025-10-31' }, + { id: 103, category: 'Leisure & Fun', limit: 400.00, spent: 462.55, startDate: '2025-10-01', endDate: '2025-10-31' }, + ] +}; + +// --- 3. Local Storage Handling (Simulating Database) --- + +/** + * Loads data from localStorage, falling back to mockData if empty. + * @param {string} key - The key for the storage item (e.g., STORAGE_KEYS.EXPENSES) + * @returns {Array} The loaded data array. + */ +function loadData(key) { + const dataJSON = localStorage.getItem(key); + if (dataJSON) { + return JSON.parse(dataJSON); + } + + // Initialize with mock data if storage is empty + if (key === STORAGE_KEYS.EXPENSES) return mockData.expenses; + if (key === STORAGE_KEYS.BUDGETS) return mockData.budgets; + return []; +} + +/** + * Saves data to localStorage. + * @param {string} key - The key for the storage item. + * @param {Array} data - The data array to save. + */ +function saveData(key, data) { + localStorage.setItem(key, JSON.stringify(data)); +} + +// Initial check to populate localStorage with mock data if it's the first run +if (!localStorage.getItem(STORAGE_KEYS.EXPENSES)) { + saveData(STORAGE_KEYS.EXPENSES, mockData.expenses); +} +if (!localStorage.getItem(STORAGE_KEYS.BUDGETS)) { + saveData(STORAGE_KEYS.BUDGETS, mockData.budgets); +} + + +// --- 4. Core Calculation Utilities --- + +/** + * Calculates the total amount for a given data set and type. + * @param {Array} transactions - Array of transaction objects. + * @param {string} type - 'income' or 'expense'. + * @returns {number} The total amount. + */ +function calculateTotal(transactions, type) { + return transactions + .filter(t => t.type === type) + .reduce((total, t) => total + t.amount, 0); +} + +/** + * Groups and sums transactions by category. + * @param {Array} transactions - Array of transaction objects. + * @returns {object} An object with category names as keys and total spent as values. + */ +function getSpendingByCategory(transactions) { + const expenses = transactions.filter(t => t.type === 'expense'); + return expenses.reduce((totals, t) => { + const cat = t.category || 'Uncategorized'; + totals[cat] = (totals[cat] || 0) + t.amount; + return totals; + }, {}); +} + + +// --- 5. Export Public Functions --- +export { + STORAGE_KEYS, + loadData, + saveData, + calculateTotal, + getSpendingByCategory +}; \ No newline at end of file diff --git a/Domains/Frontend/MiniProjects/FinanceManager/settings.css b/Domains/Frontend/MiniProjects/FinanceManager/settings.css new file mode 100644 index 00000000..e6a28253 --- /dev/null +++ b/Domains/Frontend/MiniProjects/FinanceManager/settings.css @@ -0,0 +1,189 @@ +/* settings.css */ +.settings-content { + max-width: var(--max-width); + margin: 0 auto; + padding: 90px 40px var(--spacing-2xl) 40px; +} + +.settings-layout { + display: grid; + grid-template-columns: 250px 1fr; + gap: var(--spacing-xl); +} + +/* Sidebar Navigation */ +.settings-sidebar { + height: fit-content; + padding: var(--spacing-md); + position: sticky; + top: 90px; /* Aligns with header */ +} + +.sidebar-item { + display: block; + padding: 12px 15px; + margin: 5px 0; + color: var(--color-text-secondary); + border-radius: var(--radius-md); + transition: var(--transition-normal); +} + +.sidebar-item i { + margin-right: 10px; +} + +.sidebar-item:hover, .sidebar-item.active { + background-color: var(--color-bg-hover); + color: var(--color-primary); +} + +.sidebar-item.active { + border-left: 3px solid var(--color-primary); + padding-left: 12px; +} + +/* Main Settings Area */ +.settings-main { + display: flex; + flex-direction: column; + gap: var(--spacing-lg); +} + +.settings-section h2 { + color: var(--color-primary); + border-bottom: 1px solid var(--color-border); + padding-bottom: var(--spacing-md); + margin-top: 0; + margin-bottom: var(--spacing-lg); +} + +/* Profile Section */ +.profile-header { + display: flex; + align-items: center; + margin-bottom: var(--spacing-xl); +} + +.avatar-placeholder { + width: 80px; + height: 80px; + border-radius: var(--radius-full); + background-color: var(--color-bg-hover); + border: 3px solid var(--color-primary); + display: flex; + justify-content: center; + align-items: center; + margin-right: var(--spacing-lg); + font-size: 1.5em; + color: var(--color-primary); +} + +.user-info h3 { + margin-bottom: 0; + font-size: 1.5em; +} + +.user-info p { + color: var(--color-text-secondary); +} + +.edit-btn { + font-size: 0.9em; + color: var(--color-primary); + text-decoration: underline; +} + +/* Form Styling */ +.input-group { + margin-bottom: var(--spacing-md); +} + +.input-group label { + display: block; + margin-bottom: 5px; + color: var(--color-text-primary); + font-weight: 500; +} + +/* Toggle Switch Styling */ +.setting-row, .toggle-setting { + display: flex; + justify-content: space-between; + align-items: center; + padding: 10px 0; + border-bottom: 1px dashed var(--color-border); + margin-bottom: var(--spacing-md); +} + +.toggle-switch { + position: relative; + display: inline-block; + width: 50px; + height: 28px; +} + +.toggle-switch input { + opacity: 0; + width: 0; + height: 0; +} + +.slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: var(--color-bg-hover); + transition: 0.4s; + border-radius: 28px; +} + +.slider:before { + position: absolute; + content: ""; + height: 20px; + width: 20px; + left: 4px; + bottom: 4px; + background-color: white; + transition: 0.4s; + border-radius: 50%; +} + +input:checked + .slider { + background-color: var(--color-primary); +} + +input:checked + .slider:before { + transform: translateX(22px); +} + +/* Danger Button */ +.btn-danger { + background-color: var(--color-danger); + color: white; + padding: 10px 20px; + border: none; + border-radius: var(--radius-md); + cursor: pointer; + transition: var(--transition-normal); +} + +.btn-danger:hover { + opacity: 0.9; + box-shadow: 0 4px 15px rgba(255, 0, 110, 0.3); +} + +/* Mobile Responsiveness */ +@media (max-width: 768px) { + .settings-layout { + grid-template-columns: 1fr; /* Stack sidebar and content */ + gap: var(--spacing-lg); + } + .settings-sidebar { + position: static; + width: 100%; + } +} \ No newline at end of file diff --git a/Domains/Frontend/MiniProjects/FinanceManager/settings.html b/Domains/Frontend/MiniProjects/FinanceManager/settings.html new file mode 100644 index 00000000..bada4b4d --- /dev/null +++ b/Domains/Frontend/MiniProjects/FinanceManager/settings.html @@ -0,0 +1,122 @@ + + + + + + MONEYFY - Settings + + + + + + + + + +
+

Settings

+ +
+ + + +
+ +
+

Profile Information

+
+
+ +
+ +
+
+ + +
+
+ + +
+ +
+ +
+

Preferences

+
+ + +
+
+

Show Balance on Dashboard

+ +
+
+

Enable Monthly Reminders

+ +
+ +
+ +
+

Security

+
+

Two-Factor Authentication (2FA)

+ +
+ +
+ +
+

Data & Privacy

+ + +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/Domains/Frontend/MiniProjects/FinanceManager/styles.css b/Domains/Frontend/MiniProjects/FinanceManager/styles.css new file mode 100644 index 00000000..0097f57f --- /dev/null +++ b/Domains/Frontend/MiniProjects/FinanceManager/styles.css @@ -0,0 +1,142 @@ +/* styles.css */ + +/* --- Section 1: CSS Variables (Global Settings) --- */ +:root { + /* Colors */ + --color-primary: #00D9FF; /* Bright Neon Blue */ + --color-primary-hover: #00BFFF; + --color-primary-dark: #0099FF; + --color-primary-text: #000000; /* Text on bright buttons */ + + --color-bg-primary: #000000; /* Deep Black */ + --color-bg-secondary: #0a0a0a; + --color-bg-tertiary: #111111; /* Header/Sidebar BG */ + --color-bg-quaternary: #1a1a1a; /* Card BG */ + --color-bg-hover: #2a2a2a; /* Generic Hover State */ + + --color-text-primary: #E0E0E0; + --color-text-secondary: #A0A0A0; + + --color-success: #00FF41; /* Income/Profit */ + --color-danger: #FF006E; /* Expenses/Losses */ + --color-warning: #FFA500; + + --color-border: #2a2a2a; /* Subtle borders */ + + /* Spacing & Layout */ + --spacing-lg: 24px; + --spacing-xl: 32px; + --max-width: 1400px; + + /* Border Radius */ + --radius-md: 8px; + --radius-lg: 16px; /* Card border-radius */ + + /* Transitions */ + --transition-normal: 0.3s ease; +} + +/* --- Section 2: Global Resets and Typography --- */ +* { + box-sizing: border-box; + margin: 0; + padding: 0; + font-family: 'Poppins', 'Segoe UI', sans-serif; +} + +body { + background-color: var(--color-bg-primary); + color: var(--color-text-primary); + line-height: 1.6; + min-height: 100vh; +} + +h1, h2, h3 { + font-weight: 700; + color: var(--color-text-primary); + margin-bottom: var(--spacing-lg); +} + +a { + text-decoration: none; + color: var(--color-primary); + transition: color var(--transition-normal); +} + +/* --- Section 3: Utility Classes & Components (Based on Section 4) --- */ + +/* Primary Button (CTA) */ +.btn-primary { + background-color: var(--color-primary); + color: var(--color-primary-text); + padding: 12px 32px; + border: none; + border-radius: var(--radius-md); + font-weight: 600; + cursor: pointer; + transition: var(--transition-normal); + box-shadow: 0 0 10px rgba(0, 217, 255, 0); /* Initial shadow for smooth hover */ +} + +.btn-primary:hover { + background-color: var(--color-primary-hover); + box-shadow: 0 8px 24px rgba(0, 217, 255, 0.4); + transform: translateY(-2px); +} + +/* Secondary Button (Ghost) */ +.btn-secondary { + background: transparent; + border: 2px solid var(--color-primary); + color: var(--color-primary); + padding: 10px 28px; + border-radius: var(--radius-md); + font-weight: 600; + cursor: pointer; + transition: var(--transition-normal); +} + +.btn-secondary:hover { + background: rgba(0, 217, 255, 0.1); + border-color: var(--color-primary-hover); + box-shadow: 0 4px 12px rgba(0, 217, 255, 0.2); +} + +/* General Card Styling */ +.card { + background-color: var(--color-bg-quaternary); + border: 1px solid var(--color-border); + border-radius: var(--radius-lg); + padding: var(--spacing-lg); + transition: all var(--transition-normal); + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); +} + +.card:hover { + border-color: var(--color-primary); + transform: scale(1.01); +} + +/* Input/Form Styling */ +.input-group input, .input-group select, .input-group textarea { + background-color: var(--color-bg-quaternary); + border: 1px solid var(--color-border); + border-radius: 6px; + padding: 12px 16px; + color: var(--color-text-primary); + width: 100%; + font-size: 14px; + transition: all var(--transition-normal); +} + +.input-group input:focus, .input-group textarea:focus { + border: 2px solid var(--color-primary); + background-color: var(--color-bg-hover); + outline: none; + box-shadow: 0 0 12px rgba(0, 217, 255, 0.2); +} + +.input-group input::placeholder, .input-group textarea::placeholder { + color: var(--color-text-secondary); + opacity: 0.7; +} \ No newline at end of file diff --git a/Domains/Frontend/MiniProjects/FinanceManager/transactions.css b/Domains/Frontend/MiniProjects/FinanceManager/transactions.css new file mode 100644 index 00000000..462e5018 --- /dev/null +++ b/Domains/Frontend/MiniProjects/FinanceManager/transactions.css @@ -0,0 +1,269 @@ +/* transactions.css */ + +.transactions-content { + max-width: var(--max-width); + margin: 0 auto; + padding: 90px 40px var(--spacing-2xl) 40px; +} + +/* Filter & Search */ +.filters-container { + padding: var(--spacing-lg); + margin-bottom: var(--spacing-lg); + border-top: 4px solid var(--color-primary); /* Neon Blue accent border */ +} + +.filter-bar { + display: flex; + gap: var(--spacing-md); + margin-bottom: var(--spacing-md); +} + +.search-full-width { + flex-grow: 1; +} + +.filter-btn { + white-space: nowrap; + min-width: 120px; +} + +.active-filters { + display: flex; + gap: var(--spacing-sm); +} + +.filter-tag { + background-color: rgba(0, 217, 255, 0.15); + color: var(--color-primary); + padding: 5px 10px; + border-radius: 4px; + font-size: 0.9em; + cursor: pointer; +} + +.filter-tag i { + margin-left: 5px; + font-size: 0.8em; +} + +/* Transaction Table */ +.transaction-table-container { + overflow-x: auto; +} + +table { + width: 100%; + border-collapse: collapse; +} + +th, td { + padding: 16px; + text-align: left; + border-bottom: 1px solid var(--color-border); +} + +thead th { + color: var(--color-primary); + font-weight: 600; + font-size: 0.9em; + text-transform: uppercase; + background-color: var(--color-bg-hover); +} + +tbody tr:nth-child(even) { + background-color: var(--color-bg-secondary); +} + +tbody tr:hover { + background-color: var(--color-bg-hover) !important; + border-left: 4px solid var(--color-primary); + cursor: pointer; +} + +.amount-header, .amount { + text-align: right; +} + +.income-amount { + color: var(--color-success); +} +.expense-amount { + color: var(--color-danger); +} + +.category-tag { + display: inline-block; + padding: 4px 8px; + border-radius: 4px; + font-size: 0.8em; + font-weight: 500; + text-align: center; +} +.income-tag { background-color: rgba(0, 255, 65, 0.15); color: var(--color-success); } +.expense-tag { background-color: rgba(255, 0, 110, 0.15); color: var(--color-danger); } + +.action-icon { + margin-left: 10px; + color: var(--color-text-secondary); + cursor: pointer; + transition: color var(--transition-normal); +} + +.action-icon:hover { + color: var(--color-primary); +} + +.action-icon.delete-icon:hover { + color: var(--color-danger); +} + +/* Pagination */ +.pagination { + display: flex; + justify-content: flex-end; + align-items: center; + padding: var(--spacing-lg) 0; + border-top: 1px solid var(--color-border); + margin-top: var(--spacing-md); +} + +.page-number, .prev-next-btn { + padding: 8px 12px; + margin: 0 5px; + border-radius: 4px; + color: var(--color-text-secondary); + transition: all var(--transition-normal); +} + +.page-number.active-page { + background-color: var(--color-primary); + color: var(--color-primary-text); +} + +.page-number:hover, .prev-next-btn:hover { + background-color: var(--color-bg-hover); + color: var(--color-primary); +} + + +/* Modal Styling */ +.modal-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.8); + display: flex; + justify-content: center; + align-items: center; + z-index: 2000; +} + +.modal-overlay.hidden { + display: none; +} + +.modal-content { + background-color: var(--color-bg-tertiary); + border: 2px solid var(--color-primary); + border-radius: var(--radius-lg); + padding: var(--spacing-xl); + width: 90%; + max-width: 500px; + position: relative; + box-shadow: 0 0 50px rgba(0, 217, 255, 0.5); +} + +.close-btn { + position: absolute; + top: 15px; + right: 25px; + font-size: 2em; + font-weight: 300; + color: var(--color-text-secondary); + cursor: pointer; + transition: color var(--transition-normal); +} + +.close-btn:hover { + color: var(--color-danger); +} + +.radio-group label { + margin-right: var(--spacing-lg); + color: var(--color-text-primary); +} + +.modal-save-btn { + margin-top: var(--spacing-lg); + width: 100%; +} + +/* --- Mobile View for Transactions --- */ +@media (max-width: 767px) { + table, thead, tbody, th, td, tr { + display: block; /* Force table elements to block for card layout */ + } + + thead { + display: none; /* Hide header */ + } + + .transaction-table-container { + padding: 0; + background-color: transparent; + border: none; + } + + .transaction-row-data { + background-color: var(--color-bg-quaternary); + border: 1px solid var(--color-border); + border-radius: var(--radius-lg); + margin-bottom: var(--spacing-md); + padding: var(--spacing-md); + display: grid; + grid-template-areas: + "date amount action" + "desc category action"; + grid-template-columns: 1fr 1fr auto; + } + + .transaction-row-data td { + border: none; + padding: 5px 0; + } + + .transaction-row-data td:nth-child(1) { grid-area: date; font-size: 0.9em; color: var(--color-text-secondary); } + .transaction-row-data td:nth-child(2) { grid-area: desc; font-weight: 600; } + .transaction-row-data td:nth-child(3) { grid-area: category; } + .transaction-row-data td:nth-child(4) { grid-area: amount; text-align: right; font-size: 1.1em;} + .transaction-row-data td:nth-child(5) { + grid-area: action; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + gap: 10px; + border-left: 1px solid var(--color-border); + padding-left: 10px; + } + + .filter-bar { + flex-wrap: wrap; + } + .filter-btn, .search-full-width { + width: calc(50% - 8px); + min-width: 0; + flex-grow: 0; + } + .search-full-width { + width: 100%; + order: -1; + } + #add-transaction-btn { + width: 100%; + margin-top: var(--spacing-md); + } +} \ No newline at end of file diff --git a/Domains/Frontend/MiniProjects/FinanceManager/transactions.html b/Domains/Frontend/MiniProjects/FinanceManager/transactions.html new file mode 100644 index 00000000..2d8a36e5 --- /dev/null +++ b/Domains/Frontend/MiniProjects/FinanceManager/transactions.html @@ -0,0 +1,114 @@ + + + + + + MONEYFY - Transactions + + + + + + + + + +
+

All Transactions

+ +
+
+ + + + + +
+
+ Expense + Oct 2025 +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
DateDescriptionCategoryAmountAction
2025-10-20Monthly Salary Income+$4,250.00 + + +
2025-10-20Electricity Bill Bills-$98.50 + + +
+ +
+ +
+ + + + + + \ No newline at end of file