From c70ce7a11cbb837dadb6a8303c81e08ba7488a8e Mon Sep 17 00:00:00 2001 From: EdKMathew <145998975+EdKMathew@users.noreply.github.com> Date: Sat, 8 Mar 2025 15:31:35 +0530 Subject: [PATCH 01/13] The Think Tank.md --- README.md | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 48a05e012..55bb60b06 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,32 @@ # Define 3.0 -The official template repository for Define 3.0 ![DefineHack 2025 Logo](https://github.com/user-attachments/assets/8173bc16-418e-4912-b500-c6427e4ba4b6) - -# < Project Name > - Cover Image If applicable - +# Finura ### Team Information -- **Team Name**: -- **Track**: < Track > +- **Team Name**: The Think Tank +- **Track**: FinTech ### Team Members | Name | Role | GitHub | LinkedIn | |------|------|--------|----------| -| [Full Name] | [Role] | [@username](https://github.com/username) | [Profile](https://linkedin.com/in/username) | -| [Full Name] | [Role] | [@username](https://github.com/username) | [Profile](https://linkedin.com/in/username) | -| [Full Name] | [Role] | [@username](https://github.com/username) | [Profile](https://linkedin.com/in/username) | -| [Full Name] | [Role] | [@username](https://github.com/username) | [Profile](https://linkedin.com/in/username) | +| Joshua Sunny nian | Chatbot | [Joshualostinearth](https://github.com/Joshualostonearth) | [Profile](https://www.linkedin.com/in/joshua-sunny-ninan-391517271/) | +| Allan Jigi Mathew | info gathering and presnetation | [Allantalks](https://github.com/Allantalks) | [Profile](https://www.linkedin.com/in/allan-jigi-mathew-694104308/) | +| Advaith A Arun | Frontend/Backend | [ADU773](https://github.com/ADU773) | [Profile](https://www.linkedin.com/in/advaith-a-arun-3431a82a7/) | +| Edwin K Mathew | Frontend/Backend | [EdKMathew](https://github.com/EdKMathew) | [Profile](linkedin.com/in/edwin-k-mathew-39a15a296) | ## Project Details ### Overview -_A concise summary of your project (2-3 sentences)_ +We intend to build a basic fintech website that provides users with financial insights and customer support through an AI-powered chatbot. The website will feature a simple dashboard displaying sample financial data in a user-friendly interface. ### Problem Statement -_Describe the problem your project aims to solve_ +Develop a basic prototype of a fintech website with an AI-powered chatbot that provides users with financial insights and customer support. The website should have a clean, user-friendly interface with a simple dashboard displaying sample financial data and a chatbot capable of handling basic FAQs related to fintech services ### Solution -_Explain your approach to solving the problem_ +The fintech website prototype will feature a user-friendly dashboard displaying sample financial data, including account balance, recent transactions, and spending trends. An AI-powered chatbot will handle basic fintech FAQs and provide financial insights such as budgeting tips and savings suggestions. Additionally, the platform will promote sustainability by encouraging digital transactions, eco-friendly financial habits, and energy-efficient coding practices. ### Demo [![Project Demo](https://img.youtube.com/vi/VIDEO_ID/0.jpg)](https://www.youtube.com/watch?v=VIDEO_ID) @@ -49,10 +45,19 @@ _Replace VIDEO_ID with your YouTube video ID or provide an alternative demo link - **DevOps**: [Technologies] - **Other Tools**: [Technologies] -### Key Features -- Feature 1 -- Feature 2 -- Feature 3 +## Key Features +### 1. User-Friendly Dashboard +- Displays sample financial data (e.g., account balance, recent transactions, spending trends). +- Clean UI with easy navigation. + +### 2. AI-Powered Chatbot +- Handles **basic FAQs** related to fintech services (e.g., "How to check my balance?" or "What are the investment options?"). +- Provides **financial insights** such as budgeting tips and savings suggestions. + +### 3. Sustainability Integration +- Encouraging digital transactions to reduce paper waste. +- Promoting eco-friendly financial habits (e.g., sustainable investment options). +- Implementing efficient coding practices for energy conservation. ## Setup Instructions From 99301330685733942dfca4a2eb7394b82b5ef31d Mon Sep 17 00:00:00 2001 From: EdKMathew <145998975+EdKMathew@users.noreply.github.com> Date: Sat, 8 Mar 2025 18:35:06 +0530 Subject: [PATCH 02/13] The Think Tank.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 55bb60b06..4af4f85cd 100644 --- a/README.md +++ b/README.md @@ -38,10 +38,10 @@ _Replace VIDEO_ID with your YouTube video ID or provide an alternative demo link ## Technical Implementation ### Technologies Used -- **Frontend**: [Technologies] +- **Frontend**: React - **Backend**: [Technologies] -- **Database**: [Technologies] -- **APIs**: [Technologies] +- **Database**: MongoDB +- **APIs**: Screener,Mistren - **DevOps**: [Technologies] - **Other Tools**: [Technologies] @@ -97,7 +97,7 @@ _Share your vision for future development_ - [ ] Completed all sections of this README - [ ] Added project demo video - [ ] Provided live project link -- [ ] Ensured all team members are listed +- [x] Ensured all team members are listed - [ ] Included setup instructions - [ ] Submitted final code to repository From 95909b6acef561971ac8eb8e3bdb93cb9f3cbc23 Mon Sep 17 00:00:00 2001 From: EdKMathew <145998975+EdKMathew@users.noreply.github.com> Date: Sat, 8 Mar 2025 21:36:18 +0530 Subject: [PATCH 03/13] The think tank.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4af4f85cd..68af89873 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ ### Team Members | Name | Role | GitHub | LinkedIn | |------|------|--------|----------| -| Joshua Sunny nian | Chatbot | [Joshualostinearth](https://github.com/Joshualostonearth) | [Profile](https://www.linkedin.com/in/joshua-sunny-ninan-391517271/) | +| Joshua Sunny ninan | Chatbot | [Joshualostinearth](https://github.com/Joshualostonearth) | [Profile](https://www.linkedin.com/in/joshua-sunny-ninan-391517271/) | | Allan Jigi Mathew | info gathering and presnetation | [Allantalks](https://github.com/Allantalks) | [Profile](https://www.linkedin.com/in/allan-jigi-mathew-694104308/) | | Advaith A Arun | Frontend/Backend | [ADU773](https://github.com/ADU773) | [Profile](https://www.linkedin.com/in/advaith-a-arun-3431a82a7/) | | Edwin K Mathew | Frontend/Backend | [EdKMathew](https://github.com/EdKMathew) | [Profile](linkedin.com/in/edwin-k-mathew-39a15a296) | From 5a7652d5fbb26d62ee8fb3f832e1718475650861 Mon Sep 17 00:00:00 2001 From: Joshua Sunny Ninan <145998098+Joshualostonearth@users.noreply.github.com> Date: Sat, 8 Mar 2025 21:47:05 +0530 Subject: [PATCH 04/13] Add files via upload --- package-lock.json | 980 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 12 + public/index.html | 231 +++++++++++ server.js | 220 +++++++++++ 4 files changed, 1443 insertions(+) create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 public/index.html create mode 100644 server.js diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..97631bc7e --- /dev/null +++ b/package-lock.json @@ -0,0 +1,980 @@ +{ + "name": "fintech-chatbot", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "fintech-chatbot", + "version": "1.0.0", + "dependencies": { + "express": "^4.18.2", + "mongodb": "^6.14.2" + } + }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.2.0.tgz", + "integrity": "sha512-+ywrb0AqkfaYuhHs6LxKWgqbh3I72EpEgESCw37o+9qPx9WTCkgDm2B+eMrwehGtHBWHFU4GXvnSCNiFhhausg==", + "license": "MIT", + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==", + "license": "MIT" + }, + "node_modules/@types/whatwg-url": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", + "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", + "license": "MIT", + "dependencies": { + "@types/webidl-conversions": "*" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/bson": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.10.3.tgz", + "integrity": "sha512-MTxGsqgYTwfshYWTRdmZRC+M7FnG1b4y7RO7p2k3X24Wq0yv1m77Wsj0BzlPzd/IowgESfsruQCUToa7vbOpPQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=16.20.1" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "license": "MIT" + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mongodb": { + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.14.2.tgz", + "integrity": "sha512-kMEHNo0F3P6QKDq17zcDuPeaywK/YaJVCEQRzPF3TOM/Bl9MFg64YE5Tu7ifj37qZJMhwU1tl2Ioivws5gRG5Q==", + "license": "Apache-2.0", + "dependencies": { + "@mongodb-js/saslprep": "^1.1.9", + "bson": "^6.10.3", + "mongodb-connection-string-url": "^3.0.0" + }, + "engines": { + "node": ">=16.20.1" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.1.0 || ^2.0.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.2.2", + "socks": "^2.7.1" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + }, + "socks": { + "optional": true + } + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.2.tgz", + "integrity": "sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==", + "license": "Apache-2.0", + "dependencies": { + "@types/whatwg-url": "^11.0.2", + "whatwg-url": "^14.1.0 || ^13.0.0" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "license": "MIT" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "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/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "license": "MIT", + "dependencies": { + "memory-pager": "^1.0.2" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tr46": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.1.tgz", + "integrity": "sha512-mDGf9diDad/giZ/Sm9Xi2YcyzaFpbdLpJPr+E9fSkyQ7KpQD4SdFcugkRQYzhmfI4KeV4Qpnn2sKPdo+kmsgRQ==", + "license": "MIT", + "dependencies": { + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 000000000..d0f731771 --- /dev/null +++ b/package.json @@ -0,0 +1,12 @@ +{ + "name": "fintech-chatbot", + "version": "1.0.0", + "main": "server.js", + "scripts": { + "start": "node server.js" + }, + "dependencies": { + "express": "^4.18.2", + "mongodb": "^6.14.2" + } +} diff --git a/public/index.html b/public/index.html new file mode 100644 index 000000000..c231cd642 --- /dev/null +++ b/public/index.html @@ -0,0 +1,231 @@ + + + + + + FinTech FAQ Chatbot + + + +

FinBot

+
+
+ + +
+ + + + \ No newline at end of file diff --git a/server.js b/server.js new file mode 100644 index 000000000..352ccae70 --- /dev/null +++ b/server.js @@ -0,0 +1,220 @@ +// server.js +const express = require('express'); +const app = express(); +const port = 3000; + +// Configuration +const API_TOKEN = "xyz"; // Your Hugging Face token +const API_URL = "https://api-inference.huggingface.co/models/mistralai/Mixtral-8x7B-Instruct-v0.1"; +const headers = { + "Authorization": `Bearer ${API_TOKEN}`, + "Content-Type": "application/json" +}; + +// Basic FAQ database +const faqDatabase = { + "what is a stock": "A stock represents ownership in a company. When you buy a stock, you own a small piece of that company.", + "how do i invest": "To invest, you typically need to open a brokerage account, deposit funds, and then choose investments like stocks, bonds, or mutual funds.", + "what is interest": "Interest is the cost of borrowing money or the return earned on savings/investments, usually expressed as a percentage." +}; + +// Hardcoded exchange rates (for demo purposes; replace with API in production) +const exchangeRates = { + "aed": { "inr": 23.6569 }, // 1 UAE Dirham to Indian Rupee (approx. March 8, 2025) + "usd": { "inr": 83.50 }, // 1 US Dollar to Indian Rupee + "inr": { "aed": 0.04227 } // 1 Indian Rupee to UAE Dirham +}; + +// Middleware +app.use(express.json()); +app.use(express.static('public')); + +// Helper function for FAQ checking +function checkFAQ(message) { + const lowerMessage = message.toLowerCase().trim(); + return faqDatabase[lowerMessage] || null; +} + +// Function to convert **text** to text +function formatBoldText(text) { + return text.replace(/\*\*(.*?)\*\*/g, '$1'); +} + +// Helper function to check if the question is finance-related +function isFinanceRelated(message) { + const lowerMessage = message.toLowerCase().trim(); + const financeKeywords = [ + // General Finance Terms + 'stock', 'invest', 'interest', 'finance', 'money', 'budget', 'savings', 'retirement', + 'bank', 'loan', 'credit', 'debt', 'fund', 'bond', 'mutual', 'portfolio', 'economy', + 'financial', 'wealth', 'trade', 'trading', 'currency', 'tax', 'insurance', 'mortgage', + 'dividend', 'equity', 'crypto', 'cryptocurrency', 'market', 'capital', 'asset', 'liability', + 'dirham', 'dharam', 'dh', 'dhs', 'aed', 'rupee', 'rupies', 'inr', 'dollar', 'usd', + 'exchange', 'rate', 'convert', 'fixed', 'deposit', 'account', 'return', 'principal', + + // Digital Banking Terms + 'upi', 'netbanking', 'neft', 'rtgs', 'imps', 'wallet', 'paytm', 'google pay', 'apple pay', + 'paypal', 'venmo', 'revolut', 'stripe', 'square', 'fintech', 'digital wallet', + 'virtual card', 'contactless', 'online banking', 'mobile banking', 'qr code', 'upi pin', + + // Investment and Trading Terms + 'etf', 'index fund', 'stock market', 'broker', 'payment','nifty', 'sensex', 'forex', 'nasdaq', + 'ipo', 'shares', 'bull market', 'bear market', 'futures', 'options', 'hedge fund', + 'short selling', 'leveraged', 'derivatives', 'stop loss', 'blue chip', + + // Financial Services Terms + 'lending', 'microfinance', 'remittance', 'wire transfer', 'overdraft', + 'credit score', 'fico', 'bank statement', 'atm', 'cheque', 'checkbook', + 'credit card', 'debit card', 'prepaid card', 'interest rate', 'balance transfer', + 'loan emi', 'emi calculator', 'mortgage calculator', 'personal loan', 'home loan', + 'auto loan', 'student loan', 'refinance', 'collateral', 'default', 'foreclosure', + + // Accounting & Bookkeeping + 'invoice', 'ledger', 'audit', 'cash flow', 'profit', 'loss', 'balance sheet', + 'income statement', 'tax filing', 'gst', 'vat', 'capital gains', 'net worth', + 'payroll', 'dividends', 'expense report', + + // International Finance & Currencies + 'euro', 'eur', 'pound', 'gbp', 'yen', 'jpy', 'yuan', 'cny', 'franc', 'chf', + 'peso', 'cad', 'aud', 'krw', 'sgd', 'idr', 'myr', 'zar', + + // Crypto-Specific Terms + 'blockchain', 'bitcoin', 'ethereum', 'dogecoin', 'nft', 'mining', 'wallet address', + 'ledger', 'defi', 'metamask', 'cold wallet', 'hot wallet', + + // Banking & Account Management Keywords + 'account balance', 'check balance', 'reset password', 'lost card', 'stolen card', + 'replace card', 'contact information', 'update details', 'two-factor', '2fa', + 'authentication', 'security question', 'pin code', 'pin number', 'account number', + 'routing number', 'iban', 'swift code', 'branch code', 'internet banking', + + // Digital Transactions & Payments Keywords + 'online payment', 'payment failed', 'transaction failed', 'payment declined', + 'spending limit', 'card limit', 'transaction limit', 'digital wallet', 'e-wallet', + 'e-statement', 'paperless', 'contactless payment', 'tap to pay', 'nfc payment', + 'merchant', 'pos terminal', 'payment gateway', 'payment processor', 'chargeback', + 'refund', 'transaction history', 'pending transaction', 'authorized payment', + + // Budgeting & Financial Insights Keywords + 'track expenses', 'expense tracking', 'monthly expenses', '50/30/20 rule', + 'budgeting rule', 'reduce spending', 'cut expenses', 'financial planning', + 'credit score', 'improve credit', 'fico score', 'utility bills', 'financial goal', + 'spending habit', 'financial health', 'money management', 'expense ratio', + 'cash flow', 'discretionary spending', 'necessary expenses', 'zero-based budget', + + // Security & Fraud Prevention Keywords + 'phishing', 'scam', 'fraud', 'suspicious activity', 'suspicious transaction', + 'security breach', 'data breach', 'identity theft', 'secure transaction', + 'tokenization', 'password manager', 'strong password', 'secure password', + 'account security', 'transaction alert', 'fraud alert', 'security question', + 'biometric', 'fingerprint', 'face recognition', 'voice recognition', + + // Sustainability & Eco-Friendly Finance Keywords + 'green investment', 'sustainable investment', 'esg', 'environmental', + 'social', 'governance', 'carbon footprint', 'carbon neutral', 'eco-friendly', + 'paperless statement', 'digital statement', 'socially responsible', + 'ethical investing', 'impact investing', 'green bond', 'climate risk', + 'sustainability', 'renewable energy', 'clean energy', 'green banking', + 'sustainable finance', 'green credit card', 'eco card' + ]; + + return financeKeywords.some(keyword => lowerMessage.includes(keyword)); +} + + +// Helper function to handle currency conversion +function handleCurrencyConversion(message) { + const lowerMessage = message.toLowerCase().trim(); + const conversionPattern = /(?:how much is|what is|convert)\s*(\d*\.?\d*)\s*(dirham|dharam|dh|dhs|aed|dollar|usd|rupee|rupies|inr)\s*(in|to|into)?\s*(dirham|dharam|dh|dhs|aed|dollar|usd|rupee|rupies|inr)/i; + const match = lowerMessage.match(conversionPattern); + + if (match) { + const amount = parseFloat(match[1]) || 1; + let fromCurrency = match[2].toLowerCase() + .replace(/dharam|dh|dhs/, 'aed') + .replace(/dollar/, 'usd') + .replace(/rupies|rupee/, 'inr'); + let toCurrency = match[4].toLowerCase() + .replace(/dharam|dh|dhs/, 'aed') + .replace(/dollar/, 'usd') + .replace(/rupies|rupee/, 'inr'); + + const fromRate = exchangeRates[fromCurrency]; + if (fromRate && fromRate[toCurrency]) { + const rate = fromRate[toCurrency]; + const convertedAmount = amount * rate; + return `FinBot: ${amount} ${fromCurrency.toUpperCase()} is approximately ${convertedAmount.toFixed(2)} ${toCurrency.toUpperCase()} based on current exchange rates.`; + } else { + return "FinBot: Sorry, I don’t have the exchange rate for that currency pair."; + } + } + return null; +} + +// Chat endpoint +app.post('/chat', async (req, res) => { + const { message } = req.body; + try { + // Check if the question is finance-related + if (!isFinanceRelated(message)) { + const response = "FinBot: I can't help you with that, can you ask about something related to finance?"; + return res.json({ response }); + } + + // Check for currency conversion + const conversionResponse = handleCurrencyConversion(message); + if (conversionResponse) { + return res.json({ response: conversionResponse }); + } + + // Check FAQ first + const faqAnswer = checkFAQ(message); + if (faqAnswer) { + const formattedResponse = formatBoldText(`FinBot: ${faqAnswer}`); + return res.json({ response: formattedResponse }); + } + + // Fallback to model using built-in fetch + const prompt = `[INST] You are a FinTech expert. Provide a concise answer to this finance-related question with numbered steps where applicable, using **text** to highlight key points. If the question is not finance-related, respond only with: "I can't help you with that, can you ask about something related to finance?": ${message} [/INST]`; + const response = await fetch(API_URL, { + method: 'POST', + headers: headers, + body: JSON.stringify({ + inputs: prompt, + parameters: { + max_length: 150, + temperature: 0.7, + top_p: 0.95 + } + }) + }); + + if (!response.ok) { + const errorText = await response.text(); + throw new Error(`HTTP error! status: ${response.status}, details: ${errorText}`); + } + + const data = await response.json(); + if (!data[0]?.generated_text) { + throw new Error('Invalid response format from API'); + } + + const botResponse = formatBoldText( + data[0].generated_text.replace(prompt, "").trim() + ); + res.json({ response: `FinBot: ${botResponse}` }); + } catch (error) { + console.error('Error:', error.message); + const errorResponse = formatBoldText(`FinBot: Sorry, I encountered an error: ${error.message}`); + res.status(500).json({ response: errorResponse }); + } +}); + +// Serve the HTML file +app.get('/', (req, res) => { + res.sendFile(__dirname + '/public/index.html'); +}); + +app.listen(port, () => { + console.log(`Server running at http://localhost:${port}`); +}); \ No newline at end of file From 418706d490beb50ee89f73118e202e03b10e981a Mon Sep 17 00:00:00 2001 From: Advaith A Arun <148091632+ADU773@users.noreply.github.com> Date: Sat, 8 Mar 2025 21:48:24 +0530 Subject: [PATCH 05/13] Add files via upload --- src/Analitics.jsx | 24 ++++ src/App.css | 49 +++++++ src/components/Analytics.jsx | 74 +++++++++++ src/components/Dashboard.jsx | 75 +++++++++++ src/components/LoginButton.jsx | 18 +++ src/components/LoginModal.jsx | 53 ++++++++ src/components/StateDropdown.jsx | 25 ++++ src/main.jsx | 28 ++++ src/mainpage.jsx | 40 ++++++ src/mainpagestyle.css | 174 ++++++++++++++++++++++++ src/navbar.jsx | 31 +++++ src/styles/analytics.css | 37 ++++++ src/styles/dashboard.css | 219 +++++++++++++++++++++++++++++++ src/styles/loginButton.css | 20 +++ src/styles/loginModal.css | 95 ++++++++++++++ src/styles/navbar.css | 214 ++++++++++++++++++++++++++++++ src/styles/stateDropdown.css | 34 +++++ src/transaction.jsx | 64 +++++++++ src/utils/product_trancation.jsx | 64 +++++++++ src/utils/userData.jsx | 50 +++++++ 20 files changed, 1388 insertions(+) create mode 100644 src/Analitics.jsx create mode 100644 src/App.css create mode 100644 src/components/Analytics.jsx create mode 100644 src/components/Dashboard.jsx create mode 100644 src/components/LoginButton.jsx create mode 100644 src/components/LoginModal.jsx create mode 100644 src/components/StateDropdown.jsx create mode 100644 src/main.jsx create mode 100644 src/mainpage.jsx create mode 100644 src/mainpagestyle.css create mode 100644 src/navbar.jsx create mode 100644 src/styles/analytics.css create mode 100644 src/styles/dashboard.css create mode 100644 src/styles/loginButton.css create mode 100644 src/styles/loginModal.css create mode 100644 src/styles/navbar.css create mode 100644 src/styles/stateDropdown.css create mode 100644 src/transaction.jsx create mode 100644 src/utils/product_trancation.jsx create mode 100644 src/utils/userData.jsx diff --git a/src/Analitics.jsx b/src/Analitics.jsx new file mode 100644 index 000000000..e3c59ea80 --- /dev/null +++ b/src/Analitics.jsx @@ -0,0 +1,24 @@ +//Main page for the analytics section + +import React from "react"; +import { BarChart, Bar, XAxis, YAxis, Tooltip, Legend, ResponsiveContainer } from "recharts"; + +const AnalyticsChart = ({ data }) => { + return ( +
+

Income vs Outcome

