From b537450c57daeaa262187577fdac29fc591ba5c6 Mon Sep 17 00:00:00 2001 From: asaad-intelmatix Date: Sun, 15 Feb 2026 14:00:26 +0200 Subject: [PATCH] feat: Introduce PasswordInput Component for Enhanced Password Handling - Added a new PasswordInput component to encapsulate password input logic, including visibility toggling and error handling. - Updated LoginForm, Registration, and ResetPassword components to utilize PasswordInput, improving code reusability and readability. - Removed redundant password input code from these components, streamlining the authentication forms. This change enhances user experience by providing a consistent and accessible password input interface across the application. --- client/src/components/Auth/LoginForm.tsx | 43 +++--- client/src/components/Auth/PasswordInput.tsx | 68 ++++++++++ client/src/components/Auth/Registration.tsx | 45 ++++--- client/src/components/Auth/ResetPassword.tsx | 133 +++++++------------ client/src/components/Auth/index.ts | 1 + 5 files changed, 163 insertions(+), 127 deletions(-) create mode 100644 client/src/components/Auth/PasswordInput.tsx diff --git a/client/src/components/Auth/LoginForm.tsx b/client/src/components/Auth/LoginForm.tsx index c51c2002e3..d67d34d751 100644 --- a/client/src/components/Auth/LoginForm.tsx +++ b/client/src/components/Auth/LoginForm.tsx @@ -7,6 +7,7 @@ import type { TAuthContext } from '~/common'; import { useResendVerificationEmail, useGetStartupConfig } from '~/data-provider'; import { validateEmail } from '~/utils'; import { useLocalize } from '~/hooks'; +import PasswordInput from './PasswordInput'; type TLoginFormProps = { onSubmit: (data: TLoginUser) => void; @@ -116,34 +117,20 @@ const LoginForm: React.FC = ({ onSubmit, startupConfig, error, {renderError('email')} -
-
- - -
- {renderError('password')} -
+ {startupConfig.passwordResetEnabled && ( = ({ + id, + label, + register, + error, + autoComplete = 'current-password', + 'data-testid': dataTestId, +}) => { + const localize = useLocalize(); + const [showPassword, setShowPassword] = useState(false); + + const togglePasswordVisibility = () => { + setShowPassword((prev) => !prev); + }; + + return ( +
+
+ + + +
+ {error && ( + + {String(error.message)} + + )} +
+ ); +}; + +export default PasswordInput; diff --git a/client/src/components/Auth/Registration.tsx b/client/src/components/Auth/Registration.tsx index 3766bdff50..8df760ed98 100644 --- a/client/src/components/Auth/Registration.tsx +++ b/client/src/components/Auth/Registration.tsx @@ -9,6 +9,7 @@ import type { TRegisterUser, TError } from 'librechat-data-provider'; import type { TLoginLayoutContext } from '~/common'; import { useLocalize, TranslationKeys } from '~/hooks'; import { ErrorMessage } from './ErrorMessage'; +import PasswordInput from './PasswordInput'; const Registration: React.FC = () => { const navigate = useNavigate(); @@ -163,21 +164,35 @@ const Registration: React.FC = () => { message: localize('com_auth_email_pattern'), }, })} - {renderInput('password', 'com_auth_password', 'password', { - required: localize('com_auth_password_required'), - minLength: { - value: startupConfig?.minPasswordLength || 8, - message: localize('com_auth_password_min_length'), - }, - maxLength: { - value: 128, - message: localize('com_auth_password_max_length'), - }, - })} - {renderInput('confirm_password', 'com_auth_password_confirm', 'password', { - validate: (value: string) => - value === password || localize('com_auth_password_not_match'), - })} + + + value === password || localize('com_auth_password_not_match'), + })} + error={errors.confirm_password} + data-testid="confirm_password" + /> {startupConfig?.turnstile?.siteKey && (
diff --git a/client/src/components/Auth/ResetPassword.tsx b/client/src/components/Auth/ResetPassword.tsx index 6bececb7fe..94978d3134 100644 --- a/client/src/components/Auth/ResetPassword.tsx +++ b/client/src/components/Auth/ResetPassword.tsx @@ -6,6 +6,7 @@ import { useResetPasswordMutation } from 'librechat-data-provider/react-query'; import type { TResetPassword } from 'librechat-data-provider'; import type { TLoginLayoutContext } from '~/common'; import { useLocalize } from '~/hooks'; +import PasswordInput from './PasswordInput'; function ResetPassword() { const localize = useLocalize(); @@ -61,90 +62,54 @@ function ResetPassword() { method="POST" onSubmit={handleSubmit(onSubmit)} > -
-
- - - - -
- - {errors.password && ( - - {errors.password.message} - - )} -
-
-
- value === password || localize('com_auth_password_not_match'), - })} - aria-invalid={!!errors.confirm_password} - className="webkit-dark-styles transition-color peer w-full rounded-2xl border border-border-light bg-surface-primary px-3.5 pb-2.5 pt-3 text-text-primary duration-200 focus:border-green-500 focus:outline-none" - placeholder=" " - /> - -
- {errors.confirm_password && ( - - {errors.confirm_password.message} - - )} - {errors.token && ( - - {errors.token.message} - - )} - {errors.userId && ( - - {errors.userId.message} - - )} -
+ + + + value === password || localize('com_auth_password_not_match'), + })} + error={errors.confirm_password} + /> + {errors.token && ( + + {errors.token.message} + + )} + {errors.userId && ( + + {errors.userId.message} + + )}