From c8fdee60f5472b9e874f6c8c3cbcfc2f4ece56aa Mon Sep 17 00:00:00 2001 From: Nikita Mashchenko Date: Sun, 2 Jul 2023 05:34:03 -0500 Subject: [PATCH 1/5] Updated registration --- client/package-lock.json | 894 ++++++++++++++++++ client/package.json | 3 + .../EducationWork/EducationWork.jsx | 7 +- .../components/InitialPart/InitialPart.jsx | 15 +- .../InitialPart/InitialPart.styles.js | 33 +- .../InitialPart/ParticlesContainer.jsx | 89 ++ .../MultiStepRegistration.jsx | 34 +- .../MultiStepRegistration.styles.js | 29 +- .../components/NavLogo/NavLogo.js | 42 +- .../components/NavLogo/NavLogo.styles.js | 11 +- .../NavigationButtons/NavigationButtons.jsx | 35 +- .../NavigationButtons.styles.js | 14 + .../AvatarForm/AvatarForm.jsx | 3 +- .../AvatarSelection/AvatarSelection.jsx | 6 +- .../AvatarSelection/AvatarSelection.styles.js | 38 +- .../InfoForm/InfoForm.styles.js | 4 + .../InfoForm/UserInfoForm/UserInfoForm.jsx | 10 +- .../UserEducationForm/UserEducationForm.jsx | 78 +- .../UserEducationForm.styles.js | 13 +- .../UserExperienceForm/UserExperienceForm.jsx | 4 +- .../UserJobForm/UserJobForm.jsx | 78 +- .../components/Stepper/Stepper.styles.js | 8 + .../components/RegistrationPipeline/index.js | 104 +- client/src/constants/degrees.js | 22 + client/src/constants/majors.js | 177 ++++ client/src/schemas/index.js | 315 +++--- .../CustomButton/CustomButon.styles.js | 16 +- .../Formik/CustomInput/CustomInput.styles.js | 13 + .../CustomRadioButtonsGroup.jsx | 8 +- .../components/Toasters/Error.toaster.js | 8 +- client/src/shared/styles/Global.styles.js | 4 +- server/src/maintenance/maintenance.service.ts | 2 +- server/src/users/dto/links-user.dto.ts | 10 +- server/src/users/dto/update-user.dto.ts | 2 +- server/src/users/users.schema.ts | 6 +- 35 files changed, 1745 insertions(+), 390 deletions(-) create mode 100644 client/src/components/RegistrationPipeline/components/InitialPart/ParticlesContainer.jsx create mode 100644 client/src/constants/degrees.js create mode 100644 client/src/constants/majors.js diff --git a/client/package-lock.json b/client/package-lock.json index 1fc537cd2..4924278d8 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -25,6 +25,7 @@ "country-code-lookup": "^0.0.20", "dotenv": "^16.0.1", "formik": "^2.2.9", + "formik-mui": "^5.0.0-alpha.0", "framer-motion": "^10.12.10", "jwt-decode": "^3.1.2", "lodash": "^4.17.21", @@ -38,6 +39,7 @@ "react-hot-toast": "^2.4.1", "react-loader-spinner": "^5.3.4", "react-loading-skeleton": "^3.1.0", + "react-particles": "^2.10.1", "react-query": "^3.39.2", "react-redux": "^8.0.2", "react-router-dom": "^6.3.0", @@ -48,6 +50,7 @@ "redux": "^4.2.0", "socket.io-client": "^4.6.1", "styled-components": "^5.3.5", + "tsparticles": "^2.10.1", "uuidv4": "^5.0.1", "web-vitals": "^2.1.4", "yup": "^0.32.11" @@ -7068,6 +7071,17 @@ "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==" }, + "node_modules/deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -9066,6 +9080,19 @@ "react": ">=16.8.0" } }, + "node_modules/formik-mui": { + "version": "5.0.0-alpha.0", + "resolved": "https://registry.npmjs.org/formik-mui/-/formik-mui-5.0.0-alpha.0.tgz", + "integrity": "sha512-tcY8B4I3N2UK9ghgVpeBWsXGMDe1y4LVKwI8GiUbLKGB86fI/CN9UMr4FuNo6kzNXvO42LFNmCxdEVzovNCyYQ==", + "peerDependencies": { + "@emotion/react": ">=11.5.0", + "@emotion/styled": ">=11.3.0", + "@mui/material": ">=5.2.3", + "formik": ">=2.2.9", + "react": ">=17.0.2", + "tiny-warning": ">=1.0.3" + } + }, "node_modules/formik/node_modules/deepmerge": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.2.1.tgz", @@ -15210,6 +15237,33 @@ "react": ">=16.8.0" } }, + "node_modules/react-particles": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/react-particles/-/react-particles-2.10.1.tgz", + "integrity": "sha512-7juKgk9LqMsSbfAPLbzU3kBfkmspRWrmJKbFxSpZuzXMrNizjEoQPCvGwwS1/I14w55gMz1pqzowDhB8xvmPSQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/matteobruni" + }, + { + "type": "github", + "url": "https://github.com/sponsors/tsparticles" + }, + { + "type": "buymeacoffee", + "url": "https://www.buymeacoffee.com/matteobruni" + } + ], + "hasInstallScript": true, + "dependencies": { + "deep-eql": "^4.1.3", + "tsparticles-engine": "^2.10.1" + }, + "peerDependencies": { + "react": ">=16" + } + }, "node_modules/react-query": { "version": "3.39.2", "resolved": "https://registry.npmjs.org/react-query/-/react-query-3.39.2.tgz", @@ -17103,6 +17157,450 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" }, + "node_modules/tsparticles": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles/-/tsparticles-2.10.1.tgz", + "integrity": "sha512-MIPty6UvjRDbFBtnXjedr68WrxlCSa4XmNND7beRcqqdUb+fQKy/3u64sZ15qBQ4JVV5GcvKYijlOGbmTU3SCw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/matteobruni" + }, + { + "type": "github", + "url": "https://github.com/sponsors/tsparticles" + }, + { + "type": "buymeacoffee", + "url": "https://www.buymeacoffee.com/matteobruni" + } + ], + "dependencies": { + "tsparticles-engine": "^2.10.1", + "tsparticles-interaction-external-trail": "^2.10.1", + "tsparticles-plugin-absorbers": "^2.10.1", + "tsparticles-plugin-emitters": "^2.10.1", + "tsparticles-slim": "^2.10.1", + "tsparticles-updater-destroy": "^2.10.1", + "tsparticles-updater-roll": "^2.10.1", + "tsparticles-updater-tilt": "^2.10.1", + "tsparticles-updater-twinkle": "^2.10.1", + "tsparticles-updater-wobble": "^2.10.1" + } + }, + "node_modules/tsparticles-engine": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-engine/-/tsparticles-engine-2.10.1.tgz", + "integrity": "sha512-DV2gYsbChyiXYIZYgnXtKHSAZdvnNMJpVf9Cw0gO7vjQ6pcgLAeyboRtvsaTfwKZNzzA7BeSf1lVhgGxorL4CQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/matteobruni" + }, + { + "type": "github", + "url": "https://github.com/sponsors/tsparticles" + }, + { + "type": "buymeacoffee", + "url": "https://www.buymeacoffee.com/matteobruni" + } + ], + "hasInstallScript": true + }, + "node_modules/tsparticles-interaction-external-attract": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-interaction-external-attract/-/tsparticles-interaction-external-attract-2.10.1.tgz", + "integrity": "sha512-n/G8YWmoBc8CxZgwPwRA858bWe0dyl/7HS7sUi72m64ptzZlMEcUzfMD6v+PoqTsypLRLN4vWIiGoczkZKxOuw==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-interaction-external-bounce": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-interaction-external-bounce/-/tsparticles-interaction-external-bounce-2.10.1.tgz", + "integrity": "sha512-XKsZ8eQJy3w+bjqJYbgOTs3BpL4ykB4Ank7xUNxOgkjtVz/YtUJyCEBlVN+2aRZGLnbFEs2ZZGQVIx+6wyjcCw==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-interaction-external-bubble": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-interaction-external-bubble/-/tsparticles-interaction-external-bubble-2.10.1.tgz", + "integrity": "sha512-tY2rySRyyn89K2bjE0gWXI5nuBZljjIW2UbY7rOqd7YeGm6FrcUfuuU1G0sG13cX/u0ufRYi0kDnzCvlfLqwJg==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-interaction-external-connect": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-interaction-external-connect/-/tsparticles-interaction-external-connect-2.10.1.tgz", + "integrity": "sha512-tNPlc0csQa9vrzSarlAw+K2YbB5EDU302OkejVUWc7h58hxpPgzR3Fy8O2CsFy8OC1Pw6MNUO+5grG+QvCMj3A==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-interaction-external-grab": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-interaction-external-grab/-/tsparticles-interaction-external-grab-2.10.1.tgz", + "integrity": "sha512-5HPjZ4BaRi0k6dUq3UBf/vQ+eMS/e2GERsFMQz8p1Efm7SLz3Uu6gDu3AnamKtzQLUPVtlaUIS+BCsFPZ6EM8w==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-interaction-external-pause": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-interaction-external-pause/-/tsparticles-interaction-external-pause-2.10.1.tgz", + "integrity": "sha512-eW5mh/+tM2ipKXyvDZ1MCj6pMTEBStzB+p4coVYfvn2mBXgviY1ktPbN4yGAJc8Fii6YdeqgKQxw7JHSFe6HbQ==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-interaction-external-push": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-interaction-external-push/-/tsparticles-interaction-external-push-2.10.1.tgz", + "integrity": "sha512-cjpEnjxN0OEIZwVRDVLdBIEnS0aYxOlV8K7TVtIDvWCAEWi52C+YnVu7XHzr9CGERVlBOElQSLua5CvoM0XYSA==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-interaction-external-remove": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-interaction-external-remove/-/tsparticles-interaction-external-remove-2.10.1.tgz", + "integrity": "sha512-6qi4Q61JkmOhPCOf8NXGqWHb1uMlp/BQteSWSEBR1a/jztcbzEpz90spYsObettfZaNDPqVSUiGN4uHtX747CA==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-interaction-external-repulse": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-interaction-external-repulse/-/tsparticles-interaction-external-repulse-2.10.1.tgz", + "integrity": "sha512-t4P9ReEBejBYP6Hjrm9jRioFcFTlEuahD1BK7roYaG2pvesBubCmIzS5Gzr79ZEvUQNpQ0r3KmYFIVZyBqaVbQ==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-interaction-external-slow": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-interaction-external-slow/-/tsparticles-interaction-external-slow-2.10.1.tgz", + "integrity": "sha512-XAnUscVedw/cMiGJIM7rJ+7RfJSLYWET1WT2eo86B/A3YrDawg2xL5QdzfqurKalvnwRBhAYjpQM0qp6w9//Pw==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-interaction-external-trail": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-interaction-external-trail/-/tsparticles-interaction-external-trail-2.10.1.tgz", + "integrity": "sha512-ubGdlLi7JPeunof4roAx/c1BAVWPHqwRcnZK61TPVF3yITsrWli3j5g52KU+kcPaqfdlnRB1rqB6dMjUU2omlA==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-interaction-particles-attract": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-interaction-particles-attract/-/tsparticles-interaction-particles-attract-2.10.1.tgz", + "integrity": "sha512-o7p8Te65HXMM/8Qev8wyA4if4W+5VtfD/hTziQEt5Fp3mdxXWdit7jgfvOYnphJoswD0Cr5rEEjvhGuHGoC3dw==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-interaction-particles-collisions": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-interaction-particles-collisions/-/tsparticles-interaction-particles-collisions-2.10.1.tgz", + "integrity": "sha512-xSijIyjhUOOZEvdk59HZJksBM8BXUbOtNHx7di7qguUmeQ+MeB2GbP8sje/xSEA1wAEzeD6FFBmOTtDlZQTWOg==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-interaction-particles-links": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-interaction-particles-links/-/tsparticles-interaction-particles-links-2.10.1.tgz", + "integrity": "sha512-O6NkvV5muOsitJkicW3eqwPCjkRDWZzY5Twq8NkqCKTXkzpQtow8ByTMKcIWsW1GR6ltylrgyCId5KMwLRArbA==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-move-base": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-move-base/-/tsparticles-move-base-2.10.1.tgz", + "integrity": "sha512-Q7JHIRPuJZw/Jz7vEeCePMR/69ace5rpWPqZ3+KLJnrtayxDEvj4tNRjnPtZusJ1Ve+wp0IxjOwrfGxeHxbmsQ==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-move-parallax": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-move-parallax/-/tsparticles-move-parallax-2.10.1.tgz", + "integrity": "sha512-FeP+rwanLZvFtftPjTbzJCTZa6kSgP2UWa9WL3VUWzXWTt2UKqPeahhtNqXyRvjqxtVlcZDxFeX7lOvdDHxTNA==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-particles.js": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-particles.js/-/tsparticles-particles.js-2.10.1.tgz", + "integrity": "sha512-9mtKrvAJ6bQVUvZlPfea48RwoKUM5qz/NYtXbxpPjJxfsHLnie6R6brHl+8DgrP710UO4rVN2jyPZLvwHWVfyQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/matteobruni" + }, + { + "type": "github", + "url": "https://github.com/sponsors/tsparticles" + }, + { + "type": "buymeacoffee", + "url": "https://www.buymeacoffee.com/matteobruni" + } + ], + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-plugin-absorbers": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-plugin-absorbers/-/tsparticles-plugin-absorbers-2.10.1.tgz", + "integrity": "sha512-OSQCtIrWyDJc32Q6hk1B0vWrMATTZtqeu2mGR1Jg5d2/Ur4q9QkDB5oSYmAT1LVCEz0aipyOwqMaRBh5a65S2Q==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-plugin-easing-quad": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-plugin-easing-quad/-/tsparticles-plugin-easing-quad-2.10.1.tgz", + "integrity": "sha512-KJHqsEgX4PSaG0gUE/oSd9kcxxRKuC+VbblN1YLsamMw1lPwNulxgh0hOWg3j87YasiUH+LkyC+XvyzF8/x8pQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/matteobruni" + }, + { + "type": "github", + "url": "https://github.com/sponsors/tsparticles" + }, + { + "type": "buymeacoffee", + "url": "https://www.buymeacoffee.com/matteobruni" + } + ], + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-plugin-emitters": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-plugin-emitters/-/tsparticles-plugin-emitters-2.10.1.tgz", + "integrity": "sha512-SHuPH0qYA70gWNeOzn3DXk9W/IjTMtbeYhHWLOruTThrcLgBT4bRI5ooLnITjraMaTYf4FWdl7Mi/1MRkT5yUg==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-shape-circle": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-shape-circle/-/tsparticles-shape-circle-2.10.1.tgz", + "integrity": "sha512-oWfoF1rwBNDS8X8EBZVwt/UF9wBqh3OpV71LxCvTE9lh73FeUeQZ9aSW46t9XODIsNBMPbnAQNkP1wz4zNiw2A==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-shape-image": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-shape-image/-/tsparticles-shape-image-2.10.1.tgz", + "integrity": "sha512-elayAfRPJquv9GhPYpWmDQ4oyRQqa1poxidyKL0qhnU35nyk2yW3fW2awX2QrBDdU+HusBQgP64k+v6HZApsdg==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-shape-line": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-shape-line/-/tsparticles-shape-line-2.10.1.tgz", + "integrity": "sha512-3BWNjY0l1vsvKJvMMjkFNtCts3YPOnnd9w4d0d19XXv03jWNbhXC159Xeho/w+jlVcQWsExMxhVPlJYLOPa+Qw==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-shape-polygon": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-shape-polygon/-/tsparticles-shape-polygon-2.10.1.tgz", + "integrity": "sha512-ycNJ9j3fNDkqh02J2NUQhNSXxXjQ/GYa9XIuy8dbUTfOrTcMnx7+u0dOSG8gcqp0F8EovLhOlansLYQbEuV4wQ==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-shape-square": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-shape-square/-/tsparticles-shape-square-2.10.1.tgz", + "integrity": "sha512-mThpV69K96piNuuti74t2xWKXUJ8fGBXVRg+s72lP34mTbF2O5S4A+HMQMixLLbiq1TFgcLGf7MfxRMRo9sZBA==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-shape-star": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-shape-star/-/tsparticles-shape-star-2.10.1.tgz", + "integrity": "sha512-IWydbZ+ttv8+yyC3OucZvOffyYDZxfsHQYg1w8pWS5p/CyB4Ln+dn0Jp7TDDz/Y7HEaEr4mIzMHyL7ZQTj2wIw==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-shape-text": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-shape-text/-/tsparticles-shape-text-2.10.1.tgz", + "integrity": "sha512-g2f3CPj/M4rKCKA18eKFOC6D90p+aToPFKzADVmJhDx7I3k5VAM/y/IDkQTDc1w6DmTOvEd5BY+QrYbfTvs+YQ==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-slim": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-slim/-/tsparticles-slim-2.10.1.tgz", + "integrity": "sha512-A2DMPfZKINQp4GtW2rVv435flaLAun8MMZnOEdZdpnk51tbPHiBTVybfzYZVSOK2B7z8uCzmaplTyYkyDZsk1A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/matteobruni" + }, + { + "type": "github", + "url": "https://github.com/sponsors/tsparticles" + }, + { + "type": "buymeacoffee", + "url": "https://www.buymeacoffee.com/matteobruni" + } + ], + "dependencies": { + "tsparticles-engine": "^2.10.1", + "tsparticles-interaction-external-attract": "^2.10.1", + "tsparticles-interaction-external-bounce": "^2.10.1", + "tsparticles-interaction-external-bubble": "^2.10.1", + "tsparticles-interaction-external-connect": "^2.10.1", + "tsparticles-interaction-external-grab": "^2.10.1", + "tsparticles-interaction-external-pause": "^2.10.1", + "tsparticles-interaction-external-push": "^2.10.1", + "tsparticles-interaction-external-remove": "^2.10.1", + "tsparticles-interaction-external-repulse": "^2.10.1", + "tsparticles-interaction-external-slow": "^2.10.1", + "tsparticles-interaction-particles-attract": "^2.10.1", + "tsparticles-interaction-particles-collisions": "^2.10.1", + "tsparticles-interaction-particles-links": "^2.10.1", + "tsparticles-move-base": "^2.10.1", + "tsparticles-move-parallax": "^2.10.1", + "tsparticles-particles.js": "^2.10.1", + "tsparticles-plugin-easing-quad": "^2.10.1", + "tsparticles-shape-circle": "^2.10.1", + "tsparticles-shape-image": "^2.10.1", + "tsparticles-shape-line": "^2.10.1", + "tsparticles-shape-polygon": "^2.10.1", + "tsparticles-shape-square": "^2.10.1", + "tsparticles-shape-star": "^2.10.1", + "tsparticles-shape-text": "^2.10.1", + "tsparticles-updater-color": "^2.10.1", + "tsparticles-updater-life": "^2.10.1", + "tsparticles-updater-opacity": "^2.10.1", + "tsparticles-updater-out-modes": "^2.10.1", + "tsparticles-updater-rotate": "^2.10.1", + "tsparticles-updater-size": "^2.10.1", + "tsparticles-updater-stroke-color": "^2.10.1" + } + }, + "node_modules/tsparticles-updater-color": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-updater-color/-/tsparticles-updater-color-2.10.1.tgz", + "integrity": "sha512-/7FCR/VzpOuiE0ztGEzzN4vNeLGbS9QUBX78OM59GDZujlHfjfWh1jqedyNXrhkb6mf08B3FZWiQWGysPeL31Q==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-updater-destroy": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-updater-destroy/-/tsparticles-updater-destroy-2.10.1.tgz", + "integrity": "sha512-lFTyVgLNt4x1T4jBHRs+V8gFUQKwXkMbeNF5JUNwlrmGBr/Mx0A36XBcJ4BKZR5+jWO1C6I8jgYzIrFPx6Z+MQ==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-updater-life": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-updater-life/-/tsparticles-updater-life-2.10.1.tgz", + "integrity": "sha512-qhd+uVxxGLS50bN75POU2lHgqBhXBpRmdY/RnW6mwHGrs5SgiU0XoM0il3+RoAnvpscWG/5ZgEXvpm7ZvbNUWA==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-updater-opacity": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-updater-opacity/-/tsparticles-updater-opacity-2.10.1.tgz", + "integrity": "sha512-l1FOevfK9CMz9cBRT5prQpHACijYJ+3dHvIfx0Y5M5Do4etoT+PurZxDpQlQU6Yd0vXKm3r37paPiQbH5U3Vqg==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-updater-out-modes": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-updater-out-modes/-/tsparticles-updater-out-modes-2.10.1.tgz", + "integrity": "sha512-nzP/puePd97FlME9gzmjwdQWoqm+O7GtnkbD33a4NBlzJMgtjbGtmz/Tmc4hLicb/qwS5D8j9xvB+srsuxT7LA==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-updater-roll": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-updater-roll/-/tsparticles-updater-roll-2.10.1.tgz", + "integrity": "sha512-5v43esqjPy/GbXXJKOqOF4fD7zndQFE7G5iqF76dp8RaG2V+tIb96j8+wx2B32K9VjEOk3XwOKjYnHtdpYPhvg==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-updater-rotate": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-updater-rotate/-/tsparticles-updater-rotate-2.10.1.tgz", + "integrity": "sha512-GWCyLrB0JaEY0nugFU5E22b/LjSF6Bv4q5dXsbtzqjD9Ka/DPMJ8js8bzJhNf3jftQzf6zBXf72W0kyZH79VIQ==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-updater-size": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-updater-size/-/tsparticles-updater-size-2.10.1.tgz", + "integrity": "sha512-Kdtskqm0CRrlsovOsJLcS6NXF0alJ6NlwmW7oWnTK6EeLvEKaqisG/hjcFf+l7eXlmL8j9rYgh6wctaef6GBCw==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-updater-stroke-color": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-updater-stroke-color/-/tsparticles-updater-stroke-color-2.10.1.tgz", + "integrity": "sha512-iYLO1y9lH0bOxxE5gPRdsYR5UVIvtxWpera8C5JBXaHywROkJ8CSXxA2pIe01kUIwIOcOv8j26RJvKNdttv9kQ==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-updater-tilt": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-updater-tilt/-/tsparticles-updater-tilt-2.10.1.tgz", + "integrity": "sha512-MLNZPSc+nM+M5KV9i6tHtzxqSIhQ9VQAuKOuKqHRxs3fkFXboc1dNKA5Ou16roi/efqpc1gXrtZvhPF+holp2Q==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-updater-twinkle": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-updater-twinkle/-/tsparticles-updater-twinkle-2.10.1.tgz", + "integrity": "sha512-Y+/34BCG2/tTm1lpHniNhh3P5M0u5i6qjt/MGquR6yXzQqjmRkhW29vtqd8tZcVx4KZ7Rj0mOUIHFX8bc3YRHQ==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, + "node_modules/tsparticles-updater-wobble": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-updater-wobble/-/tsparticles-updater-wobble-2.10.1.tgz", + "integrity": "sha512-Kf5MfhjkXKlB0hiZPUJCv0PCxRH2E1nmyUnqu05xSZGjQDTS+A/uNtUvIA1nrq7l38VVgpRREtnYka2whOhzwQ==", + "dependencies": { + "tsparticles-engine": "^2.10.1" + } + }, "node_modules/tsutils": { "version": "3.21.0", "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", @@ -23253,6 +23751,14 @@ "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==" }, + "deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "requires": { + "type-detect": "^4.0.0" + } + }, "deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -24712,6 +25218,12 @@ } } }, + "formik-mui": { + "version": "5.0.0-alpha.0", + "resolved": "https://registry.npmjs.org/formik-mui/-/formik-mui-5.0.0-alpha.0.tgz", + "integrity": "sha512-tcY8B4I3N2UK9ghgVpeBWsXGMDe1y4LVKwI8GiUbLKGB86fI/CN9UMr4FuNo6kzNXvO42LFNmCxdEVzovNCyYQ==", + "requires": {} + }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -28972,6 +29484,15 @@ "integrity": "sha512-j1U1CWWs68nBPOg7tkQqnlFcAMFF6oEK6MgqAo15f8A5p7mjH6xyKn2gHbkcimpwfO0VQXqxAswnSYVr8lWzjw==", "requires": {} }, + "react-particles": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/react-particles/-/react-particles-2.10.1.tgz", + "integrity": "sha512-7juKgk9LqMsSbfAPLbzU3kBfkmspRWrmJKbFxSpZuzXMrNizjEoQPCvGwwS1/I14w55gMz1pqzowDhB8xvmPSQ==", + "requires": { + "deep-eql": "^4.1.3", + "tsparticles-engine": "^2.10.1" + } + }, "react-query": { "version": "3.39.2", "resolved": "https://registry.npmjs.org/react-query/-/react-query-3.39.2.tgz", @@ -30371,6 +30892,379 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" }, + "tsparticles": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles/-/tsparticles-2.10.1.tgz", + "integrity": "sha512-MIPty6UvjRDbFBtnXjedr68WrxlCSa4XmNND7beRcqqdUb+fQKy/3u64sZ15qBQ4JVV5GcvKYijlOGbmTU3SCw==", + "requires": { + "tsparticles-engine": "^2.10.1", + "tsparticles-interaction-external-trail": "^2.10.1", + "tsparticles-plugin-absorbers": "^2.10.1", + "tsparticles-plugin-emitters": "^2.10.1", + "tsparticles-slim": "^2.10.1", + "tsparticles-updater-destroy": "^2.10.1", + "tsparticles-updater-roll": "^2.10.1", + "tsparticles-updater-tilt": "^2.10.1", + "tsparticles-updater-twinkle": "^2.10.1", + "tsparticles-updater-wobble": "^2.10.1" + } + }, + "tsparticles-engine": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-engine/-/tsparticles-engine-2.10.1.tgz", + "integrity": "sha512-DV2gYsbChyiXYIZYgnXtKHSAZdvnNMJpVf9Cw0gO7vjQ6pcgLAeyboRtvsaTfwKZNzzA7BeSf1lVhgGxorL4CQ==" + }, + "tsparticles-interaction-external-attract": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-interaction-external-attract/-/tsparticles-interaction-external-attract-2.10.1.tgz", + "integrity": "sha512-n/G8YWmoBc8CxZgwPwRA858bWe0dyl/7HS7sUi72m64ptzZlMEcUzfMD6v+PoqTsypLRLN4vWIiGoczkZKxOuw==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-interaction-external-bounce": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-interaction-external-bounce/-/tsparticles-interaction-external-bounce-2.10.1.tgz", + "integrity": "sha512-XKsZ8eQJy3w+bjqJYbgOTs3BpL4ykB4Ank7xUNxOgkjtVz/YtUJyCEBlVN+2aRZGLnbFEs2ZZGQVIx+6wyjcCw==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-interaction-external-bubble": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-interaction-external-bubble/-/tsparticles-interaction-external-bubble-2.10.1.tgz", + "integrity": "sha512-tY2rySRyyn89K2bjE0gWXI5nuBZljjIW2UbY7rOqd7YeGm6FrcUfuuU1G0sG13cX/u0ufRYi0kDnzCvlfLqwJg==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-interaction-external-connect": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-interaction-external-connect/-/tsparticles-interaction-external-connect-2.10.1.tgz", + "integrity": "sha512-tNPlc0csQa9vrzSarlAw+K2YbB5EDU302OkejVUWc7h58hxpPgzR3Fy8O2CsFy8OC1Pw6MNUO+5grG+QvCMj3A==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-interaction-external-grab": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-interaction-external-grab/-/tsparticles-interaction-external-grab-2.10.1.tgz", + "integrity": "sha512-5HPjZ4BaRi0k6dUq3UBf/vQ+eMS/e2GERsFMQz8p1Efm7SLz3Uu6gDu3AnamKtzQLUPVtlaUIS+BCsFPZ6EM8w==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-interaction-external-pause": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-interaction-external-pause/-/tsparticles-interaction-external-pause-2.10.1.tgz", + "integrity": "sha512-eW5mh/+tM2ipKXyvDZ1MCj6pMTEBStzB+p4coVYfvn2mBXgviY1ktPbN4yGAJc8Fii6YdeqgKQxw7JHSFe6HbQ==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-interaction-external-push": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-interaction-external-push/-/tsparticles-interaction-external-push-2.10.1.tgz", + "integrity": "sha512-cjpEnjxN0OEIZwVRDVLdBIEnS0aYxOlV8K7TVtIDvWCAEWi52C+YnVu7XHzr9CGERVlBOElQSLua5CvoM0XYSA==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-interaction-external-remove": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-interaction-external-remove/-/tsparticles-interaction-external-remove-2.10.1.tgz", + "integrity": "sha512-6qi4Q61JkmOhPCOf8NXGqWHb1uMlp/BQteSWSEBR1a/jztcbzEpz90spYsObettfZaNDPqVSUiGN4uHtX747CA==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-interaction-external-repulse": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-interaction-external-repulse/-/tsparticles-interaction-external-repulse-2.10.1.tgz", + "integrity": "sha512-t4P9ReEBejBYP6Hjrm9jRioFcFTlEuahD1BK7roYaG2pvesBubCmIzS5Gzr79ZEvUQNpQ0r3KmYFIVZyBqaVbQ==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-interaction-external-slow": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-interaction-external-slow/-/tsparticles-interaction-external-slow-2.10.1.tgz", + "integrity": "sha512-XAnUscVedw/cMiGJIM7rJ+7RfJSLYWET1WT2eo86B/A3YrDawg2xL5QdzfqurKalvnwRBhAYjpQM0qp6w9//Pw==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-interaction-external-trail": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-interaction-external-trail/-/tsparticles-interaction-external-trail-2.10.1.tgz", + "integrity": "sha512-ubGdlLi7JPeunof4roAx/c1BAVWPHqwRcnZK61TPVF3yITsrWli3j5g52KU+kcPaqfdlnRB1rqB6dMjUU2omlA==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-interaction-particles-attract": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-interaction-particles-attract/-/tsparticles-interaction-particles-attract-2.10.1.tgz", + "integrity": "sha512-o7p8Te65HXMM/8Qev8wyA4if4W+5VtfD/hTziQEt5Fp3mdxXWdit7jgfvOYnphJoswD0Cr5rEEjvhGuHGoC3dw==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-interaction-particles-collisions": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-interaction-particles-collisions/-/tsparticles-interaction-particles-collisions-2.10.1.tgz", + "integrity": "sha512-xSijIyjhUOOZEvdk59HZJksBM8BXUbOtNHx7di7qguUmeQ+MeB2GbP8sje/xSEA1wAEzeD6FFBmOTtDlZQTWOg==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-interaction-particles-links": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-interaction-particles-links/-/tsparticles-interaction-particles-links-2.10.1.tgz", + "integrity": "sha512-O6NkvV5muOsitJkicW3eqwPCjkRDWZzY5Twq8NkqCKTXkzpQtow8ByTMKcIWsW1GR6ltylrgyCId5KMwLRArbA==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-move-base": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-move-base/-/tsparticles-move-base-2.10.1.tgz", + "integrity": "sha512-Q7JHIRPuJZw/Jz7vEeCePMR/69ace5rpWPqZ3+KLJnrtayxDEvj4tNRjnPtZusJ1Ve+wp0IxjOwrfGxeHxbmsQ==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-move-parallax": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-move-parallax/-/tsparticles-move-parallax-2.10.1.tgz", + "integrity": "sha512-FeP+rwanLZvFtftPjTbzJCTZa6kSgP2UWa9WL3VUWzXWTt2UKqPeahhtNqXyRvjqxtVlcZDxFeX7lOvdDHxTNA==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-particles.js": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-particles.js/-/tsparticles-particles.js-2.10.1.tgz", + "integrity": "sha512-9mtKrvAJ6bQVUvZlPfea48RwoKUM5qz/NYtXbxpPjJxfsHLnie6R6brHl+8DgrP710UO4rVN2jyPZLvwHWVfyQ==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-plugin-absorbers": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-plugin-absorbers/-/tsparticles-plugin-absorbers-2.10.1.tgz", + "integrity": "sha512-OSQCtIrWyDJc32Q6hk1B0vWrMATTZtqeu2mGR1Jg5d2/Ur4q9QkDB5oSYmAT1LVCEz0aipyOwqMaRBh5a65S2Q==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-plugin-easing-quad": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-plugin-easing-quad/-/tsparticles-plugin-easing-quad-2.10.1.tgz", + "integrity": "sha512-KJHqsEgX4PSaG0gUE/oSd9kcxxRKuC+VbblN1YLsamMw1lPwNulxgh0hOWg3j87YasiUH+LkyC+XvyzF8/x8pQ==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-plugin-emitters": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-plugin-emitters/-/tsparticles-plugin-emitters-2.10.1.tgz", + "integrity": "sha512-SHuPH0qYA70gWNeOzn3DXk9W/IjTMtbeYhHWLOruTThrcLgBT4bRI5ooLnITjraMaTYf4FWdl7Mi/1MRkT5yUg==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-shape-circle": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-shape-circle/-/tsparticles-shape-circle-2.10.1.tgz", + "integrity": "sha512-oWfoF1rwBNDS8X8EBZVwt/UF9wBqh3OpV71LxCvTE9lh73FeUeQZ9aSW46t9XODIsNBMPbnAQNkP1wz4zNiw2A==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-shape-image": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-shape-image/-/tsparticles-shape-image-2.10.1.tgz", + "integrity": "sha512-elayAfRPJquv9GhPYpWmDQ4oyRQqa1poxidyKL0qhnU35nyk2yW3fW2awX2QrBDdU+HusBQgP64k+v6HZApsdg==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-shape-line": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-shape-line/-/tsparticles-shape-line-2.10.1.tgz", + "integrity": "sha512-3BWNjY0l1vsvKJvMMjkFNtCts3YPOnnd9w4d0d19XXv03jWNbhXC159Xeho/w+jlVcQWsExMxhVPlJYLOPa+Qw==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-shape-polygon": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-shape-polygon/-/tsparticles-shape-polygon-2.10.1.tgz", + "integrity": "sha512-ycNJ9j3fNDkqh02J2NUQhNSXxXjQ/GYa9XIuy8dbUTfOrTcMnx7+u0dOSG8gcqp0F8EovLhOlansLYQbEuV4wQ==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-shape-square": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-shape-square/-/tsparticles-shape-square-2.10.1.tgz", + "integrity": "sha512-mThpV69K96piNuuti74t2xWKXUJ8fGBXVRg+s72lP34mTbF2O5S4A+HMQMixLLbiq1TFgcLGf7MfxRMRo9sZBA==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-shape-star": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-shape-star/-/tsparticles-shape-star-2.10.1.tgz", + "integrity": "sha512-IWydbZ+ttv8+yyC3OucZvOffyYDZxfsHQYg1w8pWS5p/CyB4Ln+dn0Jp7TDDz/Y7HEaEr4mIzMHyL7ZQTj2wIw==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-shape-text": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-shape-text/-/tsparticles-shape-text-2.10.1.tgz", + "integrity": "sha512-g2f3CPj/M4rKCKA18eKFOC6D90p+aToPFKzADVmJhDx7I3k5VAM/y/IDkQTDc1w6DmTOvEd5BY+QrYbfTvs+YQ==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-slim": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-slim/-/tsparticles-slim-2.10.1.tgz", + "integrity": "sha512-A2DMPfZKINQp4GtW2rVv435flaLAun8MMZnOEdZdpnk51tbPHiBTVybfzYZVSOK2B7z8uCzmaplTyYkyDZsk1A==", + "requires": { + "tsparticles-engine": "^2.10.1", + "tsparticles-interaction-external-attract": "^2.10.1", + "tsparticles-interaction-external-bounce": "^2.10.1", + "tsparticles-interaction-external-bubble": "^2.10.1", + "tsparticles-interaction-external-connect": "^2.10.1", + "tsparticles-interaction-external-grab": "^2.10.1", + "tsparticles-interaction-external-pause": "^2.10.1", + "tsparticles-interaction-external-push": "^2.10.1", + "tsparticles-interaction-external-remove": "^2.10.1", + "tsparticles-interaction-external-repulse": "^2.10.1", + "tsparticles-interaction-external-slow": "^2.10.1", + "tsparticles-interaction-particles-attract": "^2.10.1", + "tsparticles-interaction-particles-collisions": "^2.10.1", + "tsparticles-interaction-particles-links": "^2.10.1", + "tsparticles-move-base": "^2.10.1", + "tsparticles-move-parallax": "^2.10.1", + "tsparticles-particles.js": "^2.10.1", + "tsparticles-plugin-easing-quad": "^2.10.1", + "tsparticles-shape-circle": "^2.10.1", + "tsparticles-shape-image": "^2.10.1", + "tsparticles-shape-line": "^2.10.1", + "tsparticles-shape-polygon": "^2.10.1", + "tsparticles-shape-square": "^2.10.1", + "tsparticles-shape-star": "^2.10.1", + "tsparticles-shape-text": "^2.10.1", + "tsparticles-updater-color": "^2.10.1", + "tsparticles-updater-life": "^2.10.1", + "tsparticles-updater-opacity": "^2.10.1", + "tsparticles-updater-out-modes": "^2.10.1", + "tsparticles-updater-rotate": "^2.10.1", + "tsparticles-updater-size": "^2.10.1", + "tsparticles-updater-stroke-color": "^2.10.1" + } + }, + "tsparticles-updater-color": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-updater-color/-/tsparticles-updater-color-2.10.1.tgz", + "integrity": "sha512-/7FCR/VzpOuiE0ztGEzzN4vNeLGbS9QUBX78OM59GDZujlHfjfWh1jqedyNXrhkb6mf08B3FZWiQWGysPeL31Q==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-updater-destroy": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-updater-destroy/-/tsparticles-updater-destroy-2.10.1.tgz", + "integrity": "sha512-lFTyVgLNt4x1T4jBHRs+V8gFUQKwXkMbeNF5JUNwlrmGBr/Mx0A36XBcJ4BKZR5+jWO1C6I8jgYzIrFPx6Z+MQ==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-updater-life": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-updater-life/-/tsparticles-updater-life-2.10.1.tgz", + "integrity": "sha512-qhd+uVxxGLS50bN75POU2lHgqBhXBpRmdY/RnW6mwHGrs5SgiU0XoM0il3+RoAnvpscWG/5ZgEXvpm7ZvbNUWA==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-updater-opacity": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-updater-opacity/-/tsparticles-updater-opacity-2.10.1.tgz", + "integrity": "sha512-l1FOevfK9CMz9cBRT5prQpHACijYJ+3dHvIfx0Y5M5Do4etoT+PurZxDpQlQU6Yd0vXKm3r37paPiQbH5U3Vqg==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-updater-out-modes": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-updater-out-modes/-/tsparticles-updater-out-modes-2.10.1.tgz", + "integrity": "sha512-nzP/puePd97FlME9gzmjwdQWoqm+O7GtnkbD33a4NBlzJMgtjbGtmz/Tmc4hLicb/qwS5D8j9xvB+srsuxT7LA==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-updater-roll": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-updater-roll/-/tsparticles-updater-roll-2.10.1.tgz", + "integrity": "sha512-5v43esqjPy/GbXXJKOqOF4fD7zndQFE7G5iqF76dp8RaG2V+tIb96j8+wx2B32K9VjEOk3XwOKjYnHtdpYPhvg==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-updater-rotate": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-updater-rotate/-/tsparticles-updater-rotate-2.10.1.tgz", + "integrity": "sha512-GWCyLrB0JaEY0nugFU5E22b/LjSF6Bv4q5dXsbtzqjD9Ka/DPMJ8js8bzJhNf3jftQzf6zBXf72W0kyZH79VIQ==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-updater-size": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-updater-size/-/tsparticles-updater-size-2.10.1.tgz", + "integrity": "sha512-Kdtskqm0CRrlsovOsJLcS6NXF0alJ6NlwmW7oWnTK6EeLvEKaqisG/hjcFf+l7eXlmL8j9rYgh6wctaef6GBCw==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-updater-stroke-color": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-updater-stroke-color/-/tsparticles-updater-stroke-color-2.10.1.tgz", + "integrity": "sha512-iYLO1y9lH0bOxxE5gPRdsYR5UVIvtxWpera8C5JBXaHywROkJ8CSXxA2pIe01kUIwIOcOv8j26RJvKNdttv9kQ==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-updater-tilt": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-updater-tilt/-/tsparticles-updater-tilt-2.10.1.tgz", + "integrity": "sha512-MLNZPSc+nM+M5KV9i6tHtzxqSIhQ9VQAuKOuKqHRxs3fkFXboc1dNKA5Ou16roi/efqpc1gXrtZvhPF+holp2Q==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-updater-twinkle": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-updater-twinkle/-/tsparticles-updater-twinkle-2.10.1.tgz", + "integrity": "sha512-Y+/34BCG2/tTm1lpHniNhh3P5M0u5i6qjt/MGquR6yXzQqjmRkhW29vtqd8tZcVx4KZ7Rj0mOUIHFX8bc3YRHQ==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, + "tsparticles-updater-wobble": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/tsparticles-updater-wobble/-/tsparticles-updater-wobble-2.10.1.tgz", + "integrity": "sha512-Kf5MfhjkXKlB0hiZPUJCv0PCxRH2E1nmyUnqu05xSZGjQDTS+A/uNtUvIA1nrq7l38VVgpRREtnYka2whOhzwQ==", + "requires": { + "tsparticles-engine": "^2.10.1" + } + }, "tsutils": { "version": "3.21.0", "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", diff --git a/client/package.json b/client/package.json index 67ab438b6..3405f6788 100644 --- a/client/package.json +++ b/client/package.json @@ -20,6 +20,7 @@ "country-code-lookup": "^0.0.20", "dotenv": "^16.0.1", "formik": "^2.2.9", + "formik-mui": "^5.0.0-alpha.0", "framer-motion": "^10.12.10", "jwt-decode": "^3.1.2", "lodash": "^4.17.21", @@ -33,6 +34,7 @@ "react-hot-toast": "^2.4.1", "react-loader-spinner": "^5.3.4", "react-loading-skeleton": "^3.1.0", + "react-particles": "^2.10.1", "react-query": "^3.39.2", "react-redux": "^8.0.2", "react-router-dom": "^6.3.0", @@ -43,6 +45,7 @@ "redux": "^4.2.0", "socket.io-client": "^4.6.1", "styled-components": "^5.3.5", + "tsparticles": "^2.10.1", "uuidv4": "^5.0.1", "web-vitals": "^2.1.4", "yup": "^0.32.11" diff --git a/client/src/components/Profile/components/ResumeInfo/EducationWork/EducationWork.jsx b/client/src/components/Profile/components/ResumeInfo/EducationWork/EducationWork.jsx index b877fcf7c..5c76433a7 100644 --- a/client/src/components/Profile/components/ResumeInfo/EducationWork/EducationWork.jsx +++ b/client/src/components/Profile/components/ResumeInfo/EducationWork/EducationWork.jsx @@ -27,7 +27,9 @@ const EducationWork = ({ showingUser, setIsEditing, userStatus }) => { {university?.addmissionDate?.split('-')[0]} -{' '} - {university?.graduationDate?.split('-')[0]} + {university?.addmissionDate && !university?.graduationDate + ? 'Present' + : university?.graduationDate?.split('-')[0]} )) @@ -55,7 +57,8 @@ const EducationWork = ({ showingUser, setIsEditing, userStatus }) => { {job.title} - {job.company} - {job.startDate.split('-')[0]} - {job.endDate.split('-')[0]} + {job?.startDate?.split('-')[0]} -{' '} + {job?.startDate && !job?.endDate ? 'Present' : job?.endDate?.split('-')[0]} )) diff --git a/client/src/components/RegistrationPipeline/components/InitialPart/InitialPart.jsx b/client/src/components/RegistrationPipeline/components/InitialPart/InitialPart.jsx index 132e0b42b..fc0d60557 100644 --- a/client/src/components/RegistrationPipeline/components/InitialPart/InitialPart.jsx +++ b/client/src/components/RegistrationPipeline/components/InitialPart/InitialPart.jsx @@ -19,6 +19,7 @@ import { MiddleTextContainer, TopText, } from './InitialPart.styles' +import { ParticlesContainer } from './ParticlesContainer' function InitialPart() { const dispatch = useDispatch() @@ -44,16 +45,11 @@ function InitialPart() { <> -
- Welcome to the family ❤️ -
- - Please, fill the form to complete the registration. - - - It will take approximately 5 minutes but will help us better understand your skills - and what are you looking for here. + Welcome to our family ❤️ + + Please fill out the registration form so we can learn more about your skills and what + you're looking for here. It'll only take about 5 minutes.
+ ) } diff --git a/client/src/components/RegistrationPipeline/components/InitialPart/InitialPart.styles.js b/client/src/components/RegistrationPipeline/components/InitialPart/InitialPart.styles.js index 794628451..53572d271 100644 --- a/client/src/components/RegistrationPipeline/components/InitialPart/InitialPart.styles.js +++ b/client/src/components/RegistrationPipeline/components/InitialPart/InitialPart.styles.js @@ -7,42 +7,38 @@ export const CardContainer = styled.div` flex-direction: column; justify-content: center; align-items: center; - width: 770px; - height: 470px; + max-width: 470px; + width: 100%; + min-height: 350px; background: ${BLACK.cardContainer}; - border-radius: 25px; - margin-bottom: 78px; - box-shadow: 0px 5px 50px rgba(0, 0, 0, 0.1); + border-radius: 15px; + padding: 32px; + gap: 24px; ` export const Container = styled.div` display: flex; - flex-direction: row; - gap: 50px; justify-content: center; align-items: center; - min-height: 100vh; + min-height: 100dvh; width: 100%; - background: ${BLACK.background}; + /* background: ${BLACK.background}; */ + padding: 20px; ` export const ContinueButton = styled.button` font-weight: 600; font-size: 16px; - margin-top: 80px; border: none; - width: 271px; - height: 50px; + width: 100%; + height: 40px; + padding: 0px 16px; color: ${WHITE.main}; - background: ${GREEN.button}; - border-radius: 5px; + background: #46a11b; + border-radius: 10px; &:hover { cursor: pointer; - transition: 0.3s ease-in-out; - -webkit-transform: scale(1.05); - -ms-transform: scale(1.05); - transform: scale(1.05); } ` @@ -50,7 +46,6 @@ export const MiddleTextContainer = styled.div` display: flex; flex-direction: column; justify-content: center; - max-width: 550px; width: 100%; ` diff --git a/client/src/components/RegistrationPipeline/components/InitialPart/ParticlesContainer.jsx b/client/src/components/RegistrationPipeline/components/InitialPart/ParticlesContainer.jsx new file mode 100644 index 000000000..9b2e17af0 --- /dev/null +++ b/client/src/components/RegistrationPipeline/components/InitialPart/ParticlesContainer.jsx @@ -0,0 +1,89 @@ +import React, { useCallback, useMemo } from 'react' +import { Particles } from 'react-particles' +import { loadFull } from 'tsparticles' + +export function ParticlesContainer() { + const particlesInit = useCallback(async (engine) => { + console.log(engine) + // you can initiate the tsParticles instance (engine) here, adding custom shapes or presets + // this loads the tsparticles package bundle, it's the easiest method for getting everything ready + // starting from v2 you can add only the features you need reducing the bundle size + await loadFull(engine) + }, []) + + const particlesLoaded = useCallback(async (container) => { + await console.log(container) + }, []) + + // using useMemo is not mandatory, but it's recommended since this value can be memoized if static + const options = useMemo(() => { + // using an empty options object will load the default options, which are static particles with no background and 3px radius, opacity 100%, white color + // all options can be found here: https://particles.js.org/docs/interfaces/Options_Interfaces_IOptions.IOptions.html + return { + fullScreen: { + enable: true, + zIndex: -1, + }, + name: 'Nyan Cat 2', + particles: { + number: { + value: 100, + density: { + enable: false, + }, + }, + color: { + value: '#ffffff', + }, + shape: { + type: 'star', + options: { + star: { + sides: 5, + }, + }, + }, + opacity: { + value: 0.5, + }, + size: { + value: { + min: 1, + max: 4, + }, + }, + move: { + enable: true, + speed: 6, + direction: 'left', + straight: true, + }, + }, + interactivity: { + events: { + onClick: { + enable: true, + mode: 'repulse', + }, + }, + modes: { + repulse: { + distance: 200, + duration: 0.4, + }, + }, + }, + background: { + color: '#26292B', + image: "url('https://vincentgarreau.com/particles.js/assets/img/kbLd9vb_new.gif')", + position: '-60% 5%', + repeat: 'no-repeat', + size: '60%', + }, + } + }, []) + + return ( + + ) +} diff --git a/client/src/components/RegistrationPipeline/components/MultiStepRegistration/MultiStepRegistration.jsx b/client/src/components/RegistrationPipeline/components/MultiStepRegistration/MultiStepRegistration.jsx index 19f27386a..0c3c1422d 100644 --- a/client/src/components/RegistrationPipeline/components/MultiStepRegistration/MultiStepRegistration.jsx +++ b/client/src/components/RegistrationPipeline/components/MultiStepRegistration/MultiStepRegistration.jsx @@ -3,6 +3,7 @@ import { useSelector } from 'react-redux' import { Form, Formik } from 'formik' import { useCheckAuth } from '../../../../api/hooks/auth/useCheckAuth' +import FlexWrapper from '../../../../shared/components/FlexWrapper/FlexWrapper' import Loader from '../../../../shared/components/Loader/Loader' import CurrentStep from '../CurrentStep/CurrentStep' import NavigationButtons from '../NavigationButtons/NavigationButtons' @@ -28,9 +29,9 @@ const MultiStepRegistration = ({ submitForm(values, userData) } - if (isFetching || isFinishingRegistration) { - return - } + // if (isFetching) { + // return + // } return ( - - - - + + + + + + diff --git a/client/src/components/RegistrationPipeline/components/MultiStepRegistration/MultiStepRegistration.styles.js b/client/src/components/RegistrationPipeline/components/MultiStepRegistration/MultiStepRegistration.styles.js index 7138a75a2..0eb4966ea 100644 --- a/client/src/components/RegistrationPipeline/components/MultiStepRegistration/MultiStepRegistration.styles.js +++ b/client/src/components/RegistrationPipeline/components/MultiStepRegistration/MultiStepRegistration.styles.js @@ -1,4 +1,4 @@ -import styled from 'styled-components' +import styled, { css } from 'styled-components' import { BLACK, WHITE } from '../../../../constants/colors' @@ -8,11 +8,19 @@ export const RegistrationContainer = styled.div` display: flex; flex-direction: column; padding: 3rem 9.6875rem 5rem 8.125rem; + + @media screen and (max-width: 1124px) { + padding: 52px; + } + + @media screen and (max-width: 1024px) { + padding: 32px; + } ` export const Container = styled.div` display: flex; - min-height: 100vh; + min-height: 100dvh; ` export const ResetButton = styled.button` @@ -36,6 +44,11 @@ export const ResetButton = styled.button` export const StepContainer = styled.div` margin-top: 6rem; height: 100%; + + @media screen and (max-width: 600px) { + margin-top: 24px; + height: auto; + } ` export const ContentContainer = styled.div` @@ -49,4 +62,16 @@ export const ContentContainer = styled.div` height: 100%; gap: ${(props) => props.gap || '3.5rem'}; + + @media screen and (max-width: 768px) { + ${({ transformToFlex }) => + transformToFlex && + css` + display: flex; + flex-direction: column; + `}; + + gap: 32px; + height: auto; + } ` diff --git a/client/src/components/RegistrationPipeline/components/NavLogo/NavLogo.js b/client/src/components/RegistrationPipeline/components/NavLogo/NavLogo.js index 269f277db..ee97dcbed 100644 --- a/client/src/components/RegistrationPipeline/components/NavLogo/NavLogo.js +++ b/client/src/components/RegistrationPipeline/components/NavLogo/NavLogo.js @@ -1,17 +1,18 @@ // * Modules import { useState } from 'react' -import AppBar from '@mui/material/AppBar' -import Box from '@mui/material/Box' import InfoIcon from '../../../../assets/Shared/InfoIcon' +import { useGetScreenWidth } from '../../../../hooks/useGetScreenWidth' +import FlexWrapper from '../../../../shared/components/FlexWrapper/FlexWrapper' import { Text } from '../../../../shared/styles/Tpography.styles' // * Assets import Hover from './Hover' -import { InfoContainer, NavBar, SectionName, SectionNameOptionalText } from './NavLogo.styles' +import { InfoContainer, SectionName, SectionNameOptionalText } from './NavLogo.styles' function NavLogo({ sectionName, isOptionalStep, oneOfOptionalFieldsHasValue }) { const [anchorEl, setAnchorEl] = useState(null) + const width = useGetScreenWidth() const handlePopoverOpen = (event) => { setAnchorEl(event.currentTarget) @@ -24,25 +25,22 @@ function NavLogo({ sectionName, isOptionalStep, oneOfOptionalFieldsHasValue }) { const open = Boolean(anchorEl) return ( - - - - {/* */} - - {sectionName}{' '} - {isOptionalStep && !oneOfOptionalFieldsHasValue && ( - (Optional) - )} - -
- - Need Help - - - -
-
-
+ <> + + + {/* */} + + {sectionName}{' '} + {isOptionalStep && !oneOfOptionalFieldsHasValue && ( + (Optional) + )} + + + {width > 600 && Need Help} + + + + ) } diff --git a/client/src/components/RegistrationPipeline/components/NavLogo/NavLogo.styles.js b/client/src/components/RegistrationPipeline/components/NavLogo/NavLogo.styles.js index e4d6425ef..353894c4c 100644 --- a/client/src/components/RegistrationPipeline/components/NavLogo/NavLogo.styles.js +++ b/client/src/components/RegistrationPipeline/components/NavLogo/NavLogo.styles.js @@ -1,17 +1,10 @@ // * Modules -import Toolbar from '@mui/material/Toolbar' import styled from 'styled-components' // * Constants import { GREEN } from '../../../../constants/colors' import { Text } from '../../../../shared/styles/Tpography.styles' -export const NavBar = styled(Toolbar)` - background: #26292b; - padding: 0 !important; - min-height: 2.375rem !important; -` - export const InfoContainer = styled.div` display: flex; justify-content: center; @@ -26,6 +19,10 @@ export const SectionName = styled(Text)` line-height: 120%; display: flex; gap: 5px; + + @media screen and (max-width: 600px) { + font-size: 24px; + } ` export const SectionNameOptionalText = styled.span` diff --git a/client/src/components/RegistrationPipeline/components/NavigationButtons/NavigationButtons.jsx b/client/src/components/RegistrationPipeline/components/NavigationButtons/NavigationButtons.jsx index 051e78310..f1a1d9acb 100644 --- a/client/src/components/RegistrationPipeline/components/NavigationButtons/NavigationButtons.jsx +++ b/client/src/components/RegistrationPipeline/components/NavigationButtons/NavigationButtons.jsx @@ -1,4 +1,5 @@ import React, { useEffect, useState } from 'react' +import { ThreeDots } from 'react-loader-spinner' import { useDispatch } from 'react-redux' import { useNavigate } from 'react-router-dom' import { useFormikContext } from 'formik' @@ -6,26 +7,32 @@ import { useFormikContext } from 'formik' import ArrowNavigateBack from '../../../../assets/Arrows/ArrowNavigateBack' import ArrowNavigateFurther from '../../../../assets/Arrows/ArrowNavigateFurther' import { GREEN } from '../../../../constants/colors' +import { useGetScreenWidth } from '../../../../hooks/useGetScreenWidth' import CustomButton from '../../../../shared/components/CustomButton/CustomButton' +import { Text } from '../../../../shared/styles/Tpography.styles' import { setStep } from '../../../../store/reducers/RegistrationAuth' -import { ButtonsContainer } from './NavigationButtons.styles' +import { ButtonsContainer, MobileStepper } from './NavigationButtons.styles' const NavigationButtons = ({ step, isOptionalStep, isLastStep, + steps, validationSchema, setOneOfOptionalFieldsHasValue, oneOfOptionalFieldsHasValue, + isFinishingRegistration, }) => { const dispatch = useDispatch() const navigate = useNavigate() const { isValid, values } = useFormikContext() + const width = useGetScreenWidth() useEffect(() => { if (isOptionalStep) { const currentStepFields = validationSchema[step - 1]._nodes + const hasValue = currentStepFields.some((field) => { const value = values[field] @@ -60,6 +67,11 @@ const NavigationButtons = ({ > {step === 1 ? 'Cancel' : 'Back'} + + + {step} / {steps.length} + + {!isLastStep && ( - {isOptionalStep && !oneOfOptionalFieldsHasValue ? 'Skip' : 'Next Step'} + {isOptionalStep && !oneOfOptionalFieldsHasValue + ? 'Skip' + : width > 600 + ? 'Next Step' + : 'Next'} )} {isLastStep && ( @@ -80,7 +96,20 @@ const NavigationButtons = ({ iconPosition="right" background={GREEN.button} > - Finish + {isFinishingRegistration ? ( + + ) : ( + 'Finish' + )} )} diff --git a/client/src/components/RegistrationPipeline/components/NavigationButtons/NavigationButtons.styles.js b/client/src/components/RegistrationPipeline/components/NavigationButtons/NavigationButtons.styles.js index 42892ba86..73453d2e7 100644 --- a/client/src/components/RegistrationPipeline/components/NavigationButtons/NavigationButtons.styles.js +++ b/client/src/components/RegistrationPipeline/components/NavigationButtons/NavigationButtons.styles.js @@ -6,4 +6,18 @@ export const ButtonsContainer = styled.div` justify-content: space-between; // margin-top: ${(props) => props.marginTop || '3rem'}; align-items: center; + + @media screen and (max-width: 600px) { + margin-top: 32px; + gap: 16px; + } +` + +export const MobileStepper = styled.div` + display: none; + white-space: nowrap; + + @media screen and (max-width: 600px) { + display: block; + } ` diff --git a/client/src/components/RegistrationPipeline/components/RegistrationForms/AvatarForm/AvatarForm.jsx b/client/src/components/RegistrationPipeline/components/RegistrationForms/AvatarForm/AvatarForm.jsx index 4d6467d12..3991817b2 100644 --- a/client/src/components/RegistrationPipeline/components/RegistrationForms/AvatarForm/AvatarForm.jsx +++ b/client/src/components/RegistrationPipeline/components/RegistrationForms/AvatarForm/AvatarForm.jsx @@ -1,5 +1,6 @@ import React from 'react' +import ChooseAvatar from '../../../../../shared/components/ChooseAvatar/ChooseAvatar' import { ContentContainer } from '../../MultiStepRegistration/MultiStepRegistration.styles' import AvatarSelection from './components/AvatarSelection/AvatarSelection' @@ -7,7 +8,7 @@ import { AvatarFormText } from './AvatarForm.styles' const AvatarForm = ({ text }) => { return ( - + {text} diff --git a/client/src/components/RegistrationPipeline/components/RegistrationForms/AvatarForm/components/AvatarSelection/AvatarSelection.jsx b/client/src/components/RegistrationPipeline/components/RegistrationForms/AvatarForm/components/AvatarSelection/AvatarSelection.jsx index d339d6b68..2b363cddd 100644 --- a/client/src/components/RegistrationPipeline/components/RegistrationForms/AvatarForm/components/AvatarSelection/AvatarSelection.jsx +++ b/client/src/components/RegistrationPipeline/components/RegistrationForms/AvatarForm/components/AvatarSelection/AvatarSelection.jsx @@ -2,7 +2,7 @@ import { useFormikContext } from 'formik' import ChooseAvatar from '../../../../../../../shared/components/ChooseAvatar/ChooseAvatar' -import { Avatar, AvatarSelectionContainer } from './AvatarSelection.styles' +import { Avatar, AvatarSelectionContainer, AvatarWrapper } from './AvatarSelection.styles' const AvatarSelection = () => { const { getFieldProps } = useFormikContext() @@ -10,7 +10,9 @@ const AvatarSelection = () => { return ( - + + + ) diff --git a/client/src/components/RegistrationPipeline/components/RegistrationForms/AvatarForm/components/AvatarSelection/AvatarSelection.styles.js b/client/src/components/RegistrationPipeline/components/RegistrationForms/AvatarForm/components/AvatarSelection/AvatarSelection.styles.js index c15b53b2b..70ea93e78 100644 --- a/client/src/components/RegistrationPipeline/components/RegistrationForms/AvatarForm/components/AvatarSelection/AvatarSelection.styles.js +++ b/client/src/components/RegistrationPipeline/components/RegistrationForms/AvatarForm/components/AvatarSelection/AvatarSelection.styles.js @@ -2,11 +2,43 @@ import styled from 'styled-components' export const AvatarSelectionContainer = styled.div` display: flex; - gap: 8.125rem; + gap: 130px; + width: 100%; + justify-content: space-between; + + @media screen and (max-width: 1264px) { + gap: 45px; + } + + @media screen and (max-width: 768px) { + flex-direction: column; + justify-content: center; + align-items: center; + } +` + +export const AvatarWrapper = styled.div` + @media screen and (max-width: 768px) { + display: flex; + justify-content: center; + align-items: center; + } ` export const Avatar = styled.img` - width: 16.875rem; - height: 16.875rem; + width: 270px; + height: 270px; border-radius: 50%; + object-fit: cover; + + @media screen and (max-width: 900px) { + width: 170px; + height: 170px; + } + + @media screen and (max-width: 768px) { + width: 140px; + height: 140px; + max-width: none; + } ` diff --git a/client/src/components/RegistrationPipeline/components/RegistrationForms/InfoForm/InfoForm.styles.js b/client/src/components/RegistrationPipeline/components/RegistrationForms/InfoForm/InfoForm.styles.js index f67d2d2ec..ed19c8310 100644 --- a/client/src/components/RegistrationPipeline/components/RegistrationForms/InfoForm/InfoForm.styles.js +++ b/client/src/components/RegistrationPipeline/components/RegistrationForms/InfoForm/InfoForm.styles.js @@ -3,4 +3,8 @@ import styled from 'styled-components' export const InputsContainer = styled(Stack)` gap: 2.25rem; + + @media screen and (max-width: 768px) { + gap: 32px; + } ` diff --git a/client/src/components/RegistrationPipeline/components/RegistrationForms/InfoForm/UserInfoForm/UserInfoForm.jsx b/client/src/components/RegistrationPipeline/components/RegistrationForms/InfoForm/UserInfoForm/UserInfoForm.jsx index 1bf5eac1f..436fd181a 100644 --- a/client/src/components/RegistrationPipeline/components/RegistrationForms/InfoForm/UserInfoForm/UserInfoForm.jsx +++ b/client/src/components/RegistrationPipeline/components/RegistrationForms/InfoForm/UserInfoForm/UserInfoForm.jsx @@ -4,6 +4,7 @@ import countryList from 'react-select-country-list' import { useDebounce } from '../../../../../../api/hooks/temeights/useDebounce' import { useValidateUsername } from '../../../../../../api/hooks/user/useValidateUsername' import { countries } from '../../../../../../constants/countries' +import { useGetScreenWidth } from '../../../../../../hooks/useGetScreenWidth' import CustomInput from '../../../../../../shared/components/Formik/CustomInput/CustomInput' import { GroupContainer, @@ -15,6 +16,7 @@ import { InputsContainer } from '../InfoForm.styles' const UserInfoForm = () => { let { mutate: validateUsername, data: errorStatus } = useValidateUsername() + const width = useGetScreenWidth() // State and setters for ... // Search term @@ -86,12 +88,12 @@ const UserInfoForm = () => { 768 ? 'calc(100% - 5rem)' : '38px' }} label="About me (optional)" name="description" - placeholder="Write something about yourself..." - maxLength={200} - margin="0 0 5rem 0" + placeholder={width > 468 ? 'Write something about yourself...' : 'Write about you...'} + maxLength={230} + margin={width > 768 ? '0 0 5rem 0' : 0} /> ) diff --git a/client/src/components/RegistrationPipeline/components/RegistrationForms/UserEducationForm/UserEducationForm.jsx b/client/src/components/RegistrationPipeline/components/RegistrationForms/UserEducationForm/UserEducationForm.jsx index d62dea930..ecfdfb743 100644 --- a/client/src/components/RegistrationPipeline/components/RegistrationForms/UserEducationForm/UserEducationForm.jsx +++ b/client/src/components/RegistrationPipeline/components/RegistrationForms/UserEducationForm/UserEducationForm.jsx @@ -1,7 +1,10 @@ import React, { useState } from 'react' import { useFormikContext } from 'formik' +import { degrees } from '../../../../../constants/degrees' +import { majors } from '../../../../../constants/majors' import CustomInput from '../../../../../shared/components/Formik/CustomInput/CustomInput' +import CustomSelectAutocomplete from '../../../../../shared/components/Formik/CustomSelectAutocomplete/CustomSelectAutocomplete' import CheckboxWithLabel from '../../CheckboxWithLabel/CheckboxWithLabel' import { ContentContainer } from '../../MultiStepRegistration/MultiStepRegistration.styles' @@ -9,61 +12,58 @@ import { GroupItems, InputWrapper } from './UserEducationForm.styles' const UserEducationForm = () => { const [checkbox, setCheckbox] = useState(false) - const { setFieldValue } = useFormikContext() + const { setFieldValue, values } = useFormikContext() const handleClick = () => { if (checkbox) { setCheckbox(false) - setFieldValue('graduationDate', '') + setFieldValue('universityData[0].graduationDate', '') } else { setCheckbox(true) - setFieldValue('graduationDate', '0') + setFieldValue('universityData[0].graduationDate', '0') } } return ( - - - - - - - - - - - - - - - - + + + + + + props.grow || '1'}; - width: ${(props) => props.width || '100%'}; + display: flex; + gap: 130px; + width: 100%; + + @media screen and (max-width: 600px) { + gap: 100px; + } ` diff --git a/client/src/components/RegistrationPipeline/components/RegistrationForms/UserExperienceForm/UserExperienceForm.jsx b/client/src/components/RegistrationPipeline/components/RegistrationForms/UserExperienceForm/UserExperienceForm.jsx index 9f97a305a..993006e00 100644 --- a/client/src/components/RegistrationPipeline/components/RegistrationForms/UserExperienceForm/UserExperienceForm.jsx +++ b/client/src/components/RegistrationPipeline/components/RegistrationForms/UserExperienceForm/UserExperienceForm.jsx @@ -14,11 +14,11 @@ const UserExperienceForm = () => { How many years of experience you have? - + Do you want to be a leader of the team? - + Please note that leaders typically have 1-3+ years of experience and will be required to diff --git a/client/src/components/RegistrationPipeline/components/RegistrationForms/UserJobForm/UserJobForm.jsx b/client/src/components/RegistrationPipeline/components/RegistrationForms/UserJobForm/UserJobForm.jsx index f857ef998..4e0aabda6 100644 --- a/client/src/components/RegistrationPipeline/components/RegistrationForms/UserJobForm/UserJobForm.jsx +++ b/client/src/components/RegistrationPipeline/components/RegistrationForms/UserJobForm/UserJobForm.jsx @@ -4,59 +4,59 @@ import { useFormikContext } from 'formik' import CustomInput from '../../../../../shared/components/Formik/CustomInput/CustomInput' import CheckboxWithLabel from '../../CheckboxWithLabel/CheckboxWithLabel' import { ContentContainer } from '../../MultiStepRegistration/MultiStepRegistration.styles' -import { GroupItems, InputWrapper } from '../UserEducationForm/UserEducationForm.styles' +import { InputWrapper } from '../UserEducationForm/UserEducationForm.styles' const UserJobForm = () => { const [checkbox, setCheckbox] = useState(false) - const { setFieldValue } = useFormikContext() + const { setFieldValue, values } = useFormikContext() + + console.log(values) const handleClick = () => { if (checkbox) { setCheckbox(false) - setFieldValue('endDate', '') + setFieldValue('jobData[0].endDate', '') } else { setCheckbox(true) - setFieldValue('endDate', '0') + setFieldValue('jobData[0].endDate', '0') } } return ( - - - - - - - - - - - - - - - - + + + + + + + state.registrationReducer) - const { mutate: finishRegistration, isLoading: isFinishingRegistration } = - useEditUserDetails(onSuccess) + const { + mutate: finishRegistration, + isLoading: isFinishingRegistration, + isError, + error, + } = useEditUserDetails(onSuccess) const { mutate: updateAvatar } = useUpdateAvatar('users') const dispatch = useDispatch() const navigate = useNavigate() + console.log(error) + console.log(isFinishingRegistration) + const steps = [ { component: , name: 'User Profile', isOptional: false }, { component: , name: 'Concentration', isOptional: false }, @@ -56,18 +63,27 @@ function FinishRegistration() { concentration: '', experience: '', leader: '', - university: '', - degree: ``, - major: '', - addmissionDate: '', - graduationDate: '', - title: '', - company: '', - startDate: '', - endDate: '', + jobData: [ + { + title: '', + company: '', + startDate: '', + endDate: '', + }, + ], + universityData: [ + { + university: '', + degree: ``, + major: '', + addmissionDate: '', + graduationDate: '', + }, + ], github: '', linkedIn: '', telegram: '', + behance: '', file: null, } @@ -78,55 +94,47 @@ function FinishRegistration() { } const submitForm = (formData, userCurrentData) => { - let universityDates = convertYearToDate(formData.addmissionDate, formData.graduationDate) + const jobAfterRemovedEmptyFields = removeEmptyFields(formData.jobData[0]) - let jobDates = convertYearToDate(formData.startDate, formData.endDate) + if (jobAfterRemovedEmptyFields) { + let jobDates = convertYearToDate(formData.jobData[0].startDate, formData.jobData[0].endDate) - let universityData = { - university: formData.university, - degree: formData.degree, - major: formData.major, - addmissionDate: universityDates.dateOne, - graduationDate: universityDates.dateTwo, + formData.jobData[0].startDate = jobDates.dateOne + formData.jobData[0].endDate = jobDates.dateTwo + } else { + formData.jobData = undefined } - let universityValidated = removeEmptyFields(universityData) + const universityAfterRemovedEmptyFields = removeEmptyFields(formData.universityData[0]) + + if (universityAfterRemovedEmptyFields) { + let universityDates = convertYearToDate( + formData.universityData[0].addmissionDate, + formData.universityData[0].graduationDate, + ) - let jobData = { - title: formData.title, - company: formData.company, - startDate: jobDates.dateOne, - endDate: jobDates.dateTwo, + formData.universityData[0].addmissionDate = universityDates.dateOne + formData.universityData[0].graduationDate = universityDates.dateTwo + } else { + formData.universityData = undefined } - let jobValidated = removeEmptyFields(jobData) - - const registrationData = { - email: userCurrentData.email, - username: formData.username, - fullName: formData.fullName, - dateOfBirth: formatDateString(formData.dateOfBirth), - description: formData.description, - concentration: formData.concentration, - country: formData.country, - experience: formData.experience, - isLeader: formData.leader === 'true', - links: { - github: formData.github, - telegram: formData.telegram, - linkedIn: formData.linkedIn, - }, - programmingLanguages: formData.programmingLanguages, - frameworks: formData.frameworks, - jobData: jobValidated !== null ? jobValidated : undefined, - universityData: universityValidated !== null ? universityValidated : undefined, - isRegistered: false, + formData.links = { + github: formData.github, + telegram: formData.telegram, + linkedIn: formData.linkedIn, + behance: formData.behance, } + formData.dateOfBirth = formatDateString(formData.dateOfBirth) + formData.isRegistered = false + formData.email = userCurrentData.email + if (formData.file) { updateAvatar({ email: userCurrentData.email, image: formData.file.split(',')[1] }) } - finishRegistration(registrationData) + + finishRegistration(formData) } return ( diff --git a/client/src/constants/degrees.js b/client/src/constants/degrees.js new file mode 100644 index 000000000..cc17abbb0 --- /dev/null +++ b/client/src/constants/degrees.js @@ -0,0 +1,22 @@ +export const degrees = [ + { + label: 'Associate degree', + value: 'AA', + }, + { + label: "Bachelor's Degree", + value: 'BA', + }, + { + label: "Master's Degree", + value: 'MA', + }, + { + label: 'Doctoral degree', + value: 'PhD', + }, + { + label: 'Other', + value: 'Other', + }, +] diff --git a/client/src/constants/majors.js b/client/src/constants/majors.js new file mode 100644 index 000000000..7ca7e5f79 --- /dev/null +++ b/client/src/constants/majors.js @@ -0,0 +1,177 @@ +export const majors = [ + { label: 'General Agriculture', value: 1 }, + { label: 'Agriculture Production And Management', value: 2 }, + { label: 'Agricultural Economics', value: 3 }, + { label: 'Animal Sciences', value: 4 }, + { label: 'Food Science', value: 5 }, + { label: 'Plant Science And Agronomy', value: 6 }, + { label: 'Soil Science', value: 7 }, + { label: 'Miscellaneous Agriculture', value: 8 }, + { label: 'Forestry', value: 9 }, + { label: 'Natural Resources Management', value: 10 }, + { label: 'Fine Arts', value: 11 }, + { label: 'Drama And Theater Arts', value: 12 }, + { label: 'Music', value: 13 }, + { label: 'Visual And Performing Arts', value: 14 }, + { label: 'Commercial Art And Graphic Design', value: 15 }, + { label: 'Film Video And Photographic Arts', value: 16 }, + { label: 'Studio Arts', value: 17 }, + { label: 'Miscellaneous Fine Arts', value: 18 }, + { label: 'Environmental Science', value: 19 }, + { label: 'Biology', value: 20 }, + { label: 'Biochemical Sciences', value: 21 }, + { label: 'Botany', value: 22 }, + { label: 'Molecular Biology', value: 23 }, + { label: 'Ecology', value: 24 }, + { label: 'Genetics', value: 25 }, + { label: 'Microbiology', value: 26 }, + { label: 'Pharmacology', value: 27 }, + { label: 'Physiology', value: 28 }, + { label: 'Zoology', value: 29 }, + { label: 'Neuroscience', value: 30 }, + { label: 'Miscellaneous Biology', value: 31 }, + { label: 'Cognitive Science And Biopsychology', value: 32 }, + { label: 'General Business', value: 33 }, + { label: 'Accounting', value: 34 }, + { label: 'Actuarial Science', value: 35 }, + { label: 'Business Management And Administration', value: 36 }, + { label: 'Operations Logistics And E-Commerce', value: 37 }, + { label: 'Business Economics', value: 38 }, + { label: 'Marketing And Marketing Research', value: 39 }, + { label: 'Finance', value: 40 }, + { label: 'Human Resources And Personnel Management', value: 41 }, + { label: 'International Business', value: 42 }, + { label: 'Hospitality Management', value: 43 }, + { label: 'Management Information Systems And Statistics', value: 44 }, + { label: 'Miscellaneous Business & Medical Administration', value: 45 }, + { label: 'Communications', value: 46 }, + { label: 'Journalism', value: 47 }, + { label: 'Mass Media', value: 48 }, + { label: 'Advertising And Public Relations', value: 49 }, + { label: 'Communication Technologies', value: 50 }, + { label: 'Computer And Information Systems', value: 51 }, + { label: 'Computer Programming And Data Processing', value: 52 }, + { label: 'Computer Science', value: 53 }, + { label: 'Information Sciences', value: 54 }, + { label: 'Computer Administration Management And Security', value: 55 }, + { label: 'Computer Networking And Telecommunications', value: 56 }, + { label: 'Mathematics', value: 57 }, + { label: 'Applied Mathematics', value: 58 }, + { label: 'Statistics And Decision Science', value: 59 }, + { label: 'Mathematics And Computer Science', value: 60 }, + { label: 'General Education', value: 61 }, + { label: 'Educational Administration And Supervision', value: 62 }, + { label: 'School Student Counseling', value: 63 }, + { label: 'Elementary Education', value: 64 }, + { label: 'Mathematics Teacher Education', value: 65 }, + { label: 'Physical And Health Education Teaching', value: 66 }, + { label: 'Early Childhood Education', value: 67 }, + { label: 'Science And Computer Teacher Education', value: 68 }, + { label: 'Secondary Teacher Education', value: 69 }, + { label: 'Special Needs Education', value: 70 }, + { label: 'Social Science Or History Teacher Education', value: 71 }, + { label: 'Teacher Education: Multiple Levels', value: 72 }, + { label: 'Language And Drama Education', value: 73 }, + { label: 'Art And Music Education', value: 74 }, + { label: 'Miscellaneous Education', value: 75 }, + { label: 'Library Science', value: 76 }, + { label: 'Architecture', value: 77 }, + { label: 'General Engineering', value: 78 }, + { label: 'Aerospace Engineering', value: 79 }, + { label: 'Biological Engineering', value: 80 }, + { label: 'Architectural Engineering', value: 81 }, + { label: 'Biomedical Engineering', value: 82 }, + { label: 'Chemical Engineering', value: 83 }, + { label: 'Civil Engineering', value: 84 }, + { label: 'Computer Engineering', value: 85 }, + { label: 'Electrical Engineering', value: 86 }, + { label: 'Engineering Mechanics Physics And Science', value: 87 }, + { label: 'Environmental Engineering', value: 88 }, + { label: 'Geological And Geophysical Engineering', value: 89 }, + { label: 'Industrial And Manufacturing Engineering', value: 90 }, + { label: 'Materials Engineering And Materials Science', value: 91 }, + { label: 'Mechanical Engineering', value: 92 }, + { label: 'Metallurgical Engineering', value: 93 }, + { label: 'Mining And Mineral Engineering', value: 94 }, + { label: 'Naval Architecture And Marine Engineering', value: 95 }, + { label: 'Nuclear Engineering', value: 96 }, + { label: 'Petroleum Engineering', value: 97 }, + { label: 'Miscellaneous Engineering', value: 98 }, + { label: 'Engineering Technologies', value: 99 }, + { label: 'Engineering And Industrial Management', value: 100 }, + { label: 'Electrical Engineering Technology', value: 101 }, + { label: 'Industrial Production Technologies', value: 102 }, + { label: 'Mechanical Engineering Related Technologies', value: 103 }, + { label: 'Miscellaneous Engineering Technologies', value: 104 }, + { label: 'Materials Science', value: 105 }, + { label: 'Nutrition Sciences', value: 106 }, + { label: 'General Medical And Health Services', value: 107 }, + { label: 'Communication Disorders Sciences And Services', value: 108 }, + { label: 'Health And Medical Administrative Services', value: 109 }, + { label: 'Medical Assisting Services', value: 110 }, + { label: 'Medical Technologies Technicians', value: 111 }, + { label: 'Health And Medical Preparatory Programs', value: 112 }, + { label: 'Nursing', value: 113 }, + { label: 'Pharmacy Pharmaceutical Sciences And Administration', value: 114 }, + { label: 'Treatment Therapy Professions', value: 115 }, + { label: 'Community And Public Health', value: 116 }, + { label: 'Miscellaneous Health Medical Professions', value: 117 }, + { label: 'Area Ethnic And Civilization Studies', value: 118 }, + { label: 'Linguistics And Comparative Language And Literature', value: 119 }, + { label: 'French German Latin And Other Common Foreign Language Studies', value: 120 }, + { label: 'Other Foreign Languages', value: 121 }, + { label: 'English Language And Literature', value: 122 }, + { label: 'Composition And Rhetoric', value: 123 }, + { label: 'Liberal Arts', value: 124 }, + { label: 'Humanities', value: 125 }, + { label: 'Intercultural And International Studies', value: 126 }, + { label: 'Philosophy And Religious Studies', value: 127 }, + { label: 'Theology And Religious Vocations', value: 128 }, + { label: 'Anthropology And Archeology', value: 129 }, + { label: 'Art History And Criticism', value: 130 }, + { label: 'History', value: 131 }, + { label: 'United States History', value: 132 }, + { label: 'Cosmetology Services And Culinary Arts', value: 133 }, + { label: 'Family And Consumer Sciences', value: 134 }, + { label: 'Military Technologies', value: 135 }, + { label: 'Physical Fitness Parks Recreation And Leisure', value: 136 }, + { label: 'Construction Services', value: 137 }, + { label: 'Electrical, Mechanical, And Precision Technologies And Production', value: 138 }, + { label: 'Transportation Sciences And Technologies', value: 139 }, + { label: 'Multi/Interdisciplinary Studies', value: 140 }, + { label: 'Court Reporting', value: 141 }, + { label: 'Pre-Law And Legal Studies', value: 142 }, + { label: 'Criminal Justice And Fire Protection', value: 143 }, + { label: 'Public Administration', value: 144 }, + { label: 'Public Policy', value: 145 }, + { label: "N/A (Less Than Bachelor'S Degree)", value: 146 }, + { label: 'Physical Sciences', value: 147 }, + { label: 'Astronomy And Astrophysics', value: 148 }, + { label: 'Atmospheric Sciences And Meteorology', value: 149 }, + { label: 'Chemistry', value: 150 }, + { label: 'Geology And Earth Science', value: 151 }, + { label: 'Geosciences', value: 152 }, + { label: 'Oceanography', value: 153 }, + { label: 'Physics', value: 154 }, + { label: 'Multi-Disciplinary Or General Science', value: 155 }, + { label: 'Nuclear, Industrial Radiology, And Biological Technologies', value: 156 }, + { label: 'Psychology', value: 157 }, + { label: 'Educational Psychology', value: 158 }, + { label: 'Clinical Psychology', value: 159 }, + { label: 'Counseling Psychology', value: 160 }, + { label: 'Industrial And Organizational Psychology', value: 161 }, + { label: 'Social Psychology', value: 162 }, + { label: 'Miscellaneous Psychology', value: 163 }, + { label: 'Human Services And Community Organization', value: 164 }, + { label: 'Social Work', value: 165 }, + { label: 'Interdisciplinary Social Sciences', value: 166 }, + { label: 'General Social Sciences', value: 167 }, + { label: 'Economics', value: 168 }, + { label: 'Criminology', value: 169 }, + { label: 'Geography', value: 170 }, + { label: 'International Relations', value: 171 }, + { label: 'Political Science And Government', value: 172 }, + { label: 'Sociology', value: 173 }, + { label: 'Miscellaneous Social Sciences', value: 174 }, + { label: 'Other', value: 175 }, +] diff --git a/client/src/schemas/index.js b/client/src/schemas/index.js index 1ad5cb1bd..56f08d252 100644 --- a/client/src/schemas/index.js +++ b/client/src/schemas/index.js @@ -33,18 +33,31 @@ export const finishRegistrationValidation = [ yup.object().shape( { username: yup.string().required('Please input your username').max(20), - fullName: yup.string().required('Please input your name').min(8).max(20), + fullName: yup + .string() + .required('Please input your name') + .min(4, 'Full name should be at least 4 characters') + .max(20, 'Full name should be at most 20 characters'), dateOfBirth: yup .string() .matches( - /^(0[1-9]|[12][0-9]|3[01])\/(0[1-9]|1[0-2])\/\d{4}$/, + /^(0[1-9]|[12][0-9]|3[01])\/(0[1-9]|1[0-2])\/(19\d\d|20[01][0-9]|202[0-3])$/, 'Invalid date format. Please enter a date in the format dd/mm/yyyy', ) + .test('valid-year', 'Year must be between 1901 and current year', function (value) { + if (value) { + const year = parseInt(value.split('/')[2]) + + return year >= 1901 && year <= new Date().getFullYear() + } + + return true + }) .required('Please input your birthday'), country: yup.string().required('Please choose your country!'), description: yup.string().when('description', (value) => { if (value) { - return yup.string().max(200) + return yup.string().max(230) } else { return yup.string().notRequired() } @@ -65,159 +78,171 @@ export const finishRegistrationValidation = [ experience: yup.string().required('Please choose your experience'), leader: yup.string().required('Decide if you want to be a leader'), }), + yup.object().shape({ - degree: yup - .string() - .when(['university', 'major', 'addmissionDate', 'graduationDate'], { - is: (major, university, addmissionDate, graduationDate) => - !major && !university && !addmissionDate && !graduationDate, - then: yup.string(), - otherwise: yup.string().required('Please input your degree'), - }) - .matches(/^[aA-zZ\s]+$/, { - message: 'Only alphabets are allowed for this field', - }) - .nullable(), - major: yup - .string() - .test('all-required', 'Please input your major', function () { - const { major, degree, graduationDate, addmissionDate, university } = this.parent + universityData: yup + .array() + .of( + yup.object().shape({ + degree: yup + .string() + .when(['university', 'major', 'addmissionDate', 'graduationDate'], { + is: (major, university, addmissionDate, graduationDate) => + !major && !university && !addmissionDate && !graduationDate, + then: yup.string(), + otherwise: yup.string().required('Please input your degree'), + }) + .nullable(), + major: yup + .string() + .test('all-required', 'Please input your major', function () { + const { major, degree, graduationDate, addmissionDate, university } = this.parent - if (!degree && !addmissionDate && !university && !graduationDate) { - return true - } else if (major) { - return true - } else { - return false - } - }) - .matches(/^[aA-zZ\s]+$/, { - message: 'Only alphabets are allowed for this field', - excludeEmptyString: true, - }) - .nullable(), - university: yup - .string() - .test('all-required', 'Please input your university', function () { - const { major, degree, graduationDate, addmissionDate, university } = this.parent + if (!degree && !addmissionDate && !university && !graduationDate) { + return true + } else if (major) { + return true + } else { + return false + } + }) + .nullable(), + university: yup + .string() + .test('all-required', 'Please input your university', function () { + const { major, degree, graduationDate, addmissionDate, university } = this.parent - if (!degree && !major && !addmissionDate && !graduationDate) { - return true - } else if (university) { - return true - } else { - return false - } - }) - .matches(/^[aA-zZ\s]+$/, { - message: 'Only alphabets are allowed for this field', - excludeEmptyString: true, - }) - .nullable(), - addmissionDate: yup - .string() - .test('all-required', 'Please input admission date', function () { - const { major, degree, university, graduationDate, addmissionDate } = this.parent + if (!degree && !major && !addmissionDate && !graduationDate) { + return true + } else if (university) { + return true + } else { + return false + } + }) + .matches(/^[aA-zZ\s]+$/, { + message: 'Only alphabets are allowed for this field', + excludeEmptyString: true, + }) + .nullable(), + addmissionDate: yup + .string() + .test('all-required', 'Please input admission date', function () { + const { major, degree, university, graduationDate, addmissionDate } = this.parent - if (!degree && !major && !university && !graduationDate) { - return true - } else if (addmissionDate) { - return true - } else { - return false - } - }) - .matches(/^[0-9]*$/, { - message: 'Only numbers are allowed for this field', - excludeEmptyString: true, - }) - .nullable(), - graduationDate: yup - .string() - .test('all-required', 'Please input graduation date', function () { - const { major, degree, university, addmissionDate, graduationDate } = this.parent + if (!degree && !major && !university && !graduationDate) { + return true + } else if (addmissionDate) { + return true + } else { + return false + } + }) + .matches(/^[0-9]*$/, { + message: 'Only numbers are allowed for this field', + excludeEmptyString: true, + }) + .nullable(), + graduationDate: yup + .string() + .test('all-required', 'Please input graduation date', function () { + const { major, degree, university, addmissionDate, graduationDate } = this.parent - if (!degree && !major && !university && !addmissionDate) { - return true - } else if (graduationDate) { - return true - } else { - return false - } - }) - .matches(/^[0-9]*$/, { - message: 'Only numbers are allowed for this field', - excludeEmptyString: true, - }) - .nullable(), + if (!degree && !major && !university && !addmissionDate) { + return true + } else if (graduationDate) { + return true + } else { + return false + } + }) + .matches(/^[0-9]*$/, { + message: 'Only numbers are allowed for this field', + excludeEmptyString: true, + }) + .nullable(), + }), + ) + .min(0) + .max(2), }), + yup.object().shape({ - title: yup - .string() - .when(['company', 'startDate', 'endDate'], { - is: (company, startDate, endDate) => !company && !startDate && !endDate, - then: yup.string(), - otherwise: yup.string().required('Please input your title'), - }) - .matches(/^[aA-zZ\s]+$/, { - message: 'Only alphabets are allowed for this field', - }) - .nullable(), - company: yup - .string() - .test('all-required', 'Please input your company', function () { - const { title, company, startDate, endDate } = this.parent + jobData: yup + .array() + .of( + yup.object().shape({ + title: yup + .string() + .when(['company', 'startDate', 'endDate'], { + is: (company, startDate, endDate) => !company && !startDate && !endDate, + then: yup.string(), + otherwise: yup.string().required('Please input your title'), + }) + .matches(/^[aA-zZ\s]+$/, { + message: 'Only alphabets are allowed for this field', + }) + .nullable(), + company: yup + .string() + .test('all-required', 'Please input your company', function () { + const { title, company, startDate, endDate } = this.parent - if (!title && !startDate && !endDate) { - return true - } else if (company) { - return true - } else { - return false - } - }) - .matches(/^[aA-zZ\s]+$/, { - message: 'Only alphabets are allowed for this field', - excludeEmptyString: true, - }) - .nullable(), - startDate: yup - .string() - .test('all-required', 'Please input start date', function () { - const { title, company, startDate, endDate } = this.parent + if (!title && !startDate && !endDate) { + return true + } else if (company) { + return true + } else { + return false + } + }) + .matches(/^[aA-zZ\s]+$/, { + message: 'Only alphabets are allowed for this field', + excludeEmptyString: true, + }) + .nullable(), + startDate: yup + .string() + .test('all-required', 'Please input start date', function () { + const { title, company, startDate, endDate } = this.parent - if (!title && !company && !endDate) { - return true - } else if (startDate) { - return true - } else { - return false - } - }) - .matches(/^[0-9]*$/, { - message: 'Only numbers are allowed for this field', - excludeEmptyString: true, - }) - .nullable(), - endDate: yup - .string() - .test('all-required', 'Please input end date', function () { - const { title, company, startDate, endDate } = this.parent + if (!title && !company && !endDate) { + return true + } else if (startDate) { + return true + } else { + return false + } + }) + .matches(/^[0-9]*$/, { + message: 'Only numbers are allowed for this field', + excludeEmptyString: true, + }) + .nullable(), + endDate: yup + .string() + .test('all-required', 'Please input end date', function () { + const { title, company, startDate, endDate } = this.parent - if (!title && !company && !startDate) { - return true - } else if (endDate) { - return true - } else { - return false - } - }) - .matches(/^[0-9]*$/, { - message: 'Only numbers are allowed for this field', - excludeEmptyString: true, - }) - .nullable(), + if (!title && !company && !startDate) { + return true + } else if (endDate) { + return true + } else { + return false + } + }) + .matches(/^[0-9]*$/, { + message: 'Only numbers are allowed for this field', + excludeEmptyString: true, + }) + .nullable(), + }), + ) + .min(0) + .max(2), }), + yup.object().shape( { github: yup.string().when('github', (value) => { diff --git a/client/src/shared/components/CustomButton/CustomButon.styles.js b/client/src/shared/components/CustomButton/CustomButon.styles.js index ef313967b..b464e3df7 100644 --- a/client/src/shared/components/CustomButton/CustomButon.styles.js +++ b/client/src/shared/components/CustomButton/CustomButon.styles.js @@ -7,7 +7,8 @@ export const Button = styled.button` border: ${(props) => (props.border ? props.border : 'none')}; color: ${(props) => (props.transparent ? '#007bff' : '#fff')}; padding: 0.875rem 0; - width: 10.625rem; + max-width: 10.625rem; + width: 100%; border-radius: 10px; display: flex; align-items: center; @@ -15,16 +16,19 @@ export const Button = styled.button` line-height: 140%; cursor: pointer; opacity: ${(props) => (props.disabled ? '0.4' : '1')}; + font-size: 16px; - //&:hover { - // border: none; - // cursor: pointer; - // transition: 0.15s; - //} + @media screen and (max-width: 600px) { + padding: 0.575rem 0; + } ` export const IconWrapper = styled.span` display: flex; margin-right: ${(props) => (props.iconPosition === 'right' ? 0 : '0.5rem')}; margin-left: ${(props) => (props.iconPosition === 'left' ? 0 : '0.5rem')}; + + @media screen and (max-width: 600px) { + margin: 0; + } ` diff --git a/client/src/shared/components/Formik/CustomInput/CustomInput.styles.js b/client/src/shared/components/Formik/CustomInput/CustomInput.styles.js index c6c208fc7..62dce2248 100644 --- a/client/src/shared/components/Formik/CustomInput/CustomInput.styles.js +++ b/client/src/shared/components/Formik/CustomInput/CustomInput.styles.js @@ -56,6 +56,11 @@ export const GroupContainer = styled.div` display: flex; flex-basis: 33.3%; flex-direction: column; + + @media screen and (max-width: 768px) { + flex-basis: auto; + width: 100%; + } ` export const SectionContainer = styled.div` @@ -65,6 +70,14 @@ export const SectionContainer = styled.div` align-items: baseline; flex-wrap: wrap; flex: 1; + + @media screen and (max-width: 768px) { + flex-direction: column; + flex-wrap: nowrap; + justify-content: center; + gap: 32px; + flex: 0; + } ` export const InputWithIConWrapper = styled.div` diff --git a/client/src/shared/components/Formik/CustomRadioButtonsGroup/CustomRadioButtonsGroup.jsx b/client/src/shared/components/Formik/CustomRadioButtonsGroup/CustomRadioButtonsGroup.jsx index 4cc29735a..dd2fe26df 100644 --- a/client/src/shared/components/Formik/CustomRadioButtonsGroup/CustomRadioButtonsGroup.jsx +++ b/client/src/shared/components/Formik/CustomRadioButtonsGroup/CustomRadioButtonsGroup.jsx @@ -8,7 +8,7 @@ import { useField, useFormikContext } from 'formik' import { GREEN, WHITE } from '../../../../constants/colors' import { ErrorMessage } from '../../../styles/Tpography.styles' -const CustomRadioButtonsGroup = ({ options, ...props }) => { +const CustomRadioButtonsGroup = ({ options, type = 'text', ...props }) => { const [field, meta] = useField(props) // Grab values and submitForm from context @@ -75,7 +75,7 @@ const CustomRadioButtonsGroup = ({ options, ...props }) => { @@ -83,13 +83,13 @@ const CustomRadioButtonsGroup = ({ options, ...props }) => { { style: { background: '#2F3239', color: 'white' }, duration: 2000, }) - } else { + } else if (error?.response?.data?.length > 1) { let errors = error?.response?.data for (let i = 0; i < errors.length; i++) { @@ -30,5 +30,11 @@ export const errorToaster = (error) => { }) }, i * 300) // Delay each notification by i * 100 milliseconds } + } else { + toast.error('Unkwnown error, try again later!', { + id: 'Unkwnown error, try again later!', + style: { background: '#2F3239', color: 'white' }, + duration: 2000, + }) } } diff --git a/client/src/shared/styles/Global.styles.js b/client/src/shared/styles/Global.styles.js index a15d88758..eeab23488 100644 --- a/client/src/shared/styles/Global.styles.js +++ b/client/src/shared/styles/Global.styles.js @@ -10,9 +10,9 @@ export const GlobalStyle = createGlobalStyle` font-family: 'Rubik', sans-serif !important; } - html { + /* html { background: #26292B !important; - } + } */ body { background: #26292B !important; diff --git a/server/src/maintenance/maintenance.service.ts b/server/src/maintenance/maintenance.service.ts index ea822819b..2ad482fd0 100644 --- a/server/src/maintenance/maintenance.service.ts +++ b/server/src/maintenance/maintenance.service.ts @@ -189,7 +189,7 @@ export class MaintenanceService { initialUser.links = { github: 'https://github.com', linkedIn: 'https://www.linkedin.com/', - instagram: 'https://www.instagram.com/', + behance: 'https://www.behance.com/', telegram: 'https://www.telegram.com/', }; initialUser.programmingLanguages = this.getRandomEntries( diff --git a/server/src/users/dto/links-user.dto.ts b/server/src/users/dto/links-user.dto.ts index 01d610e5d..2157e54c2 100644 --- a/server/src/users/dto/links-user.dto.ts +++ b/server/src/users/dto/links-user.dto.ts @@ -20,14 +20,14 @@ export class LinksUserDto { @ValidateIf(e => e.linkedIn !== '') // check only when blank string not found readonly linkedIn: string; - @ApiProperty({ example: 'https://instagram.com', description: 'Instagram' }) + @ApiProperty({ example: 'https://behance.com', description: 'Behance' }) @IsUrl( - { host_whitelist: [/^.*instagram\.com$/] }, - { message: 'Should be correct linkedin url' }, + { host_whitelist: [/^.*behance\.com$/] }, + { message: 'Should be correct behance url' }, ) @IsOptional() - @ValidateIf(e => e.instagram !== '') // check only when blank string not found - readonly instagram: string; + @ValidateIf(e => e.behance !== '') // check only when blank string not found + readonly behance: string; // TODO: Change later @ApiProperty({ example: 'https://telegram.com', description: 'Telegram' }) diff --git a/server/src/users/dto/update-user.dto.ts b/server/src/users/dto/update-user.dto.ts index a2aa25783..dabdb41ff 100644 --- a/server/src/users/dto/update-user.dto.ts +++ b/server/src/users/dto/update-user.dto.ts @@ -92,7 +92,7 @@ export class UpdateUserDto { example: { github: 'https://github.com', linkedin: 'https://linkedin.com', - instagram: 'https://instagram.com', + behance: 'https://behance.com', telegram: 'https://telegram.com', }, description: 'Links of the user', diff --git a/server/src/users/users.schema.ts b/server/src/users/users.schema.ts index 7128cb064..34bc79fc7 100644 --- a/server/src/users/users.schema.ts +++ b/server/src/users/users.schema.ts @@ -190,7 +190,7 @@ export class User { example: { github: 'https://github.com', linkedin: 'https://linkedin.com', - instagram: 'https://instagram.com', + behance: 'https://behance.com', telegram: 'https://telegram.com', }, description: 'Links of the user', @@ -200,14 +200,14 @@ export class User { type: { github: { type: String }, linkedIn: { type: String }, - instagram: { type: String }, + behance: { type: String }, telegram: { type: String }, }, }) links: { github: string; linkedIn: string; - instagram: string; + behance: string; telegram: string; }; From 75da22495d5146529034796ba606bafd67f7109f Mon Sep 17 00:00:00 2001 From: Nikita Mashchenko Date: Mon, 3 Jul 2023 03:04:01 -0500 Subject: [PATCH 2/5] Fixed images && adaptive for registration --- client/src/api/hooks/auth/useLogoutUser.js | 8 +++ .../src/components/CreateTeam/CreateTeam.js | 54 +++++++------- .../ProfileInfo/ProfileInfo.styles.js | 1 + .../EditingComponentProfile.jsx | 11 +-- .../MultiStepRegistration.jsx | 7 +- .../components/NavLogo/NavLogo.styles.js | 5 ++ .../NavigationButtons/NavigationButtons.jsx | 9 ++- .../InfoForm/TeamInfoForm/TeamInfoForm.jsx | 7 ++ .../InfoForm/UserInfoForm/UserInfoForm.jsx | 7 ++ .../InviteMembersForm/InviteMembersForm.jsx | 72 ++++++++++--------- .../InviteMembersForm.styles.js | 31 ++++++-- .../UserConcentrationForm.jsx | 4 ++ .../UserEducationForm/UserEducationForm.jsx | 32 ++++++--- .../UserJobForm/UserJobForm.jsx | 28 ++++---- .../components/RegistrationPipeline/index.js | 59 ++++++++------- client/src/components/Team/About/About.jsx | 14 ++-- .../TeamProfileMiniCard.jsx | 4 +- .../TeamProfileMiniCard.styles.jsx | 2 + .../Team/TeamsList/TeamsList.styles.js | 2 + .../Teammates/components/UserCard/UserCard.js | 2 +- .../components/UserCard/UserCard.styles.js | 3 +- .../UserProfile/UserProfile.styles.js | 2 + client/src/constants/frameworkColors.js | 4 +- client/src/constants/frameworks.js | 2 +- client/src/hooks/usePrompt.js | 9 ++- client/src/schemas/index.js | 61 ++++++++++++++-- .../CustomSelectAutocomplete.jsx | 57 +++++++++++++-- .../TeamPreviewModal.styles.js | 4 +- .../TeamPreviewModalPhone.styles.jsx | 4 ++ .../components/Toasters/Error.toaster.js | 8 ++- .../components/Toasters/Info.toaster.js | 6 +- server/src/maintenance/maintenance.service.ts | 2 +- 32 files changed, 353 insertions(+), 168 deletions(-) diff --git a/client/src/api/hooks/auth/useLogoutUser.js b/client/src/api/hooks/auth/useLogoutUser.js index 20283241a..73223de04 100644 --- a/client/src/api/hooks/auth/useLogoutUser.js +++ b/client/src/api/hooks/auth/useLogoutUser.js @@ -3,7 +3,9 @@ import { useDispatch } from 'react-redux' import http from '../../../http' import { errorToaster } from '../../../shared/components/Toasters/Error.toaster' +import { infoToaster } from '../../../shared/components/Toasters/Info.toaster' import { userAuth } from '../../../store/reducers/UserAuth' +import { socket } from '../../sockets/notifications.socket' const { api } = http @@ -22,6 +24,10 @@ export const useLogoutUser = () => { localStorage.removeItem('token') dispatch(userAuth.actions.authUserLogout()) + socket.disconnect() + socket.offAnyOutgoing() + socket.offAny() + // remove user data queryClient.setQueryData('checkAuth', () => { return null @@ -30,6 +36,8 @@ export const useLogoutUser = () => { queryClient.setQueryData('getTeamById', () => { return null }) + + infoToaster('Successful logout. See you soon!', 'top-center', 2500) }, onError: (error) => { // set error message diff --git a/client/src/components/CreateTeam/CreateTeam.js b/client/src/components/CreateTeam/CreateTeam.js index 67715b8af..bd96f7b2b 100644 --- a/client/src/components/CreateTeam/CreateTeam.js +++ b/client/src/components/CreateTeam/CreateTeam.js @@ -21,12 +21,7 @@ import InviteMembersForm from '../RegistrationPipeline/components/RegistrationFo function CreateTeam() { const { mutate: updateAvatar, isLoading: isAvatarUpdating } = useUpdateAvatar('teams') - const { - mutate: createTeam, - isLoading: isCreatingTeam, - isError: isCreatingTeamError, - error, - } = useCreateTeam() + const { mutate: createTeam, isLoading: isCreatingTeam } = useCreateTeam() const { data: user, isLoading: isUserLoading } = useCheckAuth() @@ -77,36 +72,43 @@ function CreateTeam() { members: membersModified.members, } - createTeam(teamData, { - onSuccess: (data) => { - if (formData.file) { - updateAvatar( - { teamID: data._id, image: formData.file.split(',')[1] }, - { - onSuccess: (updatedTeam) => { - dispatch(setIsFinishRegistrationStarted(false)) - dispatch(setStep(1)) - navigate(`/team/${updatedTeam.data._id}`) + try { + createTeam(teamData, { + onSuccess: (data) => { + if (formData.file) { + updateAvatar( + { teamID: data._id, image: formData.file.split(',')[1] }, + { + onSuccess: (updatedTeam) => { + dispatch(setIsFinishRegistrationStarted(false)) + dispatch(setStep(1)) + navigate(`/team/${updatedTeam.data._id}`) + }, + onError: (error) => { + errorToaster(error) + }, }, - }, - ) - } - }, - }) - } - - if (isCreatingTeamError && !isCreatingTeam) { - errorToaster(error) + ) + } + }, + onError: (error) => { + errorToaster(error) + }, + }) + } catch (e) { + /* empty */ + } } return ( <> - {(isUserLoading || isCreatingTeam || isAvatarUpdating) && } + {isUserLoading && } ) diff --git a/client/src/components/Profile/components/ProfileInfo/ProfileInfo.styles.js b/client/src/components/Profile/components/ProfileInfo/ProfileInfo.styles.js index ffebad93d..f39e99dbc 100644 --- a/client/src/components/Profile/components/ProfileInfo/ProfileInfo.styles.js +++ b/client/src/components/Profile/components/ProfileInfo/ProfileInfo.styles.js @@ -15,6 +15,7 @@ export const AvatarWrapper = styled.div` export const AvatarImg = styled.img` display: block; border-radius: 50%; + object-fit: cover; width: 100px; height: 100px; user-select: none; diff --git a/client/src/components/Profile/components/ResumeInfo/EditingComponents/EditingComponentProfile.jsx b/client/src/components/Profile/components/ResumeInfo/EditingComponents/EditingComponentProfile.jsx index 80d3c85f9..57e443354 100644 --- a/client/src/components/Profile/components/ResumeInfo/EditingComponents/EditingComponentProfile.jsx +++ b/client/src/components/Profile/components/ResumeInfo/EditingComponents/EditingComponentProfile.jsx @@ -32,19 +32,12 @@ function EditingComponentProfile() { {isActive === 'general' && ( <> - + )} diff --git a/client/src/components/RegistrationPipeline/components/MultiStepRegistration/MultiStepRegistration.jsx b/client/src/components/RegistrationPipeline/components/MultiStepRegistration/MultiStepRegistration.jsx index 0c3c1422d..3a4abf811 100644 --- a/client/src/components/RegistrationPipeline/components/MultiStepRegistration/MultiStepRegistration.jsx +++ b/client/src/components/RegistrationPipeline/components/MultiStepRegistration/MultiStepRegistration.jsx @@ -4,7 +4,6 @@ import { Form, Formik } from 'formik' import { useCheckAuth } from '../../../../api/hooks/auth/useCheckAuth' import FlexWrapper from '../../../../shared/components/FlexWrapper/FlexWrapper' -import Loader from '../../../../shared/components/Loader/Loader' import CurrentStep from '../CurrentStep/CurrentStep' import NavigationButtons from '../NavigationButtons/NavigationButtons' import NavLogo from '../NavLogo/NavLogo' @@ -19,20 +18,18 @@ const MultiStepRegistration = ({ isFinishingRegistration, submitForm, }) => { + console.log(isFinishingRegistration) const [oneOfOptionalFieldsHasValue, setOneOfOptionalFieldsHasValue] = useState(false) const { step, isOptionalStep } = useSelector((state) => state.registrationReducer) const { data: userData, isFetching } = useCheckAuth() + const currentStepData = steps[step - 1] const isLastStep = step === steps.length const handleSubmit = (values) => { submitForm(values, userData) } - // if (isFetching) { - // return - // } - return ( { const dispatch = useDispatch() const navigate = useNavigate() - const { isValid, values } = useFormikContext() + const { isValid, values, dirty } = useFormikContext() const width = useGetScreenWidth() + const { mutate: logoutUser, isLoading: isUserLoggingOut } = useLogoutUser() useEffect(() => { if (isOptionalStep) { @@ -45,6 +47,9 @@ const NavigationButtons = ({ const navigateBack = () => { if (step === 1) { navigate('/') + if (!dirty) { + logoutUser() + } } else { dispatch(setStep(step - 1)) } @@ -92,7 +97,7 @@ const NavigationButtons = ({ } + icon={isFinishingRegistration ? null : } iconPosition="right" background={GREEN.button} > diff --git a/client/src/components/RegistrationPipeline/components/RegistrationForms/InfoForm/TeamInfoForm/TeamInfoForm.jsx b/client/src/components/RegistrationPipeline/components/RegistrationForms/InfoForm/TeamInfoForm/TeamInfoForm.jsx index 5f018838e..c005d55f0 100644 --- a/client/src/components/RegistrationPipeline/components/RegistrationForms/InfoForm/TeamInfoForm/TeamInfoForm.jsx +++ b/client/src/components/RegistrationPipeline/components/RegistrationForms/InfoForm/TeamInfoForm/TeamInfoForm.jsx @@ -1,9 +1,11 @@ import React, { useEffect, useState } from 'react' +import { useFormikContext } from 'formik' import { useGetByTag } from '../../../../../../api/hooks/team/useGetByTag' import { useDebounce } from '../../../../../../api/hooks/temeights/useDebounce' import { countries } from '../../../../../../constants/countries' import { teamTypes } from '../../../../../../constants/teamFormData' +import { usePrompt } from '../../../../../../hooks/usePrompt' import CustomInput from '../../../../../../shared/components/Formik/CustomInput/CustomInput' import { GroupContainer, @@ -15,6 +17,7 @@ import { InputsContainer } from '../InfoForm.styles' const TeamInfoForm = () => { let { mutate: getTeamByTag, data: errorStatus } = useGetByTag() + const { values, dirty } = useFormikContext() // State and setters for ... // Search term @@ -46,6 +49,8 @@ const TeamInfoForm = () => { setSearchTerm(value) // Update the search term state with the input value } + usePrompt('You have unsaved changes. Do you want to discard them?', dirty, false) + return ( <> @@ -59,6 +64,7 @@ const TeamInfoForm = () => { name="country" options={countries} placeholder="Select country" + value={values['country']} /> @@ -80,6 +86,7 @@ const TeamInfoForm = () => { name="type" options={teamTypes} placeholder="Select type" + value={values['type']} /> diff --git a/client/src/components/RegistrationPipeline/components/RegistrationForms/InfoForm/UserInfoForm/UserInfoForm.jsx b/client/src/components/RegistrationPipeline/components/RegistrationForms/InfoForm/UserInfoForm/UserInfoForm.jsx index 436fd181a..f50272b82 100644 --- a/client/src/components/RegistrationPipeline/components/RegistrationForms/InfoForm/UserInfoForm/UserInfoForm.jsx +++ b/client/src/components/RegistrationPipeline/components/RegistrationForms/InfoForm/UserInfoForm/UserInfoForm.jsx @@ -1,10 +1,12 @@ import React, { useEffect, useState } from 'react' import countryList from 'react-select-country-list' +import { useFormikContext } from 'formik' import { useDebounce } from '../../../../../../api/hooks/temeights/useDebounce' import { useValidateUsername } from '../../../../../../api/hooks/user/useValidateUsername' import { countries } from '../../../../../../constants/countries' import { useGetScreenWidth } from '../../../../../../hooks/useGetScreenWidth' +import { usePrompt } from '../../../../../../hooks/usePrompt' import CustomInput from '../../../../../../shared/components/Formik/CustomInput/CustomInput' import { GroupContainer, @@ -16,6 +18,7 @@ import { InputsContainer } from '../InfoForm.styles' const UserInfoForm = () => { let { mutate: validateUsername, data: errorStatus } = useValidateUsername() + const { values, dirty } = useFormikContext() const width = useGetScreenWidth() // State and setters for ... @@ -48,6 +51,9 @@ const UserInfoForm = () => { setSearchTerm(value) // Update the search term state with the input value } + // prevent updating/etc when user has data + usePrompt('You have unsaved changes. Do you want to discard them?', dirty, true) + return ( <> @@ -61,6 +67,7 @@ const UserInfoForm = () => { name="country" options={countries} placeholder="Select country" + value={values['country']} /> diff --git a/client/src/components/RegistrationPipeline/components/RegistrationForms/InviteMembersForm/InviteMembersForm.jsx b/client/src/components/RegistrationPipeline/components/RegistrationForms/InviteMembersForm/InviteMembersForm.jsx index dc3157952..55165310f 100644 --- a/client/src/components/RegistrationPipeline/components/RegistrationForms/InviteMembersForm/InviteMembersForm.jsx +++ b/client/src/components/RegistrationPipeline/components/RegistrationForms/InviteMembersForm/InviteMembersForm.jsx @@ -3,7 +3,8 @@ import { useFormikContext } from 'formik' import AddUserIcon from '../../../../../assets/Shared/AddUserIcon' import DeleteIcon from '../../../../../assets/Shared/DeleteIcon' -import { LOCAL_PATH } from '../../../../../http' +import { useGetScreenWidth } from '../../../../../hooks/useGetScreenWidth' +import FlexWrapper from '../../../../../shared/components/FlexWrapper/FlexWrapper' import SearchUsersAutocomplete from '../../../../../shared/components/SearchUsersAutocomplete/SearchUsersAutocomplete' import { errorToaster } from '../../../../../shared/components/Toasters/Error.toaster' import { ContentContainer } from '../../MultiStepRegistration/MultiStepRegistration.styles' @@ -21,6 +22,7 @@ import { const InviteMembersForm = () => { const [value, setValue] = useState(null) + const width = useGetScreenWidth() const { setFieldValue, setTouched, values } = useFormikContext() @@ -53,43 +55,45 @@ const InviteMembersForm = () => { } return ( - + You can invite up to 7 members to join your team. Send invites now or later.
Team members can be removed as needed.
- - - - - Send invite - - - - {values.members.map((member, index) => { - return ( - - - - {member?.username} - - {index === 0 ? ( - // Render without delete icon for the first user -
- - this is you. - -
- ) : ( - // Render with delete icon for other users -
removeUserFromInviteQueue(member)}> - -
- )} -
- ) - })} -
+ + + + + + Send invite + + + + {values.members.map((member, index) => { + return ( + + + + {member?.username} + + {index === 0 ? ( + // Render without delete icon for the first user +
+ + this is you. + +
+ ) : ( + // Render with delete icon for other users +
removeUserFromInviteQueue(member)}> + +
+ )} +
+ ) + })} +
+
) } diff --git a/client/src/components/RegistrationPipeline/components/RegistrationForms/InviteMembersForm/InviteMembersForm.styles.js b/client/src/components/RegistrationPipeline/components/RegistrationForms/InviteMembersForm/InviteMembersForm.styles.js index 6e6391774..e7f017413 100644 --- a/client/src/components/RegistrationPipeline/components/RegistrationForms/InviteMembersForm/InviteMembersForm.styles.js +++ b/client/src/components/RegistrationPipeline/components/RegistrationForms/InviteMembersForm/InviteMembersForm.styles.js @@ -3,16 +3,27 @@ import styled from 'styled-components' export const InviteFormText = styled.p` color: #fff; font-weight: 400; + + @media screen and (min-width: 769px) and (max-width: 800px) { + margin-bottom: 32px; + } ` export const InviteArea = styled.div` display: flex; gap: 16px; + width: 100%; + max-width: 890px; + + @media screen and (max-width: 600px) { + flex-direction: column; + } ` export const CustomButton = styled.button` - width: 142px; - height: 48px; + max-width: 142px; + width: 100%; + height: 40px; background: #46a11b; border-radius: 10px; @@ -28,10 +39,8 @@ export const CustomButton = styled.button` gap: 6px; - &:hover { - -webkit-transform: scale(1.01); - -ms-transform: scale(1.01); - transform: scale(1.01); + @media screen and (max-width: 600px) { + max-width: 100%; } ` @@ -41,6 +50,12 @@ export const InvitedUsersContainer = styled.div` grid-template-rows: repeat(4, 58px); grid-gap: 16px 30px; /* Adjust the gap between grid items as desired */ grid-auto-flow: dense; /* Fills in empty spaces */ + + @media screen and (max-width: 800px) { + display: flex; + flex-direction: column; + margin-bottom: 52px; + } ` export const InvitedUser = styled.div` @@ -58,6 +73,10 @@ export const InvitedUser = styled.div` cursor: pointer; background: #2f3239; } + + @media screen and (max-width: 800px) { + width: 100%; + } ` export const UserAvatar = styled.img` diff --git a/client/src/components/RegistrationPipeline/components/RegistrationForms/UserConcentrationForm/UserConcentrationForm.jsx b/client/src/components/RegistrationPipeline/components/RegistrationForms/UserConcentrationForm/UserConcentrationForm.jsx index bd2fb33a3..5ed332542 100644 --- a/client/src/components/RegistrationPipeline/components/RegistrationForms/UserConcentrationForm/UserConcentrationForm.jsx +++ b/client/src/components/RegistrationPipeline/components/RegistrationForms/UserConcentrationForm/UserConcentrationForm.jsx @@ -1,10 +1,13 @@ import React from 'react' +import { useFormikContext } from 'formik' import { userConcentrations } from '../../../../../constants/finishRegistrationData' import CustomSelectAutocomplete from '../../../../../shared/components/Formik/CustomSelectAutocomplete/CustomSelectAutocomplete' import { ContentContainer } from '../../MultiStepRegistration/MultiStepRegistration.styles' const UserConcentrationForm = () => { + const { values } = useFormikContext() + return ( {userConcentrations.map((concentration) => ( @@ -14,6 +17,7 @@ const UserConcentrationForm = () => { label={concentration.label} name={concentration.name} options={concentration.options} + value={values[concentration.name]} /> ))} diff --git a/client/src/components/RegistrationPipeline/components/RegistrationForms/UserEducationForm/UserEducationForm.jsx b/client/src/components/RegistrationPipeline/components/RegistrationForms/UserEducationForm/UserEducationForm.jsx index ecfdfb743..f6bac0b78 100644 --- a/client/src/components/RegistrationPipeline/components/RegistrationForms/UserEducationForm/UserEducationForm.jsx +++ b/client/src/components/RegistrationPipeline/components/RegistrationForms/UserEducationForm/UserEducationForm.jsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react' +import React, { useEffect, useState } from 'react' import { useFormikContext } from 'formik' import { degrees } from '../../../../../constants/degrees' @@ -14,6 +14,12 @@ const UserEducationForm = () => { const [checkbox, setCheckbox] = useState(false) const { setFieldValue, values } = useFormikContext() + useEffect(() => { + values && values.universityData[0].graduationDate === '0' + ? setCheckbox(true) + : setCheckbox(false) + }, []) + const handleClick = () => { if (checkbox) { setCheckbox(false) @@ -31,12 +37,14 @@ const UserEducationForm = () => { name="universityData[0].degree" placeholder="Ex: Bachelor’s degree" options={degrees} + value={values['universityData'][0].degree} /> { shouldFormatYear={true} containerWidth="100%" /> - + {values && values.universityData[0].graduationDate !== '0' && ( + + )} { const [checkbox, setCheckbox] = useState(false) const { setFieldValue, values } = useFormikContext() - console.log(values) + useEffect(() => { + values && values.jobData[0].endDate === '0' ? setCheckbox(true) : setCheckbox(false) + }, []) const handleClick = () => { if (checkbox) { @@ -45,16 +47,18 @@ const UserJobForm = () => { shouldFormatYear={true} containerWidth="100%" /> - + {values && values.jobData[0].endDate !== '0' && ( + + )} , name: 'User Profile', isOptional: false }, { component: , name: 'Concentration', isOptional: false }, @@ -94,47 +92,56 @@ function FinishRegistration() { } const submitForm = (formData, userCurrentData) => { - const jobAfterRemovedEmptyFields = removeEmptyFields(formData.jobData[0]) + const initialObject = cloneDeep(formData) + + const jobAfterRemovedEmptyFields = removeEmptyFields(initialObject.jobData[0]) if (jobAfterRemovedEmptyFields) { - let jobDates = convertYearToDate(formData.jobData[0].startDate, formData.jobData[0].endDate) + let jobDates = convertYearToDate( + initialObject.jobData[0].startDate, + initialObject.jobData[0].endDate, + ) - formData.jobData[0].startDate = jobDates.dateOne - formData.jobData[0].endDate = jobDates.dateTwo + initialObject.jobData[0].startDate = jobDates.dateOne + initialObject.jobData[0].endDate = jobDates.dateTwo } else { - formData.jobData = undefined + initialObject.jobData = undefined } - const universityAfterRemovedEmptyFields = removeEmptyFields(formData.universityData[0]) + const universityAfterRemovedEmptyFields = removeEmptyFields(initialObject.universityData[0]) if (universityAfterRemovedEmptyFields) { let universityDates = convertYearToDate( - formData.universityData[0].addmissionDate, - formData.universityData[0].graduationDate, + initialObject.universityData[0].addmissionDate, + initialObject.universityData[0].graduationDate, ) - formData.universityData[0].addmissionDate = universityDates.dateOne - formData.universityData[0].graduationDate = universityDates.dateTwo + initialObject.universityData[0].addmissionDate = universityDates.dateOne + initialObject.universityData[0].graduationDate = universityDates.dateTwo } else { - formData.universityData = undefined + initialObject.universityData = undefined } - formData.links = { - github: formData.github, - telegram: formData.telegram, - linkedIn: formData.linkedIn, - behance: formData.behance, + initialObject.links = { + github: initialObject.github, + telegram: initialObject.telegram, + linkedIn: initialObject.linkedIn, + behance: initialObject.behance, } - formData.dateOfBirth = formatDateString(formData.dateOfBirth) - formData.isRegistered = false - formData.email = userCurrentData.email + initialObject.dateOfBirth = formatDateString(initialObject.dateOfBirth) + initialObject.isRegistered = false + initialObject.email = userCurrentData.email - if (formData.file) { - updateAvatar({ email: userCurrentData.email, image: formData.file.split(',')[1] }) - } + try { + if (initialObject.file) { + updateAvatar({ email: userCurrentData.email, image: initialObject.file.split(',')[1] }) + } - finishRegistration(formData) + finishRegistration(initialObject) + } catch (e) { + /* empty */ + } } return ( diff --git a/client/src/components/Team/About/About.jsx b/client/src/components/Team/About/About.jsx index 7f64d9f93..658fd5355 100644 --- a/client/src/components/Team/About/About.jsx +++ b/client/src/components/Team/About/About.jsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from 'react' -import { Form } from 'formik' +import { Form, useFormikContext } from 'formik' import { useGetByTag } from '../../../api/hooks/team/useGetByTag' import { useDebounce } from '../../../api/hooks/temeights/useDebounce' @@ -11,18 +11,12 @@ import CustomSelectAutocomplete from '../../../shared/components/Formik/CustomSe import CustomTextArea from '../../../shared/components/Formik/CustomTextArea/CustomTextArea' import Loader from '../../../shared/components/Loader/Loader' -import { - EditTeam, - FormContainer, - LabelFieldContainer, - LabelTextFieldContainer, - LeaderActionsBox, - LeaveTeam, -} from './About.styles' +import { FormContainer } from './About.styles' import RegularAbout from './RegularAbout' const About = ({ team, isEditing, setIsEditing, handleOpenDelete }) => { let { mutate: getTeamByTag, data: errorStatus } = useGetByTag() + const { values } = useFormikContext() // State and setters for ... // Search term @@ -73,12 +67,14 @@ const About = ({ team, isEditing, setIsEditing, handleOpenDelete }) => { name="country" options={countries} placeholder="Select country" + value={values['country']} /> diff --git a/client/src/components/Team/TeamProfileMiniCard/TeamProfileMiniCard.jsx b/client/src/components/Team/TeamProfileMiniCard/TeamProfileMiniCard.jsx index ce71fbda0..1670ba94d 100644 --- a/client/src/components/Team/TeamProfileMiniCard/TeamProfileMiniCard.jsx +++ b/client/src/components/Team/TeamProfileMiniCard/TeamProfileMiniCard.jsx @@ -23,7 +23,7 @@ const TeamProfileMiniCard = ({ team, isEditing, setEditImage, actionType, editIm <> -
+
)}
-
+
props.width || '60px'}; height: ${(props) => props.height || '60px'}; border-radius: 50%; + object-fit: cover; + user-select: none; ` export const TeamButton = styled.button` diff --git a/client/src/components/Teammates/components/UserCard/UserCard.js b/client/src/components/Teammates/components/UserCard/UserCard.js index 1dabbc5c8..dfe5cd5fb 100644 --- a/client/src/components/Teammates/components/UserCard/UserCard.js +++ b/client/src/components/Teammates/components/UserCard/UserCard.js @@ -116,7 +116,7 @@ const UserCard = React.forwardRef((props, ref) => { {person.isLeader === true ? ( - crown + crown ) : (
diff --git a/client/src/components/Teammates/components/UserCard/UserCard.styles.js b/client/src/components/Teammates/components/UserCard/UserCard.styles.js index 4491db606..f5d083b78 100644 --- a/client/src/components/Teammates/components/UserCard/UserCard.styles.js +++ b/client/src/components/Teammates/components/UserCard/UserCard.styles.js @@ -18,6 +18,8 @@ export const UserImage = styled.img` width: 70px; height: 70px; border-radius: 5px; + object-fit: cover; + user-select: none; ` export const AndMore = styled.span` @@ -95,7 +97,6 @@ export const Framework = styled.div` font-weight: 400; font-size: 16px; color: ${(props) => props.color || 'white'}; - text-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25); } ` diff --git a/client/src/components/Teammates/components/UserProfile/UserProfile.styles.js b/client/src/components/Teammates/components/UserProfile/UserProfile.styles.js index 26608fb15..25a56965c 100644 --- a/client/src/components/Teammates/components/UserProfile/UserProfile.styles.js +++ b/client/src/components/Teammates/components/UserProfile/UserProfile.styles.js @@ -63,6 +63,8 @@ export const UserImg = styled.img` width: 70px; height: 70px; border-radius: 70px; + object-fit: cover; + user-select: none; ` export const FlagIcon = styled.img` diff --git a/client/src/constants/frameworkColors.js b/client/src/constants/frameworkColors.js index 18a0afdbc..15a1e428b 100644 --- a/client/src/constants/frameworkColors.js +++ b/client/src/constants/frameworkColors.js @@ -2,7 +2,7 @@ const frameworkColors = Object.freeze({ NodeJS: '#5A9E54', Ruby: '#900E04', Angular: '#C3002F', - Android: '#06B75D', + AndroidSDK: '#06B75D', IOS: '#F2F2F2', Hadoop: '#E4E017', Ember: '#E24B31', @@ -20,7 +20,7 @@ const frameworkTextColors = Object.freeze({ NodeJS: 'white', Ruby: 'white', Angular: 'white', - Android: 'white', + AndroidSDK: 'white', IOS: '#1E1E1E', Hadoop: '#1E1E1E', Ember: 'white', diff --git a/client/src/constants/frameworks.js b/client/src/constants/frameworks.js index 0d807d6ac..e13854b6a 100644 --- a/client/src/constants/frameworks.js +++ b/client/src/constants/frameworks.js @@ -2,7 +2,7 @@ const frameworkOptions = [ { label: 'NodeJS', value: 'nodejs' }, { label: 'Ruby', value: 'ruby' }, { label: 'Angular', value: 'angular' }, - { label: 'Android', value: 'android' }, + { label: 'AndroidSDK', value: 'android' }, { label: 'IOS', value: 'ios' }, { label: 'Hadoop', value: 'hadoop' }, { label: 'Ember', value: 'ember' }, diff --git a/client/src/hooks/usePrompt.js b/client/src/hooks/usePrompt.js index d697ee804..a7c199870 100644 --- a/client/src/hooks/usePrompt.js +++ b/client/src/hooks/usePrompt.js @@ -1,11 +1,18 @@ import { useCallback } from 'react' +import { useLogoutUser } from '../api/hooks/auth/useLogoutUser' + import { useBlocker } from './useBlocker' -export function usePrompt(message, when = true) { +export function usePrompt(message, when = true, shouldLogoutAfter = false) { + const { mutate: logoutUser, isLoading: isUserLoggingOut } = useLogoutUser() + const blocker = useCallback( (tx) => { if (window.confirm(message)) { + if (shouldLogoutAfter) { + logoutUser() + } tx.retry() } }, diff --git a/client/src/schemas/index.js b/client/src/schemas/index.js index 56f08d252..9c6291181 100644 --- a/client/src/schemas/index.js +++ b/client/src/schemas/index.js @@ -120,8 +120,8 @@ export const finishRegistrationValidation = [ return false } }) - .matches(/^[aA-zZ\s]+$/, { - message: 'Only alphabets are allowed for this field', + .matches(/^[a-zA-Z0-9\s]+$/, { + message: 'Only alphabets and numbers are allowed for this field', excludeEmptyString: true, }) .nullable(), @@ -142,6 +142,13 @@ export const finishRegistrationValidation = [ message: 'Only numbers are allowed for this field', excludeEmptyString: true, }) + .test('valid-year', 'Year must be between 1901 and current year', function (value) { + if (value) { + return value >= 1901 && value <= new Date().getFullYear() + } + + return true + }) .nullable(), graduationDate: yup .string() @@ -160,6 +167,23 @@ export const finishRegistrationValidation = [ message: 'Only numbers are allowed for this field', excludeEmptyString: true, }) + .test( + 'valid-year', + 'Year must be from 1901 and bigger than addmission', + function (value) { + if (value) { + const { addmissionDate } = this.parent + + if (value === '0') { + return true + } + + return value >= 1901 && addmissionDate < value + } + + return true + }, + ) .nullable(), }), ) @@ -179,8 +203,9 @@ export const finishRegistrationValidation = [ then: yup.string(), otherwise: yup.string().required('Please input your title'), }) - .matches(/^[aA-zZ\s]+$/, { - message: 'Only alphabets are allowed for this field', + .matches(/^[a-zA-Z0-9\s]+$/, { + message: 'Only alphabets and numbers are allowed for this field', + excludeEmptyString: true, }) .nullable(), company: yup @@ -196,8 +221,8 @@ export const finishRegistrationValidation = [ return false } }) - .matches(/^[aA-zZ\s]+$/, { - message: 'Only alphabets are allowed for this field', + .matches(/^[a-zA-Z0-9\s]+$/, { + message: 'Only alphabets and numbers are allowed for this field', excludeEmptyString: true, }) .nullable(), @@ -218,6 +243,13 @@ export const finishRegistrationValidation = [ message: 'Only numbers are allowed for this field', excludeEmptyString: true, }) + .test('valid-year', 'Year must be between 1901 and current year', function (value) { + if (value) { + return value >= 1901 && value <= new Date().getFullYear() + } + + return true + }) .nullable(), endDate: yup .string() @@ -236,6 +268,23 @@ export const finishRegistrationValidation = [ message: 'Only numbers are allowed for this field', excludeEmptyString: true, }) + .test( + 'valid-year', + 'Year must be from 1901 and bigger than addmission', + function (value) { + if (value) { + const { startDate } = this.parent + + if (value === '0') { + return true + } + + return value >= 1901 && startDate < value + } + + return true + }, + ) .nullable(), }), ) diff --git a/client/src/shared/components/Formik/CustomSelectAutocomplete/CustomSelectAutocomplete.jsx b/client/src/shared/components/Formik/CustomSelectAutocomplete/CustomSelectAutocomplete.jsx index 0dbab2362..555ffedcf 100644 --- a/client/src/shared/components/Formik/CustomSelectAutocomplete/CustomSelectAutocomplete.jsx +++ b/client/src/shared/components/Formik/CustomSelectAutocomplete/CustomSelectAutocomplete.jsx @@ -1,5 +1,5 @@ import { Autocomplete, Chip, FormControl, TextField, ThemeProvider } from '@mui/material' -import { useField, useFormikContext } from 'formik' +import { Field, useField, useFormikContext } from 'formik' import ArrowDown from '../../../../assets/Arrows/ArrowDown' import AlertIcon from '../../../../assets/Inputs/AlertIcon' @@ -17,6 +17,7 @@ const CustomSelectAutocomplete = ({ margin, hideLabelOnSelect = false, line = true, + value, ...props }) => { const { setFieldValue, values } = useFormikContext() @@ -28,14 +29,13 @@ const CustomSelectAutocomplete = ({ */ const handleChange = (e, option, reason) => { if (!multiple) { - setFieldValue(field.name, option.label) + setFieldValue(field.name, option) } else { if (reason === 'removeOption') { setFieldValue(field.name, option) } else if (reason === 'selectOption') { - let lastElement = option.pop() - - setFieldValue(field.name, [...values[field.name], lastElement.label]) + console.log(option) + setFieldValue(field.name, option) } } } @@ -45,7 +45,50 @@ const CustomSelectAutocomplete = ({ {!hideLabelOnSelect && label && } - option.label) ?? []} + // isOptionEqualToValue={(option, value) => option.label === value} + value={value ? value : null} + disableClearable + popupIcon={isError ? : } + autoHighlight + getOptionLabel={(option) => option.label ?? option} + multiple={multiple} + onChange={handleChange} + disableCloseOnSelect={multiple ? true : false} + renderTags={(value, getTagProps) => + value.map((option, index) => ( + + )) + } + renderInput={(params) => ( + + )} + /> + {/* )} - /> + /> */} {displayError && isError && {meta.error}} diff --git a/client/src/shared/components/Modal/TeamPreviewModal/TeamPreviewModal.styles.js b/client/src/shared/components/Modal/TeamPreviewModal/TeamPreviewModal.styles.js index 8a3ddf275..4c9bee9e5 100644 --- a/client/src/shared/components/Modal/TeamPreviewModal/TeamPreviewModal.styles.js +++ b/client/src/shared/components/Modal/TeamPreviewModal/TeamPreviewModal.styles.js @@ -36,7 +36,9 @@ export const TeamText = styled.div` export const TeamCardTopIcon = styled.img` width: ${(props) => props.w || '75px'}; height: ${(props) => props.h || '75px'}; - border-radius: ${(props) => props.borderRadius || '50%'}; ; + border-radius: ${(props) => props.borderRadius || '50%'}; + object-fit: cover; + user-select: none; ` export const TypeCountryFlagContainer = styled.div` diff --git a/client/src/shared/components/Modal/TeamPreviewModalPhone/TeamPreviewModalPhone.styles.jsx b/client/src/shared/components/Modal/TeamPreviewModalPhone/TeamPreviewModalPhone.styles.jsx index d7ffc3a4b..4dcabeaa2 100644 --- a/client/src/shared/components/Modal/TeamPreviewModalPhone/TeamPreviewModalPhone.styles.jsx +++ b/client/src/shared/components/Modal/TeamPreviewModalPhone/TeamPreviewModalPhone.styles.jsx @@ -59,6 +59,8 @@ export const TeamImg = styled.img` width: 70px; height: 70px; border-radius: 70px; + object-fit: cover; + user-select: none; ` export const Text = styled.h3` @@ -96,6 +98,8 @@ export const UserImg = styled.img` width: 50px; height: 50px; border-radius: 50px; + object-fit: cover; + user-select: none; @media screen and (max-width: 400px) { width: 40px; diff --git a/client/src/shared/components/Toasters/Error.toaster.js b/client/src/shared/components/Toasters/Error.toaster.js index 17e966ac2..b772113c2 100644 --- a/client/src/shared/components/Toasters/Error.toaster.js +++ b/client/src/shared/components/Toasters/Error.toaster.js @@ -10,7 +10,13 @@ export const errorToaster = (error) => { }) } // Display the toast with the error message - else if (error?.response?.data?.message) { + else if (error?.response?.data?.length === 1 && !error?.response?.data?.message) { + toast.error(error?.response?.data[0], { + id: error?.response?.data[0], + style: { background: '#2F3239', color: 'white' }, + duration: 2000, + }) + } else if (error?.response?.data?.message) { toast.error(error?.response?.data?.message, { id: error?.response?.data?.message, style: { background: '#2F3239', color: 'white' }, diff --git a/client/src/shared/components/Toasters/Info.toaster.js b/client/src/shared/components/Toasters/Info.toaster.js index aef3ce20b..0cfc515a4 100644 --- a/client/src/shared/components/Toasters/Info.toaster.js +++ b/client/src/shared/components/Toasters/Info.toaster.js @@ -1,13 +1,13 @@ import { toast } from 'react-hot-toast' -export const infoToaster = (message) => { +export const infoToaster = (message, position = 'bottom-right', duration = 1000) => { if (typeof message === 'string') { toast(message, { id: message, style: { background: '#2F3239', color: 'white' }, - duration: 1000, + duration: duration, icon: '⚡️', - position: 'bottom-right', + position: position, }) } } diff --git a/server/src/maintenance/maintenance.service.ts b/server/src/maintenance/maintenance.service.ts index 2ad482fd0..cb36bdaa6 100644 --- a/server/src/maintenance/maintenance.service.ts +++ b/server/src/maintenance/maintenance.service.ts @@ -63,7 +63,7 @@ export class MaintenanceService { 'NodeJS', 'Ruby', 'Angular', - 'Android', + 'AndroidSDK', 'IOS', 'Hadoop', 'Ember', From 2ea2add3740f78abb948f317d9e9465684f78be7 Mon Sep 17 00:00:00 2001 From: Nikita Mashchenko Date: Mon, 3 Jul 2023 06:12:14 -0500 Subject: [PATCH 3/5] Small fixes --- .../components/Team/Members/Members.styles.js | 2 ++ client/src/components/Team/NoTeam/NoTeam.jsx | 8 +++--- .../components/Team/NoTeam/NoTeam.styles.jsx | 4 --- .../src/components/Team/TeamForm/TeamForm.js | 28 +++++++++---------- .../Team/TeamForm/TeamForm.styles.js | 2 +- .../Team/TeamsList/TeamsList.styles.js | 4 +++ .../components/NotFound/NotFound.styles.js | 2 +- .../shared/components/Modal/Modal.styles.jsx | 1 + 8 files changed, 27 insertions(+), 24 deletions(-) diff --git a/client/src/components/Team/Members/Members.styles.js b/client/src/components/Team/Members/Members.styles.js index 9ffe81c24..ab8f90ee2 100644 --- a/client/src/components/Team/Members/Members.styles.js +++ b/client/src/components/Team/Members/Members.styles.js @@ -119,6 +119,8 @@ export const UserImg = styled.img` width: 50px; height: 50px; border-radius: 50%; + object-fit: cover; + user-select: none; ` export const CrownContainer = styled.div` diff --git a/client/src/components/Team/NoTeam/NoTeam.jsx b/client/src/components/Team/NoTeam/NoTeam.jsx index 10bb63c59..7e069f150 100644 --- a/client/src/components/Team/NoTeam/NoTeam.jsx +++ b/client/src/components/Team/NoTeam/NoTeam.jsx @@ -45,18 +45,18 @@ function NoTeamForm() { {isUserDataLoading && } {!user?.team && ( -
- + <> + You don't have a team yet! - + You can create a new team or join an existing team. Create Team Join Team -
+ )}
) diff --git a/client/src/components/Team/NoTeam/NoTeam.styles.jsx b/client/src/components/Team/NoTeam/NoTeam.styles.jsx index abf49c9d2..1cc786bba 100644 --- a/client/src/components/Team/NoTeam/NoTeam.styles.jsx +++ b/client/src/components/Team/NoTeam/NoTeam.styles.jsx @@ -1,10 +1,6 @@ import styled from 'styled-components' export const Center = styled.div` - position: absolute; - left: 50%; - top: 50%; - transform: translate(-50%, -50%); display: flex; align-items: center; flex-direction: column; diff --git a/client/src/components/Team/TeamForm/TeamForm.js b/client/src/components/Team/TeamForm/TeamForm.js index 050c34c2a..c56c236d7 100644 --- a/client/src/components/Team/TeamForm/TeamForm.js +++ b/client/src/components/Team/TeamForm/TeamForm.js @@ -122,20 +122,20 @@ function TeamForm() { setModalActive('RemoveMember') } - if ( - isUserTeamLoading || - isDeleting || - isLeaving || - isRemoving || - isTransferring || - isUpdatingTeamsAvatar || - isUpdatingTeam || - isUserDataLoading || - isInviting || - isJoining - ) { - return - } + // if ( + // isUserTeamLoading || + // isDeleting || + // isLeaving || + // isRemoving || + // isTransferring || + // isUpdatingTeamsAvatar || + // isUpdatingTeam || + // isUserDataLoading || + // isInviting || + // isJoining + // ) { + // return + // } if ((!isUserTeamLoading && !team) || error) { return diff --git a/client/src/components/Team/TeamForm/TeamForm.styles.js b/client/src/components/Team/TeamForm/TeamForm.styles.js index 1bb9dba28..7531dead0 100644 --- a/client/src/components/Team/TeamForm/TeamForm.styles.js +++ b/client/src/components/Team/TeamForm/TeamForm.styles.js @@ -8,7 +8,7 @@ export const Container = styled.div` min-height: 100vh; display: flex; flex-direction: column; - justify-content: start; + justify-content: center; align-items: center; background: ${BLACK.background}; padding-left: 88px; diff --git a/client/src/components/Team/TeamsList/TeamsList.styles.js b/client/src/components/Team/TeamsList/TeamsList.styles.js index 6290c2b9b..319f408d2 100644 --- a/client/src/components/Team/TeamsList/TeamsList.styles.js +++ b/client/src/components/Team/TeamsList/TeamsList.styles.js @@ -141,4 +141,8 @@ export const NotFoundContainer = styled.div` min-height: calc(100vh - 238px); /* height: 100%; */ padding-left: 88px; + + @media screen and (max-width: 768px) { + padding-left: 0px; + } ` diff --git a/client/src/components/Teammates/components/NotFound/NotFound.styles.js b/client/src/components/Teammates/components/NotFound/NotFound.styles.js index 029bafb65..c55cabeb7 100644 --- a/client/src/components/Teammates/components/NotFound/NotFound.styles.js +++ b/client/src/components/Teammates/components/NotFound/NotFound.styles.js @@ -8,7 +8,7 @@ export const Container = styled.div` align-items: center; margin-bottom: 70px; - @media screen and (min-width: 0) and (max-width: 980px) { + @media screen and (max-width: 980px) { display: flex; flex-direction: column; } diff --git a/client/src/shared/components/Modal/Modal.styles.jsx b/client/src/shared/components/Modal/Modal.styles.jsx index d3d01841e..f6641f03b 100644 --- a/client/src/shared/components/Modal/Modal.styles.jsx +++ b/client/src/shared/components/Modal/Modal.styles.jsx @@ -59,6 +59,7 @@ export const Button = styled.button` justify-content: center; align-items: center; cursor: pointer; + gap: 4px; transition: all 0.2s; &:hover { transform: translateY(-2px); From 209e85be7b1e0d64a50ea1987aa077aca1ad57bc Mon Sep 17 00:00:00 2001 From: Nikita Mashchenko Date: Mon, 3 Jul 2023 06:29:23 -0500 Subject: [PATCH 4/5] Update github-actions-demo.yml --- .github/workflows/github-actions-demo.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/github-actions-demo.yml b/.github/workflows/github-actions-demo.yml index 33c6c45c7..94825f830 100644 --- a/.github/workflows/github-actions-demo.yml +++ b/.github/workflows/github-actions-demo.yml @@ -29,6 +29,7 @@ jobs: echo AWS_ACCESS_KEY=${{ secrets.AWS_ACCESS_KEY }} >> .dev.env echo AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }} >> .dev.env echo AWS_S3_REGION=${{ secrets.AWS_S3_REGION }} >> .dev.env + echo AWS_S3_BUCKET=${{ secrets.AWS_S3_BUCKET }} >> .dev.env cat .dev.env - name: 🎧 Install modules working-directory: ./server From 1bcdf3812faa32c0bc997c08fdffad627133032e Mon Sep 17 00:00:00 2001 From: Nikita Mashchenko Date: Mon, 3 Jul 2023 06:58:23 -0500 Subject: [PATCH 5/5] Added heartbeat --- server/src/maintenance/maintenance.controller.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/server/src/maintenance/maintenance.controller.ts b/server/src/maintenance/maintenance.controller.ts index d68d62b72..073032c03 100644 --- a/server/src/maintenance/maintenance.controller.ts +++ b/server/src/maintenance/maintenance.controller.ts @@ -70,4 +70,11 @@ export class MaintenanceController { return this.maintenanceService.dropDatabase(); else return { status: 'Not authorized to make this request.' }; } + + @Get('/heartbeat') + async getHeartBeat(): Promise { + return { + status: 'All systems are up and working. Have a good day! ⚡️', + }; + } }