+ + + + + + + + + + +
+ ); +}; + +export default AnalyticsChart; diff --git a/src/App.css b/src/App.css new file mode 100644 index 000000000..6ef416aff --- /dev/null +++ b/src/App.css @@ -0,0 +1,49 @@ +#root { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +.logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: filter 300ms; +} +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); +} +.logo.react:hover { + filter: drop-shadow(0 0 2em #61dafbaa); +} + +@keyframes logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +@media (prefers-reduced-motion: no-preference) { + a:nth-of-type(2) .logo { + animation: logo-spin infinite 20s linear; + } +} + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; +} + +@media screen and (max-width: 768px) { + #root { + max-width: 100%; + padding: 1rem; + } +} diff --git a/src/components/Analytics.jsx b/src/components/Analytics.jsx new file mode 100644 index 000000000..f0e046f61 --- /dev/null +++ b/src/components/Analytics.jsx @@ -0,0 +1,74 @@ +import React, { useState, useEffect } from "react"; +import { BarChart, Bar, XAxis, YAxis, Tooltip, Legend, ResponsiveContainer } from "recharts"; +import { fetchGooglePayTransactions } from "../utils/product_trancation.jsx"; // Add .jsx extension + +const AnalyticsChart = () => { + const [transactionData, setTransactionData] = useState([]); + const [year, setYear] = useState("2024"); + + useEffect(() => { + // Fetch transactions (Replace with real API call) + const loadTransactions = async () => { + const transactions = await fetchGooglePayTransactions(); + setTransactionData(transactions); + }; + loadTransactions(); + }, []); + + // Function to process transactions and get income & outcome per month + const getMonthlyData = () => { + const monthlyData = Array.from({ length: 12 }, (_, index) => ({ + month: new Date(2024, index, 1).toLocaleString("en-US", { month: "short" }), + income: 0, + outcome: 0, + })); + + transactionData.forEach((txn) => { + const txnDate = new Date(txn.date); + const txnYear = txnDate.getFullYear().toString(); + if (txnYear === year) { + const monthIndex = txnDate.getMonth(); + if (txn.type === "income") { + monthlyData[monthIndex].income += txn.amount; + } else if (txn.type === "outcome") { + monthlyData[monthIndex].outcome += txn.amount; + } + } + }); + + return monthlyData; + }; + + return ( +
+

Analytics

+ + + + + + + + + + + + +
+ ); +}; + +export default AnalyticsChart; diff --git a/src/components/Dashboard.jsx b/src/components/Dashboard.jsx new file mode 100644 index 000000000..044c7f9b6 --- /dev/null +++ b/src/components/Dashboard.jsx @@ -0,0 +1,75 @@ +import React, { useState } from 'react'; +import { useNavigate } from 'react-router-dom'; +import '../styles/dashboard.css'; +import AnalyticsChart from './Analytics'; + +function Dashboard() { + const navigate = useNavigate(); + const [showLogoutConfirm, setShowLogoutConfirm] = useState(false); + + const handleLogoutClick = () => { + setShowLogoutConfirm(true); + }; + + const handleLogoutConfirm = () => { + localStorage.removeItem('isAuthenticated'); + localStorage.removeItem('currentUser'); + navigate('/'); + }; + + return ( +
+
+
Finura
+ + +
+ + {showLogoutConfirm && ( +
+
+

Confirm Logout

+

Are you sure you want to logout?

+
+ + +
+
+
+ )} + +
+
+
+

Financial Overview

+ +
+
+ +
+
+
+

AI Assistant

+
+
+
+ Hello! How can I help you with your finances today? +
+
+
+ + +
+
+
+
+
+ ); +} + +export default Dashboard; \ No newline at end of file diff --git a/src/components/LoginButton.jsx b/src/components/LoginButton.jsx new file mode 100644 index 000000000..9e3b15a2c --- /dev/null +++ b/src/components/LoginButton.jsx @@ -0,0 +1,18 @@ +import React, { useState } from 'react'; +import '../styles/loginButton.css'; +import LoginModal from './LoginModal'; + +function LoginButton() { + const [showModal, setShowModal] = useState(false); + + return ( + <> + + {showModal && setShowModal(false)} />} + + ); +} + +export default LoginButton; diff --git a/src/components/LoginModal.jsx b/src/components/LoginModal.jsx new file mode 100644 index 000000000..61cc6281d --- /dev/null +++ b/src/components/LoginModal.jsx @@ -0,0 +1,53 @@ +import React, { useState } from 'react'; +import '../styles/loginModal.css'; +import { authenticateUser } from '../utils/userData'; + +function LoginModal({ onClose }) { + const [credentials, setCredentials] = useState({ email: '', password: '' }); + const [error, setError] = useState(''); + + const handleSubmit = (e) => { + e.preventDefault(); + const result = authenticateUser(credentials.email, credentials.password); + + if (result.success) { + localStorage.setItem('isAuthenticated', 'true'); + localStorage.setItem('currentUser', JSON.stringify(result.user)); + window.location.href = '/dashboard'; + onClose(); + } else { + setError(result.message); + } + }; + + return ( +
+
+ +

Login

+
+ setCredentials({...credentials, email: e.target.value})} + /> + setCredentials({...credentials, password: e.target.value})} + /> + +
+ {error &&
{error}
} +
+ Forgot Password? + Create Account +
+
+
+ ); +} + +export default LoginModal; diff --git a/src/components/StateDropdown.jsx b/src/components/StateDropdown.jsx new file mode 100644 index 000000000..e2d297591 --- /dev/null +++ b/src/components/StateDropdown.jsx @@ -0,0 +1,25 @@ +import React from 'react'; +import '../styles/stateDropdown.css'; + +function StateDropdown() { + const indianStates = [ + "Andhra Pradesh", "Arunachal Pradesh", "Assam", "Bihar", "Chhattisgarh", + "Goa", "Gujarat", "Haryana", "Himachal Pradesh", "Jharkhand", "Karnataka", + "Kerala", "Madhya Pradesh", "Maharashtra", "Manipur", "Meghalaya", "Mizoram", + "Nagaland", "Odisha", "Punjab", "Rajasthan", "Sikkim", "Tamil Nadu", + "Telangana", "Tripura", "Uttar Pradesh", "Uttarakhand", "West Bengal" + ]; + + return ( +
+ +
+ ); +} + +export default StateDropdown; diff --git a/src/main.jsx b/src/main.jsx new file mode 100644 index 000000000..b52fcaba4 --- /dev/null +++ b/src/main.jsx @@ -0,0 +1,28 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' +import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom' +import MainPage from './mainpage.jsx' +import Dashboard from './components/Dashboard.jsx' +import Navbar from './navbar.jsx' +import './mainpagestyle.css' + +const ProtectedRoute = ({ children }) => { + const isAuthenticated = localStorage.getItem('isAuthenticated') === 'true'; + return isAuthenticated ? children : ; +}; + +ReactDOM.createRoot(document.getElementById('root')).render( + + + + } /> + + + + } /> + + + , +) + diff --git a/src/mainpage.jsx b/src/mainpage.jsx new file mode 100644 index 000000000..01fa9bdaf --- /dev/null +++ b/src/mainpage.jsx @@ -0,0 +1,40 @@ +import React from 'react'; +import './mainpagestyle.css'; +import StateDropdown from './components/StateDropdown'; +import LoginButton from './components/LoginButton'; +//import AnalyticsChart from './components/Analytics'; +import AnalyticsChart from 'C:\\Users\\aadva\\fintechai\\src\\Analitics.jsx'; + +function MainPage() { + return ( + <> + +
+ + +
+ +
+
+
Finura
+
"Empowering users with AI-driven financial insights and
seamless support through a smart, user-friendly fintech
dashboard."
+
+ +
+

Welcome to the Future

+

Explore our services and products

+
+ +
+
+

Financial Overview

+

Track your income and expenses effortlessly

