From 3fb107fd8b737d1fab2b22dc28929d3b291f7374 Mon Sep 17 00:00:00 2001 From: Askar Akhmetkhanov Date: Sat, 28 Sep 2024 00:12:00 +0300 Subject: [PATCH] Commit --- package-lock.json | 522 +++++++++++++++++++---- package.json | 5 +- src/backend/chat-server.js | 43 ++ src/backend/interlocutor/Interlocutor.js | 14 +- src/backend/user/User.js | 8 +- src/dashboard.tsx | 32 +- src/pages/Account.jsx | 8 +- src/pages/Chat.jsx | 212 ++++++++- src/pages/css/Chat.css | 145 +++++++ src/pages/css/account.css | 0 10 files changed, 864 insertions(+), 125 deletions(-) create mode 100644 src/backend/chat-server.js create mode 100644 src/pages/css/Chat.css create mode 100644 src/pages/css/account.css diff --git a/package-lock.json b/package-lock.json index d00f748..4114aba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,13 +13,16 @@ "@ijl/cli": "^5.1.0", "@types/react": "^18.3.5", "@types/react-dom": "^18.3.0", + "emoji-mart": "^5.6.0", "express": "^4.19.2", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-emoji-picker": "^1.0.13", "react-icons": "^5.3.0", "react-router-dom": "^6.26.1", "styled-components": "^6.1.13", - "typescript": "^5.5.4" + "typescript": "^5.5.4", + "ws": "^8.18.0" } }, "node_modules/@ampproject/remapping": { @@ -1847,30 +1850,6 @@ "node": ">=18" } }, - "node_modules/@brojs/cli/node_modules/i18next": { - "version": "23.15.1", - "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.15.1.tgz", - "integrity": "sha512-wB4abZ3uK7EWodYisHl/asf8UYEhrI/vj/8aoSsrj/ZDxj4/UXPOa1KvFt1Fq5hkUHquNqwFlDprmjZ8iySgYA==", - "funding": [ - { - "type": "individual", - "url": "https://locize.com" - }, - { - "type": "individual", - "url": "https://locize.com/i18next.html" - }, - { - "type": "individual", - "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/runtime": "^7.23.2" - } - }, "node_modules/@brojs/cli/node_modules/i18next-browser-languagedetector": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.0.0.tgz", @@ -2685,18 +2664,6 @@ "ijl-cli": "bin/ijl-cli" } }, - "node_modules/@ijl/cli/node_modules/@types/react": { - "version": "17.0.80", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.80.tgz", - "integrity": "sha512-LrgHIu2lEtIo8M7d1FcI3BdwXWoRQwMoXOZ7+dPTW0lYREjmlHl3P0U1VD0i/9tppOuv8/sam7sOjx34TxSFbA==", - "optional": true, - "peer": true, - "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "^0.16", - "csstype": "^3.0.2" - } - }, "node_modules/@ijl/cli/node_modules/loader-utils": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", @@ -2710,33 +2677,6 @@ "node": ">=8.9.0" } }, - "node_modules/@ijl/cli/node_modules/react": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", - "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", - "peer": true, - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@ijl/cli/node_modules/react-dom": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", - "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", - "peer": true, - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" - }, - "peerDependencies": { - "react": "17.0.2" - } - }, "node_modules/@ijl/cli/node_modules/react-hot-loader": { "version": "4.13.1", "resolved": "https://registry.npmjs.org/react-hot-loader/-/react-hot-loader-4.13.1.tgz", @@ -2765,16 +2705,6 @@ } } }, - "node_modules/@ijl/cli/node_modules/scheduler": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", - "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", - "peer": true, - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, "node_modules/@ijl/cli/node_modules/source-map": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", @@ -3128,13 +3058,6 @@ "@types/react": "*" } }, - "node_modules/@types/scheduler": { - "version": "0.16.8", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", - "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==", - "optional": true, - "peer": true - }, "node_modules/@types/source-list-map": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.6.tgz", @@ -3458,6 +3381,15 @@ "ajv": "^8.8.2" } }, + "node_modules/amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", + "license": "BSD-3-Clause OR MIT", + "engines": { + "node": ">=0.4.2" + } + }, "node_modules/ansi-html-community": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", @@ -3559,6 +3491,12 @@ "node": ">=0.10.0" } }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "license": "MIT" + }, "node_modules/assign-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", @@ -3567,6 +3505,15 @@ "node": ">=0.10.0" } }, + "node_modules/ast-types": { + "version": "0.9.6", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.9.6.tgz", + "integrity": "sha512-qEdtR2UH78yyHX/AUNfXmJTlM48XoFZKBdwi1nzkI1mJL21cmbu0cvjxjpkXJ5NENMq42H+hNs8VLJcqXLerBQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -3687,6 +3634,15 @@ "node": ">=0.10.0" } }, + "node_modules/base62": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/base62/-/base62-1.2.8.tgz", + "integrity": "sha512-V6YHUbjLxN1ymqNLb1DPHoU1CpfdL7d2YTIp5W3U4hhoG4hhxNmsFDs66M9EXxBiSEke5Bt5dwdfMwwZF70iLA==", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/base64id": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", @@ -4094,6 +4050,64 @@ "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==" }, + "node_modules/commoner": { + "version": "0.10.8", + "resolved": "https://registry.npmjs.org/commoner/-/commoner-0.10.8.tgz", + "integrity": "sha512-3/qHkNMM6o/KGXHITA14y78PcfmXh4+AOCJpSoF73h4VY1JpdGv3CHMS5+JW6SwLhfJt4RhNmLAa7+RRX/62EQ==", + "license": "MIT", + "dependencies": { + "commander": "^2.5.0", + "detective": "^4.3.1", + "glob": "^5.0.15", + "graceful-fs": "^4.1.2", + "iconv-lite": "^0.4.5", + "mkdirp": "^0.5.0", + "private": "^0.1.6", + "q": "^1.1.2", + "recast": "^0.11.17" + }, + "bin": { + "commonize": "bin/commonize" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commoner/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/commoner/node_modules/glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", + "dependencies": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/commoner/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, "node_modules/component-emitter": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", @@ -4224,6 +4238,13 @@ "webpack": "^5.1.0" } }, + "node_modules/core-js": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "integrity": "sha512-ZiPp9pZlgxpWRu0M+YWbm6+aQ84XEfH1JRXvfOc/fILWI0VKhLC2LX13X1NYq4fULzLMq7Hfh43CSo2/aIaUPA==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "license": "MIT" + }, "node_modules/core-js-compat": { "version": "3.38.1", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.38.1.tgz", @@ -4437,6 +4458,15 @@ "node": ">=0.10.0" } }, + "node_modules/defined": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", + "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/del": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", @@ -4531,6 +4561,28 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "node_modules/detective": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/detective/-/detective-4.7.1.tgz", + "integrity": "sha512-H6PmeeUcZloWtdt4DAkFyzFL94arpHr3NOwwmVILFiy+9Qd4JTxxXrzfyGk/lmct2qVGBwTSwSXagqu2BxmWig==", + "license": "MIT", + "dependencies": { + "acorn": "^5.2.1", + "defined": "^1.0.0" + } + }, + "node_modules/detective/node_modules/acorn": { + "version": "5.7.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", + "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -4567,6 +4619,24 @@ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.18.tgz", "integrity": "sha512-1OfuVACu+zKlmjsNdcJuVQuVE61sZOLbNM4JAQ1Rvh6EOj0/EUKhMJjRH73InPlXSh8HIJk1cVZ8pyOV/FMdUQ==" }, + "node_modules/emoji-annotation-to-unicode": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/emoji-annotation-to-unicode/-/emoji-annotation-to-unicode-0.2.4.tgz", + "integrity": "sha512-0GAasay1KK/a+Vns0aK1EwRMdLTvvvHO5Jc0SFwfwVhOhroIyT1IqBT8igZFrn3aw0u2b1LRshNsofkiL3jCkA==", + "license": "MIT" + }, + "node_modules/emoji-emoticon-to-unicode": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/emoji-emoticon-to-unicode/-/emoji-emoticon-to-unicode-0.2.2.tgz", + "integrity": "sha512-fZ/wYomR+zc1/Sp/uY85M06XaGr+P+mH/uzh4l3rPPnv3YXrF3W2Cm/IqWcXvMw8m65/vmVvigBVqvkUfPJi4A==", + "license": "MIT" + }, + "node_modules/emoji-mart": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/emoji-mart/-/emoji-mart-5.6.0.tgz", + "integrity": "sha512-eJp3QRe79pjwa+duv+n7+5YsNhRcMl812EcFVwrnRvYKoNPoQb5qxU8DG6Bgwji0akHdp6D4Ln6tYLG58MFSow==", + "license": "MIT" + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -4624,6 +4694,27 @@ "node": ">= 0.6" } }, + "node_modules/engine.io/node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/enhanced-resolve": { "version": "5.17.1", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", @@ -4644,6 +4735,19 @@ "node": ">=6" } }, + "node_modules/envify": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/envify/-/envify-3.4.1.tgz", + "integrity": "sha512-XLiBFsLtNF0MOZl+vWU59yPb3C2JtrQY2CNJn22KH75zPlHWY5ChcAQuf4knJeWT/lLkrx3sqvhP/J349bt4Bw==", + "license": "MIT", + "dependencies": { + "jstransform": "^11.0.3", + "through": "~2.3.4" + }, + "bin": { + "envify": "bin/envify" + } + }, "node_modules/envinfo": { "version": "7.13.0", "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", @@ -4721,6 +4825,31 @@ "node": ">=8.0.0" } }, + "node_modules/esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha512-AWwVMNxwhN8+NIPQzAQZCm7RkLC4RbM3B1OobMuyp3i+w73X57KCKaVIxaRZb+DYCojq7rspo+fmuQfAboyhFg==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esprima-fb": { + "version": "15001.1.0-dev-harmony-fb", + "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1.0-dev-harmony-fb.tgz", + "integrity": "sha512-59dDGQo2b3M/JfKIws0/z8dcXH2mnVHkfSPRhCYS91JNGfGNwr7GsSF6qzWZuOGvw5Ii0w9TtylrX07MGmlOoQ==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -5065,6 +5194,19 @@ "reusify": "^1.0.4" } }, + "node_modules/fbjs": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.6.1.tgz", + "integrity": "sha512-4KW7tT33ytfazK3Ekvesbsa4A5J79hUrdXONQGZ0wM6i3PFc70YknF9kj1eyx3mDupgJ7Z+ifFhcMJ+ps2eZIw==", + "license": "BSD-3-Clause", + "dependencies": { + "core-js": "^1.0.0", + "loose-envify": "^1.0.0", + "promise": "^7.0.3", + "ua-parser-js": "^0.7.9", + "whatwg-fetch": "^0.9.0" + } + }, "node_modules/filesize": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.1.0.tgz", @@ -6468,6 +6610,46 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jstransform": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/jstransform/-/jstransform-11.0.3.tgz", + "integrity": "sha512-LGm87w0A8E92RrcXt94PnNHkFqHmgDy3mKHvNZOG7QepKCTCH/VB6S+IEN+bT4uLN3gVpOT0vvOOVd96osG71g==", + "license": "BSD-3-Clause", + "dependencies": { + "base62": "^1.1.0", + "commoner": "^0.10.1", + "esprima-fb": "^15001.1.0-dev-harmony-fb", + "object-assign": "^2.0.0", + "source-map": "^0.4.2" + }, + "bin": { + "jstransform": "bin/jstransform" + }, + "engines": { + "node": ">=0.8.8" + } + }, + "node_modules/jstransform/node_modules/object-assign": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", + "integrity": "sha512-CdsOUYIh5wIiozhJ3rLQgmUTgcyzFwZZrqhkKhODMoGtPKM+wt0h0CNIoauJWMsS9822EdzPsF/6mb4nLvPN5g==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jstransform/node_modules/source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha512-Y8nIfcb1s/7DcobUz1yOO1GSp7gyL+D9zLHDehT7iRESqGSxjJ448Sg7rvfgsRJCnKLdSl11uGf0s9X80cH0/A==", + "license": "BSD-3-Clause", + "dependencies": { + "amdefine": ">=0.0.4" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/keygrip": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", @@ -6537,6 +6719,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash.compact": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash.compact/-/lodash.compact-3.0.1.tgz", + "integrity": "sha512-2ozeiPi+5eBXW1CLtzjk8XQFhQOEMwwfxblqeq6EGyTxZJ1bPATqilY0e6g2SLQpP4KuMeuioBhEnWz5Pr7ICQ==", + "license": "MIT" + }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -7342,6 +7530,15 @@ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, + "node_modules/private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -7350,6 +7547,15 @@ "node": ">= 0.6.0" } }, + "node_modules/promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "license": "MIT", + "dependencies": { + "asap": "~2.0.3" + } + }, "node_modules/prompts": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.0.tgz", @@ -7398,6 +7604,17 @@ "node": ">=6" } }, + "node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", + "license": "MIT", + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, "node_modules/qs": { "version": "6.11.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", @@ -7717,6 +7934,60 @@ "react": "^18.3.1" } }, + "node_modules/react-emoji": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/react-emoji/-/react-emoji-0.4.4.tgz", + "integrity": "sha512-NQUk+QgF3af2poGioW9Dv6kQg9nJCEZVxRsYRYLa1H2XTelEkLVMeeTNU8Y5cMjQRuVnAfl7TzJ4zSix/qxDiQ==", + "license": "MIT", + "dependencies": { + "emoji-annotation-to-unicode": "^0.2.4", + "emoji-emoticon-to-unicode": "^0.2.2", + "escape-string-regexp": "^1.0.3", + "lodash.compact": "^3.0.0", + "object-assign": "^2.0.0" + } + }, + "node_modules/react-emoji-picker": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/react-emoji-picker/-/react-emoji-picker-1.0.13.tgz", + "integrity": "sha512-nLcVgNb3Iok9Jy5frAPJoflAbHKg9Df+UZuhYVZ3bK12A2k9nFzmQyI2apTvMPC2r4h/KpHepfK10siMdqKR4g==", + "license": "ISC", + "dependencies": { + "react": "^0.14.3", + "react-emoji": "^0.4.1" + } + }, + "node_modules/react-emoji-picker/node_modules/react": { + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/react/-/react-0.14.10.tgz", + "integrity": "sha512-yxMw5aorZG4qsLVBfjae4wGFvd5708DhcxaXLJ3IOTgr1TCs8k9+ZheGgLGr5OfwWMhSahNbGvvoEDzrxVWouA==", + "license": "BSD-3-Clause", + "dependencies": { + "envify": "^3.0.0", + "fbjs": "^0.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-emoji/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/react-emoji/node_modules/object-assign": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", + "integrity": "sha512-CdsOUYIh5wIiozhJ3rLQgmUTgcyzFwZZrqhkKhODMoGtPKM+wt0h0CNIoauJWMsS9822EdzPsF/6mb4nLvPN5g==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react-error-overlay": { "version": "6.0.11", "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", @@ -7796,6 +8067,30 @@ "node": ">=8.10.0" } }, + "node_modules/recast": { + "version": "0.11.23", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.11.23.tgz", + "integrity": "sha512-+nixG+3NugceyR8O1bLU45qs84JgI3+8EauyRZafLgC9XbdAOIVgwV1Pe2da0YzGo62KzWoZwUpVEQf6qNAXWA==", + "license": "MIT", + "dependencies": { + "ast-types": "0.9.6", + "esprima": "~3.1.0", + "private": "~0.1.5", + "source-map": "~0.5.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/recast/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/rechoir": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", @@ -8455,6 +8750,27 @@ "ws": "~8.17.1" } }, + "node_modules/socket.io-adapter/node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/socket.io-parser": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", @@ -8867,6 +9183,12 @@ "tslib": "^2" } }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "license": "MIT" + }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -8996,6 +9318,32 @@ "node": ">=14.17" } }, + "node_modules/ua-parser-js": { + "version": "0.7.39", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.39.tgz", + "integrity": "sha512-IZ6acm6RhQHNibSt7+c09hhvsKy9WUr4DVbeq9U8o71qxyYtJpQeDxQnMrVqnIFMLcQjHO0I9wgfO2vIahht4w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "license": "MIT", + "bin": { + "ua-parser-js": "script/cli.js" + }, + "engines": { + "node": "*" + } + }, "node_modules/uglify-js": { "version": "3.19.3", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", @@ -9459,6 +9807,11 @@ "node": ">=6" } }, + "node_modules/whatwg-fetch": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-0.9.0.tgz", + "integrity": "sha512-DIuh7/cloHxHYwS/oRXGgkALYAntijL63nsgMQsNSnBj825AysosAqA2ZbYXGRqpPRiNH7335dTqV364euRpZw==" + }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", @@ -9540,9 +9893,10 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "license": "MIT", "engines": { "node": ">=10.0.0" }, diff --git a/package.json b/package.json index 9e88b2a..60a20b6 100644 --- a/package.json +++ b/package.json @@ -5,13 +5,16 @@ "@ijl/cli": "^5.1.0", "@types/react": "^18.3.5", "@types/react-dom": "^18.3.0", + "emoji-mart": "^5.6.0", "express": "^4.19.2", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-emoji-picker": "^1.0.13", "react-icons": "^5.3.0", "react-router-dom": "^6.26.1", "styled-components": "^6.1.13", - "typescript": "^5.5.4" + "typescript": "^5.5.4", + "ws": "^8.18.0" }, "main": "./src/index.tsx", "scripts": { diff --git a/src/backend/chat-server.js b/src/backend/chat-server.js new file mode 100644 index 0000000..340aa0f --- /dev/null +++ b/src/backend/chat-server.js @@ -0,0 +1,43 @@ +const WebSocket = require("ws"); +const wss = new WebSocket.Server({ port: 8080 }); + +const clients = new Map(); + +wss.on("connection", (ws, req) => { + console.log("New client connected"); + + ws.on("message", (message) => { + try { + const parsedMessage = JSON.parse(message); + if (parsedMessage.type === "register") { + clients.set(parsedMessage.userId, ws); + console.log(`User registered: ${parsedMessage.userId}`); + } else if (parsedMessage.type === "message") { + const recipientWs = clients.get(parsedMessage.recipientId); + if (recipientWs) { + recipientWs.send( + JSON.stringify({ + senderId: parsedMessage.senderId, + message: parsedMessage.message, + timestamp: new Date().toISOString(), + }) + ); + } else { + console.error(`User ${parsedMessage.recipientId} is not connected.`); + } + } + } catch (err) { + console.error("Error processing message:", err.message); + } + }); + + ws.on("close", () => { + console.log("Client disconnected"); + [...clients.entries()].forEach(([userId, clientWs]) => { + if (clientWs === ws) { + clients.delete(userId); + console.log(`User disconnected: ${userId}`); + } + }); + }); +}); diff --git a/src/backend/interlocutor/Interlocutor.js b/src/backend/interlocutor/Interlocutor.js index 3931c36..539b4fc 100644 --- a/src/backend/interlocutor/Interlocutor.js +++ b/src/backend/interlocutor/Interlocutor.js @@ -1,8 +1,8 @@ export default class Interlocutor { - constructor(id, name) { - this.name = name - this.id = id - } - static name; - static id; -} \ No newline at end of file + constructor(id, name) { + this.name = name; + this.id = id; + } + static name; + static id; +} diff --git a/src/backend/user/User.js b/src/backend/user/User.js index b3732a3..4dd5ff4 100644 --- a/src/backend/user/User.js +++ b/src/backend/user/User.js @@ -1,3 +1,7 @@ export default class User { - -} \ No newline at end of file + constructor(id, name) { + this.id = id; + this.name = name; + this.status = "online"; + } +} diff --git a/src/dashboard.tsx b/src/dashboard.tsx index 8fc2275..1596871 100644 --- a/src/dashboard.tsx +++ b/src/dashboard.tsx @@ -1,25 +1,25 @@ -import React from 'react'; -import { Routes, Route } from 'react-router-dom'; +import React from "react"; +import { Routes, Route } from "react-router-dom"; -import { URLs } from './__data__/urls'; +import { URLs } from "./__data__/urls"; -import Home from './pages/Home.jsx' -import Init from './pages/Init.jsx' -import Account from './pages/Account.jsx' -import Chat from './pages/Chat.jsx' -import SignIn from './pages/SignIn.jsx' -import SignUp from './pages/SignUp.jsx' +import Home from "./pages/Home.jsx"; +import Init from "./pages/Init.jsx"; +import Account from "./pages/Account.jsx"; +import Chat from "./pages/Chat.jsx"; +import SignIn from "./pages/SignIn.jsx"; +import SignUp from "./pages/SignUp.jsx"; export const Dashboard = () => { return ( - }/> - }/> - }/> - }/> - }/> - }/> - 404 page not found}/> + } /> + } /> + } /> + } /> + } /> + } /> + 404 page not found} /> ); }; diff --git a/src/pages/Account.jsx b/src/pages/Account.jsx index 6f366ae..2b76274 100644 --- a/src/pages/Account.jsx +++ b/src/pages/Account.jsx @@ -1,9 +1,7 @@ import React from "react"; const Account = () => { - return ( -

