From 35fd7c10f9c2b57a926394fe392e075cf4273483 Mon Sep 17 00:00:00 2001 From: Li Ying Kwa <41922935+liying-kwa@users.noreply.github.com> Date: Sun, 19 May 2024 11:09:38 +0800 Subject: [PATCH 1/2] Implement password validator new design (#158) --- .../components/registration-form.tsx | 96 +++++++++++++++++-- src/utilities/validators.ts | 19 +++- 2 files changed, 106 insertions(+), 9 deletions(-) diff --git a/src/features/registration/components/registration-form.tsx b/src/features/registration/components/registration-form.tsx index 405e795..1585f88 100644 --- a/src/features/registration/components/registration-form.tsx +++ b/src/features/registration/components/registration-form.tsx @@ -6,6 +6,9 @@ import { Text, VStack, Input, + Center, + Icon, + HStack, } from "@chakra-ui/react"; import { ViewIcon, ViewOffIcon } from "@chakra-ui/icons"; import { useState } from "react"; @@ -15,8 +18,13 @@ import { // DoPasswordsMatch, IsValidEmail, IsValidName, + PasswordContainsLowercase, + PasswordContainsNumber, + PasswordContainsSymbol, + PasswordContainsUppercase, } from "../../../utilities/validators"; import SignIn from "./sign-in"; +import { ImCheckboxChecked, ImCross } from 'react-icons/im' export default function RegistrationForm() { const [input, setInput] = useState({ @@ -31,7 +39,7 @@ export default function RegistrationForm() { givenName: "", famName: "", email: "", - password: "", + password: { text: "", numChecked: 0, color: "", checks: { "Minimum length": false, "Number": false, "Symbol": false, "Uppercase": false, "Lowercase": false } }, confirmPassword: "", valid: false, }); @@ -63,7 +71,12 @@ export default function RegistrationForm() { const validateInput = (event: any) => { let { name, value } = event.target; setError((prev) => { - const errorState = { ...prev, [name]: "" }; + let errorState; + if (name == "password") { + errorState = { ...prev } + } else { + errorState = { ...prev, [name]: "" }; + } errorState.valid = canEnableSignUpButton(); switch (name) { @@ -90,12 +103,65 @@ export default function RegistrationForm() { // case "confirmPassword": setNoText(typeof value != "undefined" && value.length < 1); - if (input.password && !IsPasswordMinLength(value)) { - errorState.password = - "Password must have a minimum of 8 characters, contain numbers, symbols, uppercase and lowercase characters."; + errorState.password.text = "Strong, your password is secure 💪"; + errorState.password.checks = { "Minimum length": true, "Number": true, "Symbol": true, "Uppercase": true, "Lowercase": true }; + + let numChecked = 5; + + if (!PasswordContainsSymbol(value)) { + errorState.password.text = "Almost there, add a special symbol 😉" + errorState.password.checks["Symbol"] = false errorState.valid = false; - } else { - errorState.password = ""; + numChecked -= 1; + } + + if (!PasswordContainsNumber(value)) { + errorState.password.text = "So-so, should be alphanumeric 😕" + errorState.password.checks["Number"] = false + errorState.valid = false; + numChecked -= 1; + } + + if (!PasswordContainsUppercase(value)) { + errorState.password.text = + "Weak, must have at one uppercase and lowercase letter 😖"; + errorState.password.checks["Uppercase"] = false + errorState.valid = false; + numChecked -= 1; + } + + if (!PasswordContainsLowercase(value)) { + errorState.password.text = + "Weak, must have at one uppercase and lowercase letter 😖"; + errorState.password.checks["Lowercase"] = false + errorState.valid = false; + numChecked -= 1; + } + + if (!IsPasswordMinLength(value)) { + errorState.password.text = + "Must have at least 8 characters."; + errorState.password.checks["Minimum length"] = false + errorState.valid = false; + numChecked -= 1; + } + + errorState.password.numChecked = numChecked; + switch (numChecked) { + case 1: + errorState.password.color = "red"; + break; + case 2: + case 3: + errorState.password.color = "yellow.300"; + break; + case 4: + errorState.password.color = "blue"; + break; + case 5: + default: + errorState.password.color = "green.400"; + break; } // if (!DoPasswordsMatch(input.password, value)) { @@ -167,7 +233,21 @@ export default function RegistrationForm() { - {error.password && {error.password}} + + +
+ + {error.password.text} + + {[...Array(error.password.numChecked)].map(() => )} + {[...Array(5 - error.password.numChecked)].map(() => )} + + + {Object.entries(error.password.checks).map(([item, checked]) => ( + {item} + ))} + +
{/* Confirm Password diff --git a/src/utilities/validators.ts b/src/utilities/validators.ts index 085d4c4..013e80a 100644 --- a/src/utilities/validators.ts +++ b/src/utilities/validators.ts @@ -11,7 +11,24 @@ export function IsPasswordMinLength(password: string) { // var letter = /[a-zA-Z]/; // var number = /[0-9]/; // var valid = number.test(password) && letter.test(password); //match a letter _and_ a number - return /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$/.test(password) && password.length >= 8; + // return /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$/.test(password) && password.length >= 8; + return password.length >= 8; +} + +export function PasswordContainsNumber(password: string) { + return /^(?=.*?[0-9]).+$/.test(password); +} + +export function PasswordContainsSymbol(password: string) { + return /^(?=.*?[#?!@$%^&*-]).+$/.test(password); +} + +export function PasswordContainsUppercase(password: string) { + return /^(?=.*?[A-Z]).+$/.test(password); +} + +export function PasswordContainsLowercase(password: string) { + return /^(?=.*?[a-z]).+$/.test(password); } From d29d2451dfa819645b65ff5e898c2be606f93125 Mon Sep 17 00:00:00 2001 From: karthik-Jay <32955712+karthik-Jay@users.noreply.github.com> Date: Sun, 9 Jun 2024 17:04:58 +0800 Subject: [PATCH 2/2] Feature/refactor code (#164) * Refactor code * Update to use theme folder structure. (#161) * Update AuthProvider import statement in App.tsx * Fix for import casing errors. * Further file fixes due to casing errors. * More fixes to resolve file case errors. --------- Co-authored-by: Sinthusan --- src/App.tsx | 49 ++-- src/assets/icons/link.svg | 4 +- .../Breadcrumbs/Breadcrumbs.tsx} | 15 +- src/components/Breadcrumbs/index.ts | 1 + src/components/Container/Container.tsx | 10 + src/components/Container/index.ts | 1 + src/components/Footer/Footer.tsx | 196 ++++++++++++++++ src/components/Footer/index.ts | 1 + src/components/Header/Header.tsx | 142 ++++++++++++ src/components/Header/index.ts | 1 + .../NavigationButton}/NavigationButton.tsx | 0 src/components/NavigationButton/index.ts | 1 + .../ScrollAnimation}/ScrollAnimation.tsx | 0 src/components/ScrollAnimation/index.ts | 1 + src/data/auth/authContext.tsx | 4 +- .../organisationProfileOurStory.ts | 7 +- src/data/model/organisationSummary.ts | 2 +- src/data/model/user.ts | 5 +- src/features/common/NavigationBar.tsx | 135 ----------- src/features/common/footer.tsx | 194 ---------------- .../firestore-mock/test-data/users.json | 13 -- src/features/home/components/FrontPage.tsx | 70 ------ src/features/home/components/FrontSupport.tsx | 119 ---------- src/features/home/index.tsx | 214 ------------------ .../login/components/email-credential.tsx | 59 ----- .../login/components/forgot-password.tsx | 14 -- .../components/google-sign-in-button.tsx | 50 ---- .../login/components/login-menu-message.tsx | 28 --- .../login/components/login-section.tsx | 32 --- .../login/components/sign-in-button.tsx | 55 ----- src/features/login/login-page.tsx | 19 -- .../components/ViewToggle.tsx | 53 ----- .../components/services.tsx | 70 ------ .../components/summary.tsx | 147 ------------ src/features/page-style.scss | 18 -- .../FirestoreMock.tsx} | 44 ++-- .../InitialOrganisationsMock.ts} | 38 ++-- .../QuillEditor.tsx} | 0 .../TestOrganisationsMock.ts} | 42 ++-- src/mocks/UsersMock.ts | 13 ++ src/pages/Home/HeroSection.tsx | 74 ++++++ src/pages/Home/Home.tsx | 149 ++++++++++++ src/pages/Home/SupportSection.tsx | 126 +++++++++++ src/pages/Home/TogetherSection.tsx | 53 +++++ src/pages/Home/index.ts | 1 + src/{features/home => pages/Home}/styles.ts | 0 src/pages/Login/EmailCredential.tsx | 60 +++++ src/pages/Login/ForgotPassword.tsx | 17 ++ src/pages/Login/GoogleSignInButton.tsx | 52 +++++ src/pages/Login/Login.tsx | 19 ++ .../Login/LoginDesign.tsx} | 0 .../Login/LoginForm.tsx} | 8 +- src/pages/Login/LoginMenuMessage.tsx | 18 ++ .../Login/LoginSection.tsx} | 20 +- src/pages/Login/SignInButton.tsx | 57 +++++ .../sign-up.tsx => pages/Login/SignUp.tsx} | 2 +- src/pages/Login/index.ts | 1 + .../login.scss => pages/Login/style.scss} | 2 - .../OrganisationList}/CardView.tsx | 6 +- .../OrganisationList/Const.ts} | 0 .../OrganisationList}/ListView.tsx | 16 +- .../OrganisationList/NavigationBar.tsx} | 0 .../OrganisationList/OrganisationCard.tsx} | 6 +- .../OrganisationList/OrganisationList.tsx} | 96 ++++---- src/pages/OrganisationList/ViewToggle.tsx | 88 +++++++ src/pages/OrganisationList/index.ts | 1 + .../OrganisationProfile.tsx} | 28 +-- .../OrganisationProfile/Profile.tsx} | 96 ++++---- .../OrganisationProfile/ProfileContent.tsx} | 2 +- .../OrganisationProfile/ProfileSidebar.tsx} | 0 src/pages/OrganisationProfile/Services.tsx | 70 ++++++ .../SimilarOrganisations.tsx} | 14 +- src/pages/OrganisationProfile/Summary.tsx | 150 ++++++++++++ src/pages/OrganisationProfile/index.ts | 1 + .../OrganisationProfile}/profile.scss | 3 - .../OrganisationProfile}/services.scss | 5 - .../OrganisationProfile}/similar-orgs.scss | 0 .../OrganisationProfile}/summary.scss | 0 .../Registration/GoalsForm.tsx} | 13 +- .../Registration/OrganisationInfoForm.tsx} | 18 +- .../Registration/ProfileSetup.tsx} | 16 +- .../Registration/Registration.tsx} | 10 +- .../Registration/RegistrationDesign.tsx} | 4 +- .../Registration/RegistrationForm.tsx} | 89 +++++--- .../Registration/RegistrationMenuMessage.tsx} | 4 +- .../Registration/RegistrationSection.tsx | 37 +++ .../Registration/SignIn.tsx} | 8 +- .../Registration/SignUpButton.tsx} | 14 +- .../Registration/SignUpWaiting.tsx} | 24 +- src/pages/Registration/index.ts | 1 + .../Registration}/registration.scss | 2 - .../scss => pages/Registration}/setup.scss | 2 - .../UserDashboard/UserDashboard.tsx} | 7 +- src/pages/UserDashboard/index.ts | 1 + src/pages/style.scss | 15 ++ src/{paths.ts => routing/Paths.ts} | 0 src/routing/Routing.tsx | 29 +++ src/routing/index.ts | 1 + src/services/Authentication.ts | 11 +- .../{http-common.ts => HttpCommon.ts} | 0 src/services/firebase/authProvider.tsx | 101 +++++---- src/theme.ts | 48 ---- src/theme/colours.ts | 27 +++ src/theme/components/accordion.ts | 31 +++ src/theme/components/table.ts | 27 +++ src/theme/index.ts | 20 ++ src/theme/styles.ts | 32 +++ src/theme/typography.ts | 125 ++++++++++ src/utilities/icon-mappings.tsx | 61 ----- src/utilities/iconMappings/iconMapping.tsx | 61 +++++ src/utilities/iconMappings/index.ts | 1 + src/utilities/validators/index.ts | 9 + src/utilities/{ => validators}/validators.ts | 0 113 files changed, 2146 insertions(+), 1811 deletions(-) rename src/{features/common/orgBreadCrumb.tsx => components/Breadcrumbs/Breadcrumbs.tsx} (83%) create mode 100644 src/components/Breadcrumbs/index.ts create mode 100644 src/components/Container/Container.tsx create mode 100644 src/components/Container/index.ts create mode 100644 src/components/Footer/Footer.tsx create mode 100644 src/components/Footer/index.ts create mode 100644 src/components/Header/Header.tsx create mode 100644 src/components/Header/index.ts rename src/{features/home/components => components/NavigationButton}/NavigationButton.tsx (100%) create mode 100644 src/components/NavigationButton/index.ts rename src/{features/home/components => components/ScrollAnimation}/ScrollAnimation.tsx (100%) create mode 100644 src/components/ScrollAnimation/index.ts delete mode 100644 src/features/common/NavigationBar.tsx delete mode 100644 src/features/common/footer.tsx delete mode 100644 src/features/firestore-mock/test-data/users.json delete mode 100644 src/features/home/components/FrontPage.tsx delete mode 100644 src/features/home/components/FrontSupport.tsx delete mode 100644 src/features/home/index.tsx delete mode 100644 src/features/login/components/email-credential.tsx delete mode 100644 src/features/login/components/forgot-password.tsx delete mode 100644 src/features/login/components/google-sign-in-button.tsx delete mode 100644 src/features/login/components/login-menu-message.tsx delete mode 100644 src/features/login/components/login-section.tsx delete mode 100644 src/features/login/components/sign-in-button.tsx delete mode 100644 src/features/login/login-page.tsx delete mode 100644 src/features/organisation-list/components/ViewToggle.tsx delete mode 100644 src/features/organisation-profile/components/services.tsx delete mode 100644 src/features/organisation-profile/components/summary.tsx delete mode 100644 src/features/page-style.scss rename src/{features/firestore-mock/firestore-mock.tsx => mocks/FirestoreMock.tsx} (74%) rename src/{features/firestore-mock/test-data/initial-organisations.ts => mocks/InitialOrganisationsMock.ts} (86%) rename src/{features/firestore-mock/quill-editor.tsx => mocks/QuillEditor.tsx} (100%) rename src/{features/firestore-mock/test-data/test-organisations.ts => mocks/TestOrganisationsMock.ts} (92%) create mode 100644 src/mocks/UsersMock.ts create mode 100644 src/pages/Home/HeroSection.tsx create mode 100644 src/pages/Home/Home.tsx create mode 100644 src/pages/Home/SupportSection.tsx create mode 100644 src/pages/Home/TogetherSection.tsx create mode 100644 src/pages/Home/index.ts rename src/{features/home => pages/Home}/styles.ts (100%) create mode 100644 src/pages/Login/EmailCredential.tsx create mode 100644 src/pages/Login/ForgotPassword.tsx create mode 100644 src/pages/Login/GoogleSignInButton.tsx create mode 100644 src/pages/Login/Login.tsx rename src/{features/login/components/login-design.tsx => pages/Login/LoginDesign.tsx} (100%) rename src/{features/login/components/login-form.tsx => pages/Login/LoginForm.tsx} (90%) create mode 100644 src/pages/Login/LoginMenuMessage.tsx rename src/{features/registration/components/registration-section.tsx => pages/Login/LoginSection.tsx} (50%) create mode 100644 src/pages/Login/SignInButton.tsx rename src/{features/login/components/sign-up.tsx => pages/Login/SignUp.tsx} (94%) create mode 100644 src/pages/Login/index.ts rename src/{features/login/scss/login.scss => pages/Login/style.scss} (98%) rename src/{features/organisation-list/components => pages/OrganisationList}/CardView.tsx (83%) rename src/{features/organisation-list/const.ts => pages/OrganisationList/Const.ts} (100%) rename src/{features/organisation-list/components => pages/OrganisationList}/ListView.tsx (74%) rename src/{features/organisation-list/components/navigation-bar.tsx => pages/OrganisationList/NavigationBar.tsx} (100%) rename src/{features/organisation-list/components/OrgCard.tsx => pages/OrganisationList/OrganisationCard.tsx} (93%) rename src/{features/organisation-list/index.tsx => pages/OrganisationList/OrganisationList.tsx} (77%) create mode 100644 src/pages/OrganisationList/ViewToggle.tsx create mode 100644 src/pages/OrganisationList/index.ts rename src/{features/organisation-profile/index.tsx => pages/OrganisationProfile/OrganisationProfile.tsx} (54%) rename src/{features/organisation-profile/components/profile.tsx => pages/OrganisationProfile/Profile.tsx} (87%) rename src/{features/organisation-profile/components/profile-content.tsx => pages/OrganisationProfile/ProfileContent.tsx} (98%) rename src/{features/organisation-profile/components/profile-sidebar.tsx => pages/OrganisationProfile/ProfileSidebar.tsx} (100%) create mode 100644 src/pages/OrganisationProfile/Services.tsx rename src/{features/organisation-profile/components/similar-orgs.tsx => pages/OrganisationProfile/SimilarOrganisations.tsx} (77%) create mode 100644 src/pages/OrganisationProfile/Summary.tsx create mode 100644 src/pages/OrganisationProfile/index.ts rename src/{features/organisation-profile/scss => pages/OrganisationProfile}/profile.scss (98%) rename src/{features/organisation-profile/scss => pages/OrganisationProfile}/services.scss (91%) rename src/{features/organisation-profile/scss => pages/OrganisationProfile}/similar-orgs.scss (100%) rename src/{features/organisation-profile/scss => pages/OrganisationProfile}/summary.scss (100%) rename src/{features/registration/components/goals-form.tsx => pages/Registration/GoalsForm.tsx} (92%) rename src/{features/registration/components/org-info-form.tsx => pages/Registration/OrganisationInfoForm.tsx} (94%) rename src/{features/registration/profile-setup-page.tsx => pages/Registration/ProfileSetup.tsx} (95%) rename src/{features/registration/registration-page.tsx => pages/Registration/Registration.tsx} (55%) rename src/{features/registration/components/registration-design.tsx => pages/Registration/RegistrationDesign.tsx} (80%) rename src/{features/registration/components/registration-form.tsx => pages/Registration/RegistrationForm.tsx} (77%) rename src/{features/registration/components/registration-menu-message.tsx => pages/Registration/RegistrationMenuMessage.tsx} (83%) create mode 100644 src/pages/Registration/RegistrationSection.tsx rename src/{features/registration/components/sign-in.tsx => pages/Registration/SignIn.tsx} (84%) rename src/{features/registration/components/sign-up-button.tsx => pages/Registration/SignUpButton.tsx} (60%) rename src/{features/registration/components/sign-up-waiting.tsx => pages/Registration/SignUpWaiting.tsx} (85%) create mode 100644 src/pages/Registration/index.ts rename src/{features/registration/scss => pages/Registration}/registration.scss (99%) rename src/{features/registration/scss => pages/Registration}/setup.scss (99%) rename src/{features/user-dashboard/user-dashboard-page.tsx => pages/UserDashboard/UserDashboard.tsx} (90%) create mode 100644 src/pages/UserDashboard/index.ts create mode 100644 src/pages/style.scss rename src/{paths.ts => routing/Paths.ts} (100%) create mode 100644 src/routing/Routing.tsx create mode 100644 src/routing/index.ts rename src/services/{http-common.ts => HttpCommon.ts} (100%) delete mode 100644 src/theme.ts create mode 100644 src/theme/colours.ts create mode 100644 src/theme/components/accordion.ts create mode 100644 src/theme/components/table.ts create mode 100644 src/theme/index.ts create mode 100644 src/theme/styles.ts create mode 100644 src/theme/typography.ts delete mode 100644 src/utilities/icon-mappings.tsx create mode 100644 src/utilities/iconMappings/iconMapping.tsx create mode 100644 src/utilities/iconMappings/index.ts create mode 100644 src/utilities/validators/index.ts rename src/utilities/{ => validators}/validators.ts (100%) diff --git a/src/App.tsx b/src/App.tsx index 9e50dad..c15c25a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,39 +1,28 @@ import { ChakraProvider } from "@chakra-ui/react"; -import { Route, Routes } from "react-router-dom"; -import Home from "./features/home"; -import LoginPage from "./features/login/login-page"; -import ProfileSetupPage from "./features/registration/profile-setup-page"; -import RegistrationPage from "./features/registration/registration-page"; -import OrgProfilePage from "./features/organisation-profile"; -import OrganisationList from "./features/organisation-list"; -import UserDashboardPage from "./features/user-dashboard/user-dashboard-page"; import { AuthProvider } from "./services/firebase/authProvider"; -import FirestoreMock from "./features/firestore-mock/firestore-mock"; -import { Paths } from "./paths"; -import { appTheme } from "./theme"; +import Routing from "./routing"; +import { Paths } from "./routing/Paths"; +import Header from "./components/Header"; +import Footer from "./components/Footer"; +import mendisphereTheme from "./theme/index"; function App() { + // Get current page + const currentPage = window.location.pathname; + + // Check the current page is not login and registration page + const isShowHeaderAndFooter = ![ + Paths.login, + Paths.signup, + Paths.profileSetup, + ].includes(currentPage); + return ( - + - - } /> - } /> - } /> - } /> - } /> - } - /> - } - /> - {process.env.NODE_ENV === "development" && ( - } /> - )} - + {isShowHeaderAndFooter &&
} + + {isShowHeaderAndFooter &&