diff --git a/finance-tracker/.prettierrc b/finance-tracker/.prettierrc new file mode 100644 index 0000000..e74ed9f --- /dev/null +++ b/finance-tracker/.prettierrc @@ -0,0 +1,6 @@ +{ + "trailingComma": "es5", + "tabWidth": 4, + "semi": false, + "singleQuote": true +} diff --git a/finance-tracker/app.js b/finance-tracker/app.js index 7cfcd07..3984ab5 100644 --- a/finance-tracker/app.js +++ b/finance-tracker/app.js @@ -1,3 +1,25 @@ // This is the entrypoint for your application. // node app.js +import { + addTransaction, + printAllTransactions, + printSummary, +} from './finance.js' + +const newTransaction = { + id: 6, + type: 'income', + category: 'freelance', + amount: 500, + description: 'Freelance project', + date: '2025-01-20', +} + +addTransaction(newTransaction) + +// Display all transactions +printAllTransactions() + +// Display financial summary +printSummary() diff --git a/finance-tracker/data.js b/finance-tracker/data.js index d7863ff..5be34ff 100644 --- a/finance-tracker/data.js +++ b/finance-tracker/data.js @@ -1,2 +1,45 @@ // Place here the transaction data array. Use it in your application as needed. -const transactions = []; \ No newline at end of file +const transactions = [ + { + id: 1, + type: 'income', + category: 'salary', + amount: 3000, + description: 'Monthly salary', + date: '2025-01-15', + }, + { + id: 2, + type: 'expense', + category: 'groceries', + amount: 150, + description: 'Weekly groceries', + date: '2025-01-16', + }, + { + id: 3, + type: 'expense', + category: 'utilities', + amount: 120, + description: 'Electricity bill', + date: '2025-01-17', + }, + { + id: 4, + type: 'expense', + category: 'entertainment', + amount: 50, + description: 'Movie tickets', + date: '2025-01-18', + }, + { + id: 5, + type: 'income', + category: 'freelance', + amount: 500, + description: 'Freelance project', + date: '2025-01-19', + }, +] + +export default transactions diff --git a/finance-tracker/finance.js b/finance-tracker/finance.js index ac2118f..87f4b2c 100644 --- a/finance-tracker/finance.js +++ b/finance-tracker/finance.js @@ -1,27 +1,117 @@ +import chalk from 'chalk' +const { bold, green, red, yellow, cyan } = chalk +import transactions from './data.js' + +// Add a new transaction. Create a shallow copy using the spread +// operator so the original object passed in isn't mutated by reference. function addTransaction(transaction) { - // TODO: Implement this function + transactions.push({ ...transaction }) } function getTotalIncome() { - // TODO: Implement this function + let totalIncome = 0 + // Use for...of and object destructuring for clarity + for (const transactionItem of transactions) { + const { type, amount } = transactionItem + if (type === 'income') { + totalIncome += amount + } + } + return totalIncome } function getTotalExpenses() { - // TODO: Implement this function + let totalExpenses = 0 + // for...of loop with destructuring improves readability + for (const transactionItem of transactions) { + const { type, amount } = transactionItem + if (type === 'expense') { + totalExpenses += amount + } + } + return totalExpenses } function getBalance() { - // TODO: Implement this function + return getTotalIncome() - getTotalExpenses() } function getTransactionsByCategory(category) { - // TODO: Implement this function + const filteredTransactions = [] + // Use for...of and destructuring to collect matching entries + for (const transactionItem of transactions) { + const { category: transactionCategory } = transactionItem + if (transactionCategory === category) { + filteredTransactions.push(transactionItem) + } + } + return filteredTransactions } function getLargestExpense() { - // TODO: Implement this function + let largestAmount = 0 + // Iterate with destructuring to find the maximum expense amount + for (const transactionItem of transactions) { + const { type, amount } = transactionItem + if (type === 'expense' && amount > largestAmount) { + largestAmount = amount + } + } + return largestAmount } function printAllTransactions() { - // TODO: Implement this function -} \ No newline at end of file + console.log(bold('💰 PERSONAL FINANCE TRACKER 💰\n')) + console.log(bold('All Transactions:')) + // Use for...of for clearer iteration + for (const transactionItem of transactions) { + const { id, type, description, amount, category } = transactionItem + const typeDisplay = type.toUpperCase() + const amountColor = type === 'income' ? green : red + const categoryColor = yellow + console.log( + `${id}. [${typeDisplay}] ${description} - ${amountColor(`€${amount}`)} (${categoryColor(category)})` + ) + } + console.log() +} + +function printSummary() { + const totalIncome = getTotalIncome() + const totalExpenses = getTotalExpenses() + const balance = getBalance() + const largestExpenseAmount = getLargestExpense() + + // Find the largest expense transaction's description. We iterate + // and compare amounts; stop early when we find the matching entry. + let largestExpenseDescription = 'N/A' + for (const transactionItem of transactions) { + const { type, amount, description } = transactionItem + if (type === 'expense' && amount === largestExpenseAmount) { + largestExpenseDescription = description + break + } + } + + const balanceColor = balance >= 0 ? cyan : red + + console.log(bold('📊 FINANCIAL SUMMARY 📊')) + console.log(bold(`Total Income: ${green(`€${totalIncome}`)}`)) + console.log(bold(`Total Expenses: ${red(`€${totalExpenses}`)}`)) + console.log(bold(`Current Balance: ${balanceColor(`€${balance}`)}`)) + console.log( + `\nLargest Expense: ${largestExpenseDescription} (${red(`€${largestExpenseAmount}`)})` + ) + console.log(bold(`Total Transactions: ${transactions.length}`)) +} + +export { + addTransaction, + getTotalIncome, + getTotalExpenses, + getBalance, + getTransactionsByCategory, + getLargestExpense, + printAllTransactions, + printSummary, +} diff --git a/finance-tracker/package-lock.json b/finance-tracker/package-lock.json new file mode 100644 index 0000000..4a2318a --- /dev/null +++ b/finance-tracker/package-lock.json @@ -0,0 +1,105 @@ +{ + "name": "finance-tracker", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "finance-tracker", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "chalk": "^4.1.2" + }, + "devDependencies": { + "prettier": "3.8.1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/prettier": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + } + } +} diff --git a/finance-tracker/package.json b/finance-tracker/package.json new file mode 100644 index 0000000..441d7ca --- /dev/null +++ b/finance-tracker/package.json @@ -0,0 +1,18 @@ +{ + "name": "finance-tracker", + "version": "1.0.0", + "description": "", + "type": "module", + "license": "ISC", + "author": "Atiqa N.", + "main": "app.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "dependencies": { + "chalk": "^4.1.2" + }, + "devDependencies": { + "prettier": "3.8.1" + } +}