Skip to content

Commit

Permalink
client: add regex validation
Browse files Browse the repository at this point in the history
  • Loading branch information
Shubham-Lal authored Jul 17, 2024
2 parents 4ac982d + 10e1a0f commit c5d805d
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 39 deletions.
2 changes: 1 addition & 1 deletion client/src/components/card/claim-username.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { toast } from "sonner"
import { PiArrowUpRightBold } from "react-icons/pi"
import { LoadingSVG } from "../loading/svg"
import { useNavStore } from "../../store/useNavStore"
import { usernameRegex } from "../../data/regex"

const ClaimUsername = () => {
const { setAuthTab } = useAuthStore();
Expand All @@ -23,7 +24,6 @@ const ClaimUsername = () => {
const inputUsername = e.target.value;
setUsername(inputUsername);

const usernameRegex = /^[a-zA-Z0-9_-]+$/;
if (inputUsername) {
if (!usernameRegex.test(inputUsername)) {
setMessage({ type: 'error', content: 'Username can only contain alphanumeric characters, underscores (_) and hyphens (-). No spaces or other special characters are allowed.' });
Expand Down
6 changes: 2 additions & 4 deletions client/src/components/loading/svg.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import "./style.css"

interface Props {
size: number
color ?: string
color?: string
}

const LoadingSVG: React.FC<Props> = ({ size, color }) => {
Expand All @@ -17,9 +17,7 @@ const LoadingSVG: React.FC<Props> = ({ size, color }) => {
const LoadingComponent = () => {
return (
<div className="loading-component">
<LoadingSVG
size={30}
/>
<LoadingSVG size={30} />
</div>
)
}
Expand Down
4 changes: 1 addition & 3 deletions client/src/components/modal/auth/brief-info.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { AuthStatus, AuthTab, useAuthStore, useTempStore } from "../../../store/
import { MdModeEdit } from "react-icons/md"
import { GrCloudUpload } from "react-icons/gr"
import { IoPersonCircleOutline } from "react-icons/io5"
import { specialCharRegex, usernameRegex } from "../../../data/regex"

const BriefInfo: React.FC<RegisterDataProps> = ({ registerData, setRegisterData }) => {
const navigate = useNavigate();
Expand All @@ -24,9 +25,6 @@ const BriefInfo: React.FC<RegisterDataProps> = ({ registerData, setRegisterData

const handleInputChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
// eslint-disable-next-line no-useless-escape
const specialCharRegex = /[@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/;
const usernameRegex = /^[a-zA-Z0-9_-]+$/;

let isValid = true;
if (name === 'username') {
Expand Down
70 changes: 44 additions & 26 deletions client/src/components/modal/auth/forgot-password.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { useState, useCallback } from "react";
import { useAuthStore, AuthTab } from "../../../store/useAuthStore";
import { useState, useCallback } from "react"
import { useAuthStore, AuthTab } from "../../../store/useAuthStore"
import { toast } from "sonner"
import { LoadingSVG } from "../../loading/svg";
import { emailRegex } from "../../../data/regex"

const ForgotPassword = () => {
const { setAuthTab } = useAuthStore();
Expand All @@ -9,25 +12,20 @@ const ForgotPassword = () => {
username: ""
});
const [isSubmitted, setIsSubmitted] = useState(false);
const [validationState, setValidationState] = useState({
isEmailValid: true,
isUsernameValid: true
});
const [validationState, setValidationState] = useState(true);

const handleInputChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
setForgotData(prevState => ({
...prevState,
[name]: value
}));

setValidationState(prevState => ({
...prevState,
[`is${name.charAt(0).toUpperCase() + name.slice(1)}Valid`]: !!value
setForgotData(() => ({
email: name === "email" ? value : "",
username: name === "username" ? value : ""
}));

setValidationState(!!value);
}, []);

const handleForgotSubmit = (e: React.FormEvent<HTMLFormElement>) => {
const handleForgotSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setIsSubmitted(true);

Expand All @@ -40,14 +38,30 @@ const ForgotPassword = () => {
username: trimmedUsername
}));

setValidationState({
isEmailValid: !!trimmedEmail,
isUsernameValid: !!trimmedUsername
});
setValidationState(!!trimmedEmail || !!trimmedUsername);

if (trimmedEmail || trimmedUsername) {
// Perform further actions for forgot password
if (!emailRegex.test(trimmedEmail)) {
setIsSubmitted(false);
return toast.warning('Invalid email address');
}

if (trimmedEmail || trimmedUsername) {
await fetch(`${import.meta.env.VITE_SERVER_URL}/api/auth/recover-account`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(trimmedEmail ? { email: trimmedEmail } : { username: trimmedUsername })
})
.then(res => res.json())
.then(response => {
if (response.success) toast.success(response.message);
else {
if (response.message === 'Validation failed') {
return toast.error(`${response.errors[0].message.charAt(0).toUpperCase() + response.errors[0].message.slice(1)}`)
}
toast.error(response.message)
};
}).finally(() => setIsSubmitted(false));
} else setTimeout(() => setIsSubmitted(false), 500);
};

return (
Expand All @@ -60,8 +74,8 @@ const ForgotPassword = () => {
name="email"
value={forgotData.email}
onChange={handleInputChange}
className={`${isSubmitted && !validationState.isEmailValid ? "shake" : ""}`}
style={{ borderColor: isSubmitted && !validationState.isEmailValid ? "red" : "" }}
className={`${isSubmitted && !validationState ? "shake" : ""}`}
style={{ borderColor: isSubmitted && !validationState ? "red" : "" }}
placeholder='Enter your email'
/>
</div>
Expand All @@ -76,13 +90,17 @@ const ForgotPassword = () => {
name="username"
value={forgotData.username}
onChange={handleInputChange}
className={`${isSubmitted && !validationState.isUsernameValid ? "shake" : ""}`}
style={{ borderColor: isSubmitted && !validationState.isUsernameValid ? "red" : "" }}
className={`${isSubmitted && !validationState ? "shake" : ""}`}
style={{ borderColor: isSubmitted && !validationState ? "red" : "" }}
placeholder='Enter your username'
/>
</div>
<button type='submit'>
Check
<button
type='submit'
disabled={isSubmitted}
style={{ cursor: `${isSubmitted ? 'not-allowed' : ''}` }}
>
{isSubmitted ? <LoadingSVG size={23} /> : 'Check'}
</button>
<div className='extra-btn'>
<p><span onClick={() => setAuthTab(AuthTab.Login)}>Go Back</span></p>
Expand Down
12 changes: 10 additions & 2 deletions client/src/components/modal/auth/signup-tab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { toast } from "sonner"
import { AuthStatus, AuthTab, useAuthStore, useTempStore } from "../../../store/useAuthStore"
import { FcGoogle } from "react-icons/fc"
import { LoadingSVG } from "../../loading/svg"
import { emailRegex } from "../../../data/regex"

const SignupTab: React.FC<RegisterDataProps> = ({ registerData, setRegisterData }) => {
const { setAuthTab, isAuthenticated } = useAuthStore();
Expand Down Expand Up @@ -51,8 +52,11 @@ const SignupTab: React.FC<RegisterDataProps> = ({ registerData, setRegisterData
});

if (trimmedEmail && trimmedPassword) {
if (!emailRegex.test(trimmedEmail)) {
return toast.warning('Invalid email address');
}
if (trimmedPassword.length < 6) {
return toast.warning('Password should be atleast 6 digits')
return toast.warning('Password should be atleast 6 digits');
}
setAuthTab(AuthTab.Info);
}
Expand Down Expand Up @@ -109,7 +113,11 @@ const SignupTab: React.FC<RegisterDataProps> = ({ registerData, setRegisterData
placeholder={isSubmitted && !validationState.isPasswordValid ? 'Required' : ''}
/>
</div>
<button type='submit' disabled={isAuthenticated === AuthStatus.Authenticating}>
<button
type='submit'
disabled={isAuthenticated === AuthStatus.Authenticating}
style={{ cursor: `${isAuthenticated === AuthStatus.Authenticating ? 'not-allowed' : ''}` }}
>
{isAuthenticated === AuthStatus.Authenticating ? <LoadingSVG size={23} /> : 'Continue'}
</button>
<div className='extra-btn'>
Expand Down
1 change: 0 additions & 1 deletion client/src/components/sidebar/explore.css
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@

#explore .explore-btns a {
padding: 7.5px 15px;
background-color: var(--body_background);
border-radius: 20px;
text-transform: lowercase;
}
Expand Down
3 changes: 3 additions & 0 deletions client/src/data/regex.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const usernameRegex = /^[a-zA-Z0-9_-]+$/;
export const specialCharRegex = /[@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/;
export const emailRegex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+(com|org|net|gov|mil|biz|info|mobi|name|aero|jobs|museum|in|space)))$/;
4 changes: 2 additions & 2 deletions client/src/pages/create-debate/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#create {
position: relative;
overflow: hidden;
overscroll-behavior: none;
overscroll-behavior: contain;
}

#create-debate {
Expand Down Expand Up @@ -130,7 +130,7 @@
.preview .e-richtexteditor {
min-height: fit-content !important;
height: fit-content !important;
background-color: var(--body_background);
background-color: transparent;
border: none;
}

Expand Down

0 comments on commit c5d805d

Please sign in to comment.