forked from 77media/video-flow
密码格式验证
This commit is contained in:
parent
a5ea76a28e
commit
f2b51cd33e
@ -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"}
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user