Account

- ) -} + return

Account

; +}; -export default Account; \ No newline at end of file +export default Account; diff --git a/src/pages/Chat.jsx b/src/pages/Chat.jsx index e80b24e..fc3b392 100644 --- a/src/pages/Chat.jsx +++ b/src/pages/Chat.jsx @@ -1,20 +1,212 @@ -import React, {useEffect, useState} from 'react'; +import React, { useEffect, useState, useRef } from "react"; +import { useNavigate } from "react-router-dom"; +import "./css/Chat.css"; +import { FaPaperPlane, FaSmile } from "react-icons/fa"; + +const emojis = [ + "๐Ÿ˜€", + "๐Ÿ˜", + "๐Ÿ˜‚", + "๐Ÿคฃ", + "๐Ÿ˜ƒ", + "๐Ÿ˜„", + "๐Ÿ˜…", + "๐Ÿ˜†", + "๐Ÿ˜‰", + "๐Ÿ˜Š", + "๐Ÿ˜‹", + "๐Ÿ˜Ž", + "๐Ÿ˜", + "๐Ÿ˜˜", + "๐Ÿฅฐ", + "๐Ÿ˜—", + "๐Ÿ˜™", + "๐Ÿ˜š", + "๐Ÿ™‚", + "๐Ÿค—", + "๐Ÿคฉ", + "๐Ÿค”", + "๐Ÿ˜", + "๐Ÿ˜‘", + "๐Ÿ˜ถ", + "๐Ÿ™„", + "๐Ÿ˜", + "๐Ÿ˜ฃ", + "๐Ÿ˜ฅ", + "๐Ÿ˜ฎ", + "๐Ÿค", + "๐Ÿ˜ฏ", + "๐Ÿ˜ช", + "๐Ÿ˜ซ", + "๐Ÿ˜ด", + "๐Ÿ˜Œ", + "๐Ÿ˜›", + "๐Ÿ˜œ", + "๐Ÿคช", + "๐Ÿคจ", + "๐Ÿ˜", + "๐Ÿค‘", + "๐Ÿ˜’", + "๐Ÿ˜“", + "๐Ÿ˜”", + "๐Ÿ˜•", + "๐Ÿ˜–", + "๐Ÿ˜ž", + "๐Ÿ˜Ÿ", + "๐Ÿ˜ ", + "๐Ÿ˜ก", + "๐Ÿคฌ", + "๐Ÿ˜ฑ", + "๐Ÿ˜จ", + "๐Ÿ˜ง", + "๐Ÿ˜‡", + "๐Ÿฅณ", + "๐Ÿฅบ", + "๐Ÿ˜ป", + "๐Ÿ˜ผ", + "๐Ÿ˜ฝ", + "๐Ÿ™ˆ", + "๐Ÿ™‰", + "๐Ÿ™Š", + "๐Ÿ’€", + "๐Ÿ‘ป", + "๐Ÿ‘ฝ", +]; const Chat = () => { - const [interlocutorId, setInterlocutorId] = useState(0); // State to hold the interlocutorId + const [interlocutorId, setInterlocutorId] = useState(0); + const [messages, setMessages] = useState([]); + const [newMessage, setNewMessage] = useState(""); + const [showEmojiPicker, setShowEmojiPicker] = useState(false); + const socket = useRef(null); + const chatRef = useRef(null); + const navigate = useNavigate(); - function getInterlocutorId() { - const id = localStorage.getItem('interlocutorId'); - return id ? id : 0; + useEffect(() => { + const id = parseInt(localStorage.getItem("interlocutorId"), 10) || 0; + setInterlocutorId(id); + + socket.current = new WebSocket("ws://localhost:8080"); + + socket.current.onopen = () => { + console.log("WebSocket connected"); + socket.current.send( + JSON.stringify({ type: "register", userId: "yourUserId" }) + ); + }; + + socket.current.onmessage = (event) => { + const receivedData = JSON.parse(event.data); + setMessages((prev) => [...prev, receivedData]); + }; + + socket.current.onerror = (event) => { + console.error("WebSocket error observed:", event); + }; + + socket.current.onclose = () => { + console.log("WebSocket closed"); + }; + + return () => { + socket.current.close(); + }; + }, []); + + useEffect(() => { + if (chatRef.current) { + chatRef.current.scrollTop = chatRef.current.scrollHeight; } + }, [messages]); - useEffect(() => { - const id = getInterlocutorId(); - setInterlocutorId(id); - }, []); + const sendMessage = () => { + if (newMessage.trim()) { + const messageData = { + type: "message", + senderId: "yourUserId", + recipientId: interlocutorId, + message: newMessage, + timestamp: new Date().toLocaleTimeString(), + }; + socket.current.send(JSON.stringify(messageData)); + setMessages((prev) => [...prev, messageData]); + setNewMessage(""); + } + }; + + const handleKeyPress = (e) => { + if (e.key === "Enter") { + sendMessage(); + } + }; + + const handleEmojiSelect = (emoji) => { + setNewMessage((prev) => prev + emoji); + setShowEmojiPicker(false); + }; return ( -

Chat with ... (id = {interlocutorId})

+
+
+

Chat with ... (id = {interlocutorId})

+ {" "} + {} +
+
+ {messages.map((msg, index) => ( +
+
+ {msg.senderId === "yourUserId" ? "You" : "Interlocutor"}:{" "} + {msg.message} +
+ {msg.timestamp} +
+ ))} +
+
+ setNewMessage(e.target.value)} + placeholder="Type a message..." + className="chat-input" + onKeyPress={handleKeyPress} + /> + + + {showEmojiPicker && ( +
+ {emojis.map((emoji, index) => ( + handleEmojiSelect(emoji)} + style={{ cursor: "pointer", padding: "5px" }} + > + {emoji} + + ))} +
+ )} +
+
); }; diff --git a/src/pages/css/Chat.css b/src/pages/css/Chat.css new file mode 100644 index 0000000..4d39650 --- /dev/null +++ b/src/pages/css/Chat.css @@ -0,0 +1,145 @@ +.chat-container { + display: flex; + flex-direction: column; + width: 100%; + max-width: 600px; + margin: auto; + border: 1px solid #ddd; + border-radius: 8px; + overflow: hidden; + background-color: #f9f9f9; +} + +.chat-header { + padding: 10px; + background-color: #007bff; + color: white; + text-align: center; +} + +.chat-messages { + display: flex; + flex-direction: column; + flex-grow: 1; + padding: 10px; + overflow-y: auto; + background-color: #fff; +} + +.message-bubble { + margin: 5px; + padding: 10px 15px; + border-radius: 10px; + max-width: 70%; + word-wrap: break-word; + display: inline-block; +} + +.sent { + background-color: #007bff; + color: white; + align-self: flex-end; + text-align: right; + margin-left: auto; +} + +.received { + background-color: #f1f0f0; + align-self: flex-start; + text-align: left; + margin-right: auto; +} + +.message-content { + font-size: 14px; + margin: 0; + padding: 0; +} + +.message-timestamp { + font-size: 10px; + color: #999; + margin-top: 5px; + display: block; +} + +.chat-input-container { + display: flex; + padding: 10px; + border-top: 1px solid #ddd; + background-color: #f0f0f0; +} + +.chat-input { + flex-grow: 1; + padding: 10px; + border: 1px solid #ddd; + border-radius: 20px; + font-size: 14px; + outline: none; +} + +.send-button, +.emoji-button { + background-color: transparent; + border: none; + font-size: 20px; + margin-left: 10px; + cursor: pointer; + transition: color 0.3s; +} + +.send-button:hover, +.emoji-button:hover { + color: #0056b3; +} + +.send-button { + color: #007bff; +} + +.emoji-button { + color: #f0c040; +} + +.chat-input:focus { + border-color: #007bff; +} + +.emoji-picker { + position: absolute; + bottom: 60px; + right: 10px; + z-index: 10; + background-color: white; + border: 1px solid #ccc; + border-radius: 5px; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); + display: flex; + flex-wrap: wrap; + max-width: 200px; +} + +.emoji { + font-size: 24px; + cursor: pointer; + transition: transform 0.2s; +} + +.emoji:hover { + transform: scale(1.2); +} + +.home-button { + background-color: #4caf50; + color: white; + padding: 10px 15px; + border: none; + border-radius: 5px; + cursor: pointer; + margin-left: auto; +} + +.home-button:hover { + background-color: #45a049; +} diff --git a/src/pages/css/account.css b/src/pages/css/account.css new file mode 100644 index 0000000..e69de29