+ +
+
+
+ + ); +} + +export default MainPage; diff --git a/src/mainpagestyle.css b/src/mainpagestyle.css new file mode 100644 index 000000000..41ccb69e6 --- /dev/null +++ b/src/mainpagestyle.css @@ -0,0 +1,174 @@ +@font-face { + font-family: 'Gilroy-Bold'; + src: local('Gilroy-Bold'), url(./fonts/Gilroy-Bold.ttf) format('truetype'); + } + + @font-face { + font-family: 'Gilroy-Medium'; + src: local('Gilroy-Medium'), url(./fonts/Gilroy-Medium.ttf) format('truetype'); + } + + @font-face { + font-family: 'Gilroy-Light'; + src: local('Gilroy-Light'), url(./fonts/Gilroy-Light.ttf) format('truetype'); + } + +h1 { + color: #333; + font-size: 2.5rem; +} + +h2 { + color: #666; + font-size: 1.8rem; +} + +body { + background: #1A1A1A; + margin: 0; + padding: 0; +} + +html, body { + overflow-x: hidden; + scrollbar-width: thin; + scrollbar-color: #774EBD rgba(255, 255, 255, 0.1); +} + +.state-dropdown{ + margin-top: 35.74px; + margin-left: 1166.26px; + margin-right: 314px; +} + +.page-container { + height: 100vh; + overflow-y: auto; + position: relative; + max-width: 100vw; + overflow-x: hidden; +} + +.section { + min-height: 100vh; + width: 100%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + position: relative; +} + +.section-two { + background: #1A1A1A; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding: 2rem; +} + +.section-two h1 { + color: rgba(255, 255, 255, 0.87); + font-family:Arial, Helvetica, sans-serif; + font-size: 64px; + margin-bottom: 2rem; +} + +.Mainheading { + text-align: center; + font-family:Arial, Helvetica, sans-serif; + font-size: 250.821px; + font-style: normal; + font-weight: 400; + color: transparent; + line-height: normal; + background: linear-gradient(90deg, #774EBD 0%, #372457 100%); + background-clip: text; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + margin-top: 1rem; + margin-left: 496px; + margin-right: 495.65px; +} + +.smallpara{ + color: #FFF; + text-align: center; + font-family:Arial, Helvetica, sans-serif; + font-size: 36px; + font-style: normal; + font-weight: 300; + line-height: normal; + margin-top: 10px; + +} + +.top-controls { + position: fixed; + top: 0; + left: 0; + right: 0; + padding: 20px; + z-index: 1000; + display: flex; + justify-content: space-between; + align-items: center; +} + +@media screen and (max-width: 1200px) { + .Mainheading { + font-size: 180px; + margin: 150px 20px; + } + + .smallpara { + font-size: 28px; + margin: 20px; + } +} + +@media screen and (max-width: 768px) { + body { + margin-left: 0; + } + + .Mainheading { + font-size: 120px; + margin: 100px 15px; + } + + .smallpara { + font-size: 24px; + } +} + +@media screen and (max-width: 480px) { + .Mainheading { + font-size: 80px; + margin: 80px 10px; + } + + .smallpara { + font-size: 20px; + } +} + +/* Custom scrollbar for Chrome/Safari/Opera */ +::-webkit-scrollbar { + width: 8px; +} + +::-webkit-scrollbar-track { + background: rgba(255, 255, 255, 0.1); + border-radius: 4px; +} + +::-webkit-scrollbar-thumb { + background: linear-gradient(180deg, #774EBD 0%, #372457 100%); + border-radius: 4px; +} + +::-webkit-scrollbar-thumb:hover { + background: linear-gradient(180deg, #8b5ed4 0%, #4c2f77 100%); +} diff --git a/src/navbar.jsx b/src/navbar.jsx new file mode 100644 index 000000000..295aef367 --- /dev/null +++ b/src/navbar.jsx @@ -0,0 +1,31 @@ +import React, { useState } from "react"; +import './styles/navbar.css'; + +function Navbar() { + const [isOpen, setIsOpen] = useState(false); + + const toggleMenu = () => { + setIsOpen(!isOpen); + document.body.classList.toggle("open"); + }; + + return ( + <> +
+ + + + ); +} + +export default Navbar; diff --git a/src/styles/analytics.css b/src/styles/analytics.css new file mode 100644 index 000000000..79f924cff --- /dev/null +++ b/src/styles/analytics.css @@ -0,0 +1,37 @@ +.analytics-container { + background: rgba(18, 18, 18, 0.95); + padding: 2rem; + border-radius: 8px; + border: 1px solid rgba(255, 255, 255, 0.1); + margin: 2rem 0; + width: 100%; + min-height: 400px; + overflow: hidden; +} + +.year-select { + background: rgba(18, 18, 18, 0.95); + color: rgba(255, 255, 255, 0.87); + border: 1px solid rgba(255, 255, 255, 0.1); + padding: 8px 16px; + border-radius: 4px; + margin-bottom: 20px; + font-family: Arial, Helvetica, sans-serif; + cursor: pointer; +} + +.year-select:hover { + border-color: #774EBD; +} + +.year-select:focus { + outline: none; + border-color: #774EBD; +} + +@media screen and (max-width: 900px) { + .analytics-container { + overflow-x: auto; + padding: 1rem; + } +} diff --git a/src/styles/dashboard.css b/src/styles/dashboard.css new file mode 100644 index 000000000..c83d8c97f --- /dev/null +++ b/src/styles/dashboard.css @@ -0,0 +1,219 @@ +.dashboard-container { + background: #1A1A1A; + min-height: 100vh; + color: rgba(255, 255, 255, 0.87); + font-family: Arial, Helvetica, sans-serif; +} + +.dashboard-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 1rem 2rem; + background: rgba(18, 18, 18, 0.95); + border-bottom: 1px solid rgba(255, 255, 255, 0.1); +} + +.logo { + font-size: 1.5rem; + font-weight: bold; + background: linear-gradient(90deg, #774EBD 0%, #372457 100%); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; +} + +.dashboard-nav { + display: flex; + gap: 2rem; +} + +.dashboard-nav a { + color: rgba(255, 255, 255, 0.7); + text-decoration: none; + padding: 0.5rem 1rem; + transition: all 0.3s ease; +} + +.dashboard-nav a.active, +.dashboard-nav a:hover { + color: #774EBD; +} + +.dashboard-content { + display: grid; + grid-template-columns: 2fr 1fr; + gap: 2rem; + padding: 2rem; + height: calc(100vh - 70px); +} + +.dashboard-left, +.dashboard-right { + height: 100%; +} + +.chatbot-container { + background: rgba(18, 18, 18, 0.95); + border-radius: 8px; + border: 1px solid rgba(255, 255, 255, 0.1); + height: 100%; + display: flex; + flex-direction: column; +} + +.chatbot-header { + padding: 1rem; + border-bottom: 1px solid rgba(255, 255, 255, 0.1); +} + +.chatbot-messages { + flex: 1; + padding: 1rem; + overflow-y: auto; + scrollbar-width: thin; + scrollbar-color: #774EBD rgba(255, 255, 255, 0.1); +} + +.chatbot-messages::-webkit-scrollbar { + width: 6px; +} + +.chatbot-messages::-webkit-scrollbar-track { + background: rgba(255, 255, 255, 0.1); + border-radius: 3px; +} + +.chatbot-messages::-webkit-scrollbar-thumb { + background: linear-gradient(180deg, #774EBD 0%, #372457 100%); + border-radius: 3px; +} + +.message { + padding: 0.8rem 1rem; + border-radius: 8px; + margin-bottom: 1rem; + max-width: 80%; +} + +.message.bot { + background: rgba(119, 78, 189, 0.1); + border-left: 3px solid #774EBD; +} + +.chatbot-input { + display: flex; + padding: 1rem; + gap: 1rem; + border-top: 1px solid rgba(255, 255, 255, 0.1); +} + +.chatbot-input input { + flex: 1; + padding: 0.8rem; + border-radius: 4px; + background: rgba(255, 255, 255, 0.05); + border: 1px solid rgba(255, 255, 255, 0.1); + color: white; +} + +.chatbot-input button { + background: linear-gradient(90deg, #774EBD 0%, #372457 100%); + color: white; + border: none; + padding: 0.8rem 1.5rem; + border-radius: 4px; + cursor: pointer; +} + +@media (max-width: 768px) { + .dashboard-content { + grid-template-columns: 1fr; + } + + .dashboard-nav { + display: none; + } +} + +.dashboard-card { + background: rgba(18, 18, 18, 0.95); + padding: 20px; + border-radius: 8px; + border: 1px solid rgba(255, 255, 255, 0.1); +} + +.stats { + display: flex; + gap: 20px; + margin-top: 20px; +} + +.stat-item { + padding: 15px; + background: linear-gradient(90deg, #774EBD 0%, #372457 100%); + border-radius: 8px; + flex: 1; +} + +.logout-btn { + background: linear-gradient(90deg, #774EBD 0%, #372457 100%); + color: white; + border: none; + padding: 8px 16px; + border-radius: 4px; + cursor: pointer; +} + +.logout-confirm-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.8); + display: flex; + justify-content: center; + align-items: center; + z-index: 1000; +} + +.logout-confirm-modal { + background: #1A1A1A; + padding: 2rem; + border-radius: 8px; + border: 1px solid rgba(255, 255, 255, 0.1); + text-align: center; + max-width: 400px; + width: 90%; +} + +.logout-confirm-modal h3 { + margin-bottom: 1rem; + color: rgba(255, 255, 255, 0.87); +} + +.logout-confirm-buttons { + display: flex; + gap: 1rem; + justify-content: center; + margin-top: 2rem; +} + +.logout-confirm-buttons button { + padding: 0.8rem 1.5rem; + border-radius: 4px; + border: none; + cursor: pointer; + font-family: Arial, Helvetica, sans-serif; +} + +.logout-confirm-buttons button:first-child { + background: linear-gradient(90deg, #774EBD 0%, #372457 100%); + color: white; +} + +.logout-confirm-buttons button:last-child { + background: rgba(255, 255, 255, 0.1); + color: rgba(255, 255, 255, 0.87); +} diff --git a/src/styles/loginButton.css b/src/styles/loginButton.css new file mode 100644 index 000000000..3d101af58 --- /dev/null +++ b/src/styles/loginButton.css @@ -0,0 +1,20 @@ +.login-button { + background: linear-gradient(90deg, #774EBD 0%, #372457 100%); + color: white; + border: none; + padding: 10px 24px; + border-radius: 4px; + font-family: Arial, Helvetica, sans-serif; + font-size: 16px; + cursor: pointer; + transition: all 0.3s ease; + position: fixed; + top: 20px; + right: 40px; + z-index: 1000; +} + +.login-button:hover { + opacity: 0.9; + transform: translateY(-1px); +} diff --git a/src/styles/loginModal.css b/src/styles/loginModal.css new file mode 100644 index 000000000..e1c053732 --- /dev/null +++ b/src/styles/loginModal.css @@ -0,0 +1,95 @@ +.modal-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.8); + display: flex; + justify-content: center; + align-items: center; + z-index: 1001; +} + +.modal-content { + background: #1A1A1A; + padding: 2rem; + border-radius: 8px; + width: 100%; + max-width: 400px; + position: relative; + border: 1px solid rgba(255, 255, 255, 0.1); + font-family: Arial, Helvetica, sans-serif; +} + +.close-button { + position: absolute; + top: 10px; + right: 10px; + background: none; + border: none; + color: rgba(255, 255, 255, 0.87); + font-size: 24px; + cursor: pointer; +} + +.login-form { + display: flex; + flex-direction: column; + gap: 1rem; + margin: 1.5rem 0; +} + +.login-form input { + padding: 12px; + border-radius: 4px; + background: rgba(255, 255, 255, 0.05); + border: 1px solid rgba(255, 255, 255, 0.1); + color: white; + font-size: 16px; + font-family: Arial, Helvetica, sans-serif; +} + +.login-form input:focus { + outline: none; + border-color: #774EBD; +} + +.login-form button { + background: linear-gradient(90deg, #774EBD 0%, #372457 100%); + color: white; + padding: 12px; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 16px; + transition: opacity 0.3s; + font-family: Arial, Helvetica, sans-serif; +} + +.login-footer { + display: flex; + justify-content: space-between; + margin-top: 1rem; +} + +.login-footer a { + color: #774EBD; + text-decoration: none; + font-size: 14px; + font-family: Arial, Helvetica, sans-serif; +} + +h2 { + color: rgba(255, 255, 255, 0.87); + text-align: center; + margin-bottom: 1rem; + font-family: Arial, Helvetica, sans-serif; +} + +.error-message { + color: #ff6b6b; + text-align: center; + margin-bottom: 1rem; + font-size: 14px; +} diff --git a/src/styles/navbar.css b/src/styles/navbar.css new file mode 100644 index 000000000..abc527673 --- /dev/null +++ b/src/styles/navbar.css @@ -0,0 +1,214 @@ +.navbar { + background:rgba(18, 18, 18, 1); + position: fixed; + left: 0; + top: 0; + width: 287.713px; +height: 965px; +flex-shrink: 0; + display: flex; + flex-direction: column; + padding: 3rem 0; + border-right: 1px solid rgba(255, 255, 255, 0.1); + box-shadow: 2px 0 10px rgba(0, 0, 0, 0.1); +} + + +.navbar-brand { + color: rgba(255, 255, 255, 0.87); + font-size: 25px; + font-weight: bold; + font-family:Arial, Helvetica, sans-serif; + margin-bottom: 4rem; + padding: 25px 35px; + text-align: left; +} + +.nav-links { + display: flex; + flex-direction: column; + gap: 2rem; + margin-top: 30px; + padding: 0 35px; +} + +.navbar a { + color: rgba(255, 255, 255, 0.87); + font-family:Arial, Helvetica, sans-serif; + font-size: 18px; + font-style: normal; + font-weight: 400; + line-height: normal; + padding: 15px 0; + position: relative; + transition: all 0.3s ease; + text-decoration: none; +} + +.navbar a:hover { + color: rgb(119, 78, 189); + background-color: rgba(255, 255, 255, 0.05); + padding-left: 15px; +} + +.burger { + z-index: 4; + position: fixed; + top: 0; + left: 0; + width: 72px; + height: 72px; + display: flex; + justify-content: center; + align-items: center; /* Center the burger icon properly */ + cursor: pointer; + opacity: 0.8; + transition: 0.3s; +} + +.burger:hover { + opacity: 1; +} + +.burger input { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + cursor: pointer; + opacity: 0; + z-index: 2; +} + +.burger-icon, +.burger-icon::before, +.burger-icon::after { + display: block; + border-radius: 2px; + height: 2px; + background: rgba(255, 255, 255, 0.87); + transition: 0.5s; +} + +.burger-icon { + position: relative; + width: 32px; + height: 2px; /* Add explicit height */ + z-index: 1; +} + +.burger-icon::before, +.burger-icon::after { + content: ''; + position: absolute; + left: 0; + width: 100%; +} + +.burger-icon::before { top: -8px; } +.burger-icon::after { top: 8px; } + +.burger input:checked + .burger-icon::before { + transform: rotate(-45deg) translate(-4px, 4px); + background: rgb(119, 78, 189); +} + +.burger input:checked + .burger-icon { + background: transparent; +} + +.burger input:checked + .burger-icon::after { + transform: rotate(45deg) translate(-4px, -4px); + background: rgb(119, 78, 189); +} + +.menu { + z-index: 3; + position: fixed; + top: 0; + left: 0; + height: 100vh; + width: 300px; + background: rgba(18, 18, 18, 0.98); + translate: -100% 0; + opacity: 0; + visibility: hidden; + transition: 0.4s; + display: flex; + align-items: flex-start; + padding-top: 100px; +} + +.menu.active { + opacity: 1; + visibility: visible; + translate: 0; +} + +.nav-links a { + color: rgba(255, 255, 255, 0.87); + font-family:Arial, Helvetica, sans-serif; + font-size: 24px; + text-decoration: none; + transition: 0.4s; + padding: 8px 24px; +} + +.nav-links a:hover { + color: rgb(119, 78, 189); + padding-left: 32px; +} + +.background { + z-index: 1; + position: fixed; + inset: 0; + background: rgba(18, 18, 18, 0.5); + opacity: 0; + visibility: hidden; + transition: 0.4s; +} + +.background.active { + opacity: 1; + visibility: visible; +} + +@media screen and (max-width: 768px) { + .navbar { + width: 100%; + height: auto; + padding: 1rem 0; + } + + .menu { + width: 250px; + } + + .nav-links { + width: 100%; + text-align: center; + } + + .nav-links a { + padding: 15px; + font-size: 20px; + } + + .burger { + width: 60px; + height: 60px; + } +} + +@media screen and (max-width: 480px) { + .nav-links a { + font-size: 18px; + padding: 12px; + } + + .menu { + width: 200px; + } +} diff --git a/src/styles/stateDropdown.css b/src/styles/stateDropdown.css new file mode 100644 index 000000000..fc9d87965 --- /dev/null +++ b/src/styles/stateDropdown.css @@ -0,0 +1,34 @@ +.state-dropdown-container { + position: fixed; + top: 20px; + left: 320px; + z-index: 2; +} + +.state-select { + background: rgba(18, 18, 18, 0.95); + color: rgba(255, 255, 255, 0.87); + border: 1px solid rgba(255, 255, 255, 0.1); + padding: 8px 16px; + border-radius: 4px; + font-family: Arial, Helvetica, sans-serif; + font-size: 16px; + cursor: pointer; + transition: all 0.3s ease; +} + +.state-select:hover { + border-color: rgb(119, 78, 189); +} + +.state-select:focus { + outline: none; + border-color: rgb(119, 78, 189); + box-shadow: 0 0 0 2px rgba(119, 78, 189, 0.2); +} + +.state-select option { + background: rgba(18, 18, 18, 0.98); + color: rgba(255, 255, 255, 0.87); + padding: 8px; +} diff --git a/src/transaction.jsx b/src/transaction.jsx new file mode 100644 index 000000000..1a32127b5 --- /dev/null +++ b/src/transaction.jsx @@ -0,0 +1,64 @@ +export const fetchGooglePayTransactions = async () => { + // Simulated transaction data (Replace this with real Google Pay API integration) + return [ + { date: "2024-01-05", type: "income", amount: 5200 }, + { date: "2024-01-12", type: "outcome", amount: 2600 }, + { date: "2024-01-20", type: "income", amount: 4800 }, + { date: "2024-01-28", type: "outcome", amount: 2000 }, + + { date: "2024-02-06", type: "income", amount: 6200 }, + { date: "2024-02-15", type: "outcome", amount: 3100 }, + { date: "2024-02-22", type: "income", amount: 5300 }, + { date: "2024-02-27", type: "outcome", amount: 2900 }, + + { date: "2024-03-03", type: "income", amount: 7000 }, + { date: "2024-03-10", type: "outcome", amount: 3500 }, + { date: "2024-03-18", type: "income", amount: 7500 }, + { date: "2024-03-25", type: "outcome", amount: 3700 }, + + { date: "2024-04-07", type: "income", amount: 6700 }, + { date: "2024-04-14", type: "outcome", amount: 3300 }, + { date: "2024-04-21", type: "income", amount: 7200 }, + { date: "2024-04-29", type: "outcome", amount: 3400 }, + + { date: "2024-05-05", type: "income", amount: 8000 }, + { date: "2024-05-12", type: "outcome", amount: 3900 }, + { date: "2024-05-20", type: "income", amount: 8600 }, + { date: "2024-05-30", type: "outcome", amount: 4100 }, + + { date: "2024-06-04", type: "income", amount: 9200 }, + { date: "2024-06-13", type: "outcome", amount: 4500 }, + { date: "2024-06-21", type: "income", amount: 9800 }, + { date: "2024-06-28", type: "outcome", amount: 4600 }, + + { date: "2024-07-08", type: "income", amount: 10300 }, + { date: "2024-07-16", type: "outcome", amount: 5200 }, + { date: "2024-07-23", type: "income", amount: 10800 }, + { date: "2024-07-29", type: "outcome", amount: 5400 }, + + { date: "2024-08-06", type: "income", amount: 11000 }, + { date: "2024-08-15", type: "outcome", amount: 5600 }, + { date: "2024-08-22", type: "income", amount: 11500 }, + { date: "2024-08-30", type: "outcome", amount: 5700 }, + + { date: "2024-09-07", type: "income", amount: 9900 }, + { date: "2024-09-14", type: "outcome", amount: 5100 }, + { date: "2024-09-20", type: "income", amount: 10400 }, + { date: "2024-09-27", type: "outcome", amount: 5300 }, + + { date: "2024-10-06", type: "income", amount: 8800 }, + { date: "2024-10-15", type: "outcome", amount: 4700 }, + { date: "2024-10-22", type: "income", amount: 9200 }, + { date: "2024-10-29", type: "outcome", amount: 4900 }, + + { date: "2024-11-05", type: "income", amount: 7600 }, + { date: "2024-11-12", type: "outcome", amount: 4000 }, + { date: "2024-11-19", type: "income", amount: 8000 }, + { date: "2024-11-25", type: "outcome", amount: 4200 }, + + { date: "2024-12-08", type: "income", amount: 8400 }, + { date: "2024-12-16", type: "outcome", amount: 4500 }, + { date: "2024-12-23", type: "income", amount: 8900 }, + { date: "2024-12-30", type: "outcome", amount: 4600 }, + ]; +}; diff --git a/src/utils/product_trancation.jsx b/src/utils/product_trancation.jsx new file mode 100644 index 000000000..1a32127b5 --- /dev/null +++ b/src/utils/product_trancation.jsx @@ -0,0 +1,64 @@ +export const fetchGooglePayTransactions = async () => { + // Simulated transaction data (Replace this with real Google Pay API integration) + return [ + { date: "2024-01-05", type: "income", amount: 5200 }, + { date: "2024-01-12", type: "outcome", amount: 2600 }, + { date: "2024-01-20", type: "income", amount: 4800 }, + { date: "2024-01-28", type: "outcome", amount: 2000 }, + + { date: "2024-02-06", type: "income", amount: 6200 }, + { date: "2024-02-15", type: "outcome", amount: 3100 }, + { date: "2024-02-22", type: "income", amount: 5300 }, + { date: "2024-02-27", type: "outcome", amount: 2900 }, + + { date: "2024-03-03", type: "income", amount: 7000 }, + { date: "2024-03-10", type: "outcome", amount: 3500 }, + { date: "2024-03-18", type: "income", amount: 7500 }, + { date: "2024-03-25", type: "outcome", amount: 3700 }, + + { date: "2024-04-07", type: "income", amount: 6700 }, + { date: "2024-04-14", type: "outcome", amount: 3300 }, + { date: "2024-04-21", type: "income", amount: 7200 }, + { date: "2024-04-29", type: "outcome", amount: 3400 }, + + { date: "2024-05-05", type: "income", amount: 8000 }, + { date: "2024-05-12", type: "outcome", amount: 3900 }, + { date: "2024-05-20", type: "income", amount: 8600 }, + { date: "2024-05-30", type: "outcome", amount: 4100 }, + + { date: "2024-06-04", type: "income", amount: 9200 }, + { date: "2024-06-13", type: "outcome", amount: 4500 }, + { date: "2024-06-21", type: "income", amount: 9800 }, + { date: "2024-06-28", type: "outcome", amount: 4600 }, + + { date: "2024-07-08", type: "income", amount: 10300 }, + { date: "2024-07-16", type: "outcome", amount: 5200 }, + { date: "2024-07-23", type: "income", amount: 10800 }, + { date: "2024-07-29", type: "outcome", amount: 5400 }, + + { date: "2024-08-06", type: "income", amount: 11000 }, + { date: "2024-08-15", type: "outcome", amount: 5600 }, + { date: "2024-08-22", type: "income", amount: 11500 }, + { date: "2024-08-30", type: "outcome", amount: 5700 }, + + { date: "2024-09-07", type: "income", amount: 9900 }, + { date: "2024-09-14", type: "outcome", amount: 5100 }, + { date: "2024-09-20", type: "income", amount: 10400 }, + { date: "2024-09-27", type: "outcome", amount: 5300 }, + + { date: "2024-10-06", type: "income", amount: 8800 }, + { date: "2024-10-15", type: "outcome", amount: 4700 }, + { date: "2024-10-22", type: "income", amount: 9200 }, + { date: "2024-10-29", type: "outcome", amount: 4900 }, + + { date: "2024-11-05", type: "income", amount: 7600 }, + { date: "2024-11-12", type: "outcome", amount: 4000 }, + { date: "2024-11-19", type: "income", amount: 8000 }, + { date: "2024-11-25", type: "outcome", amount: 4200 }, + + { date: "2024-12-08", type: "income", amount: 8400 }, + { date: "2024-12-16", type: "outcome", amount: 4500 }, + { date: "2024-12-23", type: "income", amount: 8900 }, + { date: "2024-12-30", type: "outcome", amount: 4600 }, + ]; +}; diff --git a/src/utils/userData.jsx b/src/utils/userData.jsx new file mode 100644 index 000000000..0930fe555 --- /dev/null +++ b/src/utils/userData.jsx @@ -0,0 +1,50 @@ +const users = [ + { + username: "john_doe", + account_no: "ACC123456", + email: "john.doe@example.com", + password: "hashed_password_1" + }, + { + username: "alice_smith", + account_no: "ACC789012", + email: "alice.smith@example.com", + password: "hashed_password_2" + }, + { + username: "michael_brown", + account_no: "ACC345678", + email: "michael.brown@example.com", + password: "hashed_password_3" + } +]; + +export const authenticateUser = (email, password) => { + const user = users.find(u => u.email === email); + if (!user) { + return { success: false, message: "User not found" }; + } + + // In a real app, you would hash the password and compare with stored hash + if (user.password === password) { + const { password, ...userWithoutPassword } = user; + return { + success: true, + user: userWithoutPassword, + message: "Login successful" + }; + } + + return { success: false, message: "Invalid credentials" }; +}; + +export const getCurrentUser = () => { + const userData = localStorage.getItem('currentUser'); + return userData ? JSON.parse(userData) : null; +}; + +export const logoutUser = () => { + localStorage.removeItem('isAuthenticated'); + localStorage.removeItem('currentUser'); + window.location.href = '/'; +}; From 319f6ff0480d0acfc7f91a3b2775bc566996308a Mon Sep 17 00:00:00 2001 From: Joshua Sunny Ninan <145998098+Joshualostonearth@users.noreply.github.com> Date: Sat, 8 Mar 2025 22:53:49 +0530 Subject: [PATCH 06/13] Update server.js --- server.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server.js b/server.js index 352ccae70..f11dfadf1 100644 --- a/server.js +++ b/server.js @@ -4,7 +4,7 @@ const app = express(); const port = 3000; // Configuration -const API_TOKEN = "xyz"; // Your Hugging Face token +const API_TOKEN = "Your Hugging Face token"; // Your Hugging Face token const API_URL = "https://api-inference.huggingface.co/models/mistralai/Mixtral-8x7B-Instruct-v0.1"; const headers = { "Authorization": `Bearer ${API_TOKEN}`, @@ -217,4 +217,4 @@ app.get('/', (req, res) => { app.listen(port, () => { console.log(`Server running at http://localhost:${port}`); -}); \ No newline at end of file +}); From d138b500ed4624dbae4e33f6649f1cc10de25e2d Mon Sep 17 00:00:00 2001 From: Joshua Sunny Ninan <145998098+Joshualostonearth@users.noreply.github.com> Date: Sun, 9 Mar 2025 01:46:13 +0530 Subject: [PATCH 07/13] Update server.js --- server.js | 305 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 234 insertions(+), 71 deletions(-) diff --git a/server.js b/server.js index f11dfadf1..07988808c 100644 --- a/server.js +++ b/server.js @@ -3,6 +3,9 @@ const express = require('express'); const app = express(); const port = 3000; +// Import the transaction data +const { transactionData } = require('./transaction.js'); + // Configuration const API_TOKEN = "Your Hugging Face token"; // Your Hugging Face token const API_URL = "https://api-inference.huggingface.co/models/mistralai/Mixtral-8x7B-Instruct-v0.1"; @@ -44,84 +47,17 @@ function formatBoldText(text) { function isFinanceRelated(message) { const lowerMessage = message.toLowerCase().trim(); const financeKeywords = [ - // General Finance Terms 'stock', 'invest', 'interest', 'finance', 'money', 'budget', 'savings', 'retirement', 'bank', 'loan', 'credit', 'debt', 'fund', 'bond', 'mutual', 'portfolio', 'economy', 'financial', 'wealth', 'trade', 'trading', 'currency', 'tax', 'insurance', 'mortgage', 'dividend', 'equity', 'crypto', 'cryptocurrency', 'market', 'capital', 'asset', 'liability', 'dirham', 'dharam', 'dh', 'dhs', 'aed', 'rupee', 'rupies', 'inr', 'dollar', 'usd', - 'exchange', 'rate', 'convert', 'fixed', 'deposit', 'account', 'return', 'principal', - - // Digital Banking Terms - 'upi', 'netbanking', 'neft', 'rtgs', 'imps', 'wallet', 'paytm', 'google pay', 'apple pay', - 'paypal', 'venmo', 'revolut', 'stripe', 'square', 'fintech', 'digital wallet', - 'virtual card', 'contactless', 'online banking', 'mobile banking', 'qr code', 'upi pin', - - // Investment and Trading Terms - 'etf', 'index fund', 'stock market', 'broker', 'payment','nifty', 'sensex', 'forex', 'nasdaq', - 'ipo', 'shares', 'bull market', 'bear market', 'futures', 'options', 'hedge fund', - 'short selling', 'leveraged', 'derivatives', 'stop loss', 'blue chip', - - // Financial Services Terms - 'lending', 'microfinance', 'remittance', 'wire transfer', 'overdraft', - 'credit score', 'fico', 'bank statement', 'atm', 'cheque', 'checkbook', - 'credit card', 'debit card', 'prepaid card', 'interest rate', 'balance transfer', - 'loan emi', 'emi calculator', 'mortgage calculator', 'personal loan', 'home loan', - 'auto loan', 'student loan', 'refinance', 'collateral', 'default', 'foreclosure', - - // Accounting & Bookkeeping - 'invoice', 'ledger', 'audit', 'cash flow', 'profit', 'loss', 'balance sheet', - 'income statement', 'tax filing', 'gst', 'vat', 'capital gains', 'net worth', - 'payroll', 'dividends', 'expense report', - - // International Finance & Currencies - 'euro', 'eur', 'pound', 'gbp', 'yen', 'jpy', 'yuan', 'cny', 'franc', 'chf', - 'peso', 'cad', 'aud', 'krw', 'sgd', 'idr', 'myr', 'zar', - - // Crypto-Specific Terms - 'blockchain', 'bitcoin', 'ethereum', 'dogecoin', 'nft', 'mining', 'wallet address', - 'ledger', 'defi', 'metamask', 'cold wallet', 'hot wallet', - - // Banking & Account Management Keywords - 'account balance', 'check balance', 'reset password', 'lost card', 'stolen card', - 'replace card', 'contact information', 'update details', 'two-factor', '2fa', - 'authentication', 'security question', 'pin code', 'pin number', 'account number', - 'routing number', 'iban', 'swift code', 'branch code', 'internet banking', - - // Digital Transactions & Payments Keywords - 'online payment', 'payment failed', 'transaction failed', 'payment declined', - 'spending limit', 'card limit', 'transaction limit', 'digital wallet', 'e-wallet', - 'e-statement', 'paperless', 'contactless payment', 'tap to pay', 'nfc payment', - 'merchant', 'pos terminal', 'payment gateway', 'payment processor', 'chargeback', - 'refund', 'transaction history', 'pending transaction', 'authorized payment', - - // Budgeting & Financial Insights Keywords - 'track expenses', 'expense tracking', 'monthly expenses', '50/30/20 rule', - 'budgeting rule', 'reduce spending', 'cut expenses', 'financial planning', - 'credit score', 'improve credit', 'fico score', 'utility bills', 'financial goal', - 'spending habit', 'financial health', 'money management', 'expense ratio', - 'cash flow', 'discretionary spending', 'necessary expenses', 'zero-based budget', - - // Security & Fraud Prevention Keywords - 'phishing', 'scam', 'fraud', 'suspicious activity', 'suspicious transaction', - 'security breach', 'data breach', 'identity theft', 'secure transaction', - 'tokenization', 'password manager', 'strong password', 'secure password', - 'account security', 'transaction alert', 'fraud alert', 'security question', - 'biometric', 'fingerprint', 'face recognition', 'voice recognition', - - // Sustainability & Eco-Friendly Finance Keywords - 'green investment', 'sustainable investment', 'esg', 'environmental', - 'social', 'governance', 'carbon footprint', 'carbon neutral', 'eco-friendly', - 'paperless statement', 'digital statement', 'socially responsible', - 'ethical investing', 'impact investing', 'green bond', 'climate risk', - 'sustainability', 'renewable energy', 'clean energy', 'green banking', - 'sustainable finance', 'green credit card', 'eco card' + 'exchange', 'rate', 'convert', 'fixed', 'deposit', 'account', 'return', 'principal', 'transactions', + 'spent', 'lost', 'expense', 'outcome', 'income' ]; - return financeKeywords.some(keyword => lowerMessage.includes(keyword)); } - // Helper function to handle currency conversion function handleCurrencyConversion(message) { const lowerMessage = message.toLowerCase().trim(); @@ -145,9 +81,230 @@ function handleCurrencyConversion(message) { const convertedAmount = amount * rate; return `FinBot: ${amount} ${fromCurrency.toUpperCase()} is approximately ${convertedAmount.toFixed(2)} ${toCurrency.toUpperCase()} based on current exchange rates.`; } else { - return "FinBot: Sorry, I don’t have the exchange rate for that currency pair."; + return "FinBot: Sorry, I don't have the exchange rate for that currency pair."; + } + } + return null; +} + +// Helper function to handle transaction data queries +function handleTransactionQuery(message) { + const lowerMessage = message.toLowerCase().trim(); + + // Monthly summary regex patterns + const monthlySummaryPattern = /(total|sum|summary).*(income|expense|outcome|transaction).*(september|october|november|december|sept|oct|nov|dec)/i; + const monthIncomePattern = /(income).*(september|october|november|december|sept|oct|nov|dec)/i; + const monthExpensePattern = /(expense|outcome).*(september|october|november|december|sept|oct|nov|dec)/i; + + // Overall summary patterns + const totalIncomePattern = /(total|sum).*(income)/i; + const totalExpensePattern = /(total|sum).*(expense|outcome)/i; + const balancePattern = /(balance|net|difference|profit|loss)/i; + + // Last month spending/lost pattern + const lastMonthSpentPattern = /how much have i (?:totally|total) (?:spent|lost) (?:in|for|during) the last month/i; + + // Transaction category patterns + const categoryPattern = /(job|freelance|consulting|rental|project|commission|bonus|subscription|pet|gift|utility|dining|shopping|holiday|new year|celebration)/i; + + // Extract month from query if present + function extractMonth(msg) { + const today = new Date('2025-03-08'); // Current date + const lastMonth = new Date(today.setMonth(today.getMonth() - 1)); + const lastMonthStr = lastMonth.toISOString().slice(0, 7); // e.g., "2025-02" + + if (msg.includes('september') || msg.includes('sept')) return '2024-09'; + if (msg.includes('october') || msg.includes('oct')) return '2024-10'; + if (msg.includes('november') || msg.includes('nov')) return '2024-11'; + if (msg.includes('december') || msg.includes('dec')) return '2024-12'; + return lastMonthStr; // Default to last month (2025-02, but adjust to latest data month if needed) + } + + // Calculate total income + function calculateTotalIncome(month = null) { + return transactionData + .filter(t => t.type === 'income' && (month ? t.date.startsWith(month) : true)) + .reduce((sum, t) => sum + t.amount, 0); + } + + // Calculate total expenses + function calculateTotalExpenses(month = null) { + return transactionData + .filter(t => t.type === 'outcome' && (month ? t.date.startsWith(month) : true)) + .reduce((sum, t) => sum + t.amount, 0); + } + + // Get transactions by category + function getTransactionsByCategory(category) { + const categoryRegex = new RegExp(category, 'i'); + return transactionData.filter(t => categoryRegex.test(t.name)); + } + + // Last N transactions pattern + const lastTransactionsPattern = /last\s+(\d+)\s+transactions/i; + const lastTransactionsMatch = lowerMessage.match(lastTransactionsPattern); + if (lastTransactionsMatch) { + const count = parseInt(lastTransactionsMatch[1]) || 5; + + // Sort transactions by date (newest first) + const sortedTransactions = [...transactionData].sort((a, b) => + new Date(b.date) - new Date(a.date) + ); + + // Get the last N transactions + const recentTransactions = sortedTransactions.slice(0, count); + + const transactions = recentTransactions.map(t => { + const date = new Date(t.date); + const monthName = date.toLocaleString('default', { month: 'long' }); + return `• ${monthName} ${date.getDate()}: ${t.amount.toLocaleString()} (${t.name}) - ${t.type === 'income' ? 'Income' : 'Expense'}`; + }); + + return `FinBot: Here are your last ${count} transactions: + ${transactions.join('\n ')}`; + } + + // Last month spending + const month = extractMonth(lowerMessage); + if (lastMonthSpentPattern.test(lowerMessage)) { + // Since data only goes to December 2024, use the latest month available + const latestMonth = '2024-12'; // Adjust dynamically if more data is added + const expenses = calculateTotalExpenses(latestMonth); + const monthName = 'December'; // Hardcoded for now based on data + + return `FinBot: Based on your transaction data, you have spent a total of ${expenses.toLocaleString()} in ${monthName} 2024. Note: The data only includes transactions up to December 2024, so this reflects your spending for that month.`; + } + + // Monthly income or expense summary + if (monthlySummaryPattern.test(lowerMessage) && month) { + const monthName = month.split('-')[1] === '09' ? 'September' : + month.split('-')[1] === '10' ? 'October' : + month.split('-')[1] === '11' ? 'November' : 'December'; + + const income = calculateTotalIncome(month); + const expenses = calculateTotalExpenses(month); + const balance = income - expenses; + + return `FinBot: Here's your ${monthName} ${month.split('-')[0]} summary: + • Total Income: ${income.toLocaleString()} + • Total Expenses: ${expenses.toLocaleString()} + • Net Balance: ${balance.toLocaleString()} (${balance >= 0 ? 'Positive' : 'Negative'})`; + } + + // Monthly income summary + if (monthIncomePattern.test(lowerMessage) && month) { + const monthName = month.split('-')[1] === '09' ? 'September' : + month.split('-')[1] === '10' ? 'October' : + month.split('-')[1] === '11' ? 'November' : 'December'; + + const income = calculateTotalIncome(month); + const incomeTransactions = transactionData + .filter(t => t.type === 'income' && t.date.startsWith(month)) + .map(t => `• ${t.date.split('-')[2]} ${monthName}: ${t.amount.toLocaleString()} (${t.name})`); + + return `FinBot: Your ${monthName} ${month.split('-')[0]} income was ${income.toLocaleString()}: + ${incomeTransactions.join('\n ')}`; + } + + // Monthly expense summary + if (monthExpensePattern.test(lowerMessage) && month) { + const monthName = month.split('-')[1] === '09' ? 'September' : + month.split('-')[1] === '10' ? 'October' : + month.split('-')[1] === '11' ? 'November' : 'December'; + + const expenses = calculateTotalExpenses(month); + const expenseTransactions = transactionData + .filter(t => t.type === 'outcome' && t.date.startsWith(month)) + .map(t => `• ${t.date.split('-')[2]} ${monthName}: ${t.amount.toLocaleString()} (${t.name})`); + + return `FinBot: Your ${monthName} ${month.split('-')[0]} expenses were ${expenses.toLocaleString()}: + ${expenseTransactions.join('\n ')}`; + } + + // Total income summary + if (totalIncomePattern.test(lowerMessage)) { + const income = calculateTotalIncome(); + + // Group by month + const monthlyIncome = { + 'September': calculateTotalIncome('2024-09'), + 'October': calculateTotalIncome('2024-10'), + 'November': calculateTotalIncome('2024-11'), + 'December': calculateTotalIncome('2024-12') + }; + + return `FinBot: Your total income from September to December was ${income.toLocaleString()}: + • September: ${monthlyIncome['September'].toLocaleString()} + • October: ${monthlyIncome['October'].toLocaleString()} + • November: ${monthlyIncome['November'].toLocaleString()} + • December: ${monthlyIncome['December'].toLocaleString()}`; + } + + // Total expense summary + if (totalExpensePattern.test(lowerMessage)) { + const expenses = calculateTotalExpenses(); + + // Group by month + const monthlyExpenses = { + 'September': calculateTotalExpenses('2024-09'), + 'October': calculateTotalExpenses('2024-10'), + 'November': calculateTotalExpenses('2024-11'), + 'December': calculateTotalExpenses('2024-12') + }; + + return `FinBot: Your total expenses from September to December were ${expenses.toLocaleString()}: + • September: ${monthlyExpenses['September'].toLocaleString()} + • October: ${monthlyExpenses['October'].toLocaleString()} + • November: ${monthlyExpenses['November'].toLocaleString()} + • December: ${monthlyExpenses['December'].toLocaleString()}`; + } + + // Balance query + if (balancePattern.test(lowerMessage)) { + const totalIncome = calculateTotalIncome(); + const totalExpenses = calculateTotalExpenses(); + const balance = totalIncome - totalExpenses; + + // Monthly breakdown + const monthlySummary = ['09', '10', '11', '12'].map(m => { + const month = `2024-${m}`; + const monthName = m === '09' ? 'September' : m === '10' ? 'October' : m === '11' ? 'November' : 'December'; + const income = calculateTotalIncome(month); + const expenses = calculateTotalExpenses(month); + const balance = income - expenses; + return `• ${monthName}: ${balance.toLocaleString()} (Income: ${income.toLocaleString()} - Expenses: ${expenses.toLocaleString()})`; + }); + + return `FinBot: Your overall balance from September to December is ${balance.toLocaleString()}: + • Total Income: ${totalIncome.toLocaleString()} + • Total Expenses: ${totalExpenses.toLocaleString()} + + Monthly breakdown: + ${monthlySummary.join('\n ')}`; + } + + // Category queries + const categoryMatch = lowerMessage.match(categoryPattern); + if (categoryMatch) { + const category = categoryMatch[1].toLowerCase(); + const relatedTransactions = getTransactionsByCategory(category); + + if (relatedTransactions.length > 0) { + const transactions = relatedTransactions.map(t => { + const date = new Date(t.date); + const monthName = date.toLocaleString('default', { month: 'long' }); + return `• ${monthName} ${date.getDate()}: ${t.amount.toLocaleString()} (${t.name}) - ${t.type === 'income' ? 'Income' : 'Expense'}`; + }); + + const total = relatedTransactions.reduce((sum, t) => sum + (t.type === 'income' ? t.amount : -t.amount), 0); + + return `FinBot: Here are your transactions related to "${category}": + ${transactions.join('\n ')} + + Net impact on your finances: ${total.toLocaleString()} ${total >= 0 ? '(Positive)' : '(Negative)'}`; } } + return null; } @@ -161,13 +318,19 @@ app.post('/chat', async (req, res) => { return res.json({ response }); } + // Check for transaction data query + const transactionResponse = handleTransactionQuery(message); + if (transactionResponse) { + return res.json({ response: transactionResponse }); + } + // Check for currency conversion const conversionResponse = handleCurrencyConversion(message); if (conversionResponse) { return res.json({ response: conversionResponse }); } - // Check FAQ first + // Check FAQ const faqAnswer = checkFAQ(message); if (faqAnswer) { const formattedResponse = formatBoldText(`FinBot: ${faqAnswer}`); From ce980ecace34082f0d13f916422d7051b03d8545 Mon Sep 17 00:00:00 2001 From: EdKMathew <145998975+EdKMathew@users.noreply.github.com> Date: Sun, 9 Mar 2025 03:17:14 +0530 Subject: [PATCH 08/13] Delete public directory --- public/index.html | 231 ---------------------------------------------- 1 file changed, 231 deletions(-) delete mode 100644 public/index.html diff --git a/public/index.html b/public/index.html deleted file mode 100644 index c231cd642..000000000 --- a/public/index.html +++ /dev/null @@ -1,231 +0,0 @@ - - - - - - FinTech FAQ Chatbot - - - -

FinBot

-
-
- - -
- - - - \ No newline at end of file From b28d2e35ba7460b166a724fba024b206ed662028 Mon Sep 17 00:00:00 2001 From: EdKMathew <145998975+EdKMathew@users.noreply.github.com> Date: Sun, 9 Mar 2025 03:17:29 +0530 Subject: [PATCH 09/13] Delete src directory --- src/Analitics.jsx | 24 ---- src/App.css | 49 ------- src/components/Analytics.jsx | 74 ----------- src/components/Dashboard.jsx | 75 ----------- src/components/LoginButton.jsx | 18 --- src/components/LoginModal.jsx | 53 -------- src/components/StateDropdown.jsx | 25 ---- src/main.jsx | 28 ---- src/mainpage.jsx | 40 ------ src/mainpagestyle.css | 174 ------------------------ src/navbar.jsx | 31 ----- src/styles/analytics.css | 37 ------ src/styles/dashboard.css | 219 ------------------------------- src/styles/loginButton.css | 20 --- src/styles/loginModal.css | 95 -------------- src/styles/navbar.css | 214 ------------------------------ src/styles/stateDropdown.css | 34 ----- src/transaction.jsx | 64 --------- src/utils/product_trancation.jsx | 64 --------- src/utils/userData.jsx | 50 ------- 20 files changed, 1388 deletions(-) delete mode 100644 src/Analitics.jsx delete mode 100644 src/App.css delete mode 100644 src/components/Analytics.jsx delete mode 100644 src/components/Dashboard.jsx delete mode 100644 src/components/LoginButton.jsx delete mode 100644 src/components/LoginModal.jsx delete mode 100644 src/components/StateDropdown.jsx delete mode 100644 src/main.jsx delete mode 100644 src/mainpage.jsx delete mode 100644 src/mainpagestyle.css delete mode 100644 src/navbar.jsx delete mode 100644 src/styles/analytics.css delete mode 100644 src/styles/dashboard.css delete mode 100644 src/styles/loginButton.css delete mode 100644 src/styles/loginModal.css delete mode 100644 src/styles/navbar.css delete mode 100644 src/styles/stateDropdown.css delete mode 100644 src/transaction.jsx delete mode 100644 src/utils/product_trancation.jsx delete mode 100644 src/utils/userData.jsx diff --git a/src/Analitics.jsx b/src/Analitics.jsx deleted file mode 100644 index e3c59ea80..000000000 --- a/src/Analitics.jsx +++ /dev/null @@ -1,24 +0,0 @@ -//Main page for the analytics section - -import React from "react"; -import { BarChart, Bar, XAxis, YAxis, Tooltip, Legend, ResponsiveContainer } from "recharts"; - -const AnalyticsChart = ({ data }) => { - return ( -
-

Income vs Outcome

- - - - - - - - - - -
- ); -}; - -export default AnalyticsChart; diff --git a/src/App.css b/src/App.css deleted file mode 100644 index 6ef416aff..000000000 --- a/src/App.css +++ /dev/null @@ -1,49 +0,0 @@ -#root { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; - text-align: center; -} - -.logo { - height: 6em; - padding: 1.5em; - will-change: filter; - transition: filter 300ms; -} -.logo:hover { - filter: drop-shadow(0 0 2em #646cffaa); -} -.logo.react:hover { - filter: drop-shadow(0 0 2em #61dafbaa); -} - -@keyframes logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - -@media (prefers-reduced-motion: no-preference) { - a:nth-of-type(2) .logo { - animation: logo-spin infinite 20s linear; - } -} - -.card { - padding: 2em; -} - -.read-the-docs { - color: #888; -} - -@media screen and (max-width: 768px) { - #root { - max-width: 100%; - padding: 1rem; - } -} diff --git a/src/components/Analytics.jsx b/src/components/Analytics.jsx deleted file mode 100644 index f0e046f61..000000000 --- a/src/components/Analytics.jsx +++ /dev/null @@ -1,74 +0,0 @@ -import React, { useState, useEffect } from "react"; -import { BarChart, Bar, XAxis, YAxis, Tooltip, Legend, ResponsiveContainer } from "recharts"; -import { fetchGooglePayTransactions } from "../utils/product_trancation.jsx"; // Add .jsx extension - -const AnalyticsChart = () => { - const [transactionData, setTransactionData] = useState([]); - const [year, setYear] = useState("2024"); - - useEffect(() => { - // Fetch transactions (Replace with real API call) - const loadTransactions = async () => { - const transactions = await fetchGooglePayTransactions(); - setTransactionData(transactions); - }; - loadTransactions(); - }, []); - - // Function to process transactions and get income & outcome per month - const getMonthlyData = () => { - const monthlyData = Array.from({ length: 12 }, (_, index) => ({ - month: new Date(2024, index, 1).toLocaleString("en-US", { month: "short" }), - income: 0, - outcome: 0, - })); - - transactionData.forEach((txn) => { - const txnDate = new Date(txn.date); - const txnYear = txnDate.getFullYear().toString(); - if (txnYear === year) { - const monthIndex = txnDate.getMonth(); - if (txn.type === "income") { - monthlyData[monthIndex].income += txn.amount; - } else if (txn.type === "outcome") { - monthlyData[monthIndex].outcome += txn.amount; - } - } - }); - - return monthlyData; - }; - - return ( -
-

