Skip to content

Commit

Permalink
add recover account
Browse files Browse the repository at this point in the history
  • Loading branch information
Shubham-Lal authored Jul 18, 2024
2 parents c5d805d + 6a0c679 commit b5fb418
Show file tree
Hide file tree
Showing 21 changed files with 411 additions and 69 deletions.
8 changes: 6 additions & 2 deletions client/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -145,14 +145,18 @@
}

@media screen and (max-width: 480px) {
body {
background-color: var(--nav-foot__background);
}

#left-sidebar {
position: fixed;
top: unset;
left: 0;
width: 100%;
bottom: 0;
height: 60px;
background: var(--nav-foot__background);
background-color: var(--body_background);
border-top: 1px solid var(--nav_border);
}

Expand All @@ -161,7 +165,7 @@
position: fixed;
width: 100%;
height: 60px;
background: var(--body_background);
background-color: var(--body_background);
}

#main {
Expand Down
1 change: 1 addition & 0 deletions client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export default function App() {
<Route path='/auth' element={<AuthPage />} />isScrollingUp
<Route path='/login' element={<Navigate to='/auth?type=login' />} />
<Route path='/signup' element={<Navigate to='/auth?type=signup' />} />
<Route path='/forgot' element={<Navigate to='/auth?type=forgot' />} />
<Route path='/search' element={<SearchPage />} />
<Route path='/create' element={<ProtectedRoute><CreateDebatePage isVisible={isScrollingUp} isFullscreen={!sidebar} /></ProtectedRoute>} />
<Route path='/hot-topics' element={<HotTopicsPage />} />
Expand Down
47 changes: 27 additions & 20 deletions client/src/components/modal/auth/forgot-password.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,33 +40,42 @@ const ForgotPassword = () => {

setValidationState(!!trimmedEmail || !!trimmedUsername);

if (!emailRegex.test(trimmedEmail)) {
if (trimmedEmail && !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);
try {
const res = 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 })
});

const response = await res.json();
if (response.success) {
toast.success(response.message);
} else {
if (response.message === 'Validation failed') {
toast.error(`${response.errors[0].message.charAt(0).toUpperCase() + response.errors[0].message.slice(1)}`);
} else {
toast.error(response.message);
}
}
} catch (error) {
toast.error('Something went wrong');
} finally {
setIsSubmitted(false);
}
} else {
setTimeout(() => setIsSubmitted(false), 500);
}
};

return (
<div id='forgot'>
<h3>Account Recover</h3>
<h3>Recover Account</h3>
<form id='forgot-form' className='form__container' onSubmit={handleForgotSubmit}>
<div className='input__container'>
<p>Email</p>
Expand All @@ -76,7 +85,6 @@ const ForgotPassword = () => {
onChange={handleInputChange}
className={`${isSubmitted && !validationState ? "shake" : ""}`}
style={{ borderColor: isSubmitted && !validationState ? "red" : "" }}
placeholder='Enter your email'
/>
</div>
<div className='or-divider'>
Expand All @@ -92,7 +100,6 @@ const ForgotPassword = () => {
onChange={handleInputChange}
className={`${isSubmitted && !validationState ? "shake" : ""}`}
style={{ borderColor: isSubmitted && !validationState ? "red" : "" }}
placeholder='Enter your username'
/>
</div>
<button
Expand Down
13 changes: 10 additions & 3 deletions client/src/components/modal/auth/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
top: 0;
left: 0;
right: 0;
height: 100svh;
height: 100dvh;
backdrop-filter: blur(8px);
display: flex;
align-items: center;
Expand Down Expand Up @@ -84,14 +84,16 @@
#login,
#signup,
#brief,
#forgot {
#forgot,
#reset {
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
}

#forgot {
#forgot,
#reset {
gap: 20px;
}

Expand Down Expand Up @@ -324,6 +326,7 @@
height: 100%;
flex-direction: column;
gap: 10px;
background-color: var(--body_background);
border: none;
border-radius: unset;
}
Expand Down Expand Up @@ -375,4 +378,8 @@
gap: 10px;
flex-direction: column;
}

#auth-modal .form__container .input__container p {
background-color: var(--body_background);
}
}
5 changes: 4 additions & 1 deletion client/src/components/modal/auth/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import LoginTab from "./login-tab"
import SignupTab from "./signup-tab"
import BriefInfo from "./brief-info"
import ForgotPassword from "./forgot-password"
import ResetPassword from "./reset-password"
import { IoCloseOutline } from "react-icons/io5"

type RegisterData = {
Expand Down Expand Up @@ -72,8 +73,10 @@ const AuthModal = () => {
registerData={registerData}
setRegisterData={setRegisterData}
/>
) : authTab === AuthTab.Forgot && (
) : authTab === AuthTab.Forgot ? (
<ForgotPassword />
) : authTab === AuthTab.Reset && (
<ResetPassword />
)}
</div>
<>
Expand Down
127 changes: 127 additions & 0 deletions client/src/components/modal/auth/reset-password.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import { useCallback, useState } from "react"
import { useNavigate } from "react-router-dom"
import { toast } from "sonner"
import { LoadingSVG } from "../../loading/svg"

