From f9e549a7f65bc09ad2ea6d2edc0cff7e985509fb Mon Sep 17 00:00:00 2001 From: Shadi Date: Thu, 16 Apr 2026 21:55:30 +0200 Subject: [PATCH 1/2] Update dependencies and improve database integration - Added better-sqlite3 as a dependency for database management. - Updated .gitignore to include the new database file - Refactored meal and user command functionalities to utilize the new database structure. - Enhanced report generation by integrating user-specific data. - Cleaned up code formatting for better readability and consistency. --- .gitignore | 5 +- package-lock.json | 445 +++++++++++++++++++++++++++- package.json | 1 + src/cli-commands/meals-command.js | 38 ++- src/cli-commands/reports-command.js | 93 ++---- src/cli-commands/user-commands.js | 59 +--- src/databases/food_tracker.db | Bin 40960 -> 0 bytes src/index.js | 37 ++- src/intergrations/ai.js | 15 +- src/intergrations/external-api.js | 41 ++- src/repositories/goal-repository.js | 32 ++ src/repositories/meal-repository.js | 52 +++- src/repositories/user-repository.js | 25 +- src/services/meal-service.js | 43 ++- src/services/user-service.js | 51 ++-- src/utilis/helpers.js | 1 - 16 files changed, 711 insertions(+), 227 deletions(-) delete mode 100644 src/databases/food_tracker.db create mode 100644 src/repositories/goal-repository.js delete mode 100644 src/utilis/helpers.js diff --git a/.gitignore b/.gitignore index 0f63480..457b070 100644 --- a/.gitignore +++ b/.gitignore @@ -141,4 +141,7 @@ vite.config.ts.timestamp-* # OS files .DS_Store Thumbs.db -ehthumbs.db \ No newline at end of file +ehthumbs.db + +# Database files +src/databases/food_tracker.db \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index aee4d27..ab3ca7d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "better-sqlite3": "^12.9.0", "chalk": "^5.6.2", "dotenv": "^17.4.2", "openai": "^6.34.0", @@ -813,6 +814,60 @@ "node": "18 || 20 || >=22" } }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/better-sqlite3": { + "version": "12.9.0", + "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.9.0.tgz", + "integrity": "sha512-wqUv4Gm3toFpHDQmaKD4QhZm3g1DjUBI0yzS4UBl6lElUmXFYdTQmmEDpAFa5o8FiFiymURypEnfVHzILKaxqQ==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "bindings": "^1.5.0", + "prebuild-install": "^7.1.1" + }, + "engines": { + "node": "20.x || 22.x || 23.x || 24.x || 25.x" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "license": "MIT", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, "node_modules/brace-expansion": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", @@ -826,6 +881,30 @@ "node": "18 || 20 || >=22" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/chai": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", @@ -848,6 +927,12 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "license": "ISC" + }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -888,6 +973,30 @@ } } }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -899,7 +1008,6 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "dev": true, "license": "Apache-2.0", "engines": { "node": ">=8" @@ -917,6 +1025,15 @@ "url": "https://dotenvx.com" } }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/es-module-lexer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", @@ -1099,6 +1216,15 @@ "node": ">=0.10.0" } }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "license": "(MIT OR WTFPL)", + "engines": { + "node": ">=6" + } + }, "node_modules/expect-type": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", @@ -1161,6 +1287,12 @@ "node": ">=16.0.0" } }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "license": "MIT" + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -1199,6 +1331,12 @@ "dev": true, "license": "ISC" }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "license": "MIT" + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -1214,6 +1352,12 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "license": "MIT" + }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -1240,6 +1384,26 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -1260,6 +1424,18 @@ "node": ">=0.8.19" } }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC" + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -1628,6 +1804,18 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimatch": { "version": "10.2.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", @@ -1644,6 +1832,21 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "license": "MIT" + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -1670,6 +1873,12 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/napi-build-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", + "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", + "license": "MIT" + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -1677,6 +1886,18 @@ "dev": true, "license": "MIT" }, + "node_modules/node-abi": { + "version": "3.89.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.89.0.tgz", + "integrity": "sha512-6u9UwL0HlAl21+agMN3YAMXcKByMqwGx+pq+P76vii5f7hTPtKDp08/H9py6DY+cfDw7kQNTGEj/rly3IgbNQA==", + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/obug": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", @@ -1688,6 +1909,15 @@ ], "license": "MIT" }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, "node_modules/openai": { "version": "6.34.0", "resolved": "https://registry.npmjs.org/openai/-/openai-6.34.0.tgz", @@ -1835,6 +2065,33 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/prebuild-install": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", + "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", + "deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.", + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^2.0.0", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -1870,6 +2127,16 @@ "strip-ansi": "^5.0.0" } }, + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -1880,6 +2147,35 @@ "node": ">=6" } }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/rolldown": { "version": "1.0.0-rc.13", "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.13.tgz", @@ -1914,6 +2210,38 @@ "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.13" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -1944,6 +2272,51 @@ "dev": true, "license": "ISC" }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "node_modules/sliced": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/sliced/-/sliced-0.0.5.tgz", @@ -1987,6 +2360,15 @@ "dev": true, "license": "MIT" }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -1999,6 +2381,43 @@ "node": ">=6" } }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tar-fs": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", + "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", + "license": "MIT", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/tinybench": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", @@ -2051,6 +2470,18 @@ "license": "0BSD", "optional": true }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -2074,6 +2505,12 @@ "punycode": "^2.1.0" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, "node_modules/vite": { "version": "8.0.7", "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.7.tgz", @@ -2285,6 +2722,12 @@ "node": ">=0.10.0" } }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 5a3cb0d..db10619 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "vitest": "^4.1.3" }, "dependencies": { + "better-sqlite3": "^12.9.0", "chalk": "^5.6.2", "dotenv": "^17.4.2", "openai": "^6.34.0", diff --git a/src/cli-commands/meals-command.js b/src/cli-commands/meals-command.js index b4af72b..91e4242 100644 --- a/src/cli-commands/meals-command.js +++ b/src/cli-commands/meals-command.js @@ -1,25 +1,23 @@ -// Meals command -// ADD , DELETE , MEAL LISt import { addMeal, deleteMeal, listofMeal } from '../services/meal-service.js'; import chalk from 'chalk'; -export async function mealsCli(subcommand, args) { - if (!subcommand) { - console.log(chalk.yellow('Meals commands is: ADD|LIST|DELETE')); - return; - } +export async function mealsCli(subcommand, args, currentUser) { + if (!subcommand) { + console.log(chalk.yellow('Meals commands is: ADD|LIST|DELETE')); + return; + } - switch (subcommand) { - case 'ADD': - await addMeal(...args); - break; - case 'LIST': - await listofMeal(...args); - break; - case 'DELETE': - await deleteMeal(...args); - break; - default: - console.log(chalk.red('Invalid Meal action. Try ADD, LIST, or DELETE.')); - } + switch (subcommand) { + case 'ADD': + await addMeal(currentUser.id); + break; + case 'LIST': + await listofMeal(currentUser.id); + break; + case 'DELETE': + await deleteMeal(...args); + break; + default: + console.log(chalk.red('Invalid Meal action. Try ADD, LIST, or DELETE.')); + } } diff --git a/src/cli-commands/reports-command.js b/src/cli-commands/reports-command.js index 14c034a..965f4a0 100644 --- a/src/cli-commands/reports-command.js +++ b/src/cli-commands/reports-command.js @@ -1,74 +1,39 @@ -// reports -/* -We need here to get the data from database -and also we need calculation -and the recommendation from Ai +import { generateReport } from '../intergrations/ai.js'; +import { getTodaysMealsByUserId } from '../repositories/meal-repository.js'; +import { getUserGoals } from '../repositories/goal-repository.js'; -===================================== - 🍎 DAILY NUTRITION REPORT -===================================== -Date: Friday 11 April 2026 -User: Hannah - -📊 MACROS vs GOALS -------------------------------------- -Calories: 2153 / 2000 ⚠️ slightly above -Protein: 130g / 130g ✅ perfect -Fat: 74g / 70g ⚠️ slightly above -Carbs: 227g / 250g ✅ perfect -Water: 1650ml/ 2000ml ⚠️ drink more -Alcohol: 0 ✅ perfect - -🏆 SCORE: 9/10 - -💡 RECOMMENDATIONS: -1. Reduce cheese portion slightly to lower fat -2. Drink 2 more glasses of water tomorrow -3. Great job on protein — keep it -*/ import chalk from 'chalk'; - -export async function reportCli(subcommand, args) { - if (subcommand === 'SHOW') { - await dailyReports(...args); - } else if(!subcommand === 'SHOW') { - console.log(chalk.red('Invalid Report Command. Try: REPORT SHOW')); - } +export async function reportCli(subcommand, args, currentUser) { + if (subcommand === 'SHOW') { + await dailyReports(currentUser.id); + } else if (!subcommand === 'SHOW') { + console.log(chalk.red('Invalid Report Command. Try: REPORT SHOW')); + } } -export async function fetchDate(params) { -const date = new Date(); -//en-GB is Birtish format to show the date : Day 00-MM-yyyy -const weekday = date.toLocaleDateString('en-GB', { weekday: 'long' }); // long shows the fullName of the day not Fri but Friday. -const day = date.getDate(); -const month = date.toLocaleDateString('en-GB', { month: 'long' }); -const year = date.getFullYear(); +export async function fetchDate() { + const date = new Date(); + const weekday = date.toLocaleDateString('en-GB', { weekday: 'long' }); + const day = date.getDate(); + const month = date.toLocaleDateString('en-GB', { month: 'long' }); + const year = date.getFullYear(); -const formatted = `${weekday} ${day} ${month} ${year}`; // "Friday 11 April 2026" + const formatted = `${weekday} ${day} ${month} ${year}`; -console.log('Date:', formatted); + console.log('Date:', formatted); } -export async function dailyReports() { - console.log('====================================='); - console.log(" 🍎 DAILY NUTRITION REPORT"); - console.log('====================================='); - const date = fetchDate(); - //console.log(date); // ISO timestamp (UTC) - // Need to bring user from DB - console.log(user); - console.log('📊 MACROS vs GOALS'); - console.log('-------------------------------------'); - /*const result = { - calories: 2153 / 2000 ⚠️ slightly above - Protein: 130g / 130g ✅ perfect - Fat: 74g / 70g ⚠️ slightly above - Carbs: 227g / 250g ✅ perfect - Water: 1650ml/ 2000ml ⚠️ drink more - Alcohol: 0 ✅ perfect - }*/ - //console.log('Kcal:') - console.log('🏆 SCORE:'); - console.log('💡 RECOMMENDATIONS:'); +export async function dailyReports(userId) { + console.log('====================================='); + console.log(' 🍎 DAILY NUTRITION REPORT'); + console.log('====================================='); + fetchDate(); + + console.log('📊 MACROS vs GOALS'); + console.log('-------------------------------------'); + const meals = getTodaysMealsByUserId(userId); + const goals = getUserGoals(userId); + const report = await generateReport(goals, meals); + console.log(report); } diff --git a/src/cli-commands/user-commands.js b/src/cli-commands/user-commands.js index 76f0d39..87e7691 100644 --- a/src/cli-commands/user-commands.js +++ b/src/cli-commands/user-commands.js @@ -1,46 +1,9 @@ -/*import { createProfile, login } from '../services/user-service.js'; -import chalk from 'chalk'; -import promptSync from 'prompt-sync'; -//node src/cli-commands/user-commands.js -const prompt = promptSync(); -export async function userCommands() { - while (true) { - try { - console.log(chalk.blue('Welcome to FoodTracker')); - console.log(chalk.blue('Your simple daily food tracker')); - console.log('1. Create Profile'); - console.log('2. Login'); - console.log('3. Exit'); - const userInput = prompt(); - if (userInput === '3') { - console.log('GoodBye Food Tracker'); //adjust - break; - } if (userInput === '1') { - await createProfile(); //needs to be implemented - } else if (userInput === '2') { - await login(); //needs to be implemented - } else { - throw new Error(chalk.red('Invalid command')); - } - } catch (error) { - console.log(error.message); - } - } -} - -userCommands(); -*/ - import { createProfile, login } from '../services/user-service.js'; import chalk from 'chalk'; import promptSync from 'prompt-sync'; const prompt = promptSync(); -/** - * Handles the Authentication phase. - * Returns the user object once logged in so the main loop can start. - */ export async function userCommands() { while (true) { try { @@ -55,29 +18,27 @@ export async function userCommands() { if (userInput === '3') { console.log(chalk.magenta('Goodbye! Stay healthy.')); - process.exit(0); // Closes the app + process.exit(0); } if (userInput === '1') { await createProfile(); - } - else if (userInput === '2') { - const user = await login(); - + } else if (userInput === '2') { + const user = await login(); + if (user) { - console.log(chalk.green(`\nSuccess! Welcome back, ${user.name || 'User'}.`)); - // We RETURN the user object. This breaks the while loop - // and sends control back to index.js - return user; + console.log( + chalk.green(`\nSuccess! Welcome back, ${user.name || 'User'}.`) + ); + return user; } else { console.log(chalk.red('Login failed. Please try again.')); } - } - else { + } else { console.log(chalk.red('Invalid choice. Please enter 1, 2, or 3.')); } } catch (error) { console.log(chalk.red(`User Error: ${error.message}`)); } } -} \ No newline at end of file +} diff --git a/src/databases/food_tracker.db b/src/databases/food_tracker.db deleted file mode 100644 index c19a616a94d53524380ae2d74a0ef1968e344da1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40960 zcmeI)v2NQ&00!VYQjtu#3frOKP@ug|kpRcAY^Otz0%2t;5JF2SMWYEi2#j>H2}@!l z(M^IZXH!t00bZa0SG_<0uXp30oTY{C5!HcgATtNcJ8)zqo6lx z9gO%;#qt%;v3-Zt>RZkYHd}x->P!_X%HplCQ~Gi#YhASHy-96-E^BKKc@XnXD~Q#; z@sB#^i^-Z*T5)=4$<56*H91P2Tg8?ZR4WTiD?DoIx0lc4EX$&gzKDZcJ+5j{tL(TM z-~P;Xl2)){o{124Skv)pw#%-2wQbwG$*ws!S5(%xR>9=6dP6KbuAAgcFM#>AZKvtm z+t=BaQ?++opH+4|&#C*ZNltRiC^{InIrE(xev&W<`sv-<2f-i?<9n>?HtcbccF>E4 zAs?mFz8Xd`4+rU_uDDy7Icj)o=8!w0qlU93x?NERPp1XFcC;7uj*^r>rBQGCo-F~o z`>ko$s7$F>ZFo-YYF(PK$$**UdQR056cwk*q~)k6M$;ryjD{`8b;K~N*v*Q)<>X7H zY}WeJqC}0f(e0kN8EXXxaisRgr!T8k_)zjbIS3RvptXgGedRis@m!94iT_6WQ z(q(VYUR{WK2TuV1XZy_S?32@%)#l7M7FG5S3(8(~ty*a__A2S$?Rh^4dyC%|!7iWr z-{Ilz-pp9vOQnbbq`mGURD)V&wb8`~>(cy(Ye6JX^JgMn2oQh(1Rwwb2tWV=5P$## zAOHafoD_kNX^x!#h*B-)qxgzkt+u1SFScw)d?EGWHS$CHQse|bHUA*ug#ZBvKmY;| zfB*y_009U<00Izzz$p>Xb@jXc$<-wD|F4MoYLbKq1Rwwb2tWV=5P$##AOHafKmYlaR@*F0uX=z1Rwwb2tWV=5P-nx5IAoBUpKqN z{K-5N8w3bI00Izz00bZa0SG_<0uX=z1m0L+RXl{yJ(0ov1^;*UY6AO_hIN%-b(2?}cqn4(Uo(ySz%1+GT0^fWKpEuk3~G zeLf&B=;LDgnf~el|GN3B`2WB8o7f;g00Izz00bZa0SG_<0uX=z1R!u?1u{CJx?E}V z^Z)Y80Nnqd*p5ZRApijgKmY;|fB*y_009U<00Jq2jBd#Le?#8?8%8Q)Jpcccn7^3M z&8O)c#329y2tWV=5P$##AOHafKmY;|cq;;yzCn-qalgJGT|1|57{`=Pw;j*_OKTtw c0SG_<0uX=z1Rwwb2tWV=5I7wI^Yj0I1HAUrPXGV_ diff --git a/src/index.js b/src/index.js index 86fbafc..cd49c12 100644 --- a/src/index.js +++ b/src/index.js @@ -7,7 +7,9 @@ import { reportCli } from './cli-commands/reports-command.js'; const prompt = promptSync(); export function parseCommand(userInput) { - const cleaned = String(userInput || '').trim().replace(/\s+/g, ' '); + const cleaned = String(userInput || '') + .trim() + .replace(/\s+/g, ' '); const [command = '', subcommand = '', ...args] = cleaned.split(' '); return { command: command.toUpperCase(), @@ -20,30 +22,36 @@ async function startApp() { try { const currentUser = await userCommands(); - console.log(chalk.yellow.bold(`\nWhat do you want to do today, ${currentUser.name}?`)); - + console.log( + chalk.yellow.bold(`\nWhat do you want to do today, ${currentUser.name}?`) + ); while (true) { console.log(chalk.blue('\n==============================')); - const userInput = prompt(chalk.cyan(`${currentUser.name} @foodtracker> `)); - - if (userInput === '3' || (userInput && userInput.toUpperCase() === 'EXIT')) { + const userInput = prompt( + chalk.cyan(`${currentUser.name} @foodtracker> `) + ); + + if ( + userInput === '3' || + (userInput && userInput.toUpperCase() === 'EXIT') + ) { console.log(chalk.magenta('Logging out... Goodbye!')); break; } - if (!userInput) continue; // there is no action when user press Enter. + if (!userInput) continue; const { command, subcommand, args } = parseCommand(userInput); if (command === 'MEAL') { - await mealsCli(subcommand, args); - } - else if (command === 'REPORT') { - await reportCli(subcommand, args); - } - else { - console.log(chalk.red('Unknown command. Please use MEAL, REPORT, or 3 to exit.')); + await mealsCli(subcommand, args, currentUser); + } else if (command === 'REPORT') { + await reportCli(subcommand, args, currentUser); + } else { + console.log( + chalk.red('Unknown command. Please use MEAL, REPORT, or 3 to exit.') + ); } } } catch (error) { @@ -52,4 +60,3 @@ async function startApp() { } startApp(); - diff --git a/src/intergrations/ai.js b/src/intergrations/ai.js index 375b587..819fd90 100644 --- a/src/intergrations/ai.js +++ b/src/intergrations/ai.js @@ -13,20 +13,7 @@ export async function generateReport(goal, meals) { GOALS: kcal: ${goal.kcal}, protein: ${goal.protein}g, fat: ${goal.fat}g, carbs: ${goal.carbs}g, water: ${goal.water}ml, caffeine: ${goal.caffeine}mg, alcohol: ${goal.alcohol}ml MEALS: - ${meals.map((meal) => `- ${meal.name}: ${meal.amount} calorie ${meal.nutrition.kcal}kcal, portein ${meal.nutrition.protein}g, fat ${meal.nutrition.fat}g, carbs ${meal.nutrition.carbs}g, water ${meal.nutrition.water}ml, caffeine ${meal.nutrition.caffeine}ml, alcohol${meal.nutrition.alcohol}ml`).join('\n')} - TASK: - 1. Calculate total intake: -    - kcal, protein, fat, carbs -    - Estimate water, caffeine, alcohol if missing - 2. Compare totals to goals: -    - Clearly state if each is: "under", "on target", or "over" - 3. Write a short summary: -    - Start with something positive -    - Then mention the biggest gap - 4. Give a score from 1 to 10 - 5. Give exactly 3 recommendations: -    - Practical and specific -    - Focus on improvement for tomorrow + ${meals.map((meal) => `- ${meal.name}: ${meal.quantity} calorie ${meal.calories}kcal, portein ${meal.protein}g, fat ${meal.fat}g, carbs ${meal.carbs}g, water ${meal.water}ml, caffeine ${meal.caffeine}ml, alcohol ${meal.alcohol}ml`).join('\n')} OUTPUT FORMAT (STRICT): SUMMARY: (2-3 sentences, friendly, starts positive) SCORE: X/10 diff --git a/src/intergrations/external-api.js b/src/intergrations/external-api.js index 0b6f598..19b41c0 100644 --- a/src/intergrations/external-api.js +++ b/src/intergrations/external-api.js @@ -7,7 +7,6 @@ export async function getFirstFdcId(query) { if (!API_KEY) { throw new Error('Missing FDC_API_KEY in .env file'); } - const params = new URLSearchParams({ api_key: API_KEY, @@ -55,7 +54,15 @@ export async function getNutrition(fdcId) { return nutrient?.amount ?? 0; } - return { + function normalizeTo100(value, servingSize) { + if (!servingSize || servingSize <= 0) { + return value; + } + + return (value / servingSize) * 100; + } + + const rawNutrition = { kcal: getNutrientAmount([ 'Energy', 'Energy (Atwater General Factors)', @@ -68,4 +75,34 @@ export async function getNutrition(fdcId) { caffeine: getNutrientAmount(['Caffeine']), alcohol: getNutrientAmount(['Alcohol, ethyl']), }; + + const servingSize = Number(data.servingSize); + const servingSizeUnit = data.servingSizeUnit?.toLowerCase(); + + const canNormalize = + data.dataType === 'Branded' && + servingSize > 0 && + (servingSizeUnit === 'g' || servingSizeUnit === 'ml'); + + if (canNormalize) { + return { + kcal: normalizeTo100(rawNutrition.kcal, servingSize), + protein: normalizeTo100(rawNutrition.protein, servingSize), + fat: normalizeTo100(rawNutrition.fat, servingSize), + carbs: normalizeTo100(rawNutrition.carbs, servingSize), + water: normalizeTo100(rawNutrition.water, servingSize), + caffeine: normalizeTo100(rawNutrition.caffeine, servingSize), + alcohol: normalizeTo100(rawNutrition.alcohol, servingSize), + }; + } + + return { + kcal: rawNutrition.kcal, + protein: rawNutrition.protein, + fat: rawNutrition.fat, + carbs: rawNutrition.carbs, + water: rawNutrition.water, + caffeine: rawNutrition.caffeine, + alcohol: rawNutrition.alcohol, + }; } diff --git a/src/repositories/goal-repository.js b/src/repositories/goal-repository.js new file mode 100644 index 0000000..0c3509f --- /dev/null +++ b/src/repositories/goal-repository.js @@ -0,0 +1,32 @@ +import Database from 'better-sqlite3'; +import { fileURLToPath } from 'url'; +import { dirname, join } from 'path'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); + +const databaseFile = join(__dirname, '../databases/food_tracker.db'); + +const db = new Database(databaseFile); + +export function addGoal( + userId, + kCal, + protein, + fat, + carbs, + water, + caffeine, + alcohol +) { + const goals = db + .prepare( + 'INSERT INTO goals (user_id, kcal, protein, fat, carbs, water, caffeine, alcohol) VALUES (?, ?, ?, ?, ?, ?, ?, ?)' + ) + .run(userId, kCal, protein, fat, carbs, water, caffeine, alcohol); + return goals; +} + +export function getUserGoals(userId) { + const goals = db.prepare('SELECT * FROM goals WHERE user_id = ?').get(userId); + return goals; +} diff --git a/src/repositories/meal-repository.js b/src/repositories/meal-repository.js index c1bdb68..cf6d697 100644 --- a/src/repositories/meal-repository.js +++ b/src/repositories/meal-repository.js @@ -1 +1,51 @@ -//meal repo \ No newline at end of file +import Database from 'better-sqlite3'; +import { fileURLToPath } from 'url'; +import { dirname, join } from 'path'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); + +const databaseFile = join(__dirname, '../databases/food_tracker.db'); + +const db = new Database(databaseFile); + +export function addMeal( + userId, + createdAt, + name, + quantity, + calories, + protein, + fat, + carbs, + water, + caffeine, + alcohol +) { + const meal = db + .prepare( + 'INSERT INTO meals (user_id, created_at, name, quantity, calories, protein, fat, carbs, water, caffeine, alcohol) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)' + ) + .run( + userId, + createdAt, + name, + quantity, + calories, + protein, + fat, + carbs, + water, + caffeine, + alcohol + ); + return meal; +} + +export function getTodaysMealsByUserId(userId) { + const meals = db + .prepare( + "SELECT * FROM meals WHERE user_id = ? AND DATE(created_at) = DATE('now')" + ) + .all(userId); + return meals; +} diff --git a/src/repositories/user-repository.js b/src/repositories/user-repository.js index f7601b3..d131b12 100644 --- a/src/repositories/user-repository.js +++ b/src/repositories/user-repository.js @@ -1 +1,24 @@ -//user repo +import Database from 'better-sqlite3'; +import { fileURLToPath } from 'url'; +import { dirname, join } from 'path'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); + +const databaseFile = join(__dirname, '../databases/food_tracker.db'); + +const db = new Database(databaseFile); + +export function addUser(name, email) { + const user = db + .prepare('INSERT INTO users (name, email) VALUES (?, ?)') + .run(name, email); + + return { id: user.lastInsertRowid, name, email }; +} + +export function getUserByNameAndEmail(name, email) { + const user = db + .prepare('SELECT * FROM users WHERE name = ? AND email = ?') + .get(name, email); + return user; +} diff --git a/src/services/meal-service.js b/src/services/meal-service.js index 373e665..e363717 100644 --- a/src/services/meal-service.js +++ b/src/services/meal-service.js @@ -2,19 +2,9 @@ import promptSync from 'prompt-sync'; import chalk from 'chalk'; const prompt = promptSync(); import { getFirstFdcId, getNutrition } from '../intergrations/external-api.js'; -import { generateReport } from '../intergrations/ai.js'; +import { addMeal as addMealRepository } from '../repositories/meal-repository.js'; -// add delete list -// meal service -// DB -/*export async function getMeals(){ - -}*/ - -/*export async function saveMeals(){ - -}*/ -export async function addMeal() { +export async function addMeal(userId) { const foodName = prompt('Enter food name: '); let foodAmount; while (true) { @@ -25,7 +15,7 @@ export async function addMeal() { } console.log('Choose unit:'); console.log('1. g'); - console.log('2. ml'); // check the units + console.log('2. ml'); const choose = prompt('> ').trim(); let unit = 'g'; if (choose === '1' || choose === 'g') { @@ -48,20 +38,21 @@ export async function addMeal() { nutrition: await calculateNutrition(foodName, foodAmount), createdAt: new Date().toISOString(), }; - console.log( - chalk.green(`ADDED: ${foodName} ${amountWithUnit} ${JSON.stringify(meal.nutrition)}`) + addMealRepository( + userId, + meal.createdAt, + meal.name, + meal.amount, + meal.nutrition.kcal, + meal.nutrition.protein, + meal.nutrition.fat, + meal.nutrition.carbs, + meal.nutrition.water, + meal.nutrition.caffeine, + meal.nutrition.alcohol ); - // hard code the goals just for testing.Temporary - const goals = { - kcal: 2000, - protein: 2000, - fat: 2000, - carbs: 2000, - water: 2000, - caffeine: 2000, - alcohol: 120, - }; - console.log(await generateReport(goals, [meal])); + console.log(chalk.green(`ADDED: ${foodName} ${amountWithUnit}`)); + return meal; } async function calculateNutrition(foodName, foodAmount) { diff --git a/src/services/user-service.js b/src/services/user-service.js index b264cf2..2c98df1 100644 --- a/src/services/user-service.js +++ b/src/services/user-service.js @@ -1,20 +1,20 @@ -//user service -// Get User And Save User import promptSync from 'prompt-sync'; -import fs from 'fs/promises'; -import path from 'path'; import chalk from 'chalk'; -import { mealsCli } from '../cli-commands/meals-command.js'; -import { reportCli } from '../cli-commands/reports-command.js'; +import { + addUser, + getUserByNameAndEmail, +} from '../repositories/user-repository.js'; +import { addGoal } from '../repositories/goal-repository.js'; const prompt = promptSync(); -export async function setGoals() { +export async function setGoals(userId) { const calories = parseFloat(prompt('Enter desired Calories: ')); const protein = parseFloat(prompt('Enter desired Protein: ')); const carbs = parseFloat(prompt('Enter desired Carbs: ')); const fat = parseFloat(prompt('Enter desired Fat: ')); const alcohol = parseFloat(prompt('Enter desired Alcohol: ')); + const caffeine = parseFloat(prompt('Enter desired Caffeine: ')); const water = parseFloat(prompt('Enter desired Water: ')); const goals = { @@ -24,22 +24,13 @@ export async function setGoals() { fat, alcohol, water, + caffeine, + alcohol, }; - /*if{ - throw new Error(chalk.red('Invalid Amount')); - } - //save data in DB*/ + addGoal(userId, calories, protein, fat, carbs, water, caffeine, alcohol); return goals; } -/*export async function getUsers(){ - SELECT -}*/ - -/*export async function saveUsers(){ - ADD -}*/ - export async function createProfile(name, email) { console.log('Enter Your Name:'); name = String(prompt()).trim(); @@ -49,13 +40,13 @@ export async function createProfile(name, email) { throw new Error(chalk.red('ERROR: Must provide name and e-mail')); } console.log(chalk.yellow('\nSet your daily goals:')); - const goals = await setGoals(); + const user = addUser(name, email); + const goals = await setGoals(user.id); const newUser = { name, email, goals }; - - // TODO: await saveUserToDB(newUser); + console.log(chalk.green('Profile created successfully!')); - + return newUser; } @@ -67,13 +58,9 @@ export async function login(name, email) { if (!name || !email) { throw new Error(chalk.red('ERROR: Must provide name and e-mail')); } - const mockUser = { name, email, goals: {} }; - return mockUser; - // We need also to check if the name and email is not correct - // We need to fetch from db here - /*getUsers(); -const found = users.find(user => user.name === name && user.email === email); -if (!found) { - throw new Error(chalk.red('ERROR: Your name or e-mail is not correct')); -}*/ + const user = getUserByNameAndEmail(name, email); + if (!user) { + throw new Error(chalk.red('ERROR: User not found')); + } + return user; } diff --git a/src/utilis/helpers.js b/src/utilis/helpers.js deleted file mode 100644 index 76377f4..0000000 --- a/src/utilis/helpers.js +++ /dev/null @@ -1 +0,0 @@ -//helpers \ No newline at end of file From 937eabea3193b3a95b5a569871cb0a78204e142d Mon Sep 17 00:00:00 2001 From: Shadi Date: Thu, 16 Apr 2026 21:59:34 +0200 Subject: [PATCH 2/2] Update ESLint configuration and clean up user service goals - Changed ESLint language options to use globals.node instead of globals.browser. - Removed duplicate alcohol entry from the goals in setGoals function in user-service.js for improved clarity. --- eslint.config.js | 2 +- src/services/user-service.js | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/eslint.config.js b/eslint.config.js index 2fd2e79..d5ce9c3 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -7,6 +7,6 @@ export default defineConfig([ files: ['**/*.{js,mjs,cjs}'], plugins: { js }, extends: ['js/recommended'], - languageOptions: { globals: globals.browser }, + languageOptions: { globals: globals.node }, }, ]); diff --git a/src/services/user-service.js b/src/services/user-service.js index 2c98df1..7782a3a 100644 --- a/src/services/user-service.js +++ b/src/services/user-service.js @@ -25,7 +25,6 @@ export async function setGoals(userId) { alcohol, water, caffeine, - alcohol, }; addGoal(userId, calories, protein, fat, carbs, water, caffeine, alcohol); return goals;