Analytics

- - - - - - - - - - - - -
- ); -}; - -export default AnalyticsChart; diff --git a/src/components/Dashboard.jsx b/src/components/Dashboard.jsx deleted file mode 100644 index 044c7f9b6..000000000 --- a/src/components/Dashboard.jsx +++ /dev/null @@ -1,75 +0,0 @@ -import React, { useState } from 'react'; -import { useNavigate } from 'react-router-dom'; -import '../styles/dashboard.css'; -import AnalyticsChart from './Analytics'; - -function Dashboard() { - const navigate = useNavigate(); - const [showLogoutConfirm, setShowLogoutConfirm] = useState(false); - - const handleLogoutClick = () => { - setShowLogoutConfirm(true); - }; - - const handleLogoutConfirm = () => { - localStorage.removeItem('isAuthenticated'); - localStorage.removeItem('currentUser'); - navigate('/'); - }; - - return ( -
-
-
Finura
- - -
- - {showLogoutConfirm && ( -
-
-

Confirm Logout

-

Are you sure you want to logout?

-
- - -
-
-
- )} - -
-
-
-

Financial Overview

- -
-
- -
-
-
-

AI Assistant

-
-
-
- Hello! How can I help you with your finances today? -
-
-
- - -
-
-
-
-
- ); -} - -export default Dashboard; \ No newline at end of file diff --git a/src/components/LoginButton.jsx b/src/components/LoginButton.jsx deleted file mode 100644 index 9e3b15a2c..000000000 --- a/src/components/LoginButton.jsx +++ /dev/null @@ -1,18 +0,0 @@ -import React, { useState } from 'react'; -import '../styles/loginButton.css'; -import LoginModal from './LoginModal'; - -function LoginButton() { - const [showModal, setShowModal] = useState(false); - - return ( - <> - - {showModal && setShowModal(false)} />} - - ); -} - -export default LoginButton; diff --git a/src/components/LoginModal.jsx b/src/components/LoginModal.jsx deleted file mode 100644 index 61cc6281d..000000000 --- a/src/components/LoginModal.jsx +++ /dev/null @@ -1,53 +0,0 @@ -import React, { useState } from 'react'; -import '../styles/loginModal.css'; -import { authenticateUser } from '../utils/userData'; - -function LoginModal({ onClose }) { - const [credentials, setCredentials] = useState({ email: '', password: '' }); - const [error, setError] = useState(''); - - const handleSubmit = (e) => { - e.preventDefault(); - const result = authenticateUser(credentials.email, credentials.password); - - if (result.success) { - localStorage.setItem('isAuthenticated', 'true'); - localStorage.setItem('currentUser', JSON.stringify(result.user)); - window.location.href = '/dashboard'; - onClose(); - } else { - setError(result.message); - } - }; - - return ( -
-
- -

Login

-
- setCredentials({...credentials, email: e.target.value})} - /> - setCredentials({...credentials, password: e.target.value})} - /> - -
- {error &&
{error}
} - -
-
- ); -} - -export default LoginModal; diff --git a/src/components/StateDropdown.jsx b/src/components/StateDropdown.jsx deleted file mode 100644 index e2d297591..000000000 --- a/src/components/StateDropdown.jsx +++ /dev/null @@ -1,25 +0,0 @@ -import React from 'react'; -import '../styles/stateDropdown.css'; - -function StateDropdown() { - const indianStates = [ - "Andhra Pradesh", "Arunachal Pradesh", "Assam", "Bihar", "Chhattisgarh", - "Goa", "Gujarat", "Haryana", "Himachal Pradesh", "Jharkhand", "Karnataka", - "Kerala", "Madhya Pradesh", "Maharashtra", "Manipur", "Meghalaya", "Mizoram", - "Nagaland", "Odisha", "Punjab", "Rajasthan", "Sikkim", "Tamil Nadu", - "Telangana", "Tripura", "Uttar Pradesh", "Uttarakhand", "West Bengal" - ]; - - return ( -
- -
- ); -} - -export default StateDropdown; diff --git a/src/main.jsx b/src/main.jsx deleted file mode 100644 index b52fcaba4..000000000 --- a/src/main.jsx +++ /dev/null @@ -1,28 +0,0 @@ -import React from 'react' -import ReactDOM from 'react-dom/client' -import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom' -import MainPage from './mainpage.jsx' -import Dashboard from './components/Dashboard.jsx' -import Navbar from './navbar.jsx' -import './mainpagestyle.css' - -const ProtectedRoute = ({ children }) => { - const isAuthenticated = localStorage.getItem('isAuthenticated') === 'true'; - return isAuthenticated ? children : ; -}; - -ReactDOM.createRoot(document.getElementById('root')).render( - - - - } /> - - - - } /> - - - , -) - diff --git a/src/mainpage.jsx b/src/mainpage.jsx deleted file mode 100644 index 01fa9bdaf..000000000 --- a/src/mainpage.jsx +++ /dev/null @@ -1,40 +0,0 @@ -import React from 'react'; -import './mainpagestyle.css'; -import StateDropdown from './components/StateDropdown'; -import LoginButton from './components/LoginButton'; -//import AnalyticsChart from './components/Analytics'; -import AnalyticsChart from 'C:\\Users\\aadva\\fintechai\\src\\Analitics.jsx'; - -function MainPage() { - return ( - <> - -
- - -
- -
-
-
Finura
-
"Empowering users with AI-driven financial insights and
seamless support through a smart, user-friendly fintech
dashboard."
-
- -
-

Welcome to the Future

-

Explore our services and products

-
- -
-
-

Financial Overview

-

Track your income and expenses effortlessly

