diff --git a/client/package-lock.json b/client/package-lock.json index cbbf69a..9b07533 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -18,13 +18,16 @@ "@paypal/react-paypal-js": "^8.1.4", "@react-oauth/google": "^0.12.1", "axios": "^1.7.4", + "bootstrap": "^5.3.3", "firebase": "^10.6.0", "firebase-tools": "^13.6.0", "framer-motion": "^11.0.8", "fuse.js": "^7.0.0", + "lucide-react": "^0.453.0", "pdf-lib": "^1.17.1", "ratna-supermarket": "file:", "react": "^18.2.0", + "react-bootstrap": "^2.10.5", "react-dom": "^18.2.0", "react-hot-toast": "^2.4.1", "react-icons": "^5.3.0", @@ -273,9 +276,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", - "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.7.tgz", + "integrity": "sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -2545,6 +2548,20 @@ "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, + "node_modules/@react-aria/ssr": { + "version": "3.9.6", + "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.6.tgz", + "integrity": "sha512-iLo82l82ilMiVGy342SELjshuWottlb5+VefO3jOQqQRNYnJBFpUSadswDPbRimSgJUZuFwIEYs6AabkP038fA==", + "dependencies": { + "@swc/helpers": "^0.5.0" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/@react-oauth/google": { "version": "0.12.1", "resolved": "https://registry.npmjs.org/@react-oauth/google/-/google-0.12.1.tgz", @@ -2562,6 +2579,45 @@ "node": ">=14.0.0" } }, + "node_modules/@restart/hooks": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.16.tgz", + "integrity": "sha512-f7aCv7c+nU/3mF7NWLtVVr0Ra80RqsO89hO72r+Y/nvQr5+q0UFGkocElTH6MJApvReVh6JHUFYn2cw1WdHF3w==", + "dependencies": { + "dequal": "^2.0.3" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@restart/ui": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.8.0.tgz", + "integrity": "sha512-xJEOXUOTmT4FngTmhdjKFRrVVF0hwCLNPdatLCHkyS4dkiSK12cEu1Y0fjxktjJrdst9jJIc5J6ihMJCoWEN/g==", + "dependencies": { + "@babel/runtime": "^7.21.0", + "@popperjs/core": "^2.11.6", + "@react-aria/ssr": "^3.5.0", + "@restart/hooks": "^0.4.9", + "@types/warning": "^3.0.0", + "dequal": "^2.0.3", + "dom-helpers": "^5.2.0", + "uncontrollable": "^8.0.1", + "warning": "^4.0.3" + }, + "peerDependencies": { + "react": ">=16.14.0", + "react-dom": ">=16.14.0" + } + }, + "node_modules/@restart/ui/node_modules/uncontrollable": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-8.0.4.tgz", + "integrity": "sha512-ulRWYWHvscPFc0QQXvyJjY6LIXU56f0h8pQFvhxiKk5V1fcI8gp9Ht9leVAhrVjzqMw0BgjspBINx9r6oyJUvQ==", + "peerDependencies": { + "react": ">=16.14.0" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.23.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.23.0.tgz", @@ -2974,6 +3030,14 @@ "integrity": "sha512-9F4ys4C74eSTEUNndnER3VJ15oru2NumfQxS8geE+f3eB5xvfxpWyqE5XlVnxb/R14uoXi6SLbBwwiDSkv+XEw==", "dev": true }, + "node_modules/@swc/helpers": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.13.tgz", + "integrity": "sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w==", + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@swc/types": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.5.tgz", @@ -3116,6 +3180,11 @@ "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" }, + "node_modules/@types/warning": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz", + "integrity": "sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==" + }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", @@ -3814,6 +3883,24 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "node_modules/bootstrap": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz", + "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], + "peerDependencies": { + "@popperjs/core": "^2.11.8" + } + }, "node_modules/boxen": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", @@ -5028,6 +5115,14 @@ "node": ">= 0.8" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "engines": { + "node": ">=6" + } + }, "node_modules/destroy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", @@ -7263,6 +7358,14 @@ "node": ">= 0.4" } }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/ip-address": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", @@ -8344,6 +8447,14 @@ "node": "14 || >=16.14" } }, + "node_modules/lucide-react": { + "version": "0.453.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.453.0.tgz", + "integrity": "sha512-kL+RGZCcJi9BvJtzg2kshO192Ddy9hv3ij+cPrVPWSRzgCWCVazoQJxOjAwgK53NomL07HB7GPHW120FimjNhQ==", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" + } + }, "node_modules/make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -9794,6 +9905,18 @@ "react-is": "^16.13.1" } }, + "node_modules/prop-types-extra": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz", + "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==", + "dependencies": { + "react-is": "^16.3.2", + "warning": "^4.0.0" + }, + "peerDependencies": { + "react": ">=0.14.0" + } + }, "node_modules/proto-list": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", @@ -10126,6 +10249,35 @@ "node": ">=0.10.0" } }, + "node_modules/react-bootstrap": { + "version": "2.10.5", + "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.10.5.tgz", + "integrity": "sha512-XueAOEn64RRkZ0s6yzUTdpFtdUXs5L5491QU//8ZcODKJNDLt/r01tNyriZccjgRImH1REynUc9pqjiRMpDLWQ==", + "dependencies": { + "@babel/runtime": "^7.24.7", + "@restart/hooks": "^0.4.9", + "@restart/ui": "^1.6.9", + "@types/react-transition-group": "^4.4.6", + "classnames": "^2.3.2", + "dom-helpers": "^5.2.1", + "invariant": "^2.2.4", + "prop-types": "^15.8.1", + "prop-types-extra": "^1.1.0", + "react-transition-group": "^4.4.5", + "uncontrollable": "^7.2.1", + "warning": "^4.0.3" + }, + "peerDependencies": { + "@types/react": ">=16.14.8", + "react": ">=16.14.0", + "react-dom": ">=16.14.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/react-dom": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", @@ -10167,6 +10319,11 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, "node_modules/react-material-ui-carousel": { "version": "3.4.2", "resolved": "https://registry.npmjs.org/react-material-ui-carousel/-/react-material-ui-carousel-3.4.2.tgz", @@ -11926,6 +12083,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/uncontrollable": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz", + "integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==", + "dependencies": { + "@babel/runtime": "^7.6.3", + "@types/react": ">=16.9.11", + "invariant": "^2.2.4", + "react-lifecycles-compat": "^3.0.4" + }, + "peerDependencies": { + "react": ">=15.0.0" + } + }, "node_modules/underscore": { "version": "1.13.6", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", @@ -12194,6 +12365,14 @@ } } }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", diff --git a/client/package.json b/client/package.json index 06b9b17..94f19b4 100644 --- a/client/package.json +++ b/client/package.json @@ -20,13 +20,16 @@ "@paypal/react-paypal-js": "^8.1.4", "@react-oauth/google": "^0.12.1", "axios": "^1.7.4", + "bootstrap": "^5.3.3", "firebase": "^10.6.0", "firebase-tools": "^13.6.0", "framer-motion": "^11.0.8", "fuse.js": "^7.0.0", + "lucide-react": "^0.453.0", "pdf-lib": "^1.17.1", "ratna-supermarket": "file:", "react": "^18.2.0", + "react-bootstrap": "^2.10.5", "react-dom": "^18.2.0", "react-hot-toast": "^2.4.1", "react-icons": "^5.3.0", diff --git a/client/src/components/ChatbotHelp.css b/client/src/components/ChatbotHelp.css index d8f6f82..e919264 100644 --- a/client/src/components/ChatbotHelp.css +++ b/client/src/components/ChatbotHelp.css @@ -3,12 +3,12 @@ display: flex; bottom: 10px; /* Adjust this to where you want the element */ right: 20px; /* Adjust this to where you want the element */ - z-index: 1000; /* Ensures it stays on top of other elements */ + z-index: 10; /* Ensures it stays on top of other elements */ } .chatbotHelpContainer svg:nth-of-type(2){ transform: translateX(58px); - z-index: 888; + z-index: 8; transition: fill 0.3s ease, filter 0.3s ease; } @@ -25,6 +25,169 @@ } .chatbotHelpContainer svg:nth-of-type(1){ transform: translate(175px, 85px); - z-index: 889; + z-index: 9; cursor: pointer; -} \ No newline at end of file +} + +/* chatbot */ +.chatbotContainer { + position: fixed; + bottom: 90px; + right: 20px; + width: 400px; + height: 400px; + border-radius: 10px; + overflow: hidden; + display: flex; + flex-direction: column; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); + background-color: rgb(253, 134, 75); + z-index: 1000; +} +.chatbotHeader { + background-color: rgb(253, 134, 75); + color: white; + padding: 10px; + display: flex; + justify-content: space-between; + align-items: center; +} +.closeButton { + background: none; + border: none; + color: white; + cursor: pointer; +} +.chatbotBody { + flex-grow: 1; + padding: 10px; + display: flex; + flex-direction: column; + background-color: white; + overflow-y: auto; +} +.message { + max-width: 80%; + padding: 8px 12px; + border-radius: 18px; + margin-bottom: 10px; + background-color: rgb(253, 134, 75); + color: white; +} +.bot { + align-self: flex-start; +} +.user { + align-self: flex-end; +} +.chatbotFooter .input-group{ + padding: 10px; + background-color: rgb(253, 134, 75); + display: flex; + flex-direction: row; + align-items: center; +} +.chatbotFooter input { + flex-grow: 1; + border: none; + padding: 8px 20px; + border-radius: 20px; + margin-right: 10px; +} +.chatbotFooter button { + background: white; + border: none; + border-radius: 50%; + width: 36px; + height: 36px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; +} +.chatbotFooter button svg { + color: rgb(253, 134, 75); +} + +@media (max-width: 709px) { + .chatbotContainer { + width: 300px; + height: 350px; + bottom: 80px; + right: 10px; + } + .chatbotHeader { + padding: 8px; + } + .chatbotHeader h5 { + font-size: 1rem; + } + .closeButton svg { + width: 20px; + height: 20px; + } + .chatbotBody { + padding: 8px; + } + .message { + padding: 6px 10px; + font-size: 0.9rem; + } + .chatbotFooter .input-group { + padding: 8px; + } + .chatbotFooter input { + padding: 6px 15px; + font-size: 0.9rem; + } + .chatbotFooter button { + width: 32px; + height: 32px; + } + .chatbotFooter button svg { + width: 16px; + height: 16px; + } +} + +@media (max-width: 463px) { + .chatbotContainer { + width: 260px; + height: 320px; + bottom: 60px; + right: 5px; + } + .chatbotHeader { + padding: 6px; + } + .chatbotHeader h5 { + font-size: 0.9rem; + } + .closeButton svg { + width: 18px; + height: 18px; + } + .chatbotBody { + padding: 6px; + } + .message { + padding: 5px 8px; + font-size: 0.8rem; + margin-bottom: 8px; + } + .chatbotFooter .input-group { + padding: 6px; + } + .chatbotFooter input { + padding: 5px 12px; + font-size: 0.8rem; + } + .chatbotFooter button { + width: 28px; + height: 28px; + } + .chatbotFooter button svg { + width: 14px; + height: 14px; + } + } \ No newline at end of file diff --git a/client/src/components/ChatbotHelp.jsx b/client/src/components/ChatbotHelp.jsx index 3628298..3ed5e7c 100644 --- a/client/src/components/ChatbotHelp.jsx +++ b/client/src/components/ChatbotHelp.jsx @@ -1,22 +1,128 @@ -import React from "react"; +import React, { useState } from "react"; +import { Button, Form, InputGroup } from "react-bootstrap"; +// import "bootstrap/dist/css/bootstrap.min.css"; +import { X, Send } from "lucide-react"; import "./ChatbotHelp.css"; const ChatbotHelp = () => { + const [showChatbot, setShowChatbot] = useState(false); + const [messages, setMessages] = useState([ + { text: "Hello! How can I help you today?", isBot: true }, + ]); + const [inputMessage, setInputMessage] = useState(""); + + const api_key = "AIzaSyBmX8rY3EULLOV2JYJ1Zx9FG1JR7RDDpXI"; + const url = + "https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash-latest:generateContent"; + + const handleSendMessage = async () => { + if (inputMessage.trim() !== "") { + setMessages([...messages, { text: inputMessage, isBot: false }]); + setInputMessage(""); + + try { + const response = await fetch(`${url}?key=${api_key}`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + contents: [ + { + parts: [ + { + text: + inputMessage + + "You are Ratna Supermarket's customer support bot. Help the users in any way possible, add no formatting in your responses & keep it short.", + }, + ], + }, + ], + }), + }); + + if (response.ok) { + const data = await response.json(); + const botResponse = data.candidates[0].content.parts[0].text; + setMessages((prev) => [...prev, { text: botResponse, isBot: true }]); + } else { + console.error("API request failed:", response.statusText); + setMessages((prev) => [ + ...prev, + { + text: "Sorry, I couldn't process your request. Please try again.", + isBot: true, + }, + ]); + } + } catch (error) { + console.error("Error:", error); + setMessages((prev) => [ + ...prev, + { text: "An error occurred. Please try again later.", isBot: true }, + ]); + } + } + }; + return ( -