const ResetPassword = () => {
const navigate = useNavigate();

const [resetData, setResetData] = useState({
new: "",
confirm: ""
});

const [isSubmitted, setIsSubmitted] = useState(false);
const [validationState, setValidationState] = useState({
isNewValid: true,
isConfirmValid: true
});

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

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

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

const trimmedNew = resetData.new.trim();
const trimmedConfirm = resetData.confirm.trim();

setResetData(prevState => ({
...prevState,
new: trimmedNew,
confirm: trimmedConfirm
}));

setValidationState({
isNewValid: !!trimmedNew,
isConfirmValid: !!trimmedConfirm
});

if (trimmedNew !== trimmedConfirm) {
setIsSubmitted(false);
return toast.error("Password doesn't match");
}
else {
if (trimmedNew.length < 6) {
setIsSubmitted(false);
return toast.warning('Password should be atleast 6 digits');
}

await fetch(`${import.meta.env.VITE_SERVER_URL}/api/auth/reset-password`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token: new URLSearchParams(location.search).get('token'), password: trimmedNew })
}).then(res => res.json())
.then(response => {
if (response.success) {
navigate('/auth?type=login');
toast.success(response.message);
}
else {
if (response.message === 'Validation failed') {
return toast.error(`${response.errors[0].field.charAt(0).toUpperCase() + response.errors[0].field.slice(1)} ${response.errors[0].message}`)
}
toast.error(response.message)
}
})
.finally(() => setIsSubmitted(false));
}
}

return (
<div id='reset'>
<h3>Reset Password</h3>
<form id='forgot-form' className='form__container' onSubmit={handleResetSubmit}>
<div className='input__container'>
<p>New Password</p>
<input
name="new"
type="password"
value={resetData.new}
onChange={handleInputChange}
className={`${isSubmitted && !validationState.isNewValid ? "shake" : ""}`}
style={{ borderColor: isSubmitted && !validationState.isNewValid ? "red" : "" }}
/>
</div>
<div className='input__container'>
<p>Confirm Password</p>
<input
name="confirm"
type="password"
value={resetData.confirm}
onChange={handleInputChange}
className={`${isSubmitted && !validationState.isConfirmValid ? "shake" : ""}`}
style={{ borderColor: isSubmitted && !validationState.isConfirmValid ? "red" : "" }}
/>
</div>
<button
type='submit'
disabled={isSubmitted}
style={{ cursor: `${isSubmitted ? 'not-allowed' : ''}` }}
>
{isSubmitted ? <LoadingSVG size={23} /> : 'Change'}
</button>
<div className='extra-btn'>
<p>
<span onClick={() => navigate('/auth?type=login')}>
Go Back
</span>
</p>
</div>
</form>
</div>
)
}

export default ResetPassword
1 change: 1 addition & 0 deletions client/src/components/sidebar/profile.css
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@
padding-bottom: 15px;
width: 100%;
left: 0;
background-color: var(--body_background);
border: 0;
border-bottom: 1px solid var(--explore_input_bg);
border-radius: 0;
Expand Down
1 change: 0 additions & 1 deletion client/src/components/sidebar/right-sidebar.css
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,6 @@
padding: 0 10px;
display: flex;
align-items: center;
background-color: var(--nav-foot__background);
}

#right-sidebar .profile-theme__container {
Expand Down
9 changes: 7 additions & 2 deletions client/src/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@
}

:root {
--body_background: #fafafa;
--body_background: #ffffff;
--body_color: rgb(1, 1, 1);
--nav-foot__background: #ffffff;
--nav-foot__background: #fafafa;
--nav_border: #ebebeb;
--nav_profile_username: #a6a6a6;
--explore_input_bg: #dee2e6;
Expand Down Expand Up @@ -89,6 +89,11 @@
--modal_header_color: rgb(60 130 246);
}

html,
body {
overscroll-behavior-y: contain;
}

* {
margin: 0;
padding: 0;
Expand Down
7 changes: 6 additions & 1 deletion client/src/pages/auth/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@ export default function AuthPage() {
navigate(route === '/auth' || route === '/login' || route === '/signup' ? '/' : route, { replace: true });
}
else if (isAuthenticated === AuthStatus.Failed) {
setAuthTab(type === 'login' ? AuthTab.Login : type === 'signup' ? AuthTab.Signup : AuthTab.Login);
setAuthTab(
type === 'login' ? AuthTab.Login
: type === 'signup' ? AuthTab.Signup
: type === 'forgot' ? AuthTab.Forgot
: type === 'reset' && new URLSearchParams(location.search).get('token') ? AuthTab.Reset
: AuthTab.Login);
}

const userData = params.get('user');
Expand Down
2 changes: 1 addition & 1 deletion client/src/pages/create-debate/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
#create {
position: relative;
overflow: hidden;
overscroll-behavior: contain;
}

#create-debate {
Expand Down Expand Up @@ -182,6 +181,7 @@
.debate-btns {
width: 100%;
padding: 10px;
background-color: var(--body_background);
}

.debate-btns.reveal {
Expand Down
1 change: 1 addition & 0 deletions client/src/store/useAuthStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export enum AuthTab {
Signup = 'signup',
Info = 'info',
Forgot = 'forgot',
Reset = 'reset'
}

export enum AuthStatus {
Expand Down
Loading

0 comments on commit b5fb418

Please sign in to comment.