- -
-
-
- - ); -} - -export default MainPage; diff --git a/src/mainpagestyle.css b/src/mainpagestyle.css deleted file mode 100644 index 41ccb69e6..000000000 --- a/src/mainpagestyle.css +++ /dev/null @@ -1,174 +0,0 @@ -@font-face { - font-family: 'Gilroy-Bold'; - src: local('Gilroy-Bold'), url(./fonts/Gilroy-Bold.ttf) format('truetype'); - } - - @font-face { - font-family: 'Gilroy-Medium'; - src: local('Gilroy-Medium'), url(./fonts/Gilroy-Medium.ttf) format('truetype'); - } - - @font-face { - font-family: 'Gilroy-Light'; - src: local('Gilroy-Light'), url(./fonts/Gilroy-Light.ttf) format('truetype'); - } - -h1 { - color: #333; - font-size: 2.5rem; -} - -h2 { - color: #666; - font-size: 1.8rem; -} - -body { - background: #1A1A1A; - margin: 0; - padding: 0; -} - -html, body { - overflow-x: hidden; - scrollbar-width: thin; - scrollbar-color: #774EBD rgba(255, 255, 255, 0.1); -} - -.state-dropdown{ - margin-top: 35.74px; - margin-left: 1166.26px; - margin-right: 314px; -} - -.page-container { - height: 100vh; - overflow-y: auto; - position: relative; - max-width: 100vw; - overflow-x: hidden; -} - -.section { - min-height: 100vh; - width: 100%; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - position: relative; -} - -.section-two { - background: #1A1A1A; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - padding: 2rem; -} - -.section-two h1 { - color: rgba(255, 255, 255, 0.87); - font-family:Arial, Helvetica, sans-serif; - font-size: 64px; - margin-bottom: 2rem; -} - -.Mainheading { - text-align: center; - font-family:Arial, Helvetica, sans-serif; - font-size: 250.821px; - font-style: normal; - font-weight: 400; - color: transparent; - line-height: normal; - background: linear-gradient(90deg, #774EBD 0%, #372457 100%); - background-clip: text; - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - margin-top: 1rem; - margin-left: 496px; - margin-right: 495.65px; -} - -.smallpara{ - color: #FFF; - text-align: center; - font-family:Arial, Helvetica, sans-serif; - font-size: 36px; - font-style: normal; - font-weight: 300; - line-height: normal; - margin-top: 10px; - -} - -.top-controls { - position: fixed; - top: 0; - left: 0; - right: 0; - padding: 20px; - z-index: 1000; - display: flex; - justify-content: space-between; - align-items: center; -} - -@media screen and (max-width: 1200px) { - .Mainheading { - font-size: 180px; - margin: 150px 20px; - } - - .smallpara { - font-size: 28px; - margin: 20px; - } -} - -@media screen and (max-width: 768px) { - body { - margin-left: 0; - } - - .Mainheading { - font-size: 120px; - margin: 100px 15px; - } - - .smallpara { - font-size: 24px; - } -} - -@media screen and (max-width: 480px) { - .Mainheading { - font-size: 80px; - margin: 80px 10px; - } - - .smallpara { - font-size: 20px; - } -} - -/* Custom scrollbar for Chrome/Safari/Opera */ -::-webkit-scrollbar { - width: 8px; -} - -::-webkit-scrollbar-track { - background: rgba(255, 255, 255, 0.1); - border-radius: 4px; -} - -::-webkit-scrollbar-thumb { - background: linear-gradient(180deg, #774EBD 0%, #372457 100%); - border-radius: 4px; -} - -::-webkit-scrollbar-thumb:hover { - background: linear-gradient(180deg, #8b5ed4 0%, #4c2f77 100%); -} diff --git a/src/navbar.jsx b/src/navbar.jsx deleted file mode 100644 index 295aef367..000000000 --- a/src/navbar.jsx +++ /dev/null @@ -1,31 +0,0 @@ -import React, { useState } from "react"; -import './styles/navbar.css'; - -function Navbar() { - const [isOpen, setIsOpen] = useState(false); - - const toggleMenu = () => { - setIsOpen(!isOpen); - document.body.classList.toggle("open"); - }; - - return ( - <> -
- - - - ); -} - -export default Navbar; diff --git a/src/styles/analytics.css b/src/styles/analytics.css deleted file mode 100644 index 79f924cff..000000000 --- a/src/styles/analytics.css +++ /dev/null @@ -1,37 +0,0 @@ -.analytics-container { - background: rgba(18, 18, 18, 0.95); - padding: 2rem; - border-radius: 8px; - border: 1px solid rgba(255, 255, 255, 0.1); - margin: 2rem 0; - width: 100%; - min-height: 400px; - overflow: hidden; -} - -.year-select { - background: rgba(18, 18, 18, 0.95); - color: rgba(255, 255, 255, 0.87); - border: 1px solid rgba(255, 255, 255, 0.1); - padding: 8px 16px; - border-radius: 4px; - margin-bottom: 20px; - font-family: Arial, Helvetica, sans-serif; - cursor: pointer; -} - -.year-select:hover { - border-color: #774EBD; -} - -.year-select:focus { - outline: none; - border-color: #774EBD; -} - -@media screen and (max-width: 900px) { - .analytics-container { - overflow-x: auto; - padding: 1rem; - } -} diff --git a/src/styles/dashboard.css b/src/styles/dashboard.css deleted file mode 100644 index c83d8c97f..000000000 --- a/src/styles/dashboard.css +++ /dev/null @@ -1,219 +0,0 @@ -.dashboard-container { - background: #1A1A1A; - min-height: 100vh; - color: rgba(255, 255, 255, 0.87); - font-family: Arial, Helvetica, sans-serif; -} - -.dashboard-header { - display: flex; - justify-content: space-between; - align-items: center; - padding: 1rem 2rem; - background: rgba(18, 18, 18, 0.95); - border-bottom: 1px solid rgba(255, 255, 255, 0.1); -} - -.logo { - font-size: 1.5rem; - font-weight: bold; - background: linear-gradient(90deg, #774EBD 0%, #372457 100%); - -webkit-background-clip: text; - background-clip: text; - -webkit-text-fill-color: transparent; -} - -.dashboard-nav { - display: flex; - gap: 2rem; -} - -.dashboard-nav a { - color: rgba(255, 255, 255, 0.7); - text-decoration: none; - padding: 0.5rem 1rem; - transition: all 0.3s ease; -} - -.dashboard-nav a.active, -.dashboard-nav a:hover { - color: #774EBD; -} - -.dashboard-content { - display: grid; - grid-template-columns: 2fr 1fr; - gap: 2rem; - padding: 2rem; - height: calc(100vh - 70px); -} - -.dashboard-left, -.dashboard-right { - height: 100%; -} - -.chatbot-container { - background: rgba(18, 18, 18, 0.95); - border-radius: 8px; - border: 1px solid rgba(255, 255, 255, 0.1); - height: 100%; - display: flex; - flex-direction: column; -} - -.chatbot-header { - padding: 1rem; - border-bottom: 1px solid rgba(255, 255, 255, 0.1); -} - -.chatbot-messages { - flex: 1; - padding: 1rem; - overflow-y: auto; - scrollbar-width: thin; - scrollbar-color: #774EBD rgba(255, 255, 255, 0.1); -} - -.chatbot-messages::-webkit-scrollbar { - width: 6px; -} - -.chatbot-messages::-webkit-scrollbar-track { - background: rgba(255, 255, 255, 0.1); - border-radius: 3px; -} - -.chatbot-messages::-webkit-scrollbar-thumb { - background: linear-gradient(180deg, #774EBD 0%, #372457 100%); - border-radius: 3px; -} - -.message { - padding: 0.8rem 1rem; - border-radius: 8px; - margin-bottom: 1rem; - max-width: 80%; -} - -.message.bot { - background: rgba(119, 78, 189, 0.1); - border-left: 3px solid #774EBD; -} - -.chatbot-input { - display: flex; - padding: 1rem; - gap: 1rem; - border-top: 1px solid rgba(255, 255, 255, 0.1); -} - -.chatbot-input input { - flex: 1; - padding: 0.8rem; - border-radius: 4px; - background: rgba(255, 255, 255, 0.05); - border: 1px solid rgba(255, 255, 255, 0.1); - color: white; -} - -.chatbot-input button { - background: linear-gradient(90deg, #774EBD 0%, #372457 100%); - color: white; - border: none; - padding: 0.8rem 1.5rem; - border-radius: 4px; - cursor: pointer; -} - -@media (max-width: 768px) { - .dashboard-content { - grid-template-columns: 1fr; - } - - .dashboard-nav { - display: none; - } -} - -.dashboard-card { - background: rgba(18, 18, 18, 0.95); - padding: 20px; - border-radius: 8px; - border: 1px solid rgba(255, 255, 255, 0.1); -} - -.stats { - display: flex; - gap: 20px; - margin-top: 20px; -} - -.stat-item { - padding: 15px; - background: linear-gradient(90deg, #774EBD 0%, #372457 100%); - border-radius: 8px; - flex: 1; -} - -.logout-btn { - background: linear-gradient(90deg, #774EBD 0%, #372457 100%); - color: white; - border: none; - padding: 8px 16px; - border-radius: 4px; - cursor: pointer; -} - -.logout-confirm-overlay { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: rgba(0, 0, 0, 0.8); - display: flex; - justify-content: center; - align-items: center; - z-index: 1000; -} - -.logout-confirm-modal { - background: #1A1A1A; - padding: 2rem; - border-radius: 8px; - border: 1px solid rgba(255, 255, 255, 0.1); - text-align: center; - max-width: 400px; - width: 90%; -} - -.logout-confirm-modal h3 { - margin-bottom: 1rem; - color: rgba(255, 255, 255, 0.87); -} - -.logout-confirm-buttons { - display: flex; - gap: 1rem; - justify-content: center; - margin-top: 2rem; -} - -.logout-confirm-buttons button { - padding: 0.8rem 1.5rem; - border-radius: 4px; - border: none; - cursor: pointer; - font-family: Arial, Helvetica, sans-serif; -} - -.logout-confirm-buttons button:first-child { - background: linear-gradient(90deg, #774EBD 0%, #372457 100%); - color: white; -} - -.logout-confirm-buttons button:last-child { - background: rgba(255, 255, 255, 0.1); - color: rgba(255, 255, 255, 0.87); -} diff --git a/src/styles/loginButton.css b/src/styles/loginButton.css deleted file mode 100644 index 3d101af58..000000000 --- a/src/styles/loginButton.css +++ /dev/null @@ -1,20 +0,0 @@ -.login-button { - background: linear-gradient(90deg, #774EBD 0%, #372457 100%); - color: white; - border: none; - padding: 10px 24px; - border-radius: 4px; - font-family: Arial, Helvetica, sans-serif; - font-size: 16px; - cursor: pointer; - transition: all 0.3s ease; - position: fixed; - top: 20px; - right: 40px; - z-index: 1000; -} - -.login-button:hover { - opacity: 0.9; - transform: translateY(-1px); -} diff --git a/src/styles/loginModal.css b/src/styles/loginModal.css deleted file mode 100644 index e1c053732..000000000 --- a/src/styles/loginModal.css +++ /dev/null @@ -1,95 +0,0 @@ -.modal-overlay { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: rgba(0, 0, 0, 0.8); - display: flex; - justify-content: center; - align-items: center; - z-index: 1001; -} - -.modal-content { - background: #1A1A1A; - padding: 2rem; - border-radius: 8px; - width: 100%; - max-width: 400px; - position: relative; - border: 1px solid rgba(255, 255, 255, 0.1); - font-family: Arial, Helvetica, sans-serif; -} - -.close-button { - position: absolute; - top: 10px; - right: 10px; - background: none; - border: none; - color: rgba(255, 255, 255, 0.87); - font-size: 24px; - cursor: pointer; -} - -.login-form { - display: flex; - flex-direction: column; - gap: 1rem; - margin: 1.5rem 0; -} - -.login-form input { - padding: 12px; - border-radius: 4px; - background: rgba(255, 255, 255, 0.05); - border: 1px solid rgba(255, 255, 255, 0.1); - color: white; - font-size: 16px; - font-family: Arial, Helvetica, sans-serif; -} - -.login-form input:focus { - outline: none; - border-color: #774EBD; -} - -.login-form button { - background: linear-gradient(90deg, #774EBD 0%, #372457 100%); - color: white; - padding: 12px; - border: none; - border-radius: 4px; - cursor: pointer; - font-size: 16px; - transition: opacity 0.3s; - font-family: Arial, Helvetica, sans-serif; -} - -.login-footer { - display: flex; - justify-content: space-between; - margin-top: 1rem; -} - -.login-footer a { - color: #774EBD; - text-decoration: none; - font-size: 14px; - font-family: Arial, Helvetica, sans-serif; -} - -h2 { - color: rgba(255, 255, 255, 0.87); - text-align: center; - margin-bottom: 1rem; - font-family: Arial, Helvetica, sans-serif; -} - -.error-message { - color: #ff6b6b; - text-align: center; - margin-bottom: 1rem; - font-size: 14px; -} diff --git a/src/styles/navbar.css b/src/styles/navbar.css deleted file mode 100644 index abc527673..000000000 --- a/src/styles/navbar.css +++ /dev/null @@ -1,214 +0,0 @@ -.navbar { - background:rgba(18, 18, 18, 1); - position: fixed; - left: 0; - top: 0; - width: 287.713px; -height: 965px; -flex-shrink: 0; - display: flex; - flex-direction: column; - padding: 3rem 0; - border-right: 1px solid rgba(255, 255, 255, 0.1); - box-shadow: 2px 0 10px rgba(0, 0, 0, 0.1); -} - - -.navbar-brand { - color: rgba(255, 255, 255, 0.87); - font-size: 25px; - font-weight: bold; - font-family:Arial, Helvetica, sans-serif; - margin-bottom: 4rem; - padding: 25px 35px; - text-align: left; -} - -.nav-links { - display: flex; - flex-direction: column; - gap: 2rem; - margin-top: 30px; - padding: 0 35px; -} - -.navbar a { - color: rgba(255, 255, 255, 0.87); - font-family:Arial, Helvetica, sans-serif; - font-size: 18px; - font-style: normal; - font-weight: 400; - line-height: normal; - padding: 15px 0; - position: relative; - transition: all 0.3s ease; - text-decoration: none; -} - -.navbar a:hover { - color: rgb(119, 78, 189); - background-color: rgba(255, 255, 255, 0.05); - padding-left: 15px; -} - -.burger { - z-index: 4; - position: fixed; - top: 0; - left: 0; - width: 72px; - height: 72px; - display: flex; - justify-content: center; - align-items: center; /* Center the burger icon properly */ - cursor: pointer; - opacity: 0.8; - transition: 0.3s; -} - -.burger:hover { - opacity: 1; -} - -.burger input { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - cursor: pointer; - opacity: 0; - z-index: 2; -} - -.burger-icon, -.burger-icon::before, -.burger-icon::after { - display: block; - border-radius: 2px; - height: 2px; - background: rgba(255, 255, 255, 0.87); - transition: 0.5s; -} - -.burger-icon { - position: relative; - width: 32px; - height: 2px; /* Add explicit height */ - z-index: 1; -} - -.burger-icon::before, -.burger-icon::after { - content: ''; - position: absolute; - left: 0; - width: 100%; -} - -.burger-icon::before { top: -8px; } -.burger-icon::after { top: 8px; } - -.burger input:checked + .burger-icon::before { - transform: rotate(-45deg) translate(-4px, 4px); - background: rgb(119, 78, 189); -} - -.burger input:checked + .burger-icon { - background: transparent; -} - -.burger input:checked + .burger-icon::after { - transform: rotate(45deg) translate(-4px, -4px); - background: rgb(119, 78, 189); -} - -.menu { - z-index: 3; - position: fixed; - top: 0; - left: 0; - height: 100vh; - width: 300px; - background: rgba(18, 18, 18, 0.98); - translate: -100% 0; - opacity: 0; - visibility: hidden; - transition: 0.4s; - display: flex; - align-items: flex-start; - padding-top: 100px; -} - -.menu.active { - opacity: 1; - visibility: visible; - translate: 0; -} - -.nav-links a { - color: rgba(255, 255, 255, 0.87); - font-family:Arial, Helvetica, sans-serif; - font-size: 24px; - text-decoration: none; - transition: 0.4s; - padding: 8px 24px; -} - -.nav-links a:hover { - color: rgb(119, 78, 189); - padding-left: 32px; -} - -.background { - z-index: 1; - position: fixed; - inset: 0; - background: rgba(18, 18, 18, 0.5); - opacity: 0; - visibility: hidden; - transition: 0.4s; -} - -.background.active { - opacity: 1; - visibility: visible; -} - -@media screen and (max-width: 768px) { - .navbar { - width: 100%; - height: auto; - padding: 1rem 0; - } - - .menu { - width: 250px; - } - - .nav-links { - width: 100%; - text-align: center; - } - - .nav-links a { - padding: 15px; - font-size: 20px; - } - - .burger { - width: 60px; - height: 60px; - } -} - -@media screen and (max-width: 480px) { - .nav-links a { - font-size: 18px; - padding: 12px; - } - - .menu { - width: 200px; - } -} diff --git a/src/styles/stateDropdown.css b/src/styles/stateDropdown.css deleted file mode 100644 index fc9d87965..000000000 --- a/src/styles/stateDropdown.css +++ /dev/null @@ -1,34 +0,0 @@ -.state-dropdown-container { - position: fixed; - top: 20px; - left: 320px; - z-index: 2; -} - -.state-select { - background: rgba(18, 18, 18, 0.95); - color: rgba(255, 255, 255, 0.87); - border: 1px solid rgba(255, 255, 255, 0.1); - padding: 8px 16px; - border-radius: 4px; - font-family: Arial, Helvetica, sans-serif; - font-size: 16px; - cursor: pointer; - transition: all 0.3s ease; -} - -.state-select:hover { - border-color: rgb(119, 78, 189); -} - -.state-select:focus { - outline: none; - border-color: rgb(119, 78, 189); - box-shadow: 0 0 0 2px rgba(119, 78, 189, 0.2); -} - -.state-select option { - background: rgba(18, 18, 18, 0.98); - color: rgba(255, 255, 255, 0.87); - padding: 8px; -} diff --git a/src/transaction.jsx b/src/transaction.jsx deleted file mode 100644 index 1a32127b5..000000000 --- a/src/transaction.jsx +++ /dev/null @@ -1,64 +0,0 @@ -export const fetchGooglePayTransactions = async () => { - // Simulated transaction data (Replace this with real Google Pay API integration) - return [ - { date: "2024-01-05", type: "income", amount: 5200 }, - { date: "2024-01-12", type: "outcome", amount: 2600 }, - { date: "2024-01-20", type: "income", amount: 4800 }, - { date: "2024-01-28", type: "outcome", amount: 2000 }, - - { date: "2024-02-06", type: "income", amount: 6200 }, - { date: "2024-02-15", type: "outcome", amount: 3100 }, - { date: "2024-02-22", type: "income", amount: 5300 }, - { date: "2024-02-27", type: "outcome", amount: 2900 }, - - { date: "2024-03-03", type: "income", amount: 7000 }, - { date: "2024-03-10", type: "outcome", amount: 3500 }, - { date: "2024-03-18", type: "income", amount: 7500 }, - { date: "2024-03-25", type: "outcome", amount: 3700 }, - - { date: "2024-04-07", type: "income", amount: 6700 }, - { date: "2024-04-14", type: "outcome", amount: 3300 }, - { date: "2024-04-21", type: "income", amount: 7200 }, - { date: "2024-04-29", type: "outcome", amount: 3400 }, - - { date: "2024-05-05", type: "income", amount: 8000 }, - { date: "2024-05-12", type: "outcome", amount: 3900 }, - { date: "2024-05-20", type: "income", amount: 8600 }, - { date: "2024-05-30", type: "outcome", amount: 4100 }, - - { date: "2024-06-04", type: "income", amount: 9200 }, - { date: "2024-06-13", type: "outcome", amount: 4500 }, - { date: "2024-06-21", type: "income", amount: 9800 }, - { date: "2024-06-28", type: "outcome", amount: 4600 }, - - { date: "2024-07-08", type: "income", amount: 10300 }, - { date: "2024-07-16", type: "outcome", amount: 5200 }, - { date: "2024-07-23", type: "income", amount: 10800 }, - { date: "2024-07-29", type: "outcome", amount: 5400 }, - - { date: "2024-08-06", type: "income", amount: 11000 }, - { date: "2024-08-15", type: "outcome", amount: 5600 }, - { date: "2024-08-22", type: "income", amount: 11500 }, - { date: "2024-08-30", type: "outcome", amount: 5700 }, - - { date: "2024-09-07", type: "income", amount: 9900 }, - { date: "2024-09-14", type: "outcome", amount: 5100 }, - { date: "2024-09-20", type: "income", amount: 10400 }, - { date: "2024-09-27", type: "outcome", amount: 5300 }, - - { date: "2024-10-06", type: "income", amount: 8800 }, - { date: "2024-10-15", type: "outcome", amount: 4700 }, - { date: "2024-10-22", type: "income", amount: 9200 }, - { date: "2024-10-29", type: "outcome", amount: 4900 }, - - { date: "2024-11-05", type: "income", amount: 7600 }, - { date: "2024-11-12", type: "outcome", amount: 4000 }, - { date: "2024-11-19", type: "income", amount: 8000 }, - { date: "2024-11-25", type: "outcome", amount: 4200 }, - - { date: "2024-12-08", type: "income", amount: 8400 }, - { date: "2024-12-16", type: "outcome", amount: 4500 }, - { date: "2024-12-23", type: "income", amount: 8900 }, - { date: "2024-12-30", type: "outcome", amount: 4600 }, - ]; -}; diff --git a/src/utils/product_trancation.jsx b/src/utils/product_trancation.jsx deleted file mode 100644 index 1a32127b5..000000000 --- a/src/utils/product_trancation.jsx +++ /dev/null @@ -1,64 +0,0 @@ -export const fetchGooglePayTransactions = async () => { - // Simulated transaction data (Replace this with real Google Pay API integration) - return [ - { date: "2024-01-05", type: "income", amount: 5200 }, - { date: "2024-01-12", type: "outcome", amount: 2600 }, - { date: "2024-01-20", type: "income", amount: 4800 }, - { date: "2024-01-28", type: "outcome", amount: 2000 }, - - { date: "2024-02-06", type: "income", amount: 6200 }, - { date: "2024-02-15", type: "outcome", amount: 3100 }, - { date: "2024-02-22", type: "income", amount: 5300 }, - { date: "2024-02-27", type: "outcome", amount: 2900 }, - - { date: "2024-03-03", type: "income", amount: 7000 }, - { date: "2024-03-10", type: "outcome", amount: 3500 }, - { date: "2024-03-18", type: "income", amount: 7500 }, - { date: "2024-03-25", type: "outcome", amount: 3700 }, - - { date: "2024-04-07", type: "income", amount: 6700 }, - { date: "2024-04-14", type: "outcome", amount: 3300 }, - { date: "2024-04-21", type: "income", amount: 7200 }, - { date: "2024-04-29", type: "outcome", amount: 3400 }, - - { date: "2024-05-05", type: "income", amount: 8000 }, - { date: "2024-05-12", type: "outcome", amount: 3900 }, - { date: "2024-05-20", type: "income", amount: 8600 }, - { date: "2024-05-30", type: "outcome", amount: 4100 }, - - { date: "2024-06-04", type: "income", amount: 9200 }, - { date: "2024-06-13", type: "outcome", amount: 4500 }, - { date: "2024-06-21", type: "income", amount: 9800 }, - { date: "2024-06-28", type: "outcome", amount: 4600 }, - - { date: "2024-07-08", type: "income", amount: 10300 }, - { date: "2024-07-16", type: "outcome", amount: 5200 }, - { date: "2024-07-23", type: "income", amount: 10800 }, - { date: "2024-07-29", type: "outcome", amount: 5400 }, - - { date: "2024-08-06", type: "income", amount: 11000 }, - { date: "2024-08-15", type: "outcome", amount: 5600 }, - { date: "2024-08-22", type: "income", amount: 11500 }, - { date: "2024-08-30", type: "outcome", amount: 5700 }, - - { date: "2024-09-07", type: "income", amount: 9900 }, - { date: "2024-09-14", type: "outcome", amount: 5100 }, - { date: "2024-09-20", type: "income", amount: 10400 }, - { date: "2024-09-27", type: "outcome", amount: 5300 }, - - { date: "2024-10-06", type: "income", amount: 8800 }, - { date: "2024-10-15", type: "outcome", amount: 4700 }, - { date: "2024-10-22", type: "income", amount: 9200 }, - { date: "2024-10-29", type: "outcome", amount: 4900 }, - - { date: "2024-11-05", type: "income", amount: 7600 }, - { date: "2024-11-12", type: "outcome", amount: 4000 }, - { date: "2024-11-19", type: "income", amount: 8000 }, - { date: "2024-11-25", type: "outcome", amount: 4200 }, - - { date: "2024-12-08", type: "income", amount: 8400 }, - { date: "2024-12-16", type: "outcome", amount: 4500 }, - { date: "2024-12-23", type: "income", amount: 8900 }, - { date: "2024-12-30", type: "outcome", amount: 4600 }, - ]; -}; diff --git a/src/utils/userData.jsx b/src/utils/userData.jsx deleted file mode 100644 index 0930fe555..000000000 --- a/src/utils/userData.jsx +++ /dev/null @@ -1,50 +0,0 @@ -const users = [ - { - username: "john_doe", - account_no: "ACC123456", - email: "john.doe@example.com", - password: "hashed_password_1" - }, - { - username: "alice_smith", - account_no: "ACC789012", - email: "alice.smith@example.com", - password: "hashed_password_2" - }, - { - username: "michael_brown", - account_no: "ACC345678", - email: "michael.brown@example.com", - password: "hashed_password_3" - } -]; - -export const authenticateUser = (email, password) => { - const user = users.find(u => u.email === email); - if (!user) { - return { success: false, message: "User not found" }; - } - - // In a real app, you would hash the password and compare with stored hash - if (user.password === password) { - const { password, ...userWithoutPassword } = user; - return { - success: true, - user: userWithoutPassword, - message: "Login successful" - }; - } - - return { success: false, message: "Invalid credentials" }; -}; - -export const getCurrentUser = () => { - const userData = localStorage.getItem('currentUser'); - return userData ? JSON.parse(userData) : null; -}; - -export const logoutUser = () => { - localStorage.removeItem('isAuthenticated'); - localStorage.removeItem('currentUser'); - window.location.href = '/'; -}; From 3b82b63f19d0efc901072f2f23d195db175203d4 Mon Sep 17 00:00:00 2001 From: Advaith A Arun <148091632+ADU773@users.noreply.github.com> Date: Sun, 9 Mar 2025 03:22:14 +0530 Subject: [PATCH 10/13] Add files via upload --- Analitics.jsx | 78 ++++++++++++++++++ Analytics.jsx | 74 ++++++++++++++++++ App.css | 49 ++++++++++++ Dashboard.jsx | 104 ++++++++++++++++++++++++ LoginButton.jsx | 18 +++++ LoginModal.jsx | 53 +++++++++++++ StateDropdown.jsx | 25 ++++++ TransactionHistory.jsx | 43 ++++++++++ main.jsx | 28 +++++++ mainpage.jsx | 32 ++++++++ mainpagestyle.css | 174 +++++++++++++++++++++++++++++++++++++++++ navbar.jsx | 31 ++++++++ transaction.jsx | 63 +++++++++++++++ 13 files changed, 772 insertions(+) create mode 100644 Analitics.jsx create mode 100644 Analytics.jsx create mode 100644 App.css create mode 100644 Dashboard.jsx create mode 100644 LoginButton.jsx create mode 100644 LoginModal.jsx create mode 100644 StateDropdown.jsx create mode 100644 TransactionHistory.jsx create mode 100644 main.jsx create mode 100644 mainpage.jsx create mode 100644 mainpagestyle.css create mode 100644 navbar.jsx create mode 100644 transaction.jsx diff --git a/Analitics.jsx b/Analitics.jsx new file mode 100644 index 000000000..5092183cb --- /dev/null +++ b/Analitics.jsx @@ -0,0 +1,78 @@ +//Main page for the analytics section + +import React, { useState, useEffect } from "react"; +import { BarChart, Bar, XAxis, YAxis, Tooltip, Legend, ResponsiveContainer } from "recharts"; +import { fetchGooglePayTransactions } from "./transaction"; // Adjust the import path as necessary +import './styles/analytics.css'; // Add this import + +const AnalyticsChart = ({ userAccount }) => { + const [transactionData, setTransactionData] = useState([]); + const [year, setYear] = useState("2025"); + + useEffect(() => { + const loadTransactions = async () => { + const transactions = await fetchGooglePayTransactions(userAccount); + setTransactionData(transactions); + }; + loadTransactions(); + }, [userAccount]); + + // Function to process transactions and get income & outcome per month + const getMonthlyData = () => { + const monthlyData = Array.from({ length: 12 }, (_, index) => ({ + month: new Date(2025, index, 1).toLocaleString("en-US", { month: "short" }), + income: 0, + outcome: 0, + })); + + transactionData.transactions?.forEach((txn) => { + const txnDate = new Date(txn.date); + if (txnDate.getFullYear().toString() === year) { + const monthIndex = txnDate.getMonth(); + if (txn.receiver_account === userAccount) { + monthlyData[monthIndex].income += txn.amount_transferred; // Money received + } + if (txn.sender_account === userAccount) { + monthlyData[monthIndex].outcome += txn.amount_transferred; // Money spent + } + } + }); + + return monthlyData; + }; + + const monthlyData = getMonthlyData(); + + return ( +
+

Income vs Outcome

+ + + + + + + + + + +
+ ); +}; +export default AnalyticsChart; diff --git a/Analytics.jsx b/Analytics.jsx new file mode 100644 index 000000000..474fc8ef9 --- /dev/null +++ b/Analytics.jsx @@ -0,0 +1,74 @@ +import React, { useState, useEffect } from "react"; +import { BarChart, Bar, XAxis, YAxis, Tooltip, Legend, ResponsiveContainer } from "recharts"; +import { fetchGooglePayTransactions } from "../utils/product_trancation.jsx"; // Add .jsx extension + +const AnalyticsChart = () => { + const [transactionData, setTransactionData] = useState([]); + const [year, setYear] = useState("2024"); + + useEffect(() => { + // Fetch transactions (Replace with real API call) + const loadTransactions = async () => { + const transactions = await fetchGooglePayTransactions(); + setTransactionData(transactions); + }; + loadTransactions(); + }, []); + + // Function to process transactions and get income & outcome per month + const getMonthlyData = () => { + const monthlyData = Array.from({ length: 12 }, (_, index) => ({ + month: new Date(2024, index, 1).toLocaleString("en-US", { month: "short" }), + income: 0, + outcome: 0, + })); + + transactionData.forEach((txn) => { + const txnDate = new Date(txn.date); + const txnYear = txnDate.getFullYear().toString(); + if (txnYear === year) { + const monthIndex = txnDate.getMonth(); + if (txn.type === "income") { + monthlyData[monthIndex].income += txn.amount; + } else if (txn.type === "outcome") { + monthlyData[monthIndex].outcome += txn.amount; + } + } + }); + + return monthlyData; + }; + + return ( +
+

Analytics

