From 43c5e36953968b12985630f759794ed4e9a77353 Mon Sep 17 00:00:00 2001 From: Jadowacu1 <152473876+Jadowacu1@users.noreply.github.com> Date: Thu, 4 Jul 2024 14:33:57 +0200 Subject: [PATCH] Users should be presented with a reset password link --- .eslintrc.json | 12 +- package-lock.json | 53 +++++++- package.json | 3 + src/App.scss | 1 + src/App.tsx | 3 +- src/components/layout/Footer.tsx | 2 +- src/components/layout/Header.tsx | 2 +- src/index.tsx | 2 +- src/pages/LandingPage.tsx | 1 - src/pages/NotFound.tsx | 2 +- src/pages/ResetPassword.tsx | 68 ++++++++++ src/pages/SendResetPasswordLink.tsx | 26 ++++ src/router.tsx | 7 +- src/styles/LandingPage.scss | 12 -- src/styles/colors.scss | 4 + src/styles/reset-password.scss | 189 ++++++++++++++++++++++++++++ 16 files changed, 360 insertions(+), 27 deletions(-) create mode 100644 src/App.scss create mode 100644 src/pages/ResetPassword.tsx create mode 100644 src/pages/SendResetPasswordLink.tsx delete mode 100644 src/styles/LandingPage.scss create mode 100644 src/styles/colors.scss create mode 100644 src/styles/reset-password.scss diff --git a/.eslintrc.json b/.eslintrc.json index 11badfe4..2e281462 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -16,9 +16,10 @@ "airbnb-typescript", "plugin:react/recommended", "plugin:@typescript-eslint/recommended", + "plugin:jsx-a11y/recommended", "plugin:storybook/recommended" ], - "ignorePatterns":["jest.config.ts"], + "ignorePatterns": ["jest.config.ts"], "rules": { "react-hooks/rules-of-hooks": "error", "react-hooks/exhaustive-deps": "warn", @@ -58,7 +59,12 @@ "no-param-reassign": "off", "arrow-body-style": ["warn", "as-needed"], "jsx-a11y/no-static-element-interactions": "off", - "max-len": "off" + "max-len": "off", + "jsx-a11y/label-has-associated-control": ["error", { + "required": { + "some": ["nesting", "id"] + } + }] }, "settings": { "react": { @@ -72,4 +78,4 @@ } } } -} \ No newline at end of file +} diff --git a/package-lock.json b/package-lock.json index ec8bfd62..4a00c666 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,9 @@ "name": "e-commerce-ninjas-frontend", "version": "0.0.1", "dependencies": { + "@fortawesome/fontawesome-svg-core": "^6.5.2", + "@fortawesome/free-solid-svg-icons": "^6.5.2", + "@fortawesome/react-fontawesome": "^0.2.2", "@reduxjs/toolkit": "^2.2.5", "axios": "^1.7.2", "html-webpack-plugin": "^5.6.0", @@ -2725,6 +2728,51 @@ "integrity": "sha512-cEee/Z+I12mZcFJshKcCqC8tuX5hG3s+d+9nZ3LabqKF1vKdF41B92pJVCBggjAGORAeOzyyDDKrZwIkLffeOQ==", "dev": true }, + "node_modules/@fortawesome/fontawesome-common-types": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.2.tgz", + "integrity": "sha512-gBxPg3aVO6J0kpfHNILc+NMhXnqHumFxOmjYCFfOiLZfwhnnfhtsdA2hfJlDnj+8PjAs6kKQPenOTKj3Rf7zHw==", + "hasInstallScript": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/fontawesome-svg-core": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.5.2.tgz", + "integrity": "sha512-5CdaCBGl8Rh9ohNdxeeTMxIj8oc3KNBgIeLMvJosBMdslK/UnEB8rzyDRrbKdL1kDweqBPo4GT9wvnakHWucZw==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.5.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-solid-svg-icons": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.5.2.tgz", + "integrity": "sha512-QWFZYXFE7O1Gr1dTIp+D6UcFUF0qElOnZptpi7PBUMylJh+vFmIedVe1Ir6RM1t2tEQLLSV1k7bR4o92M+uqlw==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.5.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/react-fontawesome": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.2.tgz", + "integrity": "sha512-EnkrprPNqI6SXJl//m29hpaNzOp1bruISWaOiRtkMi/xSvHJlzc2j2JAYS7egxt/EbjSNV/k6Xy0AQI6vB2+1g==", + "dependencies": { + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "@fortawesome/fontawesome-svg-core": "~1 || ~6", + "react": ">=16.3" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -18776,7 +18824,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -19788,7 +19835,6 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -20095,8 +20141,7 @@ "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/react-redux": { "version": "9.1.2", diff --git a/package.json b/package.json index f87243ab..2315c272 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,9 @@ "build-storybook": "storybook build" }, "dependencies": { + "@fortawesome/fontawesome-svg-core": "^6.5.2", + "@fortawesome/free-solid-svg-icons": "^6.5.2", + "@fortawesome/react-fontawesome": "^0.2.2", "@reduxjs/toolkit": "^2.2.5", "axios": "^1.7.2", "html-webpack-plugin": "^5.6.0", diff --git a/src/App.scss b/src/App.scss new file mode 100644 index 00000000..3235feb2 --- /dev/null +++ b/src/App.scss @@ -0,0 +1 @@ +@import '../src/styles/reset-password.scss' \ No newline at end of file diff --git a/src/App.tsx b/src/App.tsx index abd182e0..09b2a6e8 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { BrowserRouter as Router } from 'react-router-dom'; import AppRouter from './router'; +import './App.scss'; const App: React.FC = () => ( @@ -9,4 +10,4 @@ const App: React.FC = () => ( ); -export default App; \ No newline at end of file +export default App; diff --git a/src/components/layout/Footer.tsx b/src/components/layout/Footer.tsx index 2708ec45..9b7dba47 100644 --- a/src/components/layout/Footer.tsx +++ b/src/components/layout/Footer.tsx @@ -14,4 +14,4 @@ const Footer: React.FC = () => ( ); -export default Footer; \ No newline at end of file +export default Footer; diff --git a/src/components/layout/Header.tsx b/src/components/layout/Header.tsx index bd999e16..fec0e12e 100644 --- a/src/components/layout/Header.tsx +++ b/src/components/layout/Header.tsx @@ -14,4 +14,4 @@ const Header: React.FC = () => ( ); -export default Header; \ No newline at end of file +export default Header; diff --git a/src/index.tsx b/src/index.tsx index 7b2dfb30..73e45fc4 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -10,4 +10,4 @@ root.render( -); \ No newline at end of file +); diff --git a/src/pages/LandingPage.tsx b/src/pages/LandingPage.tsx index 884a4781..5f386c30 100644 --- a/src/pages/LandingPage.tsx +++ b/src/pages/LandingPage.tsx @@ -4,7 +4,6 @@ import { loadWelcomeMessage } from '../store/features/welcomeSlice'; import { IWelcomeMessage } from '../utils/types/store'; import Header from '../components/layout/Header'; import Footer from '../components/layout/Footer'; -import '../styles/LandingPage.scss'; const LandingPage: React.FC = () => { const dispatch = useAppDispatch(); diff --git a/src/pages/NotFound.tsx b/src/pages/NotFound.tsx index 8001f6e6..4438fa1c 100644 --- a/src/pages/NotFound.tsx +++ b/src/pages/NotFound.tsx @@ -7,4 +7,4 @@ const NotFound: React.FC = () => ( ); -export default NotFound; \ No newline at end of file +export default NotFound; diff --git a/src/pages/ResetPassword.tsx b/src/pages/ResetPassword.tsx new file mode 100644 index 00000000..c1cb3482 --- /dev/null +++ b/src/pages/ResetPassword.tsx @@ -0,0 +1,68 @@ +import React, { useState } from 'react'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faEye, faEyeSlash } from '@fortawesome/free-solid-svg-icons'; +import Button from '../components/buttons/Button'; +import Header from '../components/layout/Header'; + +const ResetPassword: React.FC = () => { + const [showNewPassword, setShowNewPassword] = useState(false); + const [showConfirmPassword, setShowConfirmPassword] = useState(false); + + const newPasswordVisibility = () => { + setShowNewPassword(!showNewPassword); + }; + + const confirmPasswordVisibility = () => { + setShowConfirmPassword(!showConfirmPassword); + }; + + return ( +
+
+
+

