密码格式验证

This commit is contained in:
海龙 2025-08-29 03:49:50 +08:00
parent a5ea76a28e
commit f2b51cd33e
3 changed files with 124 additions and 14 deletions

View File

@ -13,10 +13,47 @@ export default function SignupPage() {
const [inviteCode, setInviteCode] = useState("");
const [isSubmitting, setIsSubmitting] = useState(false);
const [formError, setFormError] = useState("");
const [passwordError, setPasswordError] = useState("");
const [showPassword, setShowPassword] = useState(false);
const router = useRouter();
/** Password validation function with English prompts */
const validatePassword = (password: string): string => {
if (password.length < 8) {
return "Password must be at least 8 characters";
}
if (password.length > 18) {
return "Password cannot exceed 18 characters";
}
if (!/^(?=.*[a-zA-Z])(?=.*\d)[a-zA-Z\d]{8,18}$/.test(password)) {
return "Password must contain both letters and numbers";
}
return "";
};
/** 处理密码输入变化 */
const handlePasswordChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const newPassword = e.target.value;
setPassword(newPassword);
if (newPassword) {
const error = validatePassword(newPassword);
setPasswordError(error);
} else {
setPasswordError("");
}
};
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
// 验证密码
const passwordValidationError = validatePassword(password);
if (passwordValidationError) {
setPasswordError(passwordValidationError);
return;
}
setIsSubmitting(true);
setFormError("");
@ -125,14 +162,35 @@ export default function SignupPage() {
<label className="block text-sm font-medium text-white mb-1">
Password
</label>
<input
type="password"
placeholder="Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
className="w-full px-4 py-3 rounded-lg bg-black/30 border border-white/20 text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent"
/>
<div className="relative">
<input
type={showPassword ? "text" : "password"}
placeholder="8-18位英文字母+数字组合"
value={password}
onChange={handlePasswordChange}
required
className={`w-full px-4 py-3 pr-12 rounded-lg bg-black/30 border text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent ${
passwordError ? "border-red-500/50" : "border-white/20"
}`}
/>
<button
type="button"
onClick={() => setShowPassword(!showPassword)}
className="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-white transition-colors"
data-alt="toggle-password-visibility"
>
{showPassword ? "👁️" : "👁️‍🗨️"}
</button>
</div>
{passwordError && (
<p className="mt-1 text-sm text-red-400">{passwordError}</p>
)}
{password && !passwordError && (
<p className="mt-1 text-sm text-green-400"> Password format is correct</p>
)}
<p className="mt-1 text-xs text-gray-400">
Password requirements: 8-18 characters, must contain letters and numbers
</p>
</div>
<div>
@ -163,7 +221,7 @@ export default function SignupPage() {
</Link>
<button
type="submit"
disabled={isSubmitting}
disabled={isSubmitting || !!passwordError || !password}
className="flex-1 py-3 rounded-lg bg-purple-600 hover:bg-purple-700 text-white font-medium transition-colors disabled:opacity-70"
>
{isSubmitting ? "Signing up..." : "Sign Up"}

View File

@ -312,7 +312,7 @@ function HomeModule3() {
"https://cdn.qikongjian.com/videos/show (2).mp4",
"https://cdn.qikongjian.com/videos/show (3).mp4",
"https://cdn.qikongjian.com/videos/show (4).mp4",
"https://cdn.qikongjian.com/videos/show (5).mp4",
"https://cdn.qikongjian.com/videos/show (16).mp4",
],
[
"https://cdn.qikongjian.com/videos/show (6).mp4",

View File

@ -16,9 +16,42 @@ export default function Login() {
const [isSubmitting, setIsSubmitting] = useState(false);
const [formError, setFormError] = useState("");
const [successMessage, setSuccessMessage] = useState("");
const [passwordError, setPasswordError] = useState("");
const router = useRouter();
const searchParams = useSearchParams();
/** 密码验证函数 */
/**
* Password validation function with English prompts
* @param {string} password - The password to validate
* @returns {string} - Error message if invalid, empty string if valid
*/
const validatePassword = (password: string): string => {
if (password.length < 8) {
return "Password must be at least 8 characters";
}
if (password.length > 18) {
return "Password cannot exceed 18 characters";
}
if (!/^(?=.*[a-zA-Z])(?=.*\d)[a-zA-Z\d]{8,18}$/.test(password)) {
return "Password must contain both letters and numbers";
}
return "";
};
/** 处理密码输入变化 */
const handlePasswordChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const newPassword = e.target.value;
setPassword(newPassword);
if (newPassword) {
const error = validatePassword(newPassword);
setPasswordError(error);
} else {
setPasswordError("");
}
};
// Check for registered=true parameter
useEffect(() => {
const registered = searchParams?.get("registered");
@ -44,6 +77,14 @@ export default function Login() {
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
// 验证密码
const passwordValidationError = validatePassword(password);
if (passwordValidationError) {
setPasswordError(passwordValidationError);
return;
}
setIsSubmitting(true);
setFormError("");
setSuccessMessage("");
@ -136,12 +177,14 @@ export default function Login() {
<label className="form-label">Password</label>
<div className="relative">
<input
placeholder="Enter your password"
placeholder="8-18位英文字母+数字组合"
required
className="form-control pr-10"
className={`form-control pr-10 ${
passwordError ? "border-red-500/50" : ""
}`}
type={showPassword ? "text" : "password"}
value={password}
onChange={(e) => setPassword(e.target.value)}
onChange={handlePasswordChange}
/>
<button
type="button"
@ -152,6 +195,15 @@ export default function Login() {
{!showPassword ? <EyeOff size={20} /> : <Eye size={20} />}
</button>
</div>
{passwordError && (
<p className="mt-1 text-sm text-red-400">{passwordError}</p>
)}
{password && !passwordError && (
<p className="mt-1 text-sm text-green-400"> Password format is correct</p>
)}
<p className="mt-1 text-xs text-gray-400">
Password requirements: 8-18 characters, must contain letters and numbers
</p>
{/* <div className="flex justify-end mt-2">
<a
className="auth-link small"
@ -172,7 +224,7 @@ export default function Login() {
<button
type="submit"
className="w-full mt-4 btn btn-primary"
disabled={isSubmitting}
disabled={isSubmitting || !!passwordError || !password}
>
{isSubmitting ? "Logging in..." : "Login"}
</button>