+ + + + + + + + + + + + +
+ ); +}; + +export default AnalyticsChart; \ No newline at end of file diff --git a/App.css b/App.css new file mode 100644 index 000000000..6ef416aff --- /dev/null +++ b/App.css @@ -0,0 +1,49 @@ +#root { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +.logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: filter 300ms; +} +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); +} +.logo.react:hover { + filter: drop-shadow(0 0 2em #61dafbaa); +} + +@keyframes logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +@media (prefers-reduced-motion: no-preference) { + a:nth-of-type(2) .logo { + animation: logo-spin infinite 20s linear; + } +} + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; +} + +@media screen and (max-width: 768px) { + #root { + max-width: 100%; + padding: 1rem; + } +} diff --git a/Dashboard.jsx b/Dashboard.jsx new file mode 100644 index 000000000..f1886fea5 --- /dev/null +++ b/Dashboard.jsx @@ -0,0 +1,104 @@ +import React, { useState, useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; +import '../styles/dashboard.css'; +import AnalyticsChart from './Analytics'; +import TransactionHistory from './TransactionHistory'; +import StockTrends from './StockTrends'; + +function Dashboard() { + const navigate = useNavigate(); + const [showLogoutConfirm, setShowLogoutConfirm] = useState(false); + const [isLoading, setIsLoading] = useState(true); + + useEffect(() => { + // Check authentication and set up dashboard + const isAuth = localStorage.getItem('isAuthenticated'); + if (!isAuth) { + navigate('/'); + return; + } + setIsLoading(false); + }, [navigate]); + + const handleLogoutClick = () => { + setShowLogoutConfirm(true); + }; + + const handleLogoutConfirm = () => { + localStorage.removeItem('isAuthenticated'); + localStorage.removeItem('currentUser'); + navigate('/'); + }; + + if (isLoading) { + return ( +
+
Loading...
+
+ ); + } + + return ( +
+
+
Finura
+ + +
+ + {showLogoutConfirm && ( +
+
+

Confirm Logout

+

Are you sure you want to logout?

+
+ + +
+
+
+ )} + +
+
+
+

Financial Overview

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

AI Assistant

+
+
+
+ Hello! How can I help you with your finances today? +
+
+
+ + +
+
+
+
+
+ ); +} + +export default Dashboard; \ No newline at end of file diff --git a/LoginButton.jsx b/LoginButton.jsx new file mode 100644 index 000000000..9e3b15a2c --- /dev/null +++ b/LoginButton.jsx @@ -0,0 +1,18 @@ +import React, { useState } from 'react'; +import '../styles/loginButton.css'; +import LoginModal from './LoginModal'; + +function LoginButton() { + const [showModal, setShowModal] = useState(false); + + return ( + <> + + {showModal && setShowModal(false)} />} + + ); +} + +export default LoginButton; diff --git a/LoginModal.jsx b/LoginModal.jsx new file mode 100644 index 000000000..61cc6281d --- /dev/null +++ b/LoginModal.jsx @@ -0,0 +1,53 @@ +import React, { useState } from 'react'; +import '../styles/loginModal.css'; +import { authenticateUser } from '../utils/userData'; + +function LoginModal({ onClose }) { + const [credentials, setCredentials] = useState({ email: '', password: '' }); + const [error, setError] = useState(''); + + const handleSubmit = (e) => { + e.preventDefault(); + const result = authenticateUser(credentials.email, credentials.password); + + if (result.success) { + localStorage.setItem('isAuthenticated', 'true'); + localStorage.setItem('currentUser', JSON.stringify(result.user)); + window.location.href = '/dashboard'; + onClose(); + } else { + setError(result.message); + } + }; + + return ( +
+
+ +

Login

+
+ setCredentials({...credentials, email: e.target.value})} + /> + setCredentials({...credentials, password: e.target.value})} + /> + +
+ {error &&
{error}
} + +
+
+ ); +} + +export default LoginModal; diff --git a/StateDropdown.jsx b/StateDropdown.jsx new file mode 100644 index 000000000..e2d297591 --- /dev/null +++ b/StateDropdown.jsx @@ -0,0 +1,25 @@ +import React from 'react'; +import '../styles/stateDropdown.css'; + +function StateDropdown() { + const indianStates = [ + "Andhra Pradesh", "Arunachal Pradesh", "Assam", "Bihar", "Chhattisgarh", + "Goa", "Gujarat", "Haryana", "Himachal Pradesh", "Jharkhand", "Karnataka", + "Kerala", "Madhya Pradesh", "Maharashtra", "Manipur", "Meghalaya", "Mizoram", + "Nagaland", "Odisha", "Punjab", "Rajasthan", "Sikkim", "Tamil Nadu", + "Telangana", "Tripura", "Uttar Pradesh", "Uttarakhand", "West Bengal" + ]; + + return ( +
+ +
+ ); +} + +export default StateDropdown; diff --git a/TransactionHistory.jsx b/TransactionHistory.jsx new file mode 100644 index 000000000..9580c2bc0 --- /dev/null +++ b/TransactionHistory.jsx @@ -0,0 +1,43 @@ +import React from 'react'; +import { fetchGooglePayTransactions } from '../utils/product_trancation'; +import '../styles/transactionHistory.css'; + +const TransactionHistory = () => { + const [transactions, setTransactions] = React.useState([]); + + React.useEffect(() => { + const loadTransactions = async () => { + const data = await fetchGooglePayTransactions(); + // Get latest 5 transactions + const sortedData = data + .sort((a, b) => new Date(b.date) - new Date(a.date)) + .slice(0, 5); + setTransactions(sortedData); + }; + loadTransactions(); + }, []); + + return ( +
+

Recent Transactions

+
+ {transactions.map((transaction, index) => ( +
+
+ {transaction.name} + + {new Date(transaction.date).toLocaleDateString()} + +
+ + {transaction.type === 'income' ? '+' : '-'} + ${transaction.amount.toLocaleString()} + +
+ ))} +
+
+ ); +}; + +export default TransactionHistory; diff --git a/main.jsx b/main.jsx new file mode 100644 index 000000000..b52fcaba4 --- /dev/null +++ b/main.jsx @@ -0,0 +1,28 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' +import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom' +import MainPage from './mainpage.jsx' +import Dashboard from './components/Dashboard.jsx' +import Navbar from './navbar.jsx' +import './mainpagestyle.css' + +const ProtectedRoute = ({ children }) => { + const isAuthenticated = localStorage.getItem('isAuthenticated') === 'true'; + return isAuthenticated ? children : ; +}; + +ReactDOM.createRoot(document.getElementById('root')).render( + + + + } /> + + + + } /> + + + , +) + diff --git a/mainpage.jsx b/mainpage.jsx new file mode 100644 index 000000000..27ef19995 --- /dev/null +++ b/mainpage.jsx @@ -0,0 +1,32 @@ +import React from 'react'; +import './mainpagestyle.css'; +import StateDropdown from './components/StateDropdown'; +import LoginButton from './components/LoginButton'; +//import AnalyticsChart from './components/Analytics'; +import AnalyticsChart from 'C:\\Users\\aadva\\fintechai\\src\\Analitics.jsx'; + +function MainPage() { + return ( + <> + +
+ + +
+ +
+
+
Finura
+
"Empowering users with AI-driven financial insights and
seamless support through a smart, user-friendly fintech
dashboard."
+
+ +
+

Welcome to the Future

+

Explore our services and products that help you to further explore
banking and your financial health wisly
and effiecently

+
+
+ + ); +} + +export default MainPage; diff --git a/mainpagestyle.css b/mainpagestyle.css new file mode 100644 index 000000000..41ccb69e6 --- /dev/null +++ b/mainpagestyle.css @@ -0,0 +1,174 @@ +@font-face { + font-family: 'Gilroy-Bold'; + src: local('Gilroy-Bold'), url(./fonts/Gilroy-Bold.ttf) format('truetype'); + } + + @font-face { + font-family: 'Gilroy-Medium'; + src: local('Gilroy-Medium'), url(./fonts/Gilroy-Medium.ttf) format('truetype'); + } + + @font-face { + font-family: 'Gilroy-Light'; + src: local('Gilroy-Light'), url(./fonts/Gilroy-Light.ttf) format('truetype'); + } + +h1 { + color: #333; + font-size: 2.5rem; +} + +h2 { + color: #666; + font-size: 1.8rem; +} + +body { + background: #1A1A1A; + margin: 0; + padding: 0; +} + +html, body { + overflow-x: hidden; + scrollbar-width: thin; + scrollbar-color: #774EBD rgba(255, 255, 255, 0.1); +} + +.state-dropdown{ + margin-top: 35.74px; + margin-left: 1166.26px; + margin-right: 314px; +} + +.page-container { + height: 100vh; + overflow-y: auto; + position: relative; + max-width: 100vw; + overflow-x: hidden; +} + +.section { + min-height: 100vh; + width: 100%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + position: relative; +} + +.section-two { + background: #1A1A1A; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding: 2rem; +} + +.section-two h1 { + color: rgba(255, 255, 255, 0.87); + font-family:Arial, Helvetica, sans-serif; + font-size: 64px; + margin-bottom: 2rem; +} + +.Mainheading { + text-align: center; + font-family:Arial, Helvetica, sans-serif; + font-size: 250.821px; + font-style: normal; + font-weight: 400; + color: transparent; + line-height: normal; + background: linear-gradient(90deg, #774EBD 0%, #372457 100%); + background-clip: text; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + margin-top: 1rem; + margin-left: 496px; + margin-right: 495.65px; +} + +.smallpara{ + color: #FFF; + text-align: center; + font-family:Arial, Helvetica, sans-serif; + font-size: 36px; + font-style: normal; + font-weight: 300; + line-height: normal; + margin-top: 10px; + +} + +.top-controls { + position: fixed; + top: 0; + left: 0; + right: 0; + padding: 20px; + z-index: 1000; + display: flex; + justify-content: space-between; + align-items: center; +} + +@media screen and (max-width: 1200px) { + .Mainheading { + font-size: 180px; + margin: 150px 20px; + } + + .smallpara { + font-size: 28px; + margin: 20px; + } +} + +@media screen and (max-width: 768px) { + body { + margin-left: 0; + } + + .Mainheading { + font-size: 120px; + margin: 100px 15px; + } + + .smallpara { + font-size: 24px; + } +} + +@media screen and (max-width: 480px) { + .Mainheading { + font-size: 80px; + margin: 80px 10px; + } + + .smallpara { + font-size: 20px; + } +} + +/* Custom scrollbar for Chrome/Safari/Opera */ +::-webkit-scrollbar { + width: 8px; +} + +::-webkit-scrollbar-track { + background: rgba(255, 255, 255, 0.1); + border-radius: 4px; +} + +::-webkit-scrollbar-thumb { + background: linear-gradient(180deg, #774EBD 0%, #372457 100%); + border-radius: 4px; +} + +::-webkit-scrollbar-thumb:hover { + background: linear-gradient(180deg, #8b5ed4 0%, #4c2f77 100%); +} diff --git a/navbar.jsx b/navbar.jsx new file mode 100644 index 000000000..295aef367 --- /dev/null +++ b/navbar.jsx @@ -0,0 +1,31 @@ +import React, { useState } from "react"; +import './styles/navbar.css'; + +function Navbar() { + const [isOpen, setIsOpen] = useState(false); + + const toggleMenu = () => { + setIsOpen(!isOpen); + document.body.classList.toggle("open"); + }; + + return ( + <> +
+ + + + ); +} + +export default Navbar; diff --git a/transaction.jsx b/transaction.jsx new file mode 100644 index 000000000..8232c7e66 --- /dev/null +++ b/transaction.jsx @@ -0,0 +1,63 @@ +export const fetchGooglePayTransactions = async () => { + return [ + { date: "2024-01-05", type: "income", amount: 5200, name: "Salary Deposit" }, + { date: "2024-01-12", type: "outcome", amount: 2600, name: "Rent Payment" }, + { date: "2024-01-20", type: "income", amount: 4800, name: "Client Payment" }, + { date: "2024-01-28", type: "outcome", amount: 2000, name: "Utilities" }, + + { date: "2024-02-06", type: "income", amount: 6200, name: "Freelance Work" }, + { date: "2024-02-15", type: "outcome", amount: 3100, name: "Shopping" }, + { date: "2024-02-22", type: "income", amount: 5300, name: "Investment Returns" }, + { date: "2024-02-27", type: "outcome", amount: 2900, name: "Car Insurance" }, + + { date: "2024-03-03", type: "income", amount: 7000, name: "Bonus Payment" }, + { date: "2024-03-10", type: "outcome", amount: 3500, name: "Home Repairs" }, + { date: "2024-03-18", type: "income", amount: 7500, name: "Contract Work" }, + { date: "2024-03-25", type: "outcome", amount: 3700, name: "Healthcare" }, + + { date: "2024-04-07", type: "income", amount: 6700, name: "Sales Commission" }, + { date: "2024-04-14", type: "outcome", amount: 3300, name: "Education Fees" }, + { date: "2024-04-21", type: "income", amount: 7200, name: "Rental Income" }, + { date: "2024-04-29", type: "outcome", amount: 3400, name: "Travel Expenses" }, + + { date: "2024-05-05", type: "income", amount: 8000, name: "Project Payment" }, + { date: "2024-05-12", type: "outcome", amount: 3900, name: "Groceries" }, + { date: "2024-05-20", type: "income", amount: 8600, name: "Consulting Fee" }, + { date: "2024-05-30", type: "outcome", amount: 4100, name: "Dining Out" }, + + { date: "2024-06-04", type: "income", amount: 9200, name: "Stock Dividends" }, + { date: "2024-06-13", type: "outcome", amount: 4500, name: "Entertainment" }, + { date: "2024-06-21", type: "income", amount: 9800, name: "Business Income" }, + { date: "2024-06-28", type: "outcome", amount: 4600, name: "Loan Repayment" }, + + { date: "2024-07-08", type: "income", amount: 10300, name: "Salary Bonus" }, + { date: "2024-07-16", type: "outcome", amount: 5200, name: "Vacation" }, + { date: "2024-07-23", type: "income", amount: 10800, name: "Freelance Project" }, + { date: "2024-07-29", type: "outcome", amount: 5400, name: "Insurance Premium" }, + + { date: "2024-08-06", type: "income", amount: 11000, name: "Consulting Income" }, + { date: "2024-08-15", type: "outcome", amount: 5600, name: "Household Items" }, + { date: "2024-08-22", type: "income", amount: 11500, name: "Investment Profit" }, + { date: "2024-08-30", type: "outcome", amount: 5700, name: "Medical Bills" }, + + { date: "2024-09-07", type: "income", amount: 9900, name: "Side Job" }, + { date: "2024-09-14", type: "outcome", amount: 5100, name: "Car Maintenance" }, + { date: "2024-09-20", type: "income", amount: 10400, name: "Part-time Job" }, + { date: "2024-09-27", type: "outcome", amount: 5300, name: "Subscription Fees" }, + + { date: "2024-10-06", type: "income", amount: 8800, name: "Freelance Work" }, + { date: "2024-10-15", type: "outcome", amount: 4700, name: "Pet Care" }, + { date: "2024-10-22", type: "income", amount: 9200, name: "Consulting Fee" }, + { date: "2024-10-29", type: "outcome", amount: 4900, name: "Gift Purchase" }, + + { date: "2024-11-05", type: "income", amount: 7600, name: "Rental Income" }, + { date: "2024-11-12", type: "outcome", amount: 4000, name: "Utility Bills" }, + { date: "2024-11-19", type: "income", amount: 8000, name: "Project Payment" }, + { date: "2024-11-25", type: "outcome", amount: 4200, name: "Dining Out" }, + + { date: "2024-12-08", type: "income", amount: 8400, name: "Sales Commission" }, + { date: "2024-12-16", type: "outcome", amount: 4500, name: "Holiday Shopping" }, + { date: "2024-12-23", type: "income", amount: 8900, name: "Year-end Bonus" }, + { date: "2024-12-30", type: "outcome", amount: 4600, name: "New Year Celebration" }, + ]; +}; \ No newline at end of file From 65e3658813da57fedb292b028db6fb7637ccfc22 Mon Sep 17 00:00:00 2001 From: Joshua Sunny Ninan <145998098+Joshualostonearth@users.noreply.github.com> Date: Sun, 9 Mar 2025 05:54:14 +0530 Subject: [PATCH 11/13] Create index.html --- index.html | 231 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 231 insertions(+) create mode 100644 index.html diff --git a/index.html b/index.html new file mode 100644 index 000000000..091f77c17 --- /dev/null +++ b/index.html @@ -0,0 +1,231 @@ + + + + + + FinTech FAQ Chatbot + + + +

FinBot

+
+
+ + +
+ + + + From d5745bb92133f907bafd8b4a7889d43db526c97d Mon Sep 17 00:00:00 2001 From: EdKMathew <145998975+EdKMathew@users.noreply.github.com> Date: Sun, 9 Mar 2025 10:31:43 +0530 Subject: [PATCH 12/13] Update README.md --- README.md | 64 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 68af89873..9d22d8beb 100644 --- a/README.md +++ b/README.md @@ -39,11 +39,10 @@ _Replace VIDEO_ID with your YouTube video ID or provide an alternative demo link ### Technologies Used - **Frontend**: React -- **Backend**: [Technologies] +- **Backend**: node.js - **Database**: MongoDB -- **APIs**: Screener,Mistren -- **DevOps**: [Technologies] -- **Other Tools**: [Technologies] +- **APIs**: foduucom/stockmarket-future-prediction,Mistran + ## Key Features ### 1. User-Friendly Dashboard @@ -62,44 +61,75 @@ _Replace VIDEO_ID with your YouTube video ID or provide an alternative demo link ## Setup Instructions ### Prerequisites -- Requirement 1 -- Requirement 2 -- Requirement 3 +- Node.js: Ensure you have Node.js installed. You can download it from nodejs.org. +- npm: Node Package Manager, which comes with Node.js, to manage project dependencies. +- React: For the frontend development. +- Express: For the backend server. +- Fetch API: For making HTTP requests to the Hugging Face API. +- dotenv: For managing environment variables (optional but recommended) ### Installation ```bash - +npm rechart +npm install express +npm install cors +npm install node-fetch +npm install dotenv +npm install react-router-dom ``` ### Running the Project ```bash - +npm run dev ``` ## Additional Resources ### Project Timeline -_Brief overview of your development process and milestones_ +Morning: Set up the Express server with Hugging Face API integration and a basic FAQ database for finance questions. +Afternoon: Developed a robust isFinanceRelated() function with extensive finance-related keyword categories. +Evening: Implemented a currency conversion feature with regex pattern matching and support for multiple currency name variations. +Night: Built the /chat endpoint with response formatting, including HTML bold tags, and added error handling. +🗓 Sunday + +Morning: Discussed and planned transaction data integration. +Afternoon: Added a transaction dataset and improved isFinanceRelated() with transaction-related keywords. Developed a transaction query handler. +Evening: Restructured the code by moving transaction data to a separate file and ensured proper module imports/exports. +Night: Tested the chatbot’s ability to handle queries about income/expense summaries, balance breakdowns, and transaction searches. + +March 8, 2025 +Project Setup: Initialized repository, set up project structure, and installed dependencies for Node.js, Express, and React. +Backend Development: Created Express server, defined /chat endpoint, configured CORS, implemented FAQ handling, hardcoded exchange rates, and added currency conversion logic. +Frontend Development: Created React app, built Dashboard component, developed chat interface, and implemented message handling. +Testing & Debugging: Tested API using Postman, debugged server responses, and ensured correct API handling. +Styling: Applied CSS for chat interface and dashboard, ensured responsiveness with media queries. +Integration: Connected frontend with backend to process and display messages. +Feature Enhancement: Added transaction data queries, improved error handling, and implemented logging. +March 9, 2025 +Final Touches: Refined CSS styles, ensured consistency, and fixed layout issues. +Testing & Deployment: Conducted final tests, deployed backend and frontend, and verified production functionality. ### Challenges Faced -_Discuss technical challenges and how you overcame them_ +The frontend might fail to fetch data due to CORS restrictions. Ensure CORS is properly configured in your Express server ### Future Enhancements -_Share your vision for future development_ +-Improve fintuning of finance chatbot +-More functional split pay which includes sms in gmail messages +-Emergemcy fund allocater ### References (if any) -- [Reference 1](link) -- [Reference 2](link) +- [Reference 1](https://www.worldbank.org/ext/en/home) +- [Reference 2](https://www.forbes.com) --- ### Submission Checklist -- [ ] Completed all sections of this README +- [x] Completed all sections of this README - [ ] Added project demo video - [ ] Provided live project link - [x] Ensured all team members are listed -- [ ] Included setup instructions -- [ ] Submitted final code to repository +- [x] Included setup instructions +- [x] Submitted final code to repository --- From 5048640583fa942298b620574308a9232b9a47d6 Mon Sep 17 00:00:00 2001 From: Advaith A Arun <148091632+ADU773@users.noreply.github.com> Date: Sun, 9 Mar 2025 12:22:58 +0530 Subject: [PATCH 13/13] Add files via upload --- Dashboard.jsx | 153 +++++++++--- LoginButton.jsx | 4 +- LoginPage.jsx | 43 ++++ SplitPay.css | 73 ++++++ SplitPayApp.jsx | 282 +++++++++++++++++++++ StockTracker.css | 16 ++ StockTracker.jsx | 83 +++++++ StockTrends.jsx | 124 +++++++++ analytics.css | 141 +++++++++++ dashboard.css | 553 +++++++++++++++++++++++++++++++++++++++++ indexbotfile.html | 231 +++++++++++++++++ login.css | 56 +++++ loginButton.css | 21 ++ loginModal.css | 95 +++++++ mainpagestyle.css | 4 +- navbar.css | 215 ++++++++++++++++ stateDropdown.css | 36 +++ stockTrends.css | 200 +++++++++++++++ transactionHistory.css | 93 +++++++ 19 files changed, 2378 insertions(+), 45 deletions(-) create mode 100644 LoginPage.jsx create mode 100644 SplitPay.css create mode 100644 SplitPayApp.jsx create mode 100644 StockTracker.css create mode 100644 StockTracker.jsx create mode 100644 StockTrends.jsx create mode 100644 analytics.css create mode 100644 dashboard.css create mode 100644 indexbotfile.html create mode 100644 login.css create mode 100644 loginButton.css create mode 100644 loginModal.css create mode 100644 navbar.css create mode 100644 stateDropdown.css create mode 100644 stockTrends.css create mode 100644 transactionHistory.css diff --git a/Dashboard.jsx b/Dashboard.jsx index f1886fea5..271d0dde7 100644 --- a/Dashboard.jsx +++ b/Dashboard.jsx @@ -1,14 +1,26 @@ -import React, { useState, useEffect } from 'react'; -import { useNavigate } from 'react-router-dom'; +import React, { useState, useEffect, useRef } from 'react'; +import { useNavigate, Route, Routes, Link } from 'react-router-dom'; import '../styles/dashboard.css'; import AnalyticsChart from './Analytics'; import TransactionHistory from './TransactionHistory'; import StockTrends from './StockTrends'; +import SplitPayApp from './SplitPayApp'; // Import the SplitPayApp component function Dashboard() { const navigate = useNavigate(); const [showLogoutConfirm, setShowLogoutConfirm] = useState(false); const [isLoading, setIsLoading] = useState(true); + const [chatMessages, setChatMessages] = useState([]); + const [inputMessage, setInputMessage] = useState(''); + const messagesEndRef = useRef(null); + + const scrollToBottom = () => { + messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); + }; + + useEffect(() => { + scrollToBottom(); + }, [chatMessages]); useEffect(() => { // Check authentication and set up dashboard @@ -38,18 +50,111 @@ function Dashboard() { ); } + async function handleSendMessage(e) { + e.preventDefault(); + if (!inputMessage.trim()) return; + + const message = inputMessage.trim(); + setChatMessages(prev => [...prev, { type: 'user', content: message }]); + setInputMessage(''); + + try { + const response = await fetch('http://localhost:5174/chat', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ message }) + }); + + if (!response.ok) { + const errorText = await response.text(); + console.error('API Error Response:', errorText); + throw new Error(`HTTP error! status: ${response.status}`); + } + + const data = await response.json(); + console.log('Response data:', data); // Debug logging + + if (data && data.response) { + setChatMessages(prev => [...prev, { + type: 'bot', + content: data.response + }]); + } else { + throw new Error('Invalid response format'); + } + } catch (error) { + console.error('Chat Error:', error); + setChatMessages(prev => [...prev, { + type: 'bot', + content: 'FinBot: I apologize, but I am temporarily unable to process requests. Please try again shortly.' + }]); + } + } + return (
Finura
- +
+ +
+
+ + +
+
+