Reset password

+
+
+ + + +
+
+ + + +
+
+
+
+
+
+ ); +}; + +export default ResetPassword; diff --git a/src/pages/SendResetPasswordLink.tsx b/src/pages/SendResetPasswordLink.tsx new file mode 100644 index 00000000..dd33e27d --- /dev/null +++ b/src/pages/SendResetPasswordLink.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import Header from '../components/layout/Header'; +import Button from '../components/buttons/Button'; + +const SendResetPasswordLink:React.FC = () => ( + <> +
+
+
+

Get Reset Password Link

+ +
+ + +
+ +
+
+ +
+
+ +); + +export default SendResetPasswordLink; diff --git a/src/router.tsx b/src/router.tsx index 8809600d..f9805a44 100644 --- a/src/router.tsx +++ b/src/router.tsx @@ -5,6 +5,8 @@ import { Route, Routes } from 'react-router-dom'; import LandingPage from './pages/LandingPage'; import Login from './pages/Login'; import NotFound from './pages/NotFound'; +import SendResetPasswordLink from './pages/SendResetPasswordLink'; +import ResetPassword from './pages/ResetPassword'; const AppRouter: React.FC = () => { return ( @@ -12,10 +14,11 @@ const AppRouter: React.FC = () => { } /> } /> + } /> + } /> } /> ); }; - -export default AppRouter; \ No newline at end of file +export default AppRouter; diff --git a/src/styles/LandingPage.scss b/src/styles/LandingPage.scss deleted file mode 100644 index e26b291c..00000000 --- a/src/styles/LandingPage.scss +++ /dev/null @@ -1,12 +0,0 @@ -$primary-color: #FF6D18; - -.landingPage { - background: $primary-color; - color: white; - padding: 20px; - - h1 { - font-size: 2em; - margin-bottom: 10px; - } -} diff --git a/src/styles/colors.scss b/src/styles/colors.scss new file mode 100644 index 00000000..4d38928f --- /dev/null +++ b/src/styles/colors.scss @@ -0,0 +1,4 @@ +$primary-color: #FF6D18; +$button-bg-color: #FF6D18; +$button-text-color: #fff; +$text-color: #000000; \ No newline at end of file diff --git a/src/styles/reset-password.scss b/src/styles/reset-password.scss new file mode 100644 index 00000000..1240c1ad --- /dev/null +++ b/src/styles/reset-password.scss @@ -0,0 +1,189 @@ +@import "../styles//colors.scss"; +$fontFamily: "Averia Serif Libre"; +$button-font-size: 16px; +$button-border-radius: 10px; +$button-hover-bg-color: darken($button-bg-color, 10%); +$button-font-weight: bold; +$button-font-family: Arial, sans-serif; + +.landingPage { + background: $primary-color; + color: white; + padding: 20px; + + h1 { + font-size: 2em; + margin-bottom: 10px; + } +} +.resetPassword-Container { + display: flex; + flex-direction: column; + gap: 20px; + align-items: center; + margin-top: 100px; + + h1{ + color: $text-color; + font-family: $fontFamily; + font-size: 3rem; + } + + .input-container { + position: relative; + margin: 1rem 0; + + .input-label { + position: absolute; + top: 50%; + left: 0.75rem; + transform: translateY(-50%); + background: white; + padding: 0 0.25rem; + color: #6c6c6c; + font-family: 'Georgia', serif; + font-weight: bold; + font-size: 1rem; + transition: all 0.3s ease; + } + + .input-field { + width: 30vw; + height: 5vh; + border: 2px solid #f5a773; + border-radius: 0.25rem; + font-size: 1rem; + outline: none; + font-family: inherit; + font-weight: inherit; + + &:focus + .input-label, + &:not(:placeholder-shown) + .input-label { + top: 0; + left: 0.5rem; + font-size: 0.75rem; + color: #6c6c6c; + } + } + } + + .reset-Button button { + background-color: $button-bg-color; + color: $button-text-color; + font-size: $button-font-size; + width: 30vw; + height: 5vh; + border: none; + border-radius: $button-border-radius; + cursor: pointer; + text-align: center; + text-decoration: none; + display: inline-block; + font-weight: $button-font-weight; + font-family: $button-font-family; + &:hover { + background-color: $button-hover-bg-color; + } + } +} + +.resetPasswordForm { + display: flex; + flex-direction: column; + align-items: center; + gap: 10px; + + h1 { + color: $text-color; + font-family: $fontFamily; + font-size: 3rem; + } + + .input-containers { + margin-top: 30px; + display: flex; + flex-direction: column; + gap: 5px; + + .input-container1, .input-container2 { + position: relative; + margin: 1rem 0; + + .input-label1, .input-label2 { + position: absolute; + top: 50%; + left: 0.75rem; + transform: translateY(-50%); + background: white; + padding: 0 0.25rem; + color: #6c6c6c; + font-family: 'Georgia', serif; + font-weight: bold; + font-size: 1rem; + transition: all 0.3s ease; + } + + .input-field1, .input-field2 { + width: 30vw; + height: 5vh; + border: 2px solid #f5a773; + border-radius: 0.25rem; + font-size: 1rem; + outline: none; + font-family: inherit; + font-weight: inherit; + + &:focus + .input-label1, + &:not(:placeholder-shown) + .input-label1, + &:focus + .input-label2, + &:not(:placeholder-shown) + .input-label2 { + top: 0; + left: 0.5rem; + font-size: 0.75rem; + color: #6c6c6c; + } + } + } + } + + .reset-Button button { + background-color: $button-bg-color; + color: $button-text-color; + font-size: $button-font-size; + width: 30vw; + height: 5vh; + border: none; + border-radius: $button-border-radius; + cursor: pointer; + text-align: center; + text-decoration: none; + display: inline-block; + font-weight: $button-font-weight; + font-family: $button-font-family; + + &:hover { + background-color: $button-hover-bg-color; + } + } +} + +.resetPasswordForm { + .input-containers { + .input-container1, + .input-container2 { + position: relative; + + .toggle-password { + position: absolute; + color: #777777; + top: 50%; + right: 10px; + transform: translateY(-50%); + background: none; + border: none; + cursor: pointer; + outline: none; + } + } + } +} \ No newline at end of file