add change password modal window
This commit is contained in:
+248
-86
@@ -2,10 +2,11 @@
|
||||
|
||||
import styles from '@/app/styles/module/login.module.scss'
|
||||
import { useActionState, useState, useRef, useEffect } from 'react';
|
||||
import { authorization } from '@/app/actions/auth';
|
||||
import { authorization, updatePasswordAction } from '@/app/actions/auth';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { IconEye } from '@/app/ui/icons/icons';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import ModalWindow from '@/app/components/modalWindow';
|
||||
|
||||
export default function LoginForm() {
|
||||
const [state, formAction, isPending] = useActionState(
|
||||
@@ -15,8 +16,23 @@ export default function LoginForm() {
|
||||
const t = useTranslations('Login-register-form');
|
||||
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
const [showChangePasswordModal, setShowChangePasswordModal] = useState(false);
|
||||
const [pendingPasswordUpdate, setPendingPasswordUpdate] = useState(false);
|
||||
const [pendingUserData, setPendingUserData] = useState<{
|
||||
email: string;
|
||||
id: number;
|
||||
oldPassword: string;
|
||||
token: string;
|
||||
} | null>(null);
|
||||
const [passwordUpdateError, setPasswordUpdateError] = useState<string | null>(null);
|
||||
|
||||
function showPassowrd() {
|
||||
const [newPassword, setNewPassword] = useState('');
|
||||
const [confirmPassword, setConfirmPassword] = useState('');
|
||||
const [showNewPassword, setShowNewPassword] = useState(false);
|
||||
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
|
||||
const [isRedirecting, setIsRedirecting] = useState(false);
|
||||
|
||||
function toggleShowPassword() {
|
||||
setShowPassword(!showPassword);
|
||||
}
|
||||
|
||||
@@ -27,92 +43,238 @@ export default function LoginForm() {
|
||||
queryClient.clear();
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<form
|
||||
className={`${styles['form-wrapper']}`}
|
||||
action={formAction}
|
||||
>
|
||||
<div className={`${styles['form-group']}`}>
|
||||
<label className={`${styles['form-label']}`}>
|
||||
{t('email-adress')}
|
||||
</label>
|
||||
<input
|
||||
type="readOnly"
|
||||
id="email"
|
||||
name="email"
|
||||
className={`${styles['form-input']}`}
|
||||
placeholder={t('enter-email')}
|
||||
defaultValue={state?.previousState?.email ? state?.previousState?.email : ''}
|
||||
onChange={(e) => {
|
||||
e.target.value = e.target.value.toLocaleLowerCase();
|
||||
}}
|
||||
/>
|
||||
{state?.error?.email && (
|
||||
<p className={`${styles['form-error']}`}>
|
||||
{t(state?.error?.email)}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div className={`${styles['form-group']}`}>
|
||||
<label className={`${styles['form-label']}`}>
|
||||
{t('password')}
|
||||
</label>
|
||||
<div className={`${styles['password-wrapper']}`}>
|
||||
<input
|
||||
type={showPassword ? "text" : "password"}
|
||||
id="password"
|
||||
name="password"
|
||||
className={`${styles['form-input']} ${styles['password']}`}
|
||||
placeholder={t('enter-password')}
|
||||
/>
|
||||
<button
|
||||
onClick={() => {
|
||||
showPassowrd();
|
||||
}}
|
||||
type="button"
|
||||
className={`show-password-button ${showPassword ? 'show' : ''}`}
|
||||
>
|
||||
<IconEye />
|
||||
</button>
|
||||
</div>
|
||||
{state?.error?.password && (
|
||||
<p className={`${styles['form-error']}`}>
|
||||
{t(state?.error?.password)}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
{state?.error.server && (
|
||||
<p className={`${styles['form-error']}`}>
|
||||
{t(state?.error.server)}
|
||||
</p>
|
||||
)}
|
||||
{/* <div className={`${styles['form-options']}`}>
|
||||
<div className={`${styles['form-checkbox']}`}>
|
||||
<input type="checkbox" id="remember" name="remember" ref={checkBoxRememberMe} />
|
||||
<label
|
||||
onClick={() => {
|
||||
if (checkBoxRememberMe.current) {
|
||||
checkBoxRememberMe.current.click();
|
||||
}
|
||||
}}
|
||||
className="select-none"
|
||||
>
|
||||
{t('remember-me')}
|
||||
</label>
|
||||
</div>
|
||||
</div> */}
|
||||
<button
|
||||
type="submit"
|
||||
className={`${styles['btn']}`}
|
||||
disabled={isPending}
|
||||
const handlePasswordChangeRequired = (email: string, id: number, oldPassword: string, token: string) => {
|
||||
setPendingUserData({ email, id, oldPassword, token });
|
||||
setShowChangePasswordModal(true);
|
||||
};
|
||||
|
||||
const handlePasswordUpdate = async () => {
|
||||
if (!pendingUserData) return;
|
||||
|
||||
if (newPassword !== confirmPassword) {
|
||||
setPasswordUpdateError(t('passwords-do-not-match'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (newPassword.length < 6) {
|
||||
setPasswordUpdateError(t('password-too-short'));
|
||||
return;
|
||||
}
|
||||
|
||||
setPendingPasswordUpdate(true);
|
||||
setPasswordUpdateError(null);
|
||||
|
||||
try {
|
||||
const result = await updatePasswordAction(
|
||||
pendingUserData.id,
|
||||
pendingUserData.oldPassword,
|
||||
newPassword,
|
||||
pendingUserData.email,
|
||||
pendingUserData.token
|
||||
);
|
||||
|
||||
if (result.success) {
|
||||
setShowChangePasswordModal(false);
|
||||
setIsRedirecting(true);
|
||||
setTimeout(() => {
|
||||
window.location.href = '/pages/';
|
||||
}, 500);
|
||||
} else {
|
||||
setPasswordUpdateError(result.error || t('password-update-failed'));
|
||||
}
|
||||
} catch (error) {
|
||||
setPasswordUpdateError(t('password-update-failed'));
|
||||
} finally {
|
||||
setPendingPasswordUpdate(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (isRedirecting) {
|
||||
return (
|
||||
<div
|
||||
className="loading-animation"
|
||||
>
|
||||
{t("sign-in")}
|
||||
{isPending && (
|
||||
<div className="loading-animation">
|
||||
<div className="global-spinner"></div>
|
||||
<div
|
||||
className="global-spinner large"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<form
|
||||
className={`${styles['form-wrapper']}`}
|
||||
action={formAction}
|
||||
>
|
||||
<div className={`${styles['form-group']}`}>
|
||||
<label className={`${styles['form-label']}`}>
|
||||
{t('email-adress')}
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="email"
|
||||
name="email"
|
||||
className={`${styles['form-input']}`}
|
||||
placeholder={t('enter-email')}
|
||||
defaultValue={state?.previousState?.email ? state?.previousState?.email : ''}
|
||||
onChange={(e) => {
|
||||
e.target.value = e.target.value.toLowerCase();
|
||||
}}
|
||||
/>
|
||||
{state?.error?.email && (
|
||||
<p className={`${styles['form-error']}`}>
|
||||
{t(state?.error?.email)}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div className={`${styles['form-group']}`}>
|
||||
<label className={`${styles['form-label']}`}>
|
||||
{t('password')}
|
||||
</label>
|
||||
<div className={`${styles['password-wrapper']}`}>
|
||||
<input
|
||||
type={showPassword ? "text" : "password"}
|
||||
id="password"
|
||||
name="password"
|
||||
className={`${styles['form-input']} ${styles['password']}`}
|
||||
placeholder={t('enter-password')}
|
||||
/>
|
||||
<button
|
||||
onClick={toggleShowPassword}
|
||||
type="button"
|
||||
className={`show-password-button ${showPassword ? 'show' : ''}`}
|
||||
>
|
||||
<IconEye />
|
||||
</button>
|
||||
</div>
|
||||
{state?.error?.password && (
|
||||
<p className={`${styles['form-error']}`}>
|
||||
{t(state?.error?.password)}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
{state?.error?.server && (
|
||||
<p className={`${styles['form-error']}`}>
|
||||
{t(state?.error?.server)}
|
||||
</p>
|
||||
)}
|
||||
</button>
|
||||
</form>
|
||||
{state?.requirePasswordChange && state?.userData && (
|
||||
<p className={`${styles['form-error']}`}>
|
||||
{t('password-change-required')}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handlePasswordChangeRequired(state.userData.email, state.userData.id, state.userData!.password, state.userData!.token)}
|
||||
className={styles['change-password-btn']}
|
||||
>
|
||||
{t('change-password')}
|
||||
</button>
|
||||
</p>
|
||||
)}
|
||||
<button
|
||||
type="submit"
|
||||
className={`${styles['btn']}`}
|
||||
disabled={isPending}
|
||||
>
|
||||
{t("sign-in")}
|
||||
{isPending && (
|
||||
<div className="loading-animation">
|
||||
<div className="global-spinner"></div>
|
||||
</div>
|
||||
)}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<ModalWindow
|
||||
state={showChangePasswordModal}
|
||||
callBack={() => {
|
||||
setShowChangePasswordModal(false);
|
||||
setPendingUserData(null);
|
||||
setNewPassword('');
|
||||
setConfirmPassword('');
|
||||
setPasswordUpdateError(null);
|
||||
}}
|
||||
>
|
||||
<div className={styles['change-password-modal']}>
|
||||
<h3>{t('change-password')}</h3>
|
||||
<p>{t('password-change-required-message')}</p>
|
||||
|
||||
<div className={styles['form-group']}>
|
||||
<label className={styles['form-label']}>
|
||||
{t('new-password')}
|
||||
</label>
|
||||
<div className={styles['password-wrapper']}>
|
||||
<input
|
||||
type={showNewPassword ? "text" : "password"}
|
||||
value={newPassword}
|
||||
onChange={(e) => setNewPassword(e.target.value)}
|
||||
className={styles['form-input']}
|
||||
placeholder={t('enter-new-password')}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowNewPassword(!showNewPassword)}
|
||||
className="show-password-button"
|
||||
>
|
||||
<IconEye />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles['form-group']}>
|
||||
<label className={styles['form-label']}>
|
||||
{t('confirm-password')}
|
||||
</label>
|
||||
<div className={styles['password-wrapper']}>
|
||||
<input
|
||||
type={showConfirmPassword ? "text" : "password"}
|
||||
value={confirmPassword}
|
||||
onChange={(e) => setConfirmPassword(e.target.value)}
|
||||
className={styles['form-input']}
|
||||
placeholder={t('confirm-new-password')}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowConfirmPassword(!showConfirmPassword)}
|
||||
className="show-password-button"
|
||||
>
|
||||
<IconEye />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{passwordUpdateError && (
|
||||
<p className={styles['form-error']}>{passwordUpdateError}</p>
|
||||
)}
|
||||
|
||||
<div className={styles['modal-buttons']}>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
setShowChangePasswordModal(false);
|
||||
setPendingUserData(null);
|
||||
}}
|
||||
className={`${styles['btn-secondary']} ${styles['btn']}`}
|
||||
>
|
||||
{t('cancel')}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handlePasswordUpdate}
|
||||
disabled={pendingPasswordUpdate || !newPassword || !confirmPassword}
|
||||
className={styles['btn']}
|
||||
>
|
||||
{t('update-password')}
|
||||
{pendingPasswordUpdate && (
|
||||
<div className="loading-animation">
|
||||
<div className="global-spinner"></div>
|
||||
</div>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ModalWindow>
|
||||
</>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user