-
Notifications
You must be signed in to change notification settings - Fork 19
Yana P #8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Yana P #8
Changes from 3 commits
5c86a7a
e64a0db
18de204
6185a53
4bef681
3d93d31
149859f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| { | ||
| "semi": true, | ||
| "singleQuote": true, | ||
| "trailingComma": "es5", | ||
| "printWidth": 80, | ||
| "tabWidth": 2 | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,31 @@ | ||
| // This is the entrypoint for your application. | ||
| // node app.js | ||
| import { | ||
| addTransaction, | ||
| getTransactionsByCategory, | ||
| groupTransactionByMonth, | ||
| printGeneralReport, | ||
| searchTransactionsByDate, | ||
| } from './finance.js'; | ||
| import transactions from './data.js'; | ||
|
|
||
| console.log( | ||
| addTransaction( | ||
| 'expense', | ||
| 'groceries', | ||
| 98, | ||
| 'Weekly supermarket shopping', | ||
| '2026-01-25' | ||
| ) | ||
| ); | ||
|
|
||
| // console.log(getTransactionsByCategory(transactions, 'groceries')); | ||
|
|
||
| // console.log(printGeneralReport(transactions)); | ||
|
|
||
| //Bonus Challenges output | ||
| // console.log(searchTransactionsByDate(transactions, '2025-01-22', '2025-01-25')); | ||
|
|
||
| // Node.js collapses nested objects inside arrays and prints them as [Object]. To see the full structure, I use JSON.stringify(). The second argument (null)means no custom replacer, and the third argument (2) adds indentation for readability. | ||
|
|
||
| console.log(JSON.stringify(groupTransactionByMonth(transactions), null, 2)); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,77 @@ | ||
| // Place here the transaction data array. Use it in your application as needed. | ||
| const transactions = []; | ||
| const transactions = [ | ||
| { | ||
| id: 1, | ||
| type: 'income', | ||
| category: 'salary', | ||
| amount: 3000, | ||
| description: 'Monthly salary', | ||
| date: '2025-01-15', | ||
| }, | ||
| { | ||
| id: 2, | ||
| type: 'expense', | ||
| category: 'groceries', | ||
| amount: 120, | ||
| description: 'Weekly supermarket shopping', | ||
| date: '2025-01-16', | ||
| }, | ||
| { | ||
| id: 3, | ||
| type: 'expense', | ||
| category: 'transport', | ||
| amount: 45, | ||
| description: 'Monthly public transport pass', | ||
| date: '2025-01-17', | ||
| }, | ||
| { | ||
| id: 4, | ||
| type: 'income', | ||
| category: 'freelance', | ||
| amount: 600, | ||
| description: 'Freelance web project', | ||
| date: '2025-01-20', | ||
| }, | ||
| { | ||
| id: 5, | ||
| type: 'expense', | ||
| category: 'entertainment', | ||
| amount: 75, | ||
| description: 'Concert tickets', | ||
| date: '2025-01-21', | ||
| }, | ||
| { | ||
| id: 6, | ||
| type: 'expense', | ||
| category: 'utilities', | ||
| amount: 150, | ||
| description: 'Electricity and water bill', | ||
| date: '2025-01-22', | ||
| }, | ||
| { | ||
| id: 7, | ||
| type: 'income', | ||
| category: 'gift', | ||
| amount: 200, | ||
| description: 'Birthday gift from family', | ||
| date: '2025-01-23', | ||
| }, | ||
| { | ||
| id: 8, | ||
| type: 'expense', | ||
| category: 'health', | ||
| amount: 90, | ||
| description: 'Doctor appointment', | ||
| date: '2025-02-24', | ||
| }, | ||
| { | ||
| id: 9, | ||
| type: 'expense', | ||
| category: 'education', | ||
| amount: 300, | ||
| description: 'Online course fee', | ||
| date: '2025-03-25', | ||
| }, | ||
| ]; | ||
|
|
||
| export default transactions; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,27 +1,176 @@ | ||
| function addTransaction(transaction) { | ||
| // TODO: Implement this function | ||
| import transactions from './data.js'; | ||
| import chalk from 'chalk'; | ||
|
|
||
| export function addTransaction(type, category, amount, description, date) { | ||
| const newTransaction = { | ||
| id: transactions.length + 1, | ||
| type, | ||
| category, | ||
| amount, | ||
| description, | ||
| date, | ||
| }; | ||
|
|
||
| // The assignment requires using the spread operator when adding a transaction. In this task, mutating the existing array with push() feels more suitable, and that is the approach I would normally use if there were no requirement. To satisfy the task while keeping the logic I prefer, I include both: spread for the assignment, and push() for the actual update. | ||
|
|
||
| const updated = [...transactions, newTransaction]; | ||
|
|
||
| transactions.push(newTransaction); | ||
|
|
||
| return updated; | ||
| } | ||
|
|
||
| export function getTotalIncome(transactions) { | ||
| let totalIncome = 0; | ||
| for (const transaction of transactions) { | ||
| if (transaction.type === 'income') { | ||
| totalIncome += transaction.amount; | ||
| } | ||
| } | ||
| return totalIncome; | ||
| } | ||
|
|
||
| export function getTotalExpenses(transactions) { | ||
| let totalExpenses = 0; | ||
| for (const transaction of transactions) { | ||
| if (transaction.type === 'expense') { | ||
| totalExpenses += transaction.amount; | ||
| } | ||
| } | ||
| return totalExpenses; | ||
| } | ||
|
|
||
| export function getBalance(transactions) { | ||
| const totalIncome = getTotalIncome(transactions); | ||
| const totalExpenses = getTotalExpenses(transactions); | ||
| const balance = totalIncome - totalExpenses; | ||
|
|
||
| return balance; | ||
| } | ||
|
|
||
| export function getTransactionsByCategory(transactions, category) { | ||
| let transactionByCategory = []; | ||
|
|
||
| for (const transaction of transactions) { | ||
| if (transaction.category === category) { | ||
| transactionByCategory.push(transaction); | ||
| } | ||
| } | ||
|
|
||
| return transactionByCategory; | ||
| } | ||
|
|
||
| export function getLargestExpense(transactions) { | ||
| const expenseTransactions = transactions.filter( | ||
| (transaction) => transaction.type === 'expense' | ||
| ); | ||
|
|
||
| let largest = expenseTransactions[0]; | ||
|
|
||
| for (const transaction of expenseTransactions) { | ||
| if (transaction.amount > largest.amount) { | ||
| largest = transaction; | ||
| } | ||
| } | ||
|
|
||
| return largest; | ||
| } | ||
|
|
||
| function getTotalIncome() { | ||
| // TODO: Implement this function | ||
| export function printAllTransactions(transactions) { | ||
| let output = chalk.bold('All Transactions:\n'); | ||
|
|
||
| for (const transaction of transactions) { | ||
| const { id, type, category, amount, description } = transaction; | ||
|
|
||
| //formatting values by task requirements with chalk | ||
| const typeFormat = | ||
| type === 'income' | ||
| ? chalk.green(type.toUpperCase()) | ||
| : chalk.red(type.toUpperCase()); | ||
|
|
||
| const categoryFormat = getFirstCharacterToUp(chalk.yellow(category)); | ||
| const amountFormat = chalk.bold(amount); | ||
| const descriptionFormat = description.toLowerCase(); | ||
|
|
||
| //collect all in one line for each element | ||
| const line = `${id}. [${typeFormat}] ${categoryFormat} - €${amountFormat} (${descriptionFormat})`; | ||
|
|
||
| output += `${line}\n`; | ||
| } | ||
|
|
||
| return output; | ||
| } | ||
|
|
||
| function getTotalExpenses() { | ||
| // TODO: Implement this function | ||
| export function printSummary(transactions) { | ||
| //formatting values by task requirements with chalk | ||
| const totalIncome = chalk.bold.green(getTotalIncome(transactions)); | ||
| const totalExpenses = chalk.bold.red(getTotalExpenses(transactions)); | ||
| const numOfTransactions = chalk.bold(transactions.length); | ||
|
|
||
| const balance = | ||
| getBalance(transactions) >= 0 | ||
| ? chalk.bold.cyan(getBalance(transactions)) | ||
| : chalk.bold.red(getBalance(transactions)); | ||
|
|
||
| const { amount, description } = getLargestExpense(transactions); | ||
| const largestExpense = chalk.bold(amount); | ||
|
|
||
| //collect summary | ||
| const summary = `📊 ${chalk.bold('financial summary'.toUpperCase())} 📊 \nTotal Income: €${totalIncome}\nTotal Expenses: €${totalExpenses}\nCurrent Balance: €${balance}\n\nLargest Expense: ${description} (€${largestExpense})\nTotal Transactions: ${numOfTransactions}`; | ||
|
|
||
| return summary; | ||
| } | ||
|
|
||
| function getBalance() { | ||
| // TODO: Implement this function | ||
| export function printGeneralReport(transactions) { | ||
| const allTransactions = printAllTransactions(transactions); | ||
| const summary = printSummary(transactions); | ||
|
|
||
| return `💰 ${chalk.bold('personal finance tracker'.toUpperCase())} 💰\n\n${allTransactions}\n${summary}`; | ||
| } | ||
|
|
||
| function getTransactionsByCategory(category) { | ||
| // TODO: Implement this function | ||
| function getFirstCharacterToUp(word) { | ||
| if (!word) return ''; | ||
| return word[0].toUpperCase() + word.slice(1); | ||
| } | ||
|
|
||
| function getLargestExpense() { | ||
| // TODO: Implement this function | ||
| //Bonus Challenges functions | ||
|
|
||
| export function searchTransactionsByDate(transactions, startDate, endDate) { | ||
| const sorted = transactions | ||
| .slice() | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FYI: there is now an Array.toSorted() function that doesn't mutate the array but returns a new sorted array
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks! I tried using toSorted(), but my Node version (18.x) doesn’t support it yet, so I switched back to .slice().sort(), which works correctly. |
||
| .sort((a, b) => a.date.localeCompare(b.date)); | ||
|
|
||
| const startIndex = sorted.findIndex( | ||
| (transaction) => transaction.date >= startDate | ||
| ); | ||
| const endIndex = sorted.findIndex( | ||
| (transaction) => transaction.date > endDate | ||
| ); | ||
|
|
||
| const range = sorted.slice( | ||
| startIndex, | ||
| endIndex === -1 ? sorted.length : endIndex | ||
| ); | ||
|
|
||
| return range; | ||
| } | ||
|
|
||
| function printAllTransactions() { | ||
| // TODO: Implement this function | ||
| } | ||
| export function groupTransactionByMonth(transactions) { | ||
| let groupedTransactions = {}; | ||
|
|
||
| for (const transaction of transactions) { | ||
| const [year, month] = transaction.date.split('-'); | ||
|
|
||
| if (!groupedTransactions[year]) { | ||
| groupedTransactions[year] = {}; | ||
| } | ||
|
|
||
| if (!groupedTransactions[year][month]) { | ||
| groupedTransactions[year][month] = []; | ||
| } | ||
|
|
||
| groupedTransactions[year][month].push(transaction); | ||
| } | ||
|
|
||
| return groupedTransactions; | ||
| } | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you execute 3 times the same function getBalance(transactions), which is 2 times too much. Better is to store the value of getBalance(transactions) in a variable and then use that variable to check if its value > 0 and then passing it to chalk.bold.cyan() or chalk.bold.red()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for pointing this out!
I refactored the code and now store the result of getBalance(transactions) in a variable instead of calling the function multiple times. The updated version is already pushed.