Financial Overview

+ +
+
+
+ +
+
+ +
+
+
+
+ } /> + } /> {/* Add route for Split Pay */} + +
+
+
+

AI Financial Assistant

+
+
+ {chatMessages.map((msg, index) => ( +
+ {msg.type === 'user' ? `You: ${msg.content}` : msg.content} +
+ ))} +
+
+
+ setInputMessage(e.target.value)} + placeholder="Ask about your finances..." + /> + +
+
+
+
{showLogoutConfirm && (
@@ -63,40 +168,6 @@ function Dashboard() {
)} - -
-
-
-

Financial Overview

- -
-
-
- -
-
- -
-
-
- -
-
-
-

AI Assistant

-
-
-
- Hello! How can I help you with your finances today? -
-
-
- - -
-
-
-
); } diff --git a/LoginButton.jsx b/LoginButton.jsx index 9e3b15a2c..2b7dfbbb2 100644 --- a/LoginButton.jsx +++ b/LoginButton.jsx @@ -6,12 +6,12 @@ function LoginButton() { const [showModal, setShowModal] = useState(false); return ( - <> +
{showModal && setShowModal(false)} />} - +
); } diff --git a/LoginPage.jsx b/LoginPage.jsx new file mode 100644 index 000000000..f3766282c --- /dev/null +++ b/LoginPage.jsx @@ -0,0 +1,43 @@ +import React, { useState } from 'react'; +import '../styles/login.css'; + +function LoginPage() { + const [username, setUsername] = useState(''); + const [password, setPassword] = useState(''); + + const handleLogin = (e) => { + e.preventDefault(); + // Handle login logic here + }; + + return ( +
+
+

Login

+
+ + setUsername(e.target.value)} + required + /> +
+
+ + setPassword(e.target.value)} + required + /> +
+ +
+
+ ); +} + +export default LoginPage; diff --git a/SplitPay.css b/SplitPay.css new file mode 100644 index 000000000..68e2140d2 --- /dev/null +++ b/SplitPay.css @@ -0,0 +1,73 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; + font-family: Arial, sans-serif; +} + +body { + background: #121212; + color: #333; + line-height: 1.6; +} + +.container { + max-width: 800px; + margin: 20px auto; + padding: 20px; +} + +.header { + text-align: center; + margin-bottom: 20px; + color: #8662C2; +} + +.card { + background: #191919; + padding: 20px; + border-radius: 8px; + color: white; + box-shadow: 0 2px 4px rgba(255, 255, 255, 0); + margin-bottom: 20px; +} + +.form-group { + margin-bottom: 15px; +} + +input, +button { + padding: 10px; + width: 100%; + margin-bottom: 10px; + border: 1px solid #ddd; + border-radius: 4px; +} + +button { + background: #8662C2; + color: #121212; + border: none; + cursor: pointer; + transition: background 0.3s; +} + +button:hover { + background: #8662C2; +} + +.transaction-list { + list-style: none; +} + +.transaction-item { + padding: 10px; + border-bottom: 1px solid #121212; +} + +.settlement-result { + background: #e8f4f8; + padding: 15px; + border-radius: 4px; +} diff --git a/SplitPayApp.jsx b/SplitPayApp.jsx new file mode 100644 index 000000000..49f9902e8 --- /dev/null +++ b/SplitPayApp.jsx @@ -0,0 +1,282 @@ +import React, { useState, useEffect } from 'react'; +import './SplitPay.css'; // We'll move the styles to a separate CSS file + +const SplitPayApp = () => { + const [splitPay] = useState(() => new SplitPay()); + const [transactions, setTransactions] = useState([]); + const [settlementOutput, setSettlementOutput] = useState(''); + const [creditOutput, setCreditOutput] = useState(''); + + useEffect(() => { + splitPay.loadState(); + setTransactions(splitPay.transactions); + }, [splitPay]); + + const createGroup = (e) => { + e.preventDefault(); + const name = e.target.groupName.value; + const members = e.target.members.value; + const contacts = e.target.memberContacts.value; + if (name && members && contacts) { + splitPay.createGroup(name, members, contacts); + alert(`Group "${name}" created successfully!`); + e.target.reset(); + } + }; + + const addBill = (e) => { + e.preventDefault(); + const groupName = e.target.billGroup.value; + const payer = e.target.payer.value; + const amount = parseFloat(e.target.amount.value); + const description = e.target.description.value; + if (groupName && payer && amount && description) { + splitPay.addBill(groupName, payer, amount, description); + setTransactions([...splitPay.transactions]); + e.target.reset(); + } + }; + + const settleBalances = (e) => { + e.preventDefault(); + const groupName = e.target.settleGroup.value; + if (groupName) { + const settlements = splitPay.settleBalances(groupName); + setSettlementOutput( + settlements.length > 0 ? ( +
+

Settlement Instructions (Notifications Sent):

+
    + {settlements.map((s, index) => ( +
  • {`${s.from} pays ${s.to} ₹${s.amount.toFixed(2)}`}
  • + ))} +
+
+ ) : ( + 'No settlements needed or group not found.' + ) + ); + } + }; + + const requestSplitCredit = (e) => { + e.preventDefault(); + const groupName = e.target.creditGroup.value; + const amount = parseFloat(e.target.creditAmount.value); + if (groupName && amount) { + const credit = splitPay.requestSplitCredit(groupName, amount); + if (credit) { + setCreditOutput( +
+

Credit Approved!

+

Total: ₹{credit.totalAmount}

+

Per Person: ₹{credit.splitAmount.toFixed(2)}

+

Due: {credit.repaymentTerms.dueDate.toLocaleDateString()}

+
+ ); + } + } + }; + + return ( +
+

SplitPay

+ +
+

Create Group

+
+ + + + +
+
+ +
+

Add Bill

+
+ + + + + +
+
+ +
+

Transactions

+
    + {transactions.map((t) => ( +
  • + {t.description}: ₹{t.amount} paid by {t.payer} (₹{t.splitAmount.toFixed(2)} each) - {t.timestamp.toLocaleString()} +
  • + ))} +
+
+ +
+

Settle Balances

+
+ + +
+
{settlementOutput}
+
+ +
+

Request Split Credit

+
+ + + +
+
{creditOutput}
+
+
+ ); +}; + +// Move the SplitPay class outside the component +class SplitPay { + constructor() { + this.groups = new Map(); + this.transactions = []; + this.loadState(); + } + + createGroup(name, members, contacts) { + const memberList = members.split(',').map(m => m.trim()); + const contactList = contacts.split(',').map(c => c.trim()); + if (memberList.length !== contactList.length) { + alert('Number of members and contacts must match!'); + return; + } + + const group = { name, members: new Map(), totalSpent: 0 }; + memberList.forEach((member, index) => { + group.members.set(member, { + paid: 0, + owes: 0, + name: member, + contact: contactList[index] + }); + }); + + this.groups.set(name, group); + this.saveState(); + return group; + } + + addBill(groupName, payer, amount, description) { + if (!this.groups.has(groupName)) { + alert('Group not found!'); + return; + } + + const group = this.groups.get(groupName); + const splitAmount = amount / group.members.size; + group.totalSpent += amount; + + const payerData = group.members.get(payer); + if (!payerData) { + alert('Payer not found in group!'); + return; + } + + payerData.paid += amount; + group.members.forEach((memberData, memberName) => { + if (memberName !== payer) memberData.owes += splitAmount; + }); + + const transaction = { + id: Date.now(), + groupName, + payer, + amount, + splitAmount, + description, + timestamp: new Date() + }; + + this.transactions.push(transaction); + this.saveState(); + return transaction; + } + + settleBalances(groupName) { + if (!this.groups.has(groupName)) { + alert('Group not found!'); + return []; + } + + const group = this.groups.get(groupName); + const settlements = []; + group.members.forEach((memberData, memberName) => { + const netBalance = memberData.paid - memberData.owes; + settlements.push({ name: memberName, netBalance, contact: memberData.contact }); + }); + + const instructions = this.calculateSettlements(settlements); + this.notifyDebtors(groupName, instructions); + return instructions; + } + + calculateSettlements(settlements) { + const creditors = settlements.filter(s => s.netBalance > 0); + const debtors = settlements.filter(s => s.netBalance < 0); + const instructions = []; + + creditors.forEach(creditor => { + while (creditor.netBalance > 0 && debtors.length > 0) { + const debtor = debtors[0]; + const amount = Math.min(creditor.netBalance, Math.abs(debtor.netBalance)); + instructions.push({ from: debtor.name, to: creditor.name, amount, debtorContact: debtor.contact }); + creditor.netBalance -= amount; + debtor.netBalance += amount; + if (debtor.netBalance === 0) debtors.shift(); + } + }); + + return instructions; + } + + async notifyDebtors(groupName, instructions) { + instructions.forEach(instruction => { + const message = `Hi ${instruction.from}, you owe ${instruction.to} ₹${instruction.amount.toFixed(2)} for ${groupName}. Pay now: [Payment Link]`; + console.log(`Sending to ${instruction.debtorContact}: ${message}`); + alert(`Notification sent to ${instruction.from} (${instruction.debtorContact}): ${message}`); + }); + } + + requestSplitCredit(groupName, amount) { + if (!this.groups.has(groupName)) { + alert('Group not found!'); + return; + } + const group = this.groups.get(groupName); + const splitAmount = amount / group.members.size; + const credit = { + groupName, + totalAmount: amount, + splitAmount, + status: 'approved', + repaymentTerms: { perPerson: splitAmount, dueDate: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000) } + }; + this.saveState(); + return credit; + } + + saveState() { + localStorage.setItem('splitpay_groups', JSON.stringify([...this.groups])); + localStorage.setItem('splitpay_transactions', JSON.stringify(this.transactions)); + } + + loadState() { + const groups = localStorage.getItem('splitpay_groups'); + const transactions = localStorage.getItem('splitpay_transactions'); + if (groups) this.groups = new Map(JSON.parse(groups)); + if (transactions) this.transactions = JSON.parse(transactions); + } +} + +export default SplitPayApp; diff --git a/StockTracker.css b/StockTracker.css new file mode 100644 index 000000000..81fc46454 --- /dev/null +++ b/StockTracker.css @@ -0,0 +1,16 @@ +.stock-tracker { + font-family: Arial, Helvetica, sans-serif; + margin: 20px; +} + +.stock-tracker h2 { + color: #333; +} + +.stock-details { + margin-top: 20px; +} + +.stock-details p { + margin: 5px 0; +} diff --git a/StockTracker.jsx b/StockTracker.jsx new file mode 100644 index 000000000..fc7fcba91 --- /dev/null +++ b/StockTracker.jsx @@ -0,0 +1,83 @@ +import React, { useState, useEffect } from "react"; +import { Line } from "react-chartjs-2"; +import "chart.js/auto"; +import "./StockTracker.css"; + +const StockTracker = ({ symbol = "AAPL" }) => { + const API_KEY = "FOU3LD1ZKD1QFRFE"; // Keep this secure in a backend + const [stockData, setStockData] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + + const fetchStockData = async () => { + try { + const response = await fetch( + `https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=${symbol}&interval=5min&apikey=${API_KEY}` + ); + const data = await response.json(); + + if (data["Time Series (5min)"]) { + const timeSeries = data["Time Series (5min)"]; + const stockDataArray = Object.keys(timeSeries).map(timestamp => ({ + time: timestamp, + open: parseFloat(timeSeries[timestamp]["1. open"]), + high: parseFloat(timeSeries[timestamp]["2. high"]), + low: parseFloat(timeSeries[timestamp]["3. low"]), + close: parseFloat(timeSeries[timestamp]["4. close"]), + volume: parseInt(timeSeries[timestamp]["5. volume"]), + })); + + setStockData(stockDataArray); + } else { + setError("Invalid API response. Check API limits."); + } + } catch (err) { + setError("Failed to fetch stock data"); + } + setLoading(false); + }; + + useEffect(() => { + fetchStockData(); + const interval = setInterval(fetchStockData, 60000); // Update every 60 seconds + return () => clearInterval(interval); + }, [symbol]); + + const chartData = { + labels: stockData ? stockData.map(data => data.time) : [], + datasets: [ + { + label: "Stock Price", + data: stockData ? stockData.map(data => data.close) : [], + fill: false, + backgroundColor: "rgba(75,192,192,0.4)", + borderColor: "rgba(75,192,192,1)", + }, + ], + }; + + return ( +
+

Live Stock Tracker: {symbol}

