Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
964ca236e8 | ||
|
|
9c1c670ccb | ||
|
|
ff9bd3ac8c | ||
|
|
51618c8858 | ||
|
|
54f6c5c053 | ||
|
|
8fecf7cb1f | ||
|
|
49a8af611f | ||
|
|
7c4457dea4 | ||
|
|
6096bdc4cb | ||
|
|
dd10b080e8 | ||
|
|
4cf909c607 | ||
|
|
13f4d43761 | ||
|
|
22a549e269 | ||
|
|
25c3e16c74 | ||
|
|
86db5df813 | ||
|
|
d1e824ab77 | ||
|
|
073c61977f | ||
|
|
1301c145e8 | ||
|
|
ac6dffa129 | ||
|
|
8e4cad4c85 | ||
|
|
d1091e570b | ||
|
|
4a5041a65e | ||
|
|
8d0fadc906 | ||
|
|
6bea0428f4 | ||
|
|
660f2e9d5c | ||
|
|
a9b683797b | ||
|
|
a3484f4525 | ||
|
|
876ef28221 | ||
|
|
e6231f86b4 | ||
|
|
9d13f571d9 | ||
|
|
f654851e1a | ||
|
|
3fb107fd8b | ||
|
|
2a881f3920 |
@@ -23,5 +23,6 @@ module.exports = {
|
||||
},
|
||||
config: {
|
||||
"enterfront.api": "/api",
|
||||
// paste stand URL to config
|
||||
},
|
||||
};
|
||||
|
||||
694
package-lock.json
generated
694
package-lock.json
generated
@@ -1,25 +1,33 @@
|
||||
{
|
||||
"name": "enterfront",
|
||||
"version": "0.2.2",
|
||||
"version": "0.5.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "enterfront",
|
||||
"version": "0.2.2",
|
||||
"version": "0.5.1",
|
||||
"dependencies": {
|
||||
"@brojs/cli": "^1.0.0",
|
||||
"@brojs/create": "^1.0.0",
|
||||
"@ijl/cli": "^5.1.0",
|
||||
"@types/react": "^18.3.5",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"dotenv": "^16.4.5",
|
||||
"emoji-mart": "^5.6.0",
|
||||
"express": "^4.19.2",
|
||||
"jsonwebtoken": "^9.0.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",
|
||||
"react-toastify": "^10.0.5",
|
||||
"socket.io": "^4.8.0",
|
||||
"socket.io-client": "^4.8.0",
|
||||
"styled-components": "^6.1.13",
|
||||
"typescript": "^5.5.4"
|
||||
"typescript": "^5.5.4",
|
||||
"ws": "^8.18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@ampproject/remapping": {
|
||||
@@ -1848,9 +1856,9 @@
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"version": "23.15.2",
|
||||
"resolved": "https://registry.npmjs.org/i18next/-/i18next-23.15.2.tgz",
|
||||
"integrity": "sha512-zcPSWzCvw6uKnuYHIqs4W7hTuB9e3AFcSdZgvCWoPXIZsBjBd4djN2/2uOHIB+1DFFkQnMBXvhNg7J3WyCuywQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -2686,9 +2694,10 @@
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"version": "17.0.83",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.83.tgz",
|
||||
"integrity": "sha512-l0m4ArKJvmFtR4e8UmKrj1pB4tUgOhJITf+mADyF/p69Ts1YAR/E+G9XEM0mHXKVRa1dQNHseyyDNzeuAXfXQw==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
@@ -2714,6 +2723,7 @@
|
||||
"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==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
@@ -2727,6 +2737,7 @@
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
|
||||
"integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
@@ -2769,6 +2780,7 @@
|
||||
"version": "0.20.2",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz",
|
||||
"integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
@@ -3061,12 +3073,14 @@
|
||||
"node_modules/@types/cookie": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
|
||||
"integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q=="
|
||||
"integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/cors": {
|
||||
"version": "2.8.17",
|
||||
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz",
|
||||
"integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
@@ -3132,6 +3146,7 @@
|
||||
"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==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true
|
||||
},
|
||||
@@ -3458,6 +3473,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 +3583,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 +3597,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,10 +3726,20 @@
|
||||
"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",
|
||||
"integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^4.5.0 || >= 5.9"
|
||||
}
|
||||
@@ -3802,6 +3851,12 @@
|
||||
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer-equal-constant-time": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
|
||||
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/buffer-from": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||
@@ -4037,6 +4092,15 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/clsx": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
|
||||
"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/collection-visit": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
|
||||
@@ -4094,6 +4158,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 +4346,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",
|
||||
@@ -4240,6 +4369,7 @@
|
||||
"version": "2.8.5",
|
||||
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
|
||||
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"object-assign": "^4",
|
||||
"vary": "^1"
|
||||
@@ -4437,6 +4567,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 +4670,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",
|
||||
@@ -4547,6 +4708,18 @@
|
||||
"resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz",
|
||||
"integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w=="
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "16.4.5",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
|
||||
"integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://dotenvx.com"
|
||||
}
|
||||
},
|
||||
"node_modules/duplexer": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
|
||||
@@ -4557,6 +4730,15 @@
|
||||
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
|
||||
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
|
||||
},
|
||||
"node_modules/ecdsa-sig-formatter": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
|
||||
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/ee-first": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||
@@ -4567,6 +4749,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",
|
||||
@@ -4589,9 +4789,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io": {
|
||||
"version": "6.5.5",
|
||||
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz",
|
||||
"integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==",
|
||||
"version": "6.6.1",
|
||||
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.1.tgz",
|
||||
"integrity": "sha512-NEpDCw9hrvBW+hVEOK4T7v0jFJ++KgtPl4jKFwsZVfG1XhS0dCrSb3VMb9gPAd7VAdW52VT1EnaNiU2vM8C0og==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/cookie": "^0.4.1",
|
||||
"@types/cors": "^2.8.12",
|
||||
@@ -4608,6 +4809,40 @@
|
||||
"node": ">=10.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io-client": {
|
||||
"version": "6.6.1",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.1.tgz",
|
||||
"integrity": "sha512-aYuoak7I+R83M/BBPIOs2to51BmFIpC1wZe6zZzMrT2llVsHy5cvcmdsJgP2Qz6smHu+sD9oexiSUAVd8OfBPw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.1",
|
||||
"engine.io-parser": "~5.2.1",
|
||||
"ws": "~8.17.1",
|
||||
"xmlhttprequest-ssl": "~2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io-client/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/engine.io-parser": {
|
||||
"version": "5.2.3",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
|
||||
@@ -4620,10 +4855,32 @@
|
||||
"version": "0.4.2",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
|
||||
"integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"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 +4901,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 +4991,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 +5360,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 +6776,101 @@
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/jsonwebtoken": {
|
||||
"version": "9.0.2",
|
||||
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
|
||||
"integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"jws": "^3.2.2",
|
||||
"lodash.includes": "^4.3.0",
|
||||
"lodash.isboolean": "^3.0.3",
|
||||
"lodash.isinteger": "^4.0.4",
|
||||
"lodash.isnumber": "^3.0.3",
|
||||
"lodash.isplainobject": "^4.0.6",
|
||||
"lodash.isstring": "^4.0.1",
|
||||
"lodash.once": "^4.0.0",
|
||||
"ms": "^2.1.1",
|
||||
"semver": "^7.5.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12",
|
||||
"npm": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/jsonwebtoken/node_modules/semver": {
|
||||
"version": "7.6.3",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
|
||||
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"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/jwa": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
|
||||
"integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"buffer-equal-constant-time": "1.0.1",
|
||||
"ecdsa-sig-formatter": "1.0.11",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/jws": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
|
||||
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"jwa": "^1.4.1",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/keygrip": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz",
|
||||
@@ -6537,11 +6940,59 @@
|
||||
"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",
|
||||
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="
|
||||
},
|
||||
"node_modules/lodash.includes": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
|
||||
"integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isboolean": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
|
||||
"integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isinteger": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
|
||||
"integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isnumber": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
|
||||
"integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isplainobject": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
|
||||
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isstring": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
|
||||
"integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.once": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
|
||||
"integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
@@ -7342,6 +7793,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 +7810,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 +7867,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 +8197,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",
|
||||
@@ -7784,6 +8318,19 @@
|
||||
"react-dom": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/react-toastify": {
|
||||
"version": "10.0.5",
|
||||
"resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-10.0.5.tgz",
|
||||
"integrity": "sha512-mNKt2jBXJg4O7pSdbNUfDdTsK9FIdikfsIE/yUCxbAEXl4HMyJaivrVFcn3Elvt5xvCQYhUZm+hqTIu1UXM3Pw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"clsx": "^2.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=18",
|
||||
"react-dom": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/readdirp": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
@@ -7796,6 +8343,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",
|
||||
@@ -8430,15 +9001,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io": {
|
||||
"version": "4.7.5",
|
||||
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz",
|
||||
"integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==",
|
||||
"version": "4.8.0",
|
||||
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.0.tgz",
|
||||
"integrity": "sha512-8U6BEgGjQOfGz3HHTYaC/L1GaxDCJ/KM0XTkJly0EhZ5U/du9uNEZy4ZgYzEzIqlx2CMm25CrCqr1ck899eLNA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"accepts": "~1.3.4",
|
||||
"base64id": "~2.0.0",
|
||||
"cors": "~2.8.5",
|
||||
"debug": "~4.3.2",
|
||||
"engine.io": "~6.5.2",
|
||||
"engine.io": "~6.6.0",
|
||||
"socket.io-adapter": "~2.5.2",
|
||||
"socket.io-parser": "~4.2.4"
|
||||
},
|
||||
@@ -8455,6 +9027,42 @@
|
||||
"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-client": {
|
||||
"version": "4.8.0",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.0.tgz",
|
||||
"integrity": "sha512-C0jdhD5yQahMws9alf/yvtsMGTaIDBnZ8Rb5HU56svyq0l5LIrGzIDZZD5pHQlmzxLuU91Gz+VpQMKgCTNYtkw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.2",
|
||||
"engine.io-client": "~6.6.1",
|
||||
"socket.io-parser": "~4.2.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"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 +9475,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 +9610,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 +10099,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 +10185,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"
|
||||
},
|
||||
@@ -9559,6 +10205,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/xmlhttprequest-ssl": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.1.tgz",
|
||||
"integrity": "sha512-ptjR8YSJIXoA3Mbv5po7RtSYHO6mZr8s7i5VGmEk7QY2pQWyT1o0N+W1gKbOyJPUCGXGnuw0wqe8f0L6Y0ny7g==",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
|
||||
12
package.json
12
package.json
@@ -5,13 +5,21 @@
|
||||
"@ijl/cli": "^5.1.0",
|
||||
"@types/react": "^18.3.5",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"dotenv": "^16.4.5",
|
||||
"emoji-mart": "^5.6.0",
|
||||
"express": "^4.19.2",
|
||||
"jsonwebtoken": "^9.0.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",
|
||||
"react-toastify": "^10.0.5",
|
||||
"socket.io": "^4.8.0",
|
||||
"socket.io-client": "^4.8.0",
|
||||
"styled-components": "^6.1.13",
|
||||
"typescript": "^5.5.4"
|
||||
"typescript": "^5.5.4",
|
||||
"ws": "^8.18.0"
|
||||
},
|
||||
"main": "./src/index.tsx",
|
||||
"scripts": {
|
||||
@@ -21,5 +29,5 @@
|
||||
"clean": "rimraf dist"
|
||||
},
|
||||
"name": "enterfront",
|
||||
"version": "0.2.2"
|
||||
"version": "0.5.1"
|
||||
}
|
||||
|
||||
34
src/app.tsx
34
src/app.tsx
@@ -1,15 +1,39 @@
|
||||
import React from 'react';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import React, {useEffect} from 'react';
|
||||
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import { Dashboard } from './dashboard';
|
||||
|
||||
import {ToastContainer} from "react-toastify";
|
||||
import 'react-toastify/dist/ReactToastify.css';
|
||||
|
||||
|
||||
import './index.css'
|
||||
import {displayMessage} from "./backend/notifications/notifications.js";
|
||||
import {MessageType} from "./backend/notifications/message";
|
||||
|
||||
const App = () => {
|
||||
useEffect(() => {
|
||||
document.title = 'Enterfront';
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const msg = localStorage.getItem('message');
|
||||
|
||||
if (!msg) return;
|
||||
|
||||
displayMessage(msg, MessageType.SUCCESS);
|
||||
localStorage.removeItem('message');
|
||||
}, []);
|
||||
|
||||
return(
|
||||
<BrowserRouter>
|
||||
<Dashboard />
|
||||
</BrowserRouter>
|
||||
<div>
|
||||
<BrowserRouter>
|
||||
<Dashboard />
|
||||
</BrowserRouter>
|
||||
|
||||
<ToastContainer/>
|
||||
</div>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
60
src/backend/api.js
Normal file
60
src/backend/api.js
Normal file
@@ -0,0 +1,60 @@
|
||||
import {getConfigValue} from "@brojs/cli";
|
||||
|
||||
|
||||
const LOCAL = "http://localhost:8099";
|
||||
const DEV = "https://dev.bro-js.ru";
|
||||
|
||||
export const BASE_API_URL = DEV + getConfigValue("enterfront.api");
|
||||
|
||||
// fetch(`${BASE_API_URL}/books/list`)
|
||||
|
||||
export async function post(path, body) {
|
||||
const token = localStorage.getItem('token');
|
||||
|
||||
const res = await fetch(`${BASE_API_URL}${path}`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": token ? `Bearer ${token}` : undefined
|
||||
},
|
||||
body: JSON.stringify(body)
|
||||
});
|
||||
|
||||
console.log("Initial data from API:", res)
|
||||
const data = JSON.parse(await res.text());
|
||||
console.log("Data from API:", data)
|
||||
|
||||
if (res.status === 200) {
|
||||
console.log("Received post:", data);
|
||||
|
||||
return {ok: true, data: data};
|
||||
} else {
|
||||
console.log("Error during post:", data.message);
|
||||
|
||||
return {ok: false, data: data};
|
||||
}
|
||||
}
|
||||
|
||||
export async function get(path){
|
||||
const token = localStorage.getItem('token');
|
||||
|
||||
const res = await fetch(`${BASE_API_URL}${path}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Authorization": token ? `Bearer ${token}` : undefined
|
||||
}
|
||||
});
|
||||
|
||||
console.log("Data from API:", res)
|
||||
const data = await res.json();
|
||||
|
||||
if (res.status === 200) {
|
||||
console.log("Received get:", data);
|
||||
|
||||
return {ok: true, data: data};
|
||||
} else {
|
||||
console.log("Error during get:", data.message);
|
||||
|
||||
return {ok: false, data: data};
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
export default class Interlocutor {
|
||||
constructor(id, name) {
|
||||
this.name = name
|
||||
this.id = id
|
||||
}
|
||||
static name;
|
||||
static id;
|
||||
}
|
||||
6
src/backend/notifications/message.tsx
Normal file
6
src/backend/notifications/message.tsx
Normal file
@@ -0,0 +1,6 @@
|
||||
export enum MessageType {
|
||||
ERROR,
|
||||
SUCCESS,
|
||||
INFO,
|
||||
WARN
|
||||
}
|
||||
28
src/backend/notifications/notifications.js
Normal file
28
src/backend/notifications/notifications.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import {toast} from "react-toastify";
|
||||
import {MessageType} from "./message.tsx";
|
||||
|
||||
export const displayMessage = (message, type) => {
|
||||
switch (type) {
|
||||
default:
|
||||
case MessageType.ERROR:
|
||||
toast.error(message, {
|
||||
position: 'bottom-right',
|
||||
});
|
||||
break;
|
||||
case MessageType.INFO:
|
||||
toast.info(message, {
|
||||
position: 'bottom-right',
|
||||
});
|
||||
break;
|
||||
case MessageType.SUCCESS:
|
||||
toast.success(message, {
|
||||
position: 'bottom-right',
|
||||
});
|
||||
break;
|
||||
case MessageType.WARN:
|
||||
toast.warn(message, {
|
||||
position: 'bottom-right',
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
31
src/backend/server.js
Normal file
31
src/backend/server.js
Normal file
@@ -0,0 +1,31 @@
|
||||
const express = require("express");
|
||||
const http = require("http");
|
||||
const { Server } = require("socket.io");
|
||||
require("dotenv").config();
|
||||
|
||||
const app = express();
|
||||
const server = http.createServer(app);
|
||||
const io = new Server(server);
|
||||
|
||||
io.on("connection", (socket) => {
|
||||
console.log("New connection:", socket.id);
|
||||
|
||||
// For messages
|
||||
socket.on("sendMessage", (message) => {
|
||||
console.log("Message received:", message);
|
||||
socket.broadcast.emit("receiveMessage", message);
|
||||
});
|
||||
|
||||
socket.on("disconnect", () => {
|
||||
console.log("User disconnected:", socket.id);
|
||||
});
|
||||
});
|
||||
|
||||
app.get("/", (req, res) => {
|
||||
res.send("Socket.IO Server is running");
|
||||
});
|
||||
|
||||
const PORT = process.env.PORT || 8099;
|
||||
server.listen(PORT, () => {
|
||||
console.log(`Server is running on port ${PORT}`);
|
||||
});
|
||||
@@ -1,3 +0,0 @@
|
||||
export default class User {
|
||||
|
||||
}
|
||||
51
src/components/account/AccountButtons.jsx
Normal file
51
src/components/account/AccountButtons.jsx
Normal file
@@ -0,0 +1,51 @@
|
||||
import React, {useState} from 'react';
|
||||
import { URLs } from "../../__data__/urls";
|
||||
import ActionButton from "./ActionButton.jsx";
|
||||
import InputField from "../reg/InputField.jsx";
|
||||
|
||||
const AccountButtons = (props) => {
|
||||
const [chName, setChName] = useState(false);
|
||||
const [chPassword, setChPassword] = useState(false);
|
||||
|
||||
const [nickname, setNickname] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
|
||||
return (
|
||||
<div className="account-buttons">
|
||||
{props.registered ? (
|
||||
<>
|
||||
<ActionButton title={"Exit"} action={props.exitHandler}/>
|
||||
<ActionButton title={"Change Name"} action={() => setChName(true)}/>
|
||||
{chName ? (
|
||||
<InputField
|
||||
title={""}
|
||||
value={nickname}
|
||||
setValue={setNickname}
|
||||
placeholder='Enter your new nickname'
|
||||
|
||||
submit={nickname}
|
||||
enter={props.changeNameHandler}
|
||||
/>
|
||||
) : null}
|
||||
<ActionButton title={"Change Pass"} action={() => setChPassword(true)}/>
|
||||
{chPassword ? (
|
||||
<div>
|
||||
<InputField
|
||||
title={""}
|
||||
value={password}
|
||||
setValue={setPassword}
|
||||
placeholder='Enter your new password'
|
||||
|
||||
submit={password}
|
||||
enter={props.changePassHandler}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
</>
|
||||
) : null}
|
||||
<a className="MyButton mclaren-regular" href={URLs.home.url}>Back</a>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccountButtons;
|
||||
11
src/components/account/ActionButton.jsx
Normal file
11
src/components/account/ActionButton.jsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import React from 'react';
|
||||
|
||||
const ActionButton = (props) => {
|
||||
return (
|
||||
<a className="MyButton mclaren-regular" onClick={() => {
|
||||
props.action()
|
||||
}}>{props.title}</a>
|
||||
);
|
||||
};
|
||||
|
||||
export default ActionButton;
|
||||
18
src/components/account/HelloItem.jsx
Normal file
18
src/components/account/HelloItem.jsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import React from 'react';
|
||||
|
||||
const HelloItem = (props) => {
|
||||
return (
|
||||
<div className="hello-item-class">
|
||||
{!!props.nickname ? (
|
||||
<>
|
||||
<h1 className="mclaren-regular">Hello, {props.nickname}!</h1>
|
||||
<p className="mclaren-regular">Your ID: {props.id}</p>
|
||||
</>
|
||||
) : (
|
||||
<p className="mclaren-regular">You don't have an account :(</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default HelloItem;
|
||||
54
src/components/account/index.css
Normal file
54
src/components/account/index.css
Normal file
@@ -0,0 +1,54 @@
|
||||
.account-buttons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.account-buttons a {
|
||||
display: flex;
|
||||
|
||||
font-size: 1.5vw;
|
||||
transition: color 0.2s ease-in;
|
||||
|
||||
width: 20vw;
|
||||
|
||||
margin-top: 2vw;
|
||||
}
|
||||
|
||||
.account-buttons a:hover {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.hello-item-class {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.hello-item-class h1 {
|
||||
font-size: 4vw;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.hello-item-class p {
|
||||
font-size: 1.5vw;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 800px) {
|
||||
.account-buttons a {
|
||||
font-size: 2.5vh;
|
||||
width: 60vw;
|
||||
margin-top: 3vh;
|
||||
}
|
||||
|
||||
.hello-item-class h1 {
|
||||
font-size: 5vh;
|
||||
}
|
||||
|
||||
.hello-item-class p {
|
||||
font-size: 2vh;
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,10 @@ const Card = (props) => {
|
||||
transition: color 0.3s ease-in;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 10px 40px rgb(${hexToRgb(props.color)});
|
||||
cursor: pointer;
|
||||
@@ -56,7 +60,7 @@ const Card = (props) => {
|
||||
flex-direction: column;
|
||||
|
||||
border-radius: 2vh;
|
||||
padding: 3vw;
|
||||
padding: 5vw;
|
||||
}
|
||||
`
|
||||
|
||||
|
||||
@@ -1,40 +1,92 @@
|
||||
import React from 'react';
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Card from "./Card.jsx";
|
||||
import { get } from "../../backend/api";
|
||||
import { displayMessage } from "../../backend/notifications/notifications";
|
||||
import { MessageType } from "../../backend/notifications/message";
|
||||
|
||||
const ChatsList = (props) => {
|
||||
const { chats } = props;
|
||||
const { chats } = props;
|
||||
const [customChats, setCustomChats] = useState([]);
|
||||
|
||||
const colorMap = {
|
||||
orange: 'FFA500FF',
|
||||
aqua: '00FFFFFF',
|
||||
crimson: 'DC143CFF',
|
||||
red: 'FF0000FF',
|
||||
violet: '8A2BE2FF',
|
||||
seagreen: '20B2AAFF',
|
||||
green: 'ADFF2FFF',
|
||||
blue: '0000FFFF',
|
||||
pink: 'FF1493FF',
|
||||
cyan: '72FAFAFF'
|
||||
}
|
||||
const updateList = async () => {
|
||||
const username = localStorage.getItem("username");
|
||||
if (!username) return null;
|
||||
|
||||
function getColor(chatId) {
|
||||
const keys = Object.keys(colorMap);
|
||||
const index = chatId % keys.length;
|
||||
return colorMap[keys[index]];
|
||||
}
|
||||
const updatedChats = await Promise.all(
|
||||
chats.map(async (chat) => {
|
||||
const interlocutorId = chat.id1 === username ? chat.id2 : chat.id1;
|
||||
|
||||
const { ok, data } = await get("/auth/" + interlocutorId);
|
||||
if (!ok) {
|
||||
displayMessage(data.message, MessageType.ERROR);
|
||||
return null;
|
||||
}
|
||||
|
||||
const interlocutor = data.user;
|
||||
|
||||
const lastMessage =
|
||||
chat.messages.length > 0
|
||||
? chat.messages[chat.messages.length - 1]
|
||||
: { data: "", timestamp: new Date(0).toISOString() };
|
||||
|
||||
return {
|
||||
id: interlocutorId,
|
||||
name: interlocutor.nickname,
|
||||
lastMessageData: lastMessage.data,
|
||||
lastMessageTimestamp: lastMessage.timestamp,
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
const validChats = updatedChats.filter((chat) => chat !== null);
|
||||
|
||||
validChats.sort(
|
||||
(a, b) =>
|
||||
new Date(b.lastMessageTimestamp) - new Date(a.lastMessageTimestamp)
|
||||
);
|
||||
|
||||
setCustomChats(validChats);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
updateList().then();
|
||||
}, [chats]);
|
||||
|
||||
const colorMap = {
|
||||
orange: "FFA500FF",
|
||||
aqua: "00FFFFFF",
|
||||
crimson: "DC143CFF",
|
||||
red: "FF0000FF",
|
||||
violet: "8A2BE2FF",
|
||||
seagreen: "20B2AAFF",
|
||||
green: "ADFF2FFF",
|
||||
blue: "0000FFFF",
|
||||
pink: "FF1493FF",
|
||||
cyan: "72FAFAFF",
|
||||
};
|
||||
|
||||
function getColor(chatId) {
|
||||
const keys = Object.keys(colorMap);
|
||||
const numericId = Array.from(chatId).reduce(
|
||||
(sum, char) => sum + char.charCodeAt(0),
|
||||
0
|
||||
);
|
||||
const index = numericId % keys.length;
|
||||
return colorMap[keys[index]];
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="ChatsList">
|
||||
{chats.map((item, index) => (
|
||||
<Card
|
||||
key={index}
|
||||
name={item.name}
|
||||
lastMessage={item.lastMessage}
|
||||
id={item.id}
|
||||
color={getColor(item.id)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="ChatsList">
|
||||
{customChats.map((item, index) => (
|
||||
<Card
|
||||
key={index}
|
||||
name={item.name}
|
||||
lastMessage={item.lastMessageData}
|
||||
id={item.id}
|
||||
color={getColor(item.id)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
11
src/components/home/Search.jsx
Normal file
11
src/components/home/Search.jsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import React from 'react';
|
||||
|
||||
const Search = (props) => {
|
||||
return (
|
||||
<a className="MyButton search-class mclaren-regular" onClick={() => {
|
||||
props.search(props.item);
|
||||
}}>Find</a>
|
||||
);
|
||||
};
|
||||
|
||||
export default Search;
|
||||
@@ -34,6 +34,8 @@
|
||||
|
||||
margin-left: 4vw;
|
||||
margin-right: 4vw;
|
||||
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.ChatsList {
|
||||
|
||||
@@ -12,11 +12,30 @@
|
||||
color: orange;
|
||||
}
|
||||
|
||||
.search-class {
|
||||
margin-top: 2vw;
|
||||
margin-bottom: 4vw;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.search-input div input {
|
||||
background-color: white;
|
||||
color: black;
|
||||
|
||||
border: 3px solid black;
|
||||
}
|
||||
|
||||
|
||||
@media only screen and (max-width: 800px) {
|
||||
.homeTitle {
|
||||
font-size: 8vh;
|
||||
}
|
||||
|
||||
.search-class {
|
||||
margin-top: 3vh;
|
||||
}
|
||||
}
|
||||
|
||||
.chatIcon {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
@import url("reg/index.css");
|
||||
@import url("init/index.css");
|
||||
@import url("home/index.css");
|
||||
@import url("account/index.css");
|
||||
|
||||
.MyButton {
|
||||
text-decoration: none;
|
||||
|
||||
@@ -17,3 +17,16 @@
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 800px) {
|
||||
.MyButton.singleNavButton p {
|
||||
font-size: 2.5vh;
|
||||
}
|
||||
|
||||
.MyButton.singleNavButton {
|
||||
min-width: 60vw;
|
||||
border-radius: 30vh;
|
||||
|
||||
margin-top: 3vh;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
|
||||
const InputField = (props) => {
|
||||
console.log('class:', props.className)
|
||||
return (
|
||||
<div>
|
||||
<p>{props.title}</p>
|
||||
@@ -8,6 +9,14 @@ const InputField = (props) => {
|
||||
onChange={(e) => props.setValue(e.target.value)}
|
||||
value={props.value}
|
||||
className="Input"
|
||||
placeholder={(props.placeholder) ? props.placeholder : ''}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
if (props.submit) {
|
||||
props.enter(props.submit);
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -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 (
|
||||
<Routes>
|
||||
<Route path={URLs.baseUrl} element={<Init/>}/>
|
||||
<Route path={URLs.home.url} element={<Home/>}/>
|
||||
<Route path={URLs.chat.url} element={<Chat/>}/>
|
||||
<Route path={URLs.auth.url} element={<SignIn/>}/>
|
||||
<Route path={URLs.reg.url} element={<SignUp/>}/>
|
||||
<Route path={URLs.account.url} element={<Account/>}/>
|
||||
<Route path="*" element={<h1>404 page not found</h1>}/>
|
||||
<Route path={URLs.baseUrl} element={<Init />} />
|
||||
<Route path={URLs.home.url} element={<Home />} />
|
||||
<Route path={URLs.chat.url} element={<Chat />} />
|
||||
<Route path={URLs.auth.url} element={<SignIn />} />
|
||||
<Route path={URLs.reg.url} element={<SignUp />} />
|
||||
<Route path={URLs.account.url} element={<Account />} />
|
||||
<Route path="*" element={<h1>404 page not found</h1>} />
|
||||
</Routes>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,9 +1,81 @@
|
||||
import React from "react";
|
||||
import React, {useEffect, useState} from "react";
|
||||
import AccountButtons from "../components/account/AccountButtons.jsx";
|
||||
import userIcon from "../../images/user.svg";
|
||||
import {get, post} from "../backend/api";
|
||||
import {displayMessage} from "../backend/notifications/notifications";
|
||||
import {MessageType} from "../backend/notifications/message";
|
||||
import HelloItem from "../components/account/HelloItem.jsx";
|
||||
import { URLs } from "../__data__/urls";
|
||||
|
||||
const Account = () => {
|
||||
return (
|
||||
<h1>Account</h1>
|
||||
)
|
||||
}
|
||||
const exitHandler = () => {
|
||||
localStorage.removeItem("username");
|
||||
localStorage.removeItem("token");
|
||||
|
||||
export default Account;
|
||||
localStorage.setItem("message", "Exited successfully!");
|
||||
window.location.href = "/";
|
||||
}
|
||||
|
||||
const [nickname, setNickname] = useState("");
|
||||
const [id, setId] = useState("");
|
||||
|
||||
async function changeNameHandler (newNickname) {
|
||||
if (!newNickname) return;
|
||||
|
||||
const {ok, data} = await post('/change/nickname', {id: id, newNickname: newNickname});
|
||||
|
||||
if (!ok) {
|
||||
displayMessage(data.message, MessageType.ERROR);
|
||||
} else {
|
||||
localStorage.setItem("message", "Name was changed");
|
||||
window.location.href = URLs.account.url;
|
||||
}
|
||||
}
|
||||
|
||||
async function changePassHandler (newPass){
|
||||
if (!newPass) return;
|
||||
|
||||
const {ok, data} = await post('/change/password', {id: id, newPassword: newPass});
|
||||
|
||||
if (!ok) {
|
||||
displayMessage(data.message, MessageType.ERROR);
|
||||
} else {
|
||||
localStorage.setItem("message", "Password was changed");
|
||||
window.location.href = URLs.account.url;
|
||||
}
|
||||
}
|
||||
|
||||
async function getUser() {
|
||||
const username = localStorage.getItem("username");
|
||||
if (!username) {
|
||||
displayMessage("You're not logged in!", MessageType.WARN);
|
||||
return;
|
||||
}
|
||||
|
||||
const {ok, data} = await get('/auth/' + username);
|
||||
if (!ok) {
|
||||
displayMessage("Some error with auth:" + data.message, MessageType.ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
setNickname(data.user.nickname);
|
||||
setId(username);
|
||||
}
|
||||
|
||||
useEffect(() => {getUser().then()}, [])
|
||||
|
||||
return (
|
||||
<div className="account-items">
|
||||
<img src={userIcon} alt="user" />
|
||||
<HelloItem nickname={nickname} id={id} />
|
||||
<AccountButtons
|
||||
exitHandler={exitHandler}
|
||||
changeNameHandler={changeNameHandler}
|
||||
changePassHandler={changePassHandler}
|
||||
registered={!!nickname}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Account;
|
||||
|
||||
@@ -1,20 +1,242 @@
|
||||
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";
|
||||
import { get, post } from "../backend/api";
|
||||
import { displayMessage } from "../backend/notifications/notifications";
|
||||
import { MessageType } from "../backend/notifications/message";
|
||||
import io from "socket.io-client";
|
||||
|
||||
const emojis = [
|
||||
"😀",
|
||||
"😁",
|
||||
"😂",
|
||||
"🤣",
|
||||
"😃",
|
||||
"😄",
|
||||
"😅",
|
||||
"😆",
|
||||
"😉",
|
||||
"😊",
|
||||
"😋",
|
||||
"😎",
|
||||
"😍",
|
||||
"😘",
|
||||
"🥰",
|
||||
"😗",
|
||||
"😙",
|
||||
"😚",
|
||||
"🙂",
|
||||
"🤗",
|
||||
"🤩",
|
||||
"🤔",
|
||||
"😐",
|
||||
"😑",
|
||||
"😶",
|
||||
"🙄",
|
||||
"😏",
|
||||
"😣",
|
||||
"😥",
|
||||
"😮",
|
||||
"🤐",
|
||||
"😯",
|
||||
"😪",
|
||||
"😫",
|
||||
"😴",
|
||||
"😌",
|
||||
"😛",
|
||||
"😜",
|
||||
"🤪",
|
||||
"🤨",
|
||||
"😝",
|
||||
"🤑",
|
||||
"😒",
|
||||
"😓",
|
||||
"😔",
|
||||
"😕",
|
||||
"😖",
|
||||
"😞",
|
||||
"😟",
|
||||
"😠",
|
||||
"😡",
|
||||
"🤬",
|
||||
"😱",
|
||||
"😨",
|
||||
"😧",
|
||||
"😇",
|
||||
"🥳",
|
||||
"🥺",
|
||||
"😻",
|
||||
"😼",
|
||||
"😽",
|
||||
"🙈",
|
||||
"🙉",
|
||||
"🙊",
|
||||
"💀",
|
||||
"👻",
|
||||
"👽",
|
||||
];
|
||||
|
||||
const Chat = () => {
|
||||
const [interlocutorId, setInterlocutorId] = useState(0); // State to hold the interlocutorId
|
||||
const [interlocutorId, setInterlocutorId] = useState("");
|
||||
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;
|
||||
const [myId, setMyId] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
const id = localStorage.getItem("interlocutorId");
|
||||
setInterlocutorId(id);
|
||||
|
||||
const username = localStorage.getItem("username");
|
||||
setMyId(username);
|
||||
|
||||
if (!id || !username) {
|
||||
displayMessage("You are not logged in!", MessageType.WARN);
|
||||
return () => {};
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const id = getInterlocutorId();
|
||||
setInterlocutorId(id);
|
||||
}, []);
|
||||
socket.current = io("http://localhost:8099");
|
||||
|
||||
socket.current.on("receiveMessage", (message) => {
|
||||
setMessages((prev) => [...prev, message]);
|
||||
});
|
||||
|
||||
socket.current.on("connect_error", (err) => {
|
||||
console.error("Connection Error:", err.message);
|
||||
});
|
||||
|
||||
return () => {
|
||||
socket.current.disconnect();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
// retrieveMessages().then();
|
||||
const interval = setInterval(() => {
|
||||
retrieveMessages().then()
|
||||
}, 2000);
|
||||
|
||||
return () => clearInterval(interval)
|
||||
}, [myId, interlocutorId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (chatRef.current) {
|
||||
chatRef.current.scrollTop = chatRef.current.scrollHeight;
|
||||
}
|
||||
}, [messages]);
|
||||
|
||||
async function sendMessageToDB(messageData) {
|
||||
const { ok, data } = await post(
|
||||
"/chat/message/" + myId + "/" + interlocutorId,
|
||||
{ message: messageData }
|
||||
);
|
||||
if (!ok) {
|
||||
displayMessage(data.message, MessageType.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
async function retrieveMessages() {
|
||||
if (!myId || !interlocutorId) return;
|
||||
|
||||
const { ok, data } = await get("/chat/item/" + myId + "/" + interlocutorId);
|
||||
if (!ok) {
|
||||
displayMessage(data.message, MessageType.ERROR);
|
||||
return;
|
||||
}
|
||||
setMessages(data.chat.messages);
|
||||
}
|
||||
|
||||
const sendMessage = () => {
|
||||
if (newMessage.trim()) {
|
||||
const messageData = {
|
||||
senderId: myId,
|
||||
recipientId: interlocutorId,
|
||||
data: newMessage,
|
||||
timestamp: new Date().toLocaleString(),
|
||||
};
|
||||
socket.current.emit("sendMessage", messageData);
|
||||
setMessages((prev) => [...prev, messageData]);
|
||||
sendMessageToDB(messageData).then();
|
||||
setNewMessage("");
|
||||
}
|
||||
};
|
||||
|
||||
const handleKeyPress = (e) => {
|
||||
if (e.key === "Enter") {
|
||||
sendMessage();
|
||||
}
|
||||
};
|
||||
|
||||
const handleEmojiSelect = (emoji) => {
|
||||
setNewMessage((prev) => prev + emoji);
|
||||
setShowEmojiPicker(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<h2>Chat with ... (id = {interlocutorId})</h2>
|
||||
<div className="chat-container">
|
||||
<div className="chat-header">
|
||||
<h2>Chat with ... (id = {interlocutorId})</h2>
|
||||
<button
|
||||
onClick={() => navigate("/enterfront/home")}
|
||||
className="home-button"
|
||||
>
|
||||
Home
|
||||
</button>
|
||||
</div>
|
||||
<div className="chat-messages" ref={chatRef}>
|
||||
{messages.map((msg, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`message-bubble ${
|
||||
msg.senderId === myId ? "sent" : "received"
|
||||
}`}
|
||||
>
|
||||
<div className="message-content">
|
||||
<b>{msg.senderId === myId ? "You" : "They"}:</b> {msg.data}
|
||||
</div>
|
||||
<span className="message-timestamp">{msg.timestamp}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="chat-input-container">
|
||||
<input
|
||||
type="text"
|
||||
value={newMessage}
|
||||
onChange={(e) => setNewMessage(e.target.value)}
|
||||
placeholder="Type a message..."
|
||||
className="chat-input"
|
||||
onKeyDown={handleKeyPress}
|
||||
/>
|
||||
<button
|
||||
className="emoji-button"
|
||||
onClick={() => setShowEmojiPicker((prev) => !prev)}
|
||||
>
|
||||
<FaSmile />
|
||||
</button>
|
||||
<button onClick={sendMessage} className="send-button">
|
||||
<FaPaperPlane />
|
||||
</button>
|
||||
{showEmojiPicker && (
|
||||
<div className="emoji-picker">
|
||||
{emojis.map((emoji, index) => (
|
||||
<span
|
||||
key={index}
|
||||
className="emoji"
|
||||
onClick={() => handleEmojiSelect(emoji)}
|
||||
style={{ cursor: "pointer", padding: "5px" }}
|
||||
>
|
||||
{emoji}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,76 +1,86 @@
|
||||
import React from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import HomeTitle from "../components/home/HomeTitle.jsx";
|
||||
import ChatsList from "../components/home/ChatsList.jsx";
|
||||
import Header from "../components/home/Header.jsx";
|
||||
import { displayMessage } from "../backend/notifications/notifications";
|
||||
import { MessageType } from "../backend/notifications/message";
|
||||
import { get, post } from "../backend/api";
|
||||
import InputField from "../components/reg/InputField.jsx";
|
||||
import Search from "../components/home/Search.jsx";
|
||||
import { URLs } from "../__data__/urls";
|
||||
|
||||
const Home = () => {
|
||||
const [chats, setChats] = useState([]);
|
||||
const [interlocutor, setInterlocutor] = useState("");
|
||||
|
||||
// temp for testing
|
||||
const chats = [
|
||||
{
|
||||
name: "Alice Johnson",
|
||||
id: 123456,
|
||||
lastMessage: "See you later!"
|
||||
},
|
||||
{
|
||||
name: "Bob Smith",
|
||||
id: 654321,
|
||||
lastMessage: "Got it, thanks!"
|
||||
},
|
||||
{
|
||||
name: "Charlie Brown",
|
||||
id: 234567,
|
||||
lastMessage: "How's the project going? How's the project going? How's the project going?" +
|
||||
"How's the project going? How's the project going?"
|
||||
},
|
||||
{
|
||||
name: "David Clark",
|
||||
id: 765432,
|
||||
lastMessage: "I'll send the files."
|
||||
},
|
||||
{
|
||||
name: "Eve Adams",
|
||||
id: 345678,
|
||||
lastMessage: "Let's meet tomorrow."
|
||||
},
|
||||
{
|
||||
name: "Frank Wright",
|
||||
id: 876543,
|
||||
lastMessage: "Can you review this?"
|
||||
},
|
||||
{
|
||||
name: "Grace Lee",
|
||||
id: 456789,
|
||||
lastMessage: "Thanks for your help!"
|
||||
},
|
||||
{
|
||||
name: "Hannah Scott",
|
||||
id: 987654,
|
||||
lastMessage: "See you at the meeting."
|
||||
},
|
||||
{
|
||||
name: "Ian Davis",
|
||||
id: 567890,
|
||||
lastMessage: "Let me know when you're free."
|
||||
},
|
||||
{
|
||||
name: "Jill Thompson",
|
||||
id: 678901,
|
||||
lastMessage: "I'll catch up with you later."
|
||||
}
|
||||
];
|
||||
async function retrieveChats() {
|
||||
const username = localStorage.getItem("username");
|
||||
if (!username) {
|
||||
displayMessage("You're not logged in!", MessageType.WARN);
|
||||
return;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="homeWrapper">
|
||||
<div className="headerPos">
|
||||
<Header/>
|
||||
</div>
|
||||
const { ok, data } = await get("/chat/list/" + username);
|
||||
if (!ok) {
|
||||
displayMessage(data.message, MessageType.ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
<HomeTitle/>
|
||||
<p>Your chats</p>
|
||||
<ChatsList chats={chats} />
|
||||
const sortedChats = data.chats.sort((a, b) => {
|
||||
const lastMessageA = new Date(a.lastMessageTimestamp);
|
||||
const lastMessageB = new Date(b.lastMessageTimestamp);
|
||||
return lastMessageB - lastMessageA;
|
||||
});
|
||||
|
||||
setChats(sortedChats);
|
||||
}
|
||||
|
||||
async function createChat(alias) {
|
||||
const username = localStorage.getItem("username");
|
||||
if (!username) {
|
||||
displayMessage("You're not logged in!", MessageType.WARN);
|
||||
return;
|
||||
}
|
||||
|
||||
displayMessage("Sent", MessageType.INFO);
|
||||
|
||||
const { ok, data } = await post("/chat/item/" + username + "/" + alias);
|
||||
if (!ok) {
|
||||
displayMessage(data.message, MessageType.ERROR);
|
||||
} else {
|
||||
localStorage.setItem("message", "Successfully opened chat!");
|
||||
localStorage.setItem("interlocutorId", alias);
|
||||
window.location.href = URLs.chat.url;
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
retrieveChats();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="homeWrapper">
|
||||
<div className="headerPos">
|
||||
<Header />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Home
|
||||
<HomeTitle />
|
||||
|
||||
<div className="search-input">
|
||||
<InputField
|
||||
title="Create new chat"
|
||||
value={interlocutor}
|
||||
setValue={setInterlocutor}
|
||||
placeholder="Enter the username (id)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Search search={createChat} item={interlocutor} />
|
||||
|
||||
<p>Your chats</p>
|
||||
<ChatsList chats={chats} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Home;
|
||||
|
||||
@@ -3,12 +3,41 @@ import InputField from "../components/reg/InputField.jsx";
|
||||
import LoginButtons from "../components/reg/LoginButtons.jsx";
|
||||
import LoginTitle from "../components/reg/loginTitle.jsx";
|
||||
|
||||
import {MessageType} from "../backend/notifications/message.tsx";
|
||||
import {displayMessage} from "../backend/notifications/notifications.js";
|
||||
import {post} from "../backend/api.js";
|
||||
|
||||
const SignIn = () => {
|
||||
const [name, setName] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
|
||||
const submit = (e) => {
|
||||
console.log('Sign In!')
|
||||
const [nameErrorsCounter, setNameErrorsCounter] = useState(0);
|
||||
|
||||
async function submit() {
|
||||
console.log('Sign In!')
|
||||
|
||||
const {ok, data} = await post('/auth/login', {name: name, password: password});
|
||||
|
||||
if (!ok) {
|
||||
displayMessage(data.message, MessageType.ERROR);
|
||||
|
||||
if (nameErrorsCounter >= 1) {
|
||||
displayMessage("Note that you need to enter your ID name", MessageType.INFO);
|
||||
setNameErrorsCounter(0);
|
||||
} else {
|
||||
setNameErrorsCounter(nameErrorsCounter + 1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
localStorage.setItem('token', data.token);
|
||||
localStorage.setItem('username', name);
|
||||
|
||||
setNameErrorsCounter(0);
|
||||
|
||||
localStorage.setItem('message', 'Successfully logged in!');
|
||||
window.location.href = "/";
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -2,20 +2,59 @@ import React, {useState} from 'react';
|
||||
import InputField from "../components/reg/InputField.jsx";
|
||||
import LoginButtons from "../components/reg/LoginButtons.jsx";
|
||||
import LoginTitle from "../components/reg/loginTitle.jsx";
|
||||
import {post} from "../backend/api";
|
||||
import {displayMessage} from "../backend/notifications/notifications";
|
||||
import {MessageType} from "../backend/notifications/message";
|
||||
|
||||
|
||||
const SignUp = () => {
|
||||
const [name, setName] = useState("");
|
||||
const [nickname, setNickname] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [repeatPassword, setRepeatPassword] = useState("");
|
||||
|
||||
const submit = (e) => {
|
||||
console.log('Sign Up!')
|
||||
async function login(name, password) {
|
||||
const {ok, data} = await post('/auth/login', {name: name, password: password});
|
||||
return {loginStatus: ok, loginData: data};
|
||||
}
|
||||
|
||||
async function submit () {
|
||||
console.log('Sign Up!');
|
||||
|
||||
if (password !== repeatPassword) {
|
||||
displayMessage("Passwords don't match", MessageType.WARN);
|
||||
return;
|
||||
}
|
||||
|
||||
const {ok, data} = await post('/auth/reg',
|
||||
{name: name, password: password, nickname: nickname});
|
||||
|
||||
if (!ok) {
|
||||
displayMessage(data.message, MessageType.ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
const { loginStatus, loginData } = await login(name, password);
|
||||
|
||||
console.log(loginStatus, loginData)
|
||||
|
||||
if (!loginStatus) {
|
||||
displayMessage(loginData.message, MessageType.ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
localStorage.setItem('token', loginData.token);
|
||||
localStorage.setItem('username', name);
|
||||
|
||||
localStorage.setItem('message', 'Successfully signed up!');
|
||||
window.location.href = "/";
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="LoginList">
|
||||
<LoginTitle/>
|
||||
<InputField title="Name" setValue={setName} value={name}/>
|
||||
<InputField title="Nickname (for others)" setValue={setNickname} value={nickname}/>
|
||||
<InputField title="Password" setValue={setPassword} value={password}/>
|
||||
<InputField title="Repeat Password" setValue={setRepeatPassword} value={repeatPassword}/>
|
||||
|
||||
|
||||
160
src/pages/css/Chat.css
Normal file
160
src/pages/css/Chat.css
Normal file
@@ -0,0 +1,160 @@
|
||||
body {
|
||||
background: linear-gradient(to right, #e0f7fa, #fffde7);
|
||||
}
|
||||
|
||||
.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: 15px;
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
letter-spacing: 1px;
|
||||
border-bottom: 2px solid #0056b3;
|
||||
}
|
||||
|
||||
.chat-messages {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
padding: 10px;
|
||||
overflow-y: auto;
|
||||
background-color: #fff;
|
||||
max-height: 400px;
|
||||
}
|
||||
|
||||
.message-bubble {
|
||||
margin: 5px;
|
||||
padding: 10px 15px;
|
||||
border-radius: 10px;
|
||||
max-width: 70%;
|
||||
word-wrap: break-word;
|
||||
display: inline-block;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
.message-bubble:hover {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.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: black;
|
||||
text-align: right;
|
||||
margin-top: 4px;
|
||||
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;
|
||||
}
|
||||
12
src/pages/css/account.css
Normal file
12
src/pages/css/account.css
Normal file
@@ -0,0 +1,12 @@
|
||||
.account-items {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
margin-top: 5vw;
|
||||
}
|
||||
|
||||
.account-items img {
|
||||
margin-bottom: 1vw;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
@import url("css/init.css");
|
||||
@import url("css/home.css");
|
||||
@import url("css/input.css");
|
||||
@import url("css/input.css");
|
||||
@import url("css/account.css");
|
||||
73
stubs/api/auth/index.js
Normal file
73
stubs/api/auth/index.js
Normal file
@@ -0,0 +1,73 @@
|
||||
const authRouter = require('express').Router();
|
||||
|
||||
// For creating tokens
|
||||
const jwt = require('jsonwebtoken');
|
||||
|
||||
const { TOKEN_KEY } = require('../key')
|
||||
|
||||
|
||||
module.exports = authRouter;
|
||||
|
||||
const { addUserToDB, getUserFromDB } = require('../db');
|
||||
|
||||
|
||||
// Get a user by its id
|
||||
authRouter.get('/:id', (req, res) => {
|
||||
const user = getUserFromDB(req.params.id);
|
||||
|
||||
if (user) {
|
||||
res.status(200).send({user});
|
||||
} else {
|
||||
res.status(404).send({message: 'User was not found'});
|
||||
}
|
||||
})
|
||||
|
||||
// For login (authorization)
|
||||
authRouter.post('/login', (req, res) => {
|
||||
const { name, password } = req.body;
|
||||
|
||||
const user = getUserFromDB(name);
|
||||
|
||||
// Invalid identification
|
||||
if (!user) {
|
||||
res.status(401).send({message: 'Invalid credentials (id)'});
|
||||
return;
|
||||
}
|
||||
|
||||
// Invalid authentication
|
||||
if (!password || password !== user.password) {
|
||||
res.status(401).send({message: 'Invalid credentials (password)'});
|
||||
return;
|
||||
}
|
||||
|
||||
// Now, authorization
|
||||
const token = jwt.sign({id: name}, TOKEN_KEY, {
|
||||
expiresIn: '1h'
|
||||
})
|
||||
|
||||
res.status(200).send({token});
|
||||
})
|
||||
|
||||
|
||||
authRouter.post('/reg', (req, res) => {
|
||||
const { name, password, nickname } = req.body;
|
||||
|
||||
const user = getUserFromDB(name);
|
||||
|
||||
// Invalid identification
|
||||
if (user) {
|
||||
res.status(409).send({message: 'Such id already exists'});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!name || !password || !nickname) {
|
||||
res.status(401).send({message: 'Empty or invalid fields'});
|
||||
return;
|
||||
}
|
||||
|
||||
// Add to 'DB'
|
||||
const newUser = {id: name, password: password, nickname: nickname};
|
||||
addUserToDB(newUser)
|
||||
|
||||
res.status(200).send({user: newUser});
|
||||
})
|
||||
52
stubs/api/auth/users.json
Normal file
52
stubs/api/auth/users.json
Normal file
@@ -0,0 +1,52 @@
|
||||
[
|
||||
{
|
||||
"nickname": "Alice Johnson",
|
||||
"password": "1234",
|
||||
"id": "alice"
|
||||
},
|
||||
{
|
||||
"nickname": "Bob Smith",
|
||||
"password": "1234",
|
||||
"id": "bobsm"
|
||||
},
|
||||
{
|
||||
"nickname": "Charlie Brown",
|
||||
"password": "1234",
|
||||
"id": "charl"
|
||||
},
|
||||
{
|
||||
"nickname": "David Clark",
|
||||
"password": "1234",
|
||||
"id": "david"
|
||||
},
|
||||
{
|
||||
"nickname": "Eve Adams",
|
||||
"password": "1234",
|
||||
"id": "evead"
|
||||
},
|
||||
{
|
||||
"nickname": "Frank Wright",
|
||||
"password": "1234",
|
||||
"id": "frank"
|
||||
},
|
||||
{
|
||||
"nickname": "Grace Lee",
|
||||
"password": "1234",
|
||||
"id": "grace"
|
||||
},
|
||||
{
|
||||
"nickname": "Hannah Scott",
|
||||
"password": "1234",
|
||||
"id": "hanna"
|
||||
},
|
||||
{
|
||||
"nickname": "Ian Davis",
|
||||
"password": "1234",
|
||||
"id": "ianda"
|
||||
},
|
||||
{
|
||||
"nickname": "Jill Thompson",
|
||||
"password": "1234",
|
||||
"id": "jillt"
|
||||
}
|
||||
]
|
||||
64
stubs/api/change/index.js
Normal file
64
stubs/api/change/index.js
Normal file
@@ -0,0 +1,64 @@
|
||||
const changeRouter = require('express').Router();
|
||||
|
||||
module.exports = changeRouter;
|
||||
|
||||
const { getUserFromDB, deleteUserFromDB, addUserToDB } = require('../db');
|
||||
|
||||
|
||||
changeRouter.post('/nickname', (req, res) => {
|
||||
const { id, newNickname } = req.body;
|
||||
|
||||
const user = getUserFromDB(id);
|
||||
|
||||
// Invalid identification
|
||||
if (!user) {
|
||||
res.status(401).send({message: 'Invalid credentials (id)'});
|
||||
return;
|
||||
}
|
||||
|
||||
const updatedUser = {
|
||||
"nickname": newNickname,
|
||||
"password": user.password,
|
||||
"id": user.id
|
||||
};
|
||||
|
||||
// Delete the old one
|
||||
deleteUserFromDB(id)
|
||||
|
||||
// Insert updated
|
||||
addUserToDB(updatedUser);
|
||||
|
||||
res.status(200).send({});
|
||||
});
|
||||
|
||||
changeRouter.post('/password', (req, res) => {
|
||||
const { id, newPassword } = req.body;
|
||||
|
||||
const user = getUserFromDB(id);
|
||||
|
||||
// Invalid identification
|
||||
if (!user) {
|
||||
res.status(401).send({message: 'Invalid credentials (id)'});
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete the old one
|
||||
deleteUserFromDB(id)
|
||||
|
||||
// Insert updated
|
||||
const updatedUser = {
|
||||
"nickname": user.nickname,
|
||||
"password": newPassword,
|
||||
"id": user.id
|
||||
};
|
||||
addUserToDB(updatedUser);
|
||||
|
||||
res.status(200).send({});
|
||||
});
|
||||
|
||||
changeRouter.delete('/:id', (req, res) => {
|
||||
const { id } = req.params;
|
||||
|
||||
deleteUserFromDB(id);
|
||||
});
|
||||
|
||||
662
stubs/api/chat/chats.json
Normal file
662
stubs/api/chat/chats.json
Normal file
@@ -0,0 +1,662 @@
|
||||
[
|
||||
{
|
||||
"id1": "alice",
|
||||
"id2": "bobsm",
|
||||
"messages": [
|
||||
{
|
||||
"data": "Hello Bob!",
|
||||
"senderId": "alice",
|
||||
"recipientId": "bobsm",
|
||||
"timestamp": "09.10.2024 07:00:00"
|
||||
},
|
||||
{
|
||||
"data": "Hey Alice, how are you?",
|
||||
"senderId": "bobsm",
|
||||
"recipientId": "alice",
|
||||
"timestamp": "09.10.2024 07:05:00"
|
||||
},
|
||||
{
|
||||
"data": "I'm good, thanks for asking.",
|
||||
"senderId": "alice",
|
||||
"recipientId": "bobsm",
|
||||
"timestamp": "09.10.2024 07:10:00"
|
||||
},
|
||||
{
|
||||
"data": "Glad to hear!",
|
||||
"senderId": "bobsm",
|
||||
"recipientId": "alice",
|
||||
"timestamp": "09.10.2024 07:15:00"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id1": "alice",
|
||||
"id2": "charl",
|
||||
"messages": [
|
||||
{
|
||||
"data": "How's the project going?",
|
||||
"senderId": "alice",
|
||||
"recipientId": "charl",
|
||||
"timestamp": "09.10.2024 07:20:00"
|
||||
},
|
||||
{
|
||||
"data": "It's coming along, almost done!",
|
||||
"senderId": "charl",
|
||||
"recipientId": "alice",
|
||||
"timestamp": "09.10.2024 07:25:00"
|
||||
},
|
||||
{
|
||||
"data": "That's great to hear!",
|
||||
"senderId": "alice",
|
||||
"recipientId": "charl",
|
||||
"timestamp": "09.10.2024 07:30:00"
|
||||
},
|
||||
{
|
||||
"data": "Thanks for checking in.",
|
||||
"senderId": "charl",
|
||||
"recipientId": "alice",
|
||||
"timestamp": "09.10.2024 07:35:00"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id1": "alice",
|
||||
"id2": "david",
|
||||
"messages": [
|
||||
{
|
||||
"data": "Did you get the files?",
|
||||
"senderId": "david",
|
||||
"recipientId": "alice",
|
||||
"timestamp": "09.10.2024 07:40:00"
|
||||
},
|
||||
{
|
||||
"data": "Yes, I did. Thank you!",
|
||||
"senderId": "alice",
|
||||
"recipientId": "david",
|
||||
"timestamp": "09.10.2024 07:45:00"
|
||||
},
|
||||
{
|
||||
"data": "You're welcome.",
|
||||
"senderId": "david",
|
||||
"recipientId": "alice",
|
||||
"timestamp": "09.10.2024 07:50:00"
|
||||
},
|
||||
{
|
||||
"data": "Let me know if you need anything else.",
|
||||
"senderId": "alice",
|
||||
"recipientId": "david",
|
||||
"timestamp": "09.10.2024 07:55:00"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id1": "alice",
|
||||
"id2": "frank",
|
||||
"messages": [
|
||||
{
|
||||
"data": "Can you review this document for me?",
|
||||
"senderId": "alice",
|
||||
"recipientId": "frank",
|
||||
"timestamp": "09.10.2024 08:20:00"
|
||||
},
|
||||
{
|
||||
"data": "Sure, I'll take a look.",
|
||||
"senderId": "frank",
|
||||
"recipientId": "alice",
|
||||
"timestamp": "09.10.2024 08:25:00"
|
||||
},
|
||||
{
|
||||
"data": "Thanks, much appreciated!",
|
||||
"senderId": "alice",
|
||||
"recipientId": "frank",
|
||||
"timestamp": "09.10.2024 08:30:00"
|
||||
},
|
||||
{
|
||||
"data": "No problem.",
|
||||
"senderId": "frank",
|
||||
"recipientId": "alice",
|
||||
"timestamp": "09.10.2024 08:35:00"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id1": "alice",
|
||||
"id2": "grace",
|
||||
"messages": [
|
||||
{
|
||||
"data": "Hey Grace, let's meet up for coffee!",
|
||||
"senderId": "alice",
|
||||
"recipientId": "grace",
|
||||
"timestamp": "09.10.2024 08:40:00"
|
||||
},
|
||||
{
|
||||
"data": "Sounds good, when are you free?",
|
||||
"senderId": "grace",
|
||||
"recipientId": "alice",
|
||||
"timestamp": "09.10.2024 08:45:00"
|
||||
},
|
||||
{
|
||||
"data": "How about tomorrow afternoon?",
|
||||
"senderId": "alice",
|
||||
"recipientId": "grace",
|
||||
"timestamp": "09.10.2024 08:50:00"
|
||||
},
|
||||
{
|
||||
"data": "Works for me!",
|
||||
"senderId": "grace",
|
||||
"recipientId": "alice",
|
||||
"timestamp": "09.10.2024 08:55:00"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id1": "alice",
|
||||
"id2": "hanna",
|
||||
"messages": [
|
||||
{
|
||||
"data": "Hannah, do you have a moment?",
|
||||
"senderId": "alice",
|
||||
"recipientId": "hanna",
|
||||
"timestamp": "09.10.2024 09:00:00"
|
||||
},
|
||||
{
|
||||
"data": "Sure, what's up?",
|
||||
"senderId": "hanna",
|
||||
"recipientId": "alice",
|
||||
"timestamp": "09.10.2024 09:05:00"
|
||||
},
|
||||
{
|
||||
"data": "Just wanted to check on the report.",
|
||||
"senderId": "alice",
|
||||
"recipientId": "hanna",
|
||||
"timestamp": "09.10.2024 09:10:00"
|
||||
},
|
||||
{
|
||||
"data": "I'll send it soon.",
|
||||
"senderId": "hanna",
|
||||
"recipientId": "alice",
|
||||
"timestamp": "09.10.2024 09:15:00"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id1": "alice",
|
||||
"id2": "ianda",
|
||||
"messages": [
|
||||
{
|
||||
"data": "Ian, have you completed the review?",
|
||||
"senderId": "alice",
|
||||
"recipientId": "ianda",
|
||||
"timestamp": "09.10.2024 09:20:00"
|
||||
},
|
||||
{
|
||||
"data": "Yes, I sent my feedback.",
|
||||
"senderId": "ianda",
|
||||
"recipientId": "alice",
|
||||
"timestamp": "09.10.2024 09:25:00"
|
||||
},
|
||||
{
|
||||
"data": "Thanks for that.",
|
||||
"senderId": "alice",
|
||||
"recipientId": "ianda",
|
||||
"timestamp": "09.10.2024 09:30:00"
|
||||
},
|
||||
{
|
||||
"data": "Anytime!",
|
||||
"senderId": "ianda",
|
||||
"recipientId": "alice",
|
||||
"timestamp": "09.10.2024 09:35:00"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id1": "alice",
|
||||
"id2": "jillt",
|
||||
"messages": [
|
||||
{
|
||||
"data": "Jill, let's schedule a catch-up meeting.",
|
||||
"senderId": "alice",
|
||||
"recipientId": "jillt",
|
||||
"timestamp": "09.10.2024 09:40:00"
|
||||
},
|
||||
{
|
||||
"data": "Sounds good, when works for you?",
|
||||
"senderId": "jillt",
|
||||
"recipientId": "alice",
|
||||
"timestamp": "09.10.2024 09:45:00"
|
||||
},
|
||||
{
|
||||
"data": "Tomorrow afternoon?",
|
||||
"senderId": "alice",
|
||||
"recipientId": "jillt",
|
||||
"timestamp": "09.10.2024 09:50:00"
|
||||
},
|
||||
{
|
||||
"data": "That works for me!",
|
||||
"senderId": "jillt",
|
||||
"recipientId": "alice",
|
||||
"timestamp": "09.10.2024 09:55:00"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id1": "alice",
|
||||
"id2": "evead",
|
||||
"messages": [
|
||||
{
|
||||
"data": "Eve, did you send the schedule?",
|
||||
"senderId": "alice",
|
||||
"recipientId": "evead",
|
||||
"timestamp": "09.10.2024 10:00:00"
|
||||
},
|
||||
{
|
||||
"data": "Yes, just sent it.",
|
||||
"senderId": "evead",
|
||||
"recipientId": "alice",
|
||||
"timestamp": "09.10.2024 10:05:00"
|
||||
},
|
||||
{
|
||||
"data": "Thanks, much appreciated!",
|
||||
"senderId": "alice",
|
||||
"recipientId": "evead",
|
||||
"timestamp": "09.10.2024 10:10:00"
|
||||
},
|
||||
{
|
||||
"data": "No problem!",
|
||||
"senderId": "evead",
|
||||
"recipientId": "alice",
|
||||
"timestamp": "09.10.2024 10:15:00"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id1": "bobsm",
|
||||
"id2": "charl",
|
||||
"messages": [
|
||||
{
|
||||
"data": "How's everything going?",
|
||||
"senderId": "bobsm",
|
||||
"recipientId": "charl",
|
||||
"timestamp": "09.10.2024 10:20:00"
|
||||
},
|
||||
{
|
||||
"data": "Pretty good, how about you?",
|
||||
"senderId": "charl",
|
||||
"recipientId": "bobsm",
|
||||
"timestamp": "09.10.2024 10:25:00"
|
||||
},
|
||||
{
|
||||
"data": "Can't complain!",
|
||||
"senderId": "bobsm",
|
||||
"recipientId": "charl",
|
||||
"timestamp": "09.10.2024 10:30:00"
|
||||
},
|
||||
{
|
||||
"data": "Glad to hear that.",
|
||||
"senderId": "charl",
|
||||
"recipientId": "bobsm",
|
||||
"timestamp": "09.10.2024 10:35:00"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id1": "bobsm",
|
||||
"id2": "david",
|
||||
"messages": [
|
||||
{
|
||||
"data": "Can you send the report?",
|
||||
"senderId": "bobsm",
|
||||
"recipientId": "david",
|
||||
"timestamp": "09.10.2024 10:40:00"
|
||||
},
|
||||
{
|
||||
"data": "I'll send it in an hour.",
|
||||
"senderId": "david",
|
||||
"recipientId": "bobsm",
|
||||
"timestamp": "09.10.2024 10:45:00"
|
||||
},
|
||||
{
|
||||
"data": "Perfect, thanks.",
|
||||
"senderId": "bobsm",
|
||||
"recipientId": "david",
|
||||
"timestamp": "09.10.2024 10:50:00"
|
||||
},
|
||||
{
|
||||
"data": "No problem.",
|
||||
"senderId": "david",
|
||||
"recipientId": "bobsm",
|
||||
"timestamp": "09.10.2024 10:55:00"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id1": "charl",
|
||||
"id2": "evead",
|
||||
"messages": [
|
||||
{
|
||||
"data": "Hey Eve, how's it going?",
|
||||
"senderId": "charl",
|
||||
"recipientId": "evead",
|
||||
"timestamp": "09.10.2024 11:00:00"
|
||||
},
|
||||
{
|
||||
"data": "Good, how about you?",
|
||||
"senderId": "evead",
|
||||
"recipientId": "charl",
|
||||
"timestamp": "09.10.2024 11:05:00"
|
||||
},
|
||||
{
|
||||
"data": "Can't complain!",
|
||||
"senderId": "charl",
|
||||
"recipientId": "evead",
|
||||
"timestamp": "09.10.2024 11:10:00"
|
||||
},
|
||||
{
|
||||
"data": "Glad to hear.",
|
||||
"senderId": "evead",
|
||||
"recipientId": "charl",
|
||||
"timestamp": "09.10.2024 11:15:00"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id1": "charl",
|
||||
"id2": "frank",
|
||||
"messages": [
|
||||
{
|
||||
"data": "Do you have time to talk today?",
|
||||
"senderId": "charl",
|
||||
"recipientId": "frank",
|
||||
"timestamp": "09.10.2024 11:20:00"
|
||||
},
|
||||
{
|
||||
"data": "I have a meeting, but I can chat afterward.",
|
||||
"senderId": "frank",
|
||||
"recipientId": "charl",
|
||||
"timestamp": "09.10.2024 11:25:00"
|
||||
},
|
||||
{
|
||||
"data": "Sounds good.",
|
||||
"senderId": "charl",
|
||||
"recipientId": "frank",
|
||||
"timestamp": "09.10.2024 11:30:00"
|
||||
},
|
||||
{
|
||||
"data": "I'll message you after.",
|
||||
"senderId": "frank",
|
||||
"recipientId": "charl",
|
||||
"timestamp": "09.10.2024 11:35:00"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id1": "david",
|
||||
"id2": "frank",
|
||||
"messages": [
|
||||
{
|
||||
"data": "Did you review the document?",
|
||||
"senderId": "david",
|
||||
"recipientId": "frank",
|
||||
"timestamp": "09.10.2024 11:40:00"
|
||||
},
|
||||
{
|
||||
"data": "Yes, it's all good.",
|
||||
"senderId": "frank",
|
||||
"recipientId": "david",
|
||||
"timestamp": "09.10.2024 11:45:00"
|
||||
},
|
||||
{
|
||||
"data": "Great, thanks for the quick turnaround!",
|
||||
"senderId": "david",
|
||||
"recipientId": "frank",
|
||||
"timestamp": "09.10.2024 11:50:00"
|
||||
},
|
||||
{
|
||||
"data": "No worries!",
|
||||
"senderId": "frank",
|
||||
"recipientId": "david",
|
||||
"timestamp": "09.10.2024 11:55:00"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id1": "david",
|
||||
"id2": "grace",
|
||||
"messages": [
|
||||
{
|
||||
"data": "Grace, can you send the updated schedule?",
|
||||
"senderId": "david",
|
||||
"recipientId": "grace",
|
||||
"timestamp": "09.10.2024 12:00:00"
|
||||
},
|
||||
{
|
||||
"data": "Yes, I'll send it in a few minutes.",
|
||||
"senderId": "grace",
|
||||
"recipientId": "david",
|
||||
"timestamp": "09.10.2024 12:05:00"
|
||||
},
|
||||
{
|
||||
"data": "Thanks, much appreciated!",
|
||||
"senderId": "david",
|
||||
"recipientId": "grace",
|
||||
"timestamp": "09.10.2024 12:10:00"
|
||||
},
|
||||
{
|
||||
"data": "You're welcome!",
|
||||
"senderId": "grace",
|
||||
"recipientId": "david",
|
||||
"timestamp": "09.10.2024 12:15:00"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id1": "frank",
|
||||
"id2": "grace",
|
||||
"messages": [
|
||||
{
|
||||
"data": "How are you today?",
|
||||
"senderId": "frank",
|
||||
"recipientId": "grace",
|
||||
"timestamp": "09.10.2024 12:20:00"
|
||||
},
|
||||
{
|
||||
"data": "I'm doing well, thanks for asking.",
|
||||
"senderId": "grace",
|
||||
"recipientId": "frank",
|
||||
"timestamp": "09.10.2024 12:25:00"
|
||||
},
|
||||
{
|
||||
"data": "Glad to hear that.",
|
||||
"senderId": "frank",
|
||||
"recipientId": "grace",
|
||||
"timestamp": "09.10.2024 12:30:00"
|
||||
},
|
||||
{
|
||||
"data": "How about you?",
|
||||
"senderId": "grace",
|
||||
"recipientId": "frank",
|
||||
"timestamp": "09.10.2024 12:35:00"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id1": "frank",
|
||||
"id2": "hanna",
|
||||
"messages": [
|
||||
{
|
||||
"data": "Did you attend the meeting?",
|
||||
"senderId": "frank",
|
||||
"recipientId": "hanna",
|
||||
"timestamp": "09.10.2024 12:40:00"
|
||||
},
|
||||
{
|
||||
"data": "Yes, it was productive.",
|
||||
"senderId": "hanna",
|
||||
"recipientId": "frank",
|
||||
"timestamp": "09.10.2024 12:45:00"
|
||||
},
|
||||
{
|
||||
"data": "Good to hear!",
|
||||
"senderId": "frank",
|
||||
"recipientId": "hanna",
|
||||
"timestamp": "09.10.2024 12:50:00"
|
||||
},
|
||||
{
|
||||
"data": "Indeed, lots to follow up on.",
|
||||
"senderId": "hanna",
|
||||
"recipientId": "frank",
|
||||
"timestamp": "09.10.2024 12:55:00"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id1": "grace",
|
||||
"id2": "hanna",
|
||||
"messages": [
|
||||
{
|
||||
"data": "Can we meet later today?",
|
||||
"senderId": "grace",
|
||||
"recipientId": "hanna",
|
||||
"timestamp": "09.10.2024 01:00:00"
|
||||
},
|
||||
{
|
||||
"data": "Sure, what's a good time?",
|
||||
"senderId": "hanna",
|
||||
"recipientId": "grace",
|
||||
"timestamp": "09.10.2024 01:05:00"
|
||||
},
|
||||
{
|
||||
"data": "How about 3?",
|
||||
"senderId": "grace",
|
||||
"recipientId": "hanna",
|
||||
"timestamp": "09.10.2024 01:10:00"
|
||||
},
|
||||
{
|
||||
"data": "Works for me.",
|
||||
"senderId": "hanna",
|
||||
"recipientId": "grace",
|
||||
"timestamp": "09.10.2024 01:15:00"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id1": "grace",
|
||||
"id2": "ianda",
|
||||
"messages": [
|
||||
{
|
||||
"data": "Ian, did you get the message I sent?",
|
||||
"senderId": "grace",
|
||||
"recipientId": "ianda",
|
||||
"timestamp": "09.10.2024 01:20:00"
|
||||
},
|
||||
{
|
||||
"data": "Yes, I'll respond soon.",
|
||||
"senderId": "ianda",
|
||||
"recipientId": "grace",
|
||||
"timestamp": "09.10.2024 01:25:00"
|
||||
},
|
||||
{
|
||||
"data": "Thanks, appreciate it!",
|
||||
"senderId": "grace",
|
||||
"recipientId": "ianda",
|
||||
"timestamp": "09.10.2024 01:30:00"
|
||||
},
|
||||
{
|
||||
"data": "You're welcome!",
|
||||
"senderId": "ianda",
|
||||
"recipientId": "grace",
|
||||
"timestamp": "09.10.2024 01:35:00"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id1": "hanna",
|
||||
"id2": "ianda",
|
||||
"messages": [
|
||||
{
|
||||
"data": "Ian, do you have a minute?",
|
||||
"senderId": "hanna",
|
||||
"recipientId": "ianda",
|
||||
"timestamp": "09.10.2024 01:40:00"
|
||||
},
|
||||
{
|
||||
"data": "Yes, what do you need?",
|
||||
"senderId": "ianda",
|
||||
"recipientId": "hanna",
|
||||
"timestamp": "09.10.2024 01:45:00"
|
||||
},
|
||||
{
|
||||
"data": "Just a quick update on the project.",
|
||||
"senderId": "hanna",
|
||||
"recipientId": "ianda",
|
||||
"timestamp": "09.10.2024 01:50:00"
|
||||
},
|
||||
{
|
||||
"data": "I'll email you the details.",
|
||||
"senderId": "ianda",
|
||||
"recipientId": "hanna",
|
||||
"timestamp": "09.10.2024 01:55:00"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id1": "hanna",
|
||||
"id2": "jillt",
|
||||
"messages": [
|
||||
{
|
||||
"data": "Jill, can we talk tomorrow?",
|
||||
"senderId": "hanna",
|
||||
"recipientId": "jillt",
|
||||
"timestamp": "09.10.2024 02:00:00"
|
||||
},
|
||||
{
|
||||
"data": "Yes, I'm free after 2.",
|
||||
"senderId": "jillt",
|
||||
"recipientId": "hanna",
|
||||
"timestamp": "09.10.2024 02:05:00"
|
||||
},
|
||||
{
|
||||
"data": "Perfect, see you then.",
|
||||
"senderId": "hanna",
|
||||
"recipientId": "jillt",
|
||||
"timestamp": "09.10.2024 02:10:00"
|
||||
},
|
||||
{
|
||||
"data": "Looking forward to it.",
|
||||
"senderId": "jillt",
|
||||
"recipientId": "hanna",
|
||||
"timestamp": "09.10.2024 02:15:00"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id1": "ianda",
|
||||
"id2": "jillt",
|
||||
"messages": [
|
||||
{
|
||||
"data": "Jill, I have the files you requested.",
|
||||
"senderId": "ianda",
|
||||
"recipientId": "jillt",
|
||||
"timestamp": "09.10.2024 02:20:00"
|
||||
},
|
||||
{
|
||||
"data": "Thanks, please send them over.",
|
||||
"senderId": "jillt",
|
||||
"recipientId": "ianda",
|
||||
"timestamp": "09.10.2024 02:25:00"
|
||||
},
|
||||
{
|
||||
"data": "I'll send them right now.",
|
||||
"senderId": "ianda",
|
||||
"recipientId": "jillt",
|
||||
"timestamp": "09.10.2024 02:30:00"
|
||||
},
|
||||
{
|
||||
"data": "Great, thanks again!",
|
||||
"senderId": "jillt",
|
||||
"recipientId": "ianda",
|
||||
"timestamp": "09.10.2024 02:35:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
86
stubs/api/chat/index.js
Normal file
86
stubs/api/chat/index.js
Normal file
@@ -0,0 +1,86 @@
|
||||
const chatRouter = require('express').Router();
|
||||
|
||||
module.exports = chatRouter;
|
||||
|
||||
const { getChatFromDB, getUsersChats, addChatToDB, getUserFromDB,
|
||||
addMessageToChat} = require('../db');
|
||||
|
||||
chatRouter.get('/item/:id1/:id2', (req, res) => {
|
||||
const { id1, id2 } = req.params;
|
||||
|
||||
if (id1 === id2) {
|
||||
res.status(400).send({message: 'Ids should be different'});
|
||||
return;
|
||||
}
|
||||
|
||||
const chat = getChatFromDB(id1, id2);
|
||||
|
||||
if (chat) {
|
||||
res.status(200).send({chat});
|
||||
} else {
|
||||
res.status(404).send({message: 'Chat was not found'});
|
||||
}
|
||||
})
|
||||
|
||||
chatRouter.post('/item/:id1/:id2', (req, res) => {
|
||||
const { id1, id2 } = req.params;
|
||||
|
||||
if (id1 === id2) {
|
||||
res.status(400).send({message: 'Ids should be different'});
|
||||
return;
|
||||
}
|
||||
|
||||
const chat = getChatFromDB(id1, id2);
|
||||
|
||||
if (chat) {
|
||||
// Chat already exists
|
||||
res.status(200).send({chat});
|
||||
} else {
|
||||
if (!getUserFromDB(id1) || !getUserFromDB(id2)) {
|
||||
res.status(404).send({message: 'Such interlocutor does not exist'});
|
||||
} else {
|
||||
// Creating new chat
|
||||
const newChat = {
|
||||
id1: id1,
|
||||
id2: id2,
|
||||
messages: []
|
||||
}
|
||||
|
||||
addChatToDB(newChat);
|
||||
|
||||
res.status(200).send({newChat});
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
chatRouter.get('/list/:id', (req, res) => {
|
||||
const { id } = req.params;
|
||||
|
||||
const userChats = getUsersChats(id);
|
||||
|
||||
if (!userChats) {
|
||||
res.status(404).send({message: 'Error with retrieving chats'});
|
||||
} else {
|
||||
res.status(200).send({chats: userChats});
|
||||
}
|
||||
})
|
||||
|
||||
chatRouter.post('/message/:sender/:receiver', (req, res) => {
|
||||
const { sender, receiver } = req.params;
|
||||
const { message } = req.body;
|
||||
|
||||
const chat = getChatFromDB(sender, receiver);
|
||||
|
||||
if (!chat) {
|
||||
// Chat already exists
|
||||
res.status(400).send({message: "Such chat does not exist"});
|
||||
} else {
|
||||
if (!getUserFromDB(sender) || !getUserFromDB(receiver)) {
|
||||
res.status(404).send({message: 'Such people do not exist'});
|
||||
} else {
|
||||
// Add new message
|
||||
addMessageToChat(chat, message);
|
||||
res.status(200).send({});
|
||||
}
|
||||
}
|
||||
})
|
||||
74
stubs/api/db.js
Normal file
74
stubs/api/db.js
Normal file
@@ -0,0 +1,74 @@
|
||||
// Read already defined users (pseudo-DB)
|
||||
const users = require('./auth/users.json');
|
||||
const chats = require('./chat/chats.json');
|
||||
|
||||
const getUserFromDB = (userID) => {
|
||||
if (!userID) {return false;}
|
||||
|
||||
// Accessing 'DB'
|
||||
const user = users.find((user) => user.id === userID);
|
||||
|
||||
if (user) {
|
||||
return user;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const deleteUserFromDB = (userID) => {
|
||||
const index = users.findIndex(item => item.id === userID);
|
||||
if (index !== -1) {
|
||||
users.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
const addUserToDB = (user) => {
|
||||
users.push(user);
|
||||
}
|
||||
|
||||
const getChatFromDB = (firstID, secondID) => {
|
||||
if (!firstID || !secondID) {return false;}
|
||||
|
||||
// Accessing 'DB'
|
||||
const chat = chats.find((item) =>
|
||||
(item.id1 === firstID && item.id2 === secondID) || (item.id1 === secondID && item.id2 === firstID));
|
||||
|
||||
if (chat) {
|
||||
return chat;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const getUsersChats = (userID) => {
|
||||
if (!userID) {return false;}
|
||||
|
||||
const userChats = chats.filter((chat) => (chat.id1 === userID || chat.id2 === userID));
|
||||
|
||||
if (userChats) {
|
||||
return userChats;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const addMessageToChat = (chat, msg) => {
|
||||
chat.messages.push(msg);
|
||||
}
|
||||
|
||||
const deleteChatFromDB = (firstID, secondID) => {
|
||||
const index = chats.findIndex(item =>
|
||||
(item.id1 === firstID && item.id2 === secondID) || (item.id1 === secondID && item.id2 === firstID));
|
||||
|
||||
if (index !== -1) {
|
||||
chats.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
const addChatToDB = (chat) => {
|
||||
chats.push(chat);
|
||||
}
|
||||
|
||||
|
||||
module.exports = {users, chats, getUserFromDB, getChatFromDB, addUserToDB,
|
||||
deleteUserFromDB, addChatToDB, deleteChatFromDB, getUsersChats, addMessageToChat}
|
||||
@@ -1,3 +1,17 @@
|
||||
const changeRouter = require("./change");
|
||||
const authRouter = require("./auth");
|
||||
const chatRouter = require("./chat");
|
||||
|
||||
const router = require('express').Router();
|
||||
|
||||
const delay = require('./middlewares/delay');
|
||||
const verify = require('./middlewares/verify');
|
||||
|
||||
module.exports = router;
|
||||
|
||||
// router.use(delay(300));
|
||||
// router.use('/books', delay, booksRouter);
|
||||
|
||||
router.use('/auth', authRouter);
|
||||
router.use('/change', verify, changeRouter);
|
||||
router.use('/chat', verify, chatRouter)
|
||||
|
||||
3
stubs/api/key.js
Normal file
3
stubs/api/key.js
Normal file
@@ -0,0 +1,3 @@
|
||||
const TOKEN_KEY = '5frv12e4few3r';
|
||||
|
||||
module.exports = { TOKEN_KEY }
|
||||
5
stubs/api/middlewares/delay.js
Normal file
5
stubs/api/middlewares/delay.js
Normal file
@@ -0,0 +1,5 @@
|
||||
const delay = (ms = 1000) => (req, res, next) => {
|
||||
setTimeout(next, ms)
|
||||
}
|
||||
|
||||
module.exports = delay
|
||||
22
stubs/api/middlewares/verify.js
Normal file
22
stubs/api/middlewares/verify.js
Normal file
@@ -0,0 +1,22 @@
|
||||
const jwt = require('jsonwebtoken');
|
||||
|
||||
const { TOKEN_KEY } = require('../key')
|
||||
|
||||
function verifyToken(req, res, next) {
|
||||
const token = req.headers['authorization']?.split(' ')[1];
|
||||
|
||||
if (!token) {
|
||||
return res.status(401).send({ message: 'No token provided' });
|
||||
}
|
||||
|
||||
// Verify token
|
||||
jwt.verify(token, TOKEN_KEY, (err, decoded) => {
|
||||
if (err) {
|
||||
return res.status(401).send({ message: 'Unauthorized' });
|
||||
}
|
||||
|
||||
next(); // Proceed to the next middleware or route
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = verifyToken;
|
||||
Reference in New Issue
Block a user