Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion frontend/src/pages/Auth/components/SignupFormPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useState, type ChangeEvent, type FormEvent, type ReactElement } from "react";
import { ArrowRight, Eye, EyeOff, Mail, Building, User, ShieldCheck } from "lucide-react";
import { ArrowRight, Eye, EyeOff, Mail, Building, User, ShieldCheck, Check, X } from "lucide-react";
import type { SignUpFormData, SignUpSubmitPayload } from "../signUpTypes";

const TERMS_ERROR_MESSAGE = "Please agree to the terms and privacy policy";
Expand Down Expand Up @@ -118,8 +118,12 @@ const SignupFormPanel = ({
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
const [agreeTerms, setAgreeTerms] = useState(false);
const [error, setError] = useState("");
const [emailTouched, setEmailTouched] = useState(false);
const apiBaseUrl = import.meta.env.VITE_API_URL;

const isValidEmail = (email: string): boolean =>
/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(email);

const handleAgreeTermsChange = (event: ChangeEvent<HTMLInputElement>) => {
const checked = event.target.checked;
setAgreeTerms(checked);
Expand All @@ -132,6 +136,7 @@ const SignupFormPanel = ({
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
const { name, value } = event.target;
onFormChange(name as keyof SignUpFormData, value);
if (name === "email") setEmailTouched(true);
if (error) setError("");
};

Expand Down Expand Up @@ -243,6 +248,11 @@ const SignupFormPanel = ({
className="py-4 px-4 pl-12 w-full rounded-xl border-2 transition outline-none border-brand-blue/20 bg-surface-2/30 text-[1rem] text-text-strong placeholder:text-text-muted/70 focus:border-brand-blue focus:bg-surface-2/40 focus:shadow-[0_0_0_4px_rgb(var(--brand-blue)/0.12)]"
/>
</div>
{field.name === "email" && emailTouched && formData.email && !isValidEmail(formData.email) && (
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Enforce the same email rule before submitting

When the user enters an email that fails this new regex but still satisfies the browser's built-in type="email" constraint, such as user@localhost or a@b, the form shows “Please enter a valid email address” but validate() never checks isValidEmail, so clicking Create Account still calls onSubmit and sends the value to /v1/auth/register. This makes the new validation only cosmetic for those inputs; block submission using the same predicate that drives the inline error.

Useful? React with 👍 / 👎.

<span className="mt-1.5 text-xs text-accent-bad">
Please enter a valid email address
</span>
)}
</label>
))}

Expand Down Expand Up @@ -317,6 +327,14 @@ const SignupFormPanel = ({
{showConfirmPassword ? <EyeOff size={16} /> : <Eye size={16} />}
</button>
</div>
{formData.confirmPassword && (
<span className={`mt-1.5 flex items-center gap-1 text-xs ${formData.password === formData.confirmPassword ? "text-accent-good" : "text-accent-bad"}`}>
{formData.password === formData.confirmPassword
? <><Check size={12} /> Passwords match</>
: <><X size={12} /> Passwords do not match</>
}
</span>
)}
</label>

<label className="flex gap-2 items-start cursor-pointer text-text-muted">
Expand Down
Loading