+ {loading ? ( +

Loading...

+ ) : error ? ( +

{error}

+ ) : ( +
+ +
+

Time: {stockData[0].time}

+

Open: ${stockData[0].open.toFixed(2)}

+

High: ${stockData[0].high.toFixed(2)}

+

Low: ${stockData[0].low.toFixed(2)}

+

Close: ${stockData[0].close.toFixed(2)}

+

Volume: {stockData[0].volume.toLocaleString()}

+
+
+ )} +
+ ); +}; + +export default StockTracker; diff --git a/StockTrends.jsx b/StockTrends.jsx new file mode 100644 index 000000000..727922a48 --- /dev/null +++ b/StockTrends.jsx @@ -0,0 +1,124 @@ +import React, { useState, useEffect } from 'react'; +import { LineChart, Line, XAxis, YAxis, Tooltip, ResponsiveContainer } from 'recharts'; +import '../styles/stockTrends.css'; + +const StockTrends = () => { + const [stockData, setStockData] = useState([]); + const [loading, setLoading] = useState(true); + const [currentPage, setCurrentPage] = useState(0); + const [error, setError] = useState(null); + const API_KEY = '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'; + const SYMBOLS = [ + 'AAPL', 'GOOGL', 'MSFT', 'AMZN', 'TSLA', + 'META', 'NVDA', 'JPM', 'V', 'WMT', + 'JNJ', 'PG', 'MA', 'UNH', 'HD' + ]; + const STOCKS_PER_PAGE = 5; + + const MOCK_DATA = [ + { symbol: 'AAPL', price: 185.92, change: 2.34, percentChange: 1.25, high: 186.74, low: 184.21 }, + { symbol: 'GOOGL', price: 142.65, change: 1.87, percentChange: 1.31, high: 143.12, low: 141.23 }, + { symbol: 'MSFT', price: 378.85, change: 4.21, percentChange: 1.12, high: 379.21, low: 375.62 }, + { symbol: 'AMZN', price: 155.34, change: 2.12, percentChange: 1.38, high: 156.00, low: 153.89 }, + { symbol: 'TSLA', price: 248.48, change: -3.25, percentChange: -1.29, high: 251.45, low: 247.12 } + ]; + + const fetchStockData = async () => { + try { + setError(null); + const startIdx = currentPage * STOCKS_PER_PAGE; + const currentSymbols = SYMBOLS.slice(startIdx, startIdx + STOCKS_PER_PAGE); + + // Try API fetch first + try { + const API_KEY = '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'; + const promises = currentSymbols.map(async (symbol) => { + const response = await fetch(`https://finnhub.io/api/v1/quote?symbol=${symbol}&token=${API_KEY}`); + if (!response.ok) throw new Error('API request failed'); + const data = await response.json(); + return { + symbol, + price: data.c || 0, + change: data.d || 0, + percentChange: data.dp || 0, + high: data.h || 0, + low: data.l || 0 + }; + }); + + const results = await Promise.all(promises); + setStockData(results.sort((a, b) => b.percentChange - a.percentChange)); + } catch (apiError) { + console.warn('API fetch failed, using mock data', apiError); + // Use mock data as fallback + const mockDataForPage = MOCK_DATA.slice(startIdx, startIdx + STOCKS_PER_PAGE); + setStockData(mockDataForPage); + } + + setLoading(false); + } catch (error) { + console.error('Error in fetchStockData:', error); + setError('Unable to load stock data'); + setStockData(MOCK_DATA.slice(0, STOCKS_PER_PAGE)); // Fallback to mock data + setLoading(false); + } + }; + + useEffect(() => { + fetchStockData(); + // Remove the interval to stop auto-updates + }, [currentPage]); + + const nextPage = () => { + setCurrentPage((prev) => (prev + 1) % Math.ceil(SYMBOLS.length / STOCKS_PER_PAGE)); + }; + + const prevPage = () => { + setCurrentPage((prev) => + prev === 0 ? Math.ceil(SYMBOLS.length / STOCKS_PER_PAGE) - 1 : prev - 1 + ); + }; + + if (error) { + return ( +
+
{error}
+
+ ); + } + + return ( +
+
+ +

Top Performers

+ +
+
+ {loading ? ( +
Loading market data...
+ ) : ( +
+ {stockData.map((stock) => ( +
+
+ {stock.symbol} + = 0 ? 'positive' : 'negative'}`}> + {stock.percentChange.toFixed(2)}% + +
+
${stock.price.toFixed(2)}
+
+ L: ${stock.low.toFixed(2)} + H: ${stock.high.toFixed(2)} +
+
+ ))} +
+ )} +
+
+ ); +}; + +export default StockTrends; diff --git a/analytics.css b/analytics.css new file mode 100644 index 000000000..fb5477dcd --- /dev/null +++ b/analytics.css @@ -0,0 +1,141 @@ +.analytics-container { + background: rgba(18, 18, 18, 0.95); + padding: 1.5rem; + border-radius: 8px; + border: 1px solid rgba(255, 255, 255, 0.1); + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + overflow: hidden; + max-width: 100%; + overflow-x: hidden; + position: relative; + min-height: 400px; + max-height: 100%; + font-family: Arial, Helvetica, sans-serif; +} + +.year-select { + background: rgba(18, 18, 18, 0.95); + color: rgba(255, 255, 255, 0.87); + border: 1px solid rgba(255, 255, 255, 0.1); + padding: 8px 16px; + border-radius: 4px; + margin-bottom: 20px; + font-family: Arial, Helvetica, sans-serif; + cursor: pointer; +} + +.year-select:hover { + border-color: #774EBD; +} + +.year-select:focus { + outline: none; + border-color: #774EBD; +} + +@media screen and (max-width: 900px) { + .analytics-container { + overflow-x: auto; + padding: 1rem; + min-height: 450px; + } + + .chart-container { + height: calc(100% - 70px); + } + + .recharts-wrapper { + width: 90% !important; + height: 85% !important; + transform: scale(0.9); + } +} + +.chart-container { + position: relative; + width: 100%; + height: calc(100% - 50px); + padding: 0.5rem; + display: flex; + flex-direction: column; + align-items: center; +} + +.recharts-wrapper { + position: relative !important; + width: 100% !important; + height: 90% !important; + margin: 0 auto; + transform-origin: top center; + transform: scale(0.85); +} + +.recharts-responsive-container { + width: 100% !important; + height: 100% !important; + max-height: 250px !important; +} + +.chart-container h3 { + color: rgba(255, 255, 255, 0.87); + margin-bottom: 1.5rem; + font-size: 1.2rem; + font-family: Arial, Helvetica, sans-serif; +} + +/* Tooltip customization */ +.recharts-tooltip-wrapper .recharts-default-tooltip { + background-color: rgba(18, 18, 18, 0.95) !important; + border: 1px solid rgba(255, 255, 255, 0.1) !important; + border-radius: 4px; + padding: 0.5rem; +} + +.recharts-tooltip-item-list { + color: rgba(255, 255, 255, 0.87); +} + +/* Legend customization */ +.recharts-default-legend { + margin-top: 1rem !important; +} + +.recharts-legend-item-text { + color: rgba(255, 255, 255, 0.87) !important; +} + +/* Reset any transformations on the surface */ +.recharts-surface { + overflow: visible; + transform: none; +} + +/* Remove scaling from bars to fix alignment */ +.recharts-bar-rectangle { + transform: none; +} + +/* Adjust text positioning */ +.recharts-text { + font-size: 11px; +} + +.recharts-cartesian-axis-tick-value { + transform: translateY(3px); +} + +/* Ensure bars align with grid lines */ +.recharts-bar { + transform-origin: center; + shape-rendering: crispEdges; +} + +@media screen and (max-width: 768px) { + .analytics-container { + padding: 1rem; + min-height: 350px; + } +} diff --git a/dashboard.css b/dashboard.css new file mode 100644 index 000000000..1bb91deb6 --- /dev/null +++ b/dashboard.css @@ -0,0 +1,553 @@ +.dashboard-container { + background: #1A1A1A; + min-height: 100vh; + width: 100%; + /* position: fixed; */ + top: 0; + left: 0; + right: 0; + bottom: 0; + overflow-y: auto; + overflow-x: hidden; + display: flex; + flex-direction: column; + font-family: Arial, Helvetica, sans-serif; +} + +.dashboard-container.loading { + display: flex; + justify-content: center; + align-items: center; +} + +.loading-spinner { + color: #774EBD; + font-size: 1.2rem; +} + +.dashboard-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 1rem 2rem; + background: rgba(18, 18, 18, 0.95); + border-bottom: 1px solid rgba(255, 255, 255, 0.1); +} + +.logo { + font-size: 1.5rem; + font-weight: bold; + background: linear-gradient(90deg, #774EBD 0%, #372457 100%); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; +} + +.dashboard-nav { + display: flex; + gap: 2rem; +} + +.dashboard-nav a { + color: rgba(255, 255, 255, 0.7); + text-decoration: none; + padding: 0.5rem 1rem; + transition: all 0.3s ease; +} + +.dashboard-nav a.active, +.dashboard-nav a:hover { + color: #774EBD; +} + +.dashboard-main { + display: flex; + height: calc(100vh - 80px); + overflow: hidden; +} + +.dashboard-content { + position: relative; + display: grid; + grid-template-columns: 2fr 1fr; /* Shortened width */ + /* gap: 2rem; */ + /* padding: 2rem; */ + overflow-y: auto; + background: #1A1A1A; + width: 1800px; + max-width: 200vw; /* Shortened width */ +} + +.dashboard-left { + display: flex; + flex-direction: column; + gap: 2rem; + height: 100%; + max-height: calc(100vh - 85px); + overflow-y: auto; +} + +.dashboard-right { + height: 100%; + max-height: calc(100vh - 85px); + /* padding-right: 0.5rem; */ + border-left: 1px solid rgba(255, 255, 255, 0.1); + overflow-y: auto; +} + +.chatbot-container { + height: 100%; + display: flex; + flex-direction: column; + background: rgba(18, 18, 18, 0.95); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 8px; +} + +.chatbot-header { + padding: 1rem; + border-bottom: 1px solid rgba(255, 255, 255, 0.1); +} +.chatbot-header h3 { + + margin: 0; + color: rgba(255, 255, 255, 0.87); + font-size: 1.1rem; +} + +.chatbot-messages { + flex: 1; + overflow-y: auto; + padding: 1rem; + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.chatbot-messages .message { + padding: 0.8rem 1rem; + border-radius: 8px; + flex: 1; + overflow-y: auto; + padding: 1rem; + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.chatbot-messages .message { + padding: 0.8rem 1rem; + border-radius: 8px; + max-width: 85%; + color: white; /* Change message text color to white */ +} + +.chatbot-messages .user { + background: rgba(119, 78, 189, 0.1); + align-self: flex-end; + border-left: 3px solid #774EBD; +} + +.chatbot-messages .bot { + background: rgba(255, 255, 255, 0.05); + align-self: flex-start; + border-left: 3px solid #372457; +} + +.chatbot-input { + display: flex; + gap: 0.5rem; + padding: 1rem; + border-top: 1px solid rgba(255, 255, 255, 0.1); +} + +.chatbot-input input { + flex: 1; + padding: 0.8rem; + background: rgba(255, 255, 255, 0.05); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 4px; + color: white; + width: 570px; +} + +.chatbot-input button { + padding: 0.8rem 1.5rem; + background: linear-gradient(90deg, #774EBD 0%, #372457 100%); + color: white; + border: none; + border-radius: 4px; + cursor: pointer; +} + +.chatbot-input button:hover { + opacity: 0.9; +} +*/ + +.chatbot-container { + height: 100%; + max-height: 100%; + margin: 0; + padding: 0; + background: rgba(18, 18, 18, 0.95); + border-radius: 8px; + border: 1px solid rgba(255, 255, 255, 0.1); + display: flex; +} + +.chatbot-header { + padding: 1rem; + border-bottom: 1px solid rgba(255, 255, 255, 0.1); +} + +.chatbot-messages { + flex: 1; + padding: 1rem; + overflow-y: auto; + scrollbar-width: thin; + scrollbar-color: #774EBD rgba(255, 255, 255, 0.1); +} + +.chatbot-messages::-webkit-scrollbar { + width: 6px; +} + +.chatbot-messages::-webkit-scrollbar-track { + background: rgba(0, 0, 0, 0.1); + border-radius: 3px; +} + +.chatbot-messages::-webkit-scrollbar-thumb { + background: linear-gradient(180deg, #774EBD 0%, #372457 100%); + border-radius: 3px; +} + +.message { + padding: 0.8rem 1rem; + border-radius: 8px; + margin-bottom: 1rem; + max-width: 80%; + color: white; /* Change message text color to white */ +} + +.message.bot { + background: rgba(119, 78, 189, 0.1); + border-left: 3px solid #774EBD; +} + +.chatbot-input { + display: flex; + padding: 1rem; + gap: 1rem; + border-top: 1px solid rgba(255, 255, 255, 0.1); +} + +.chatbot-input input { + flex: 1; + padding: 0.8rem; + border-radius: 4px; + background: rgba(255, 255, 255, 0.05); + border: 1px solid rgba(255, 255, 255, 0.1); + color: white; +} + +.chatbot-input button { + background: linear-gradient(90deg, #774EBD 0%, #372457 100%); + color: white; + border: none; + padding: 0.8rem 1.5rem; + border-radius: 4px; + cursor: pointer; +} + +@media (max-width: 768px) { + .dashboard-content { + grid-template-columns: 1fr; + padding: 1rem; + gap: 1rem; + } + + .dashboard-header { + padding: 1rem; + } + + .dashboard-nav { + display: none; + } + + .bottom-row { + grid-template-columns: 1fr; + } + + .dashboard-card, + .bottom-row-item { + height: 350px; + min-height: 300px; + } + + .dashboard-right { + height: 400px; + } +} + +.dashboard-card { + background: rgba(18, 18, 18, 0.95); + padding: 2rem; + border-radius: 8px; + border: 1px solid rgba(255, 255, 255, 0.1); + height: 450px; + min-height: 400px; + overflow: hidden; + display: flex; + flex-direction: column; +} + +.stats { + display: flex; + gap: 10px; + margin-top: 20px; +} + +.stat-item { + padding: 15px; + background: linear-gradient(90deg, #774EBD 0%, #372457 100%); + border-radius: 8px; + flex: 1; +} + +.logout-btn { + background: linear-gradient(90deg, #774EBD 0%, #372457 100%); + color: white; + border: none; + padding: 8px 16px; + border-radius: 4px; + cursor: pointer; +} + +.logout-confirm-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.8); + display: flex; + justify-content: center; + align-items: center; + z-index: 1000; +} + +.logout-confirm-modal { + background: #1A1A1A; + padding: 2rem; + border-radius: 8px; + border: 1px solid rgba(255, 255, 255, 0.1); + text-align: center; + max-width: 400px; + width: 90%; +} + +.logout-confirm-modal h3 { + margin-bottom: 1rem; + color: rgba(255, 255, 255, 0.87); +} + +.logout-confirm-buttons { + display: flex; + gap: 1rem; + justify-content: center; + margin-top: 2rem; +} + +.logout-confirm-buttons button { + padding: 0.8rem 1.5rem; + border-radius: 4px; + border: none; + cursor: pointer; + font-family: Arial, Helvetica, sans-serif; +} + +.logout-confirm-buttons button:first-child { + background: linear-gradient(90deg, #774EBD 0%, #372457 100%); + color: white; +} + +.logout-confirm-buttons button:last-child { + background: rgba(255, 255, 255, 0.1); + color: rgba(255, 255, 255, 0.87); +} + +@media screen and (max-width: 768px) { + .dashboard-content { + grid-template-columns: 1fr; + } + + .transaction-history { + max-width: 100%; + } +} + +@media (max-width: 1200px) { + .dashboard-content { + grid-template-columns: 1fr; + } +} + +.bottom-row { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 2rem; + height: auto; + min-height: 400px; + padding: 0; +} + +.bottom-row-item { + height: 100%; + min-height: 400px; + margin: 0; + overflow: hidden; +} + +@media (max-width: 1200px) { + .bottom-row { + grid-template-columns: 1fr; + } +} + +@media (max-width: 1400px) { + .dashboard-main { + flex-direction: column; + height: auto; + } + + .dashboard-content { + grid-template-columns: 1fr; + gap: 2rem; + height: auto; + min-height: calc(100vh - 80px); + overflow-y: auto; + overflow-x: hidden; + padding: 1rem; + } + + .dashboard-left { + height: auto; + max-height: none; + } + + .dashboard-card { + height: 400px; + } + + .bottom-row { + grid-template-columns: 1fr; + height: auto; + min-height: 350px; + width: 100%; + max-width: 100%; + gap: 2rem; + } + + .bottom-row-item { + height: 350px; + min-height: 350px; + } + + .dashboard-right { + position: relative; + height: 100%; + max-height: 100%; + margin-top: 1rem; + border-left: none; + border-top: 1px solid rgba(255, 255, 255, 0.1); + } + + .chatbot-container { + height: 100%; + position: relative; + } +} + +.split-pay-modal { + display: none; /* Hidden by default */ + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.8); + justify-content: center; + align-items: center; + z-index: 1000; +} + +.split-pay-modal.active { + display: flex; /* Show the modal when active */ +} + +.split-pay-container { + background: #191919; + padding: 20px; + border-radius: 8px; + color: white; + max-width: 800px; + width: 100%; + box-shadow: 0 2px 4px rgba(255, 255, 255, 0.1); +} + +.split-pay-header { + text-align: center; + margin-bottom: 20px; + color: #8662C2; +} + +.split-pay-card { + background: #191919; + padding: 20px; + border-radius: 8px; + color: white; + box-shadow: 0 2px 4px rgba(255, 255, 255, 0.1); + margin-bottom: 20px; +} + +.split-pay-form-group { + margin-bottom: 15px; +} + +.split-pay-form-group input, +.split-pay-form-group button { + padding: 10px; + width: 100%; + margin-bottom: 10px; + border: 1px solid #ddd; + border-radius: 4px; +} + +.split-pay-form-group button { + background: #8662C2; + color: #121212; + border: none; + cursor: pointer; + transition: background 0.3s; +} + +.split-pay-form-group button:hover { + background: #6739B7; +} + +.split-pay-transaction-list { + list-style: none; +} + +.split-pay-transaction-item { + padding: 10px; + border-bottom: 1px solid #121212; +} + +.split-pay-settlement-result { + background: #e8f4f8; + padding: 15px; + border-radius: 4px; +} \ No newline at end of file diff --git a/indexbotfile.html b/indexbotfile.html new file mode 100644 index 000000000..c231cd642 --- /dev/null +++ b/indexbotfile.html @@ -0,0 +1,231 @@ + + + + + + FinTech FAQ Chatbot + + + +

FinBot

+
+
+ + +
+ + + + \ No newline at end of file diff --git a/login.css b/login.css new file mode 100644 index 000000000..867f42362 --- /dev/null +++ b/login.css @@ -0,0 +1,56 @@ +.login-container { + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + background: #121212; +} + +.login-form { + background: #191919; + padding: 20px; + border-radius: 8px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + width: 100%; + max-width: 400px; + color: white; +} + +.login-form h2 { + text-align: center; + margin-bottom: 20px; + color: #8662C2; +} + +.form-group { + margin-bottom: 15px; +} + +.form-group label { + display: block; + margin-bottom: 5px; +} + +.form-group input { + width: 100%; + padding: 10px; + border: 1px solid #ddd; + border-radius: 4px; + background: #232323; + color: white; +} + +button.login-button { + width: 100%; + padding: 12px 20px; /* Adjusted padding for appropriate size */ + background: #8662C2; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + transition: background 0.3s; +} + +button.login-button:hover { + background: #6739B7; +} diff --git a/loginButton.css b/loginButton.css new file mode 100644 index 000000000..491dd415b --- /dev/null +++ b/loginButton.css @@ -0,0 +1,21 @@ +.login-button { + background: linear-gradient(90deg, #774EBD 0%, #372457 100%); + color: white; + border: none; + padding: 10px 24px; + border-radius: 4px; + font-family: Arial, Helvetica, sans-serif; + font-size: 16px; + cursor: pointer; + transition: all 0.3s ease; + position: fixed; + top: 20px; + right: 40px; + z-index: 1000; + width:100px; +} + +.login-button:hover { + opacity: 0.9; + transform: translateY(-1px); +} \ No newline at end of file diff --git a/loginModal.css b/loginModal.css new file mode 100644 index 000000000..4a2a592da --- /dev/null +++ b/loginModal.css @@ -0,0 +1,95 @@ +.modal-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.8); + display: flex; + justify-content: center; + align-items: center; + z-index: 1001; +} + +.modal-content { + background: #1A1A1A; + padding: 2rem; + border-radius: 8px; + width: 100%; + max-width: 400px; + position: relative; + border: 1px solid rgba(255, 255, 255, 0.1); + font-family: Arial, Helvetica, sans-serif; +} + +.close-button { + top: 10px; + position: sticky; + right: 10px; + background: none; + border: none; + color: rgba(255, 255, 255, 0.87); + font-size: 24px; + cursor: pointer; +} + +.login-form { + display: flex; + flex-direction: column; + gap: 1rem; + margin: 1.5rem 0; +} + +.login-form input { + padding: 12px; + border-radius: 4px; + background: rgba(255, 255, 255, 0.05); + border: 1px solid rgba(255, 255, 255, 0.1); + color: white; + font-size: 16px; + font-family: Arial, Helvetica, sans-serif; +} + +.login-form input:focus { + outline: none; + border-color: #774EBD; +} + +.login-form button { + background: linear-gradient(90deg, #774EBD 0%, #372457 100%); + color: white; + padding: 12px; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 16px; + transition: opacity 0.3s; + font-family: Arial, Helvetica, sans-serif; +} + +.login-footer { + display: flex; + justify-content: space-between; + margin-top: 1rem; +} + +.login-footer a { + color: #774EBD; + text-decoration: none; + font-size: 14px; + font-family: Arial, Helvetica, sans-serif; +} + +h2 { + color: rgba(255, 255, 255, 0.87); + text-align: center; + margin-bottom: 1rem; + font-family: Arial, Helvetica, sans-serif; +} + +.error-message { + color: #ff6b6b; + text-align: center; + margin-bottom: 1rem; + font-size: 14px; +} \ No newline at end of file diff --git a/mainpagestyle.css b/mainpagestyle.css index 41ccb69e6..815848e1b 100644 --- a/mainpagestyle.css +++ b/mainpagestyle.css @@ -111,7 +111,7 @@ html, body { right: 0; padding: 20px; z-index: 1000; - display: flex; + display:flexbox; justify-content: space-between; align-items: center; } @@ -171,4 +171,4 @@ html, body { ::-webkit-scrollbar-thumb:hover { background: linear-gradient(180deg, #8b5ed4 0%, #4c2f77 100%); -} +} \ No newline at end of file diff --git a/navbar.css b/navbar.css new file mode 100644 index 000000000..ed3af5a70 --- /dev/null +++ b/navbar.css @@ -0,0 +1,215 @@ +.navbar { + background:rgba(18, 18, 18, 1); + position: fixed; + left: 0; + top: 0; + width: 287.713px; + height: 965px; + flex-shrink: 0; + display: flex; + flex-direction: column; + padding: 3rem 0; + border-right: 1px solid rgba(255, 255, 255, 0.1); + box-shadow: 2px 0 10px rgba(0, 0, 0, 0.1); + font-family: Arial, Helvetica, sans-serif; +} + +.navbar-brand { + color: rgba(255, 255, 255, 0.87); + font-size: 25px; + font-weight: bold; + font-family: Arial, Helvetica, sans-serif; + margin-bottom: 4rem; + padding: 25px 35px; + text-align: left; +} + +.nav-links { + display: flex; + flex-direction: column; + gap: 2rem; + margin-top: 30px; + padding: 0 35px; +} + +.navbar a { + color: rgba(255, 255, 255, 0.87); + font-family: Arial, Helvetica, sans-serif; + font-size: 18px; + font-style: normal; + font-weight: 400; + line-height: normal; + padding: 15px 0; + position: relative; + transition: all 0.3s ease; + text-decoration: none; +} + +.navbar a:hover { + color: rgb(119, 78, 189); + background-color: rgba(255, 255, 255, 0.05); + padding-left: 15px; +} + +.burger { + z-index: 4; + position: fixed; + top: 0; + left: 0; + width: 72px; + height: 72px; + display: flex; + justify-content: center; + align-items: center; /* Center the burger icon properly */ + cursor: pointer; + opacity: 0.8; + transition: 0.3s; +} + +.burger:hover { + opacity: 1; +} + +.burger input { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + cursor: pointer; + opacity: 0; + z-index: 2; +} + +.burger-icon, +.burger-icon::before, +.burger-icon::after { + display: block; + border-radius: 2px; + height: 2px; + background: rgba(255, 255, 255, 0.87); + transition: 0.5s; +} + +.burger-icon { + position: relative; + width: 32px; + height: 2px; /* Add explicit height */ + z-index: 1; +} + +.burger-icon::before, +.burger-icon::after { + content: ''; + position: absolute; + left: 0; + width: 100%; +} + +.burger-icon::before { top: -8px; } +.burger-icon::after { top: 8px; } + +.burger input:checked + .burger-icon::before { + transform: rotate(-45deg) translate(-4px, 4px); + background: rgb(119, 78, 189); +} + +.burger input:checked + .burger-icon { + background: transparent; +} + +.burger input:checked + .burger-icon::after { + transform: rotate(45deg) translate(-4px, -4px); + background: rgb(119, 78, 189); +} + +.menu { + z-index: 3; + position: fixed; + top: 0; + left: 0; + height: 100vh; + width: 300px; + background: rgba(18, 18, 18, 0.98); + translate: -100% 0; + opacity: 0; + visibility: hidden; + transition: 0.4s; + display: flex; + align-items: flex-start; + padding-top: 100px; + font-family: Arial, Helvetica, sans-serif; +} + +.menu.active { + opacity: 1; + visibility: visible; + translate: 0; +} + +.nav-links a { + color: rgba(255, 255, 255, 0.87); + font-family: Arial, Helvetica, sans-serif; + font-size: 24px; + text-decoration: none; + transition: 0.4s; + padding: 8px 24px; +} + +.nav-links a:hover { + color: rgb(119, 78, 189); + padding-left: 32px; +} + +.background { + z-index: 1; + position: fixed; + inset: 0; + background: rgba(18, 18, 18, 0.5); + opacity: 0; + visibility: hidden; + transition: 0.4s; +} + +.background.active { + opacity: 1; + visibility: visible; +} + +@media screen and (max-width: 768px) { + .navbar { + width: 100%; + height: auto; + padding: 1rem 0; + } + + .menu { + width: 250px; + } + + .nav-links { + width: 100%; + text-align: center; + } + + .nav-links a { + padding: 15px; + font-size: 20px; + } + + .burger { + width: 60px; + height: 60px; + } +} + +@media screen and (max-width: 480px) { + .nav-links a { + font-size: 18px; + padding: 12px; + } + + .menu { + width: 200px; + } +} diff --git a/stateDropdown.css b/stateDropdown.css new file mode 100644 index 000000000..318663764 --- /dev/null +++ b/stateDropdown.css @@ -0,0 +1,36 @@ +.state-dropdown-container { + position: fixed; + top: 20px; + left: 320px; + z-index: 2; + font-family: Arial, Helvetica, sans-serif; +} + +.state-select { + background: rgba(18, 18, 18, 0.95); + color: rgba(255, 255, 255, 0.87); + border: 1px solid rgba(255, 255, 255, 0.1); + padding: 8px 16px; + border-radius: 4px; + font-family: Arial, Helvetica, sans-serif; + font-size: 16px; + cursor: pointer; + transition: all 0.3s ease; +} + +.state-select:hover { + border-color: rgb(119, 78, 189); +} + +.state-select:focus { + outline: none; + border-color: rgb(119, 78, 189); + box-shadow: 0 0 0 2px rgba(119, 78, 189, 0.2); +} + +.state-select option { + background: rgba(18, 18, 18, 0.98); + color: rgba(255, 255, 255, 0.87); + padding: 8px; + font-family: Arial, Helvetica, sans-serif; +} diff --git a/stockTrends.css b/stockTrends.css new file mode 100644 index 000000000..1cfee3fb1 --- /dev/null +++ b/stockTrends.css @@ -0,0 +1,200 @@ +.stock-trends-container { + background: rgba(18, 18, 18, 0.95); + border-radius: 8px; + border: 1px solid rgba(255, 255, 255, 0.1); + padding: 0.5rem; + height: 300px; + width: 95%; + display: flex; + flex-direction: column; + margin: 0.5rem; + max-width: none; + transform: none; + font-family: Arial, Helvetica, sans-serif; +} + +.stock-trends-container.error { + justify-content: center; + align-items: center; +} + +.stock-trends-header { + padding: 0.4rem; + border-bottom: 1px solid rgba(255, 255, 255, 0.1); + display: flex; + justify-content: space-between; + align-items: center; +} + +.stock-trends-header h3 { + color: rgba(255, 255, 255, 0.87); + margin: 0; + font-size: 1.1rem; + font-family: Arial, Helvetica, sans-serif; +} + +.nav-button { + background: linear-gradient(90deg, #774EBD 0%, #372457 100%); + color: white; + border: none; + border-radius: 4px; + width: 30px; + height: 30px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + font-size: 18px; +} + +.nav-button:hover { + opacity: 0.9; +} + +.stock-trends-content { + flex: 1; + padding: 0.4rem; + overflow-y: auto; + height: 100px; /* Account for header height */ + position: relative; + margin-top: 0.5rem; + max-width: none; + margin-left: auto; + margin-right: auto; + width: 100%; +} + +.stock-trends-content::before { + content: 'No data available'; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + color: rgba(255, 255, 255, 0.3); + z-index: 0; + pointer-events: none; + display: none; +} + +.stock-trends-content:empty::before { + display: block; +} + +.stock-item { + display: flex; + justify-content: space-between; + align-items: center; + padding: 1rem; + border-bottom: 1px solid rgba(255, 255, 255, 0.1); +} + +.stock-symbol { + color: rgba(255, 255, 255, 0.87); + font-weight: bold; + font-size: 0.9rem; + max-width: 60px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-family: Arial, Helvetica, sans-serif; +} + +.stock-price { + color: rgba(255, 255, 255, 0.87); + font-size: 1rem; + font-weight: bold; + color: #774EBD; +} + +.stock-change { + font-weight: bold; +} + +.stock-change.positive { + color: #774EBD; +} + +.stock-change.negative { + color: #372457; +} + +.loading { + color: rgba(255, 255, 255, 0.6); + text-align: center; + padding: 1rem; +} + +.error-message { + color: #ff6b6b; + text-align: center; + padding: 1rem; + background: rgba(255, 107, 107, 0.1); + border-radius: 4px; + margin: 1rem; +} + +.stock-info { + display: flex; + flex-direction: column; + align-items: center; + gap: 0.5rem; +} + +.current-price { + color: #774EBD; + font-size: 1.2rem; + font-weight: bold; +} + +.stock-grid { + display: flex; + flex-direction: column; + gap: 0.75rem; + height: auto; + padding: 0.25rem; + padding-bottom: 0.5rem; + width: 100%; + padding: 0; +} + +.stock-card { + background: rgba(24, 24, 24, 0.95); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 6px; + padding: 0.35rem 0.5rem; + display: flex; + flex-direction: column; + gap: 0.25rem; + max-width: none; + width: 95%; + margin: 0 auto; + transform: none; + font-family: Arial, Helvetica, sans-serif; +} + +.stock-card-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 0.5rem; +} + +.stock-range { + display: flex; + justify-content: space-between; + font-size: 0.7rem; + color: rgba(255, 255, 255, 0.6); + gap: 0.25rem; + padding: 0 0.5rem; +} + +@media (max-width: 768px) { + .stock-trends-container { + min-height: 350px; + padding: 1.5rem; + } + + .stock-card { + padding: 0.75rem; + } +} diff --git a/transactionHistory.css b/transactionHistory.css new file mode 100644 index 000000000..554a216b5 --- /dev/null +++ b/transactionHistory.css @@ -0,0 +1,93 @@ +.transaction-history { + background: rgba(18, 18, 18, 0.95); + border-radius: 8px; + border: 1px solid rgba(255, 255, 255, 0.1); + padding: 0.5rem; + margin: 0.5rem; + height: 100%; + width: 95%; + height: 300px; + display: flex; + flex-direction: column; + font-family: Arial, Helvetica, sans-serif; + color: white; +} + +.transaction-list { + margin-top: 1rem; + flex: 1; + overflow-y: auto; + padding-right: 1rem; + scrollbar-width: thin; + scrollbar-color: #774EBD rgba(255, 255, 255, 0.1); + height: 200px; /* Account for header height */ + max-height: calc(100% - 40px); +} + +.transaction-list::-webkit-scrollbar { + width: 6px; +} + +.transaction-list::-webkit-scrollbar-track { + background: rgba(255, 255, 255, 0.1); + border-radius: 3px; +} + +.transaction-list::-webkit-scrollbar-thumb { + background: linear-gradient(180deg, #774EBD 0%, #372457 100%); + border-radius: 3px; +} + +.transaction-item { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.4rem 0.5rem; + border-bottom: 1px solid rgba(255, 255, 255, 0.1); + gap: 0.5rem; +} + +.transaction-info { + display: flex; + flex-direction: column; + gap: 0.25rem; +} + +.transaction-name { + color: rgba(255, 255, 255, 0.87); + font-family: Arial, Helvetica, sans-serif; + font-size: 0.9rem; + max-width: 150px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.transaction-date { + color: rgba(255, 255, 255, 0.6); + font-size: 0.8rem; +} + +.transaction-amount { + font-weight: bold; + font-size: 1rem; +} + +.transaction-item.income .transaction-amount { + color: #774EBD; +} + +.transaction-item.outcome .transaction-amount { + color: #372457; +} + +@media (max-width: 768px) { + .transaction-item { + padding: 0.75rem; + } + + .transaction-history { + padding: 1.5rem; + min-height: 350px; + } +}