diff --git a/.gitignore b/.gitignore index 2b76d7c..c2658d7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,158 +1 @@ -# System files -.DS_Store -Thumbs.db -[Dd]esktop.ini - -# hyf -.hyf/score.json - -# Editor and IDE settings -.vscode/ -.idea/ -*.iml -*.code-workspace -*.sublime-project -*.sublime-workspace -.history/ -.ionide/ - -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage -*.lcov - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories node_modules/ -jspm_packages/ - -# Snowpack dependency directory (https://snowpack.dev/) -web_modules/ - -# TypeScript cache -*.tsbuildinfo - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional stylelint cache -.stylelintcache - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variable files -.env -.env.* -!.env.example - -# parcel-bundler cache (https://parceljs.org/) -.cache -.parcel-cache - -# Next.js build output -.next -out - -# Nuxt.js build / generate output -.nuxt -dist - -# Gatsby files -.cache/ -# Comment in the public line in if your project uses Gatsby and not Next.js -# https://nextjs.org/blog/next-9-1#public-directory-support -# public - -# vuepress build output -.vuepress/dist - -# vuepress v2.x temp and cache directory -.temp -.cache - -# Sveltekit cache directory -.svelte-kit/ - -# vitepress build output -**/.vitepress/dist - -# vitepress cache directory -**/.vitepress/cache - -# Docusaurus cache and generated files -.docusaurus - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# Firebase cache directory -.firebase/ - -# TernJS port file -.tern-port - -# Stores VSCode versions used for testing VSCode extensions -.vscode-test - -# yarn v3 -.pnp.* -.yarn/* -!.yarn/patches -!.yarn/plugins -!.yarn/releases -!.yarn/sdks -!.yarn/versions - -# Vite logs files -vite.config.js.timestamp-* -vite.config.ts.timestamp-* - diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..94e30b6 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,6 @@ +{ + "singleQuote": true, + "semi": true, + "trailingComma": "es5", + "printWidth": 80 +} diff --git a/finance-tracker/app.js b/finance-tracker/app.js index 7cfcd07..eaeb637 100644 --- a/finance-tracker/app.js +++ b/finance-tracker/app.js @@ -1,3 +1,59 @@ // This is the entrypoint for your application. // node app.js +const { + addTransaction, + getTotalIncome, + getTotalExpenses, + getBalance, + getTransactionsByCategory, + getLargestExpense, + printAllTransactions, +} = require('./finance.js'); +console.log('Starting application...'); +printAllTransactions(); + +console.log('Total income: €' + getTotalIncome().toFixed(2)); +console.log('Total expenses: €' + getTotalExpenses().toFixed(2)); +console.log('Current balance: €' + getBalance().toFixed(2)); + +addTransaction({ + type: 'expense', + category: 'Food', + amount: 9.5, + description: 'Lunch sandwich', +}); + +addTransaction({ + type: 'income', + category: 'Sale', + amount: 40, + description: 'Sold old headphones', +}); + +console.log('\nAfter adding transactions:'); +printAllTransactions(); + +console.log('New total income: €' + getTotalIncome().toFixed(2)); +console.log('New total expenses: €' + getTotalExpenses().toFixed(2)); +console.log('New balance: €' + getBalance().toFixed(2)); + +console.log("All 'Food' transactions:"); +console.log(getTransactionsByCategory('Food')); + +console.log('\nLargest expense:'); +const biggest = getLargestExpense(); +if (biggest) { + console.log( + '#' + + biggest.id + + ' ' + + biggest.category + + ' €' + + biggest.amount + + ' – ' + + biggest.description + ); +} else { + console.log('No expenses found.'); +} diff --git a/finance-tracker/data.js b/finance-tracker/data.js index d7863ff..7061877 100644 --- a/finance-tracker/data.js +++ b/finance-tracker/data.js @@ -1,2 +1,54 @@ // 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-04' + }, + { + id: 2, + type: 'expense', + category: 'rent', + amount: 1000, + description: 'Pay for the house', + date: '2025-01-06' + }, + { + id: 3, + type: 'income', + category: 'Making hair', + amount: 5000, + description: 'Money earned working in the weekend', + date: '2025-01-29' + }, + { + id: 4, + type: 'expense', + category: 'travel card', + amount: 1500, + description: 'Pay NS for travel card', + date: '2025-01-26' + }, + { + id: 5, + type: 'expense', + category: 'tours', + amount: 2000, + description: 'Saving money for vacancy', + date: '2025-01-10' + }, + { + id: 6, + type: 'expense', + category: 'Subscriptions', + amount: 1000, + description: 'Busuu,Netflix,Spotify,Data', + date: '2025-01-15' + }, + + +]; +module.exports = { transactions }; diff --git a/finance-tracker/finance.js b/finance-tracker/finance.js index ac2118f..73c47b1 100644 --- a/finance-tracker/finance.js +++ b/finance-tracker/finance.js @@ -1,27 +1,105 @@ +const chalk = require("chalk"); +const { transactions } = require("./data.js"); + + function addTransaction(transaction) { // TODO: Implement this function + let maxId = 0; + for (let i = 0; i < transactions.length; i++) { + if (transactions[i].id > maxId) { + maxId = transactions[i].id; + } + } + transaction.id = maxId + 1; + + transactions.push(transaction); + console.log(chalk.green('→ Added transaction #' + transaction.id)); } function getTotalIncome() { // TODO: Implement this function + let total = 0; + for (let i = 0; i < transactions.length; i++) { + if (transactions[i].type === 'income') { + total += transactions[i].amount; + } + } + return total; } function getTotalExpenses() { // TODO: Implement this function + let total = 0; + for (let i = 0; i < transactions.length; i++) { + if (transactions[i].type === 'expense') { + total += transactions[i].amount; + } + } + return total; } function getBalance() { // TODO: Implement this function + return getTotalIncome() - getTotalExpenses(); } function getTransactionsByCategory(category) { // TODO: Implement this function + let found = []; + for (let i = 0; i < transactions.length; i++) { + if (transactions[i].category === category) { + found.push(transactions[i]); + } + } + return found; } function getLargestExpense() { // TODO: Implement this function + let largest = null; + let maxAmount = -1; + + for (let i = 0; i < transactions.length; i++) { + let t = transactions[i]; + if (t.type === 'expense' && t.amount > maxAmount) { + largest = t; + maxAmount = t.amount; + } + } + return largest; } function printAllTransactions() { // TODO: Implement this function -} \ No newline at end of file + console.log(chalk.bold('\n=== Transactions ===')); + console.log(chalk.bold('ID | Type | Amount | Category | Description')); + console.log('-----------------------------------------------'); + + for (let i = 0; i < transactions.length; i++) { + let t = transactions[i]; + let sign = t.type === 'income' ? '+' : '-'; + console.log( + t.id + + ' | ' + + t.type.padEnd(8) + + ' | ' + + sign + + t.amount.toFixed(2).padStart(6) + + ' | ' + + t.category.padEnd(10) + + ' | ' + + t.description + ); + } + console.log('-----------------------------------------------\n'); +} + +module.exports = { + addTransaction, + getTotalIncome, + getTotalExpenses, + getBalance, + getTransactionsByCategory, + getLargestExpense, + printAllTransactions, +}; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..228d484 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,105 @@ +{ + "name": "c55-core-week-4", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "c55-core-week-4", + "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/package.json b/package.json new file mode 100644 index 0000000..6dde4c1 --- /dev/null +++ b/package.json @@ -0,0 +1,27 @@ +{ + "name": "c55-core-week-4", + "version": "1.0.0", + "description": "The week 4 assignment for the HackYourFuture Core program can be found at the following link: https://hub.hackyourfuture.nl/core-program-week-4-assignment", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" ,"format": "prettier --write \"**/*.js\"" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/HackYourAssignment/c55-core-week-4.git" + }, + "keywords": [], + "author": "", + "license": "ISC", + "type": "commonjs", + "bugs": { + "url": "https://github.com/HackYourAssignment/c55-core-week-4/issues" + }, + "homepage": "https://github.com/HackYourAssignment/c55-core-week-4#readme", + "dependencies": { + "chalk": "^4.1.2" + }, + "devDependencies": { + "prettier": "^3.8.1" + } +}