Skip to content

Conversation

@Divyanshu-s13
Copy link

@Divyanshu-s13 Divyanshu-s13 commented Nov 20, 2025

Closes #197

📝 Description

This PR fixes a critical bug where the BasicDetails form component was accepting invalid user input without any validation or error feedback. Users could submit empty required fields, malformed emails, invalid phone numbers, and incorrect URLs without any warnings or prevention. This compromise data integrity and causes backend errors.

The fix implements comprehensive client-side validation with real-time error feedback, helping users enter correct information before submission.

🔧 Changes Made

Form State Management

  • Added controlled form inputs connected to React state for both Influencer and Brand forms
  • Implemented separate form data objects for influencer and brand user types
  • Added error state management to track validation errors

Validation Functions

  • validateEmail() - Validates email format using regex pattern
  • validatePhone() - Validates international phone number format
  • validateURL() - Validates HTTP/HTTPS URLs using URL constructor
  • validateStep() - Step-specific validation based on user type and current step

Input Validation Rules Implemented

Influencer Form - Step 0 (Basic Details):

  • First Name: Required, non-empty string
  • Last Name: Required, non-empty string
  • Email: Required, valid email format (contains @ and domain)
  • Phone: Required, valid international phone format
  • Category: Required selection

Influencer Form - Step 1 (Social Media):

  • Instagram Handle: Optional, must start with @
  • YouTube Channel: Optional, valid URL
  • Website: Optional, valid URL

Influencer Form - Step 2 (Audience):

  • Audience Size: Required, positive number
  • Engagement Rate: Required, 0-100%
  • Main Platform: Required selection
  • Audience Age: Required selection

Brand Form - Step 0 (Company Info):

  • Company Name: Required, non-empty string
  • Website: Required, valid URL
  • Industry: Required selection
  • Company Size: Required selection
  • Budget: Required selection

Brand Form - Step 1 (Campaign Preferences):

  • Target Audience: Required selection
  • Preferred Platforms: Required selection
  • Campaign Goals: Required selection

User Experience Improvements

  • Real-time validation feedback with error messages displayed below invalid fields
  • Visual error indicators: Red borders on invalid inputs
  • Error icons with AlertCircle from lucide-react
  • Required fields marked with red asterisk (*)
  • Errors automatically clear when user fixes the field
  • Next button disabled until all current step validations pass
  • Form data persists across step navigation

Code Quality

  • Type-safe validation with proper casting for different form types
  • Clean separation of validation logic from component rendering
  • Reusable validation utility functions
  • Clear error messaging with specific guidance (e.g., "Invalid phone format (e.g., +1-555-000-0000)")

Before:

  • Form accepted empty required fields
  • No error messages displayed
  • No visual indication of invalid inputs
  • Users could proceed with incomplete/invalid data

After:

  • Form shows red error messages below each invalid field
  • Invalid inputs have red borders
  • AlertCircle icons indicate errors
  • Next button disabled until validation passes
  • Real-time feedback as user types
  • Clear visual separation of required vs optional fields

Summary by CodeRabbit

  • New Features
    • Comprehensive client-side form validation with inline, per-field error messages and icons
    • Required fields clearly marked with visual indicators (asterisks)
    • Invalid entries highlighted with error states and conditional styling
    • Format validation for email, phone, and URL inputs
    • Validation-aware inputs and selects for influencer and brand fields (including social/audience)
    • Progression through the multi-step form blocked until validation errors are resolved
    • Form state and reset managed via component state rather than direct DOM clearing

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 20, 2025

Walkthrough

Adds client-side form validation and per-field error handling to the BasicDetails multi-step form: introduces validation utilities (phone, email, URL), nested formData for influencer/brand flows, an errors map, handleInputChange to update nested data and clear errors, validateStep to enforce step-specific rules, and UI updates to render inline errors and block progression on validation failures.

Changes

Cohort / File(s) Summary
Form validation & UI updates
Frontend/src/pages/BasicDetails.tsx
Adds validation utilities for phone, email, and URLs; introduces nested formData (influencer & brand) and an errors map; implements validateStep enforcing required fields and constraints per step and user type; adds handleInputChange to update nested data and clear related errors; gates nextStep on validation; updates UI to show per-field inline errors, required-field indicators, and error styling; imports AlertCircle and integrates error indicators across form sections.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Form as BasicDetails Form
    participant Validator as validateStep()
    participant State as Form State
    participant UI as UI Components

    User->>Form: Enter or modify field
    Form->>State: handleInputChange(field, value)
    State->>State: Update nested formData & clear related errors
    State->>UI: Re-render field
    alt Field invalid
        UI->>UI: Show inline error + highlight (Alert icon)
    else Field valid
        UI->>UI: Clear error styling
    end

    User->>Form: Click Next
    Form->>Validator: validateStep(currentStep, userType)
    Validator-->>Form: errors map or success
    alt Valid
        Form->>Form: Advance step
    else Invalid
        Form->>State: Set errors map
        State->>UI: Re-render showing errors
        Form-->>User: Stay on step (block progression)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Review focuses:
    • Regex/logic for email, phone, and URL validation.
    • Numeric bounds (engagement rate 0–100, audience size >0).
    • Correct mapping between nested formData keys and errors entries.
    • UI bindings to ensure errors clear on change and required indicators display correctly.

Poem

🐇 I nibble at forms both near and far,

I flag the errors like a tiny star,
Asterisk guards and alerts in view,
Fix a field — I'll hop and clear it too! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding comprehensive input validation to the BasicDetails form, addressing the core problem identified in issue #197.
Linked Issues check ✅ Passed The PR implements all coding requirements from issue #197: validation utilities for email/phone/URLs, per-field error handling with real-time messages, visual indicators (red borders, AlertCircle icons), required-field asterisks, step-specific validation rules, and disabling Next button until valid.
Out of Scope Changes check ✅ Passed All changes are directly scoped to issue #197 requirements: form validation logic, error state management, and UI feedback components within BasicDetails.tsx with no unrelated modifications.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Frontend/src/pages/BasicDetails.tsx (1)

687-695: Reset logic should operate on component state, not the raw DOM

resetForm currently clears native <input> and <select> elements via document.querySelectorAll, but all of the form fields here are controlled by component state (formData) and custom Select components:

  • Direct DOM mutations are immediately overwritten on the next render.
  • errors are never cleared, so old validation messages may persist after “Reset form”.

You should reset the React state instead and drop the DOM manipulation, for example:

   const resetForm = () => {
     setStep(0);
     setAnimationDirection(0);
-
-    document.querySelectorAll("input").forEach((input) => (input.value = ""));
-    document
-      .querySelectorAll("select")
-      .forEach((select) => (select.value = ""));
+    setFormData({
+      influencer: {
+        firstName: "",
+        lastName: "",
+        email: "",
+        phone: "",
+        category: "",
+        instagram: "",
+        youtube: "",
+        twitter: "",
+        tiktok: "",
+        website: "",
+        audienceSize: "",
+        avgEngagement: "",
+        mainPlatform: "",
+        audienceAge: "",
+      },
+      brand: {
+        companyName: "",
+        website: "",
+        industry: "",
+        size: "",
+        budget: "",
+        targetAudience: "",
+        preferredPlatforms: "",
+        campaignGoals: "",
+      },
+    });
+    setErrors({});
   };

If you’d like to avoid duplicating the initial object, you can also extract it into a shared initialFormData constant and reuse it both in useState and here.

🧹 Nitpick comments (1)
Frontend/src/pages/BasicDetails.tsx (1)

162-182: Minor improvement to error clearing in handleInputChange

The per‑field error clearing works, but it relies on the outer errors closure:

if (errors[field]) {
  setErrors(prev => {
    const newErrors = { ...prev };
    delete newErrors[field];
    return newErrors;
  });
}

You can simplify this and avoid any stale reads by always deleting the key inside the state updater:

-    // Clear error for this field
-    if (errors[field]) {
-      setErrors(prev => {
-        const newErrors = { ...prev };
-        delete newErrors[field];
-        return newErrors;
-      });
-    }
+    // Clear error for this field
+    setErrors(prev => {
+      if (!prev[field]) return prev;
+      const newErrors = { ...prev };
+      delete newErrors[field];
+      return newErrors;
+    });

Same behavior, but the logic is fully driven by the latest prev state.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a3be437 and 14b8212.

📒 Files selected for processing (1)
  • Frontend/src/pages/BasicDetails.tsx (15 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
Frontend/src/pages/BasicDetails.tsx (3)
Frontend/src/components/ui/label.tsx (1)
  • Label (25-25)
Frontend/src/components/ui/input.tsx (1)
  • Input (21-21)
Frontend/src/components/ui/select.tsx (2)
  • Select (150-150)
  • SelectTrigger (153-153)
🔇 Additional comments (1)
Frontend/src/pages/BasicDetails.tsx (1)

215-299: Field wiring and per‑field error UX look solid

The way you’ve bound each influencer/brand field to formData and errors is consistent and matches the requirements:

  • Required fields are clearly marked with a red asterisk.
  • Error states are surfaced via border color and inline text with the AlertCircle icon.
  • Optional fields (e.g., Instagram, YouTube, website) correctly only show errors when present and invalid.
  • Audience size, engagement rate, and campaign settings all have clear, specific messages.

This is a good, reusable pattern across all steps and keeps the UX coherent.

Also applies to: 303-381, 383-458, 460-559, 561-625

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Frontend/src/pages/BasicDetails.tsx (1)

180-189: Validation on final step doesn't prevent "Complete" action.

The validation guard at line 181 blocks navigation, but on the final step (step === 2 for influencer or step === 1 for brand), clicking "Complete" runs validateStep() then immediately returns because the condition on line 183 is false. This means:

  • Validation errors are set in state and displayed to the user ✓
  • But the "Complete" button performs no action whether validation passes or fails ✗

If "Complete" is meant to submit the form or navigate elsewhere, you need to add that logic after the validation guard.

Add completion logic after validation:

 const nextStep = () => {
   if (!validateStep()) return; // Don't proceed if validation fails
   
-  if ((user === "influencer" && step < 2) || (user === "brand" && step < 1)) {
+  const isLastStep = (user === "influencer" && step === 2) || (user === "brand" && step === 1);
+  
+  if (isLastStep) {
+    // TODO: Submit form data to backend or navigate to next page
+    console.log("Form completed:", formData);
+    // e.g., navigate("/dashboard") or submitFormData(formData)
+    return;
+  }
+  
+  if ((user === "influencer" && step < 2) || (user === "brand" && step < 1)) {
     setAnimationDirection(1);
     setTimeout(() => {
       setStep((prev) => prev + 1);
     }, 50);
   }
 };
🧹 Nitpick comments (1)
Frontend/src/pages/BasicDetails.tsx (1)

114-123: Consider validating Twitter/TikTok handle format for consistency.

Instagram handles are validated to start with @ (line 115-116), but Twitter and TikTok handles (which also use @ prefixes) have no validation. This inconsistency might confuse users or allow malformed data.

If you want consistent validation, add checks for Twitter and TikTok in Step 1:

       } else if (step === 1) {
         if (influData.instagram && !influData.instagram.startsWith("@")) {
           newErrors.instagram = "Instagram handle should start with @";
         }
+        if (influData.twitter && !influData.twitter.startsWith("@")) {
+          newErrors.twitter = "Twitter handle should start with @";
+        }
+        if (influData.tiktok && !influData.tiktok.startsWith("@")) {
+          newErrors.tiktok = "TikTok username should start with @";
+        }
         if (influData.youtube && !validateURL(influData.youtube)) {
           newErrors.youtube = "Invalid YouTube URL";
         }
         if (influData.website && !validateURL(influData.website)) {
           newErrors.website = "Invalid website URL";
         }
       }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 14b8212 and 849e47f.

📒 Files selected for processing (1)
  • Frontend/src/pages/BasicDetails.tsx (16 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
Frontend/src/pages/BasicDetails.tsx (3)
Frontend/src/components/ui/label.tsx (1)
  • Label (25-25)
Frontend/src/components/ui/input.tsx (1)
  • Input (21-21)
Frontend/src/components/ui/select.tsx (2)
  • Select (150-150)
  • SelectTrigger (153-153)
🔇 Additional comments (5)
Frontend/src/pages/BasicDetails.tsx (5)

58-89: LGTM!

The form state structure cleanly separates influencer and brand flows, and the errors map provides flexible field-level tracking for validation feedback.


159-179: LGTM!

The input change handler correctly updates nested state and clears field-specific errors, providing immediate feedback when users fix validation issues.


208-622: LGTM!

The UI components consistently display validation errors with clear visual indicators (red borders, AlertCircle icons, inline messages) and required-field markers. Error handling is implemented for all validated fields across both user flows.


834-840: Previous review feedback addressed: button no longer disabled on final step.

The step-based disabled logic has been removed as requested in the previous review. The button is now clickable on all steps, with validation enforced in the nextStep handler. However, see the comment on lines 180-189 regarding missing completion logic for the final step.


38-42: The regex correctly matches the documented placeholder format—no issue found.

The test confirms that "+1 (555) 000-0000" validates successfully. The original analysis incorrectly assumed the regex couldn't handle both the space and opening paren together; however, [-\s.]? consumes the space, and the separate \(? then matches the paren. The regex works as intended for the documented placeholder format.

Likely an incorrect or invalid review comment.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Frontend/src/pages/BasicDetails.tsx (1)

689-697: Critical: resetForm uses DOM manipulation instead of resetting React state.

Lines 693-696 use querySelectorAll to directly clear input/select DOM values, but this doesn't update the formData state. After clicking reset, the inputs appear empty but the React state still contains the old values, which will reappear when the form re-renders (e.g., during step navigation).

Reset the React state instead of manipulating the DOM:

 const resetForm = () => {
   setStep(0);
   setAnimationDirection(0);
-
-  document.querySelectorAll("input").forEach((input) => (input.value = ""));
-  document
-    .querySelectorAll("select")
-    .forEach((select) => (select.value = ""));
+  setFormData({
+    influencer: {
+      firstName: "",
+      lastName: "",
+      email: "",
+      phone: "",
+      category: "",
+      instagram: "",
+      youtube: "",
+      twitter: "",
+      tiktok: "",
+      website: "",
+      audienceSize: "",
+      avgEngagement: "",
+      mainPlatform: "",
+      audienceAge: "",
+    },
+    brand: {
+      companyName: "",
+      website: "",
+      industry: "",
+      size: "",
+      budget: "",
+      targetAudience: "",
+      preferredPlatforms: "",
+      campaignGoals: "",
+    },
+  });
+  setErrors({});
 };
♻️ Duplicate comments (1)
Frontend/src/pages/BasicDetails.tsx (1)

839-845: Implement real-time button disabled state per requirements.

The PR objectives explicitly state: "Next button disabled until current-step required fields are valid." However, the button is currently always enabled and validation only runs on click. While the validation guard in nextStep() prevents progression, users can click repeatedly on an invalid form with no feedback until they fix the errors.

For better UX that matches the stated requirements, compute validation state and disable the button when the current step is invalid:

+ // Add after line 94 (after errors state)
+ const [isCurrentStepValid, setIsCurrentStepValid] = useState(false);
+
+ // Add useEffect to recompute validity when formData or step changes
+ useEffect(() => {
+   // Run validation without setting errors (silent check)
+   const newErrors: Record<string, string> = {};
+   const data = user === "influencer" ? formData.influencer : formData.brand;
+   
+   // Copy the validation logic from validateStep but don't call setErrors
+   // ... (same logic as lines 103-158)
+   
+   setIsCurrentStepValid(Object.keys(newErrors).length === 0);
+ }, [formData, step, user]);

                      <Button
                        className="bg-purple-700 hover:bg-purple-800 border border-purple-800 transition-all duration-200 transform hover:scale-105 text-white"
                        onClick={nextStep}
+                       disabled={!isCurrentStepValid}
                      >

Alternatively, if you prefer validation-on-submit UX, update the PR objectives to reflect the current behavior.

🧹 Nitpick comments (1)
Frontend/src/pages/BasicDetails.tsx (1)

38-43: Phone validation remains US-centric despite international claim.

The current regex enforces a 3-3-4 digit grouping that works for US/Canada formats but will reject many valid international phone numbers (e.g., UK: +44 20 1234 5678, India: +91 98765 43210). The comment on line 39 claims "international" support but the pattern is still country-specific.

Consider either:

  1. Using a dedicated library like libphonenumber-js for true international phone validation, or
  2. Updating the comment to clarify this validates North American formats, or
  3. Relaxing the pattern to accept variable-length digit groups:
 const validatePhone = (phone: string): boolean => {
-  // Basic pattern: optional country code + local number with common separators
-  const phoneRegex =
-    /^\+?[0-9]{1,3}?[-\s.]?\(?[0-9]{3}\)?[-\s.]?[0-9]{3}[-\s.]?[0-9]{4}$/;
+  // Pattern for international phone: country code + 7-15 digits with common separators
+  const phoneRegex = /^\+?[0-9]{1,3}[-\s.]?[(]?[0-9]{1,4}[)]?[-\s.]?[0-9]{1,4}[-\s.]?[0-9]{1,9}$/;
   return phoneRegex.test(phone.trim());
 };

This approach allows more flexibility for international formats while still enforcing reasonable structure.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 849e47f and 6302d6d.

📒 Files selected for processing (1)
  • Frontend/src/pages/BasicDetails.tsx (16 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
Frontend/src/pages/BasicDetails.tsx (3)
Frontend/src/components/ui/label.tsx (1)
  • Label (25-25)
Frontend/src/components/ui/input.tsx (1)
  • Input (21-21)
Frontend/src/components/ui/select.tsx (2)
  • Select (150-150)
  • SelectTrigger (153-153)

Comment on lines +120 to +122
if (influData.instagram && !influData.instagram.startsWith("@")) {
newErrors.instagram = "Instagram handle should start with @";
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Instagram handle validation is too permissive.

Line 120 only verifies the handle starts with @, but doesn't validate the username format. This allows invalid handles like "@", "@ ", "@!@#", or "@123 456".

Instagram usernames must be 1-30 characters, alphanumeric plus periods/underscores, and cannot end with a period:

-        if (influData.instagram && !influData.instagram.startsWith("@")) {
-          newErrors.instagram = "Instagram handle should start with @";
+        if (influData.instagram) {
+          const handle = influData.instagram.trim();
+          if (!handle.startsWith("@")) {
+            newErrors.instagram = "Instagram handle should start with @";
+          } else if (!/^@[a-zA-Z0-9._]{1,30}$/.test(handle) || handle.endsWith(".")) {
+            newErrors.instagram = "Invalid Instagram handle format";
+          }
         }
🤖 Prompt for AI Agents
In Frontend/src/pages/BasicDetails.tsx around lines 120 to 122, the Instagram
handle check only ensures the value starts with "@" and allows invalid inputs;
replace this with a stricter validation that enforces Instagram rules (1–30
chars after "@", only letters, numbers, periods and underscores, and not ending
with a period). Implement either a single regex such as
^@(?!.*\.$)[A-Za-z0-9._]{1,30}$ or validate by checking length, allowed
characters, and that the final character is not '.'; update the error message to
reflect the precise format rule when invalid.

Comment on lines +164 to +184
const handleInputChange = (field: string, value: string) => {
if (user === "influencer") {
setFormData(prev => ({
...prev,
influencer: { ...prev.influencer, [field]: value }
}));
} else {
setFormData(prev => ({
...prev,
brand: { ...prev.brand, [field]: value }
}));
}
// Clear error for this field
if (errors[field]) {
setErrors(prev => {
const newErrors = { ...prev };
delete newErrors[field];
return newErrors;
});
}
};
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Trim user input before storing to prevent whitespace-only values.

The validation functions call .trim() on values (lines 42, 46, 52), but handleInputChange stores the raw input without trimming. This allows users to enter whitespace-only values (e.g., " ") that pass the isEmpty check but fail validation when trimmed, creating confusing behavior where a "filled" field shows an error.

Trim text inputs at storage time for consistency:

 const handleInputChange = (field: string, value: string) => {
+  // Trim text inputs (but not Select values which are controlled)
+  const trimmedValue = typeof value === 'string' && value.includes(' ') 
+    ? value.trim() 
+    : value;
+
   if (user === "influencer") {
     setFormData(prev => ({
       ...prev,
-      influencer: { ...prev.influencer, [field]: value }
+      influencer: { ...prev.influencer, [field]: trimmedValue }
     }));
   } else {
     setFormData(prev => ({
       ...prev,
-      brand: { ...prev.brand, [field]: value }
+      brand: { ...prev.brand, [field]: trimmedValue }
     }));
   }

Note: You may want to trim only on blur instead of on every keystroke for better UX, but at minimum trim before validation.

🤖 Prompt for AI Agents
In Frontend/src/pages/BasicDetails.tsx around lines 164-184, handleInputChange
currently stores raw input allowing whitespace-only values; trim the incoming
value before calling setFormData (e.g., compute const trimmed = value.trim() and
use trimmed when updating influencer/brand) so stored state matches validation
expectations, and use the trimmed value when clearing errors (check
errors[field] against the trimmed value if needed); this ensures whitespace-only
inputs are normalized at storage time (or alternatively move trimming to onBlur
if you prefer better UX).

Comment on lines +217 to +229
<Label htmlFor="firstName">First Name <span className="text-red-500">*</span></Label>
<Input
id="firstName"
placeholder="John"
className="border border-gray-300"
value={formData.influencer.firstName}
onChange={(e) => handleInputChange("firstName", e.target.value)}
className={`border ${errors.firstName ? "border-red-500" : "border-gray-300"}`}
/>
{errors.firstName && (
<p className="text-red-500 text-sm flex items-center gap-1">
<AlertCircle className="h-4 w-4" /> {errors.firstName}
</p>
)}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add ARIA attributes for screen reader accessibility.

The error feedback is visual-only (red borders, error text). Screen reader users won't be informed that fields are invalid or what the error messages are. This pattern repeats throughout all form inputs.

Add aria-invalid and aria-describedby to invalid inputs:

         <div className="space-y-2">
           <Label htmlFor="firstName">First Name <span className="text-red-500">*</span></Label>
           <Input
             id="firstName"
             placeholder="John"
             value={formData.influencer.firstName}
             onChange={(e) => handleInputChange("firstName", e.target.value)}
-            className={`border ${errors.firstName ? "border-red-500" : "border-gray-300"}`}
+            className={`border ${errors.firstName ? "border-red-500" : "border-gray-300"}`}
+            aria-invalid={!!errors.firstName}
+            aria-describedby={errors.firstName ? "firstName-error" : undefined}
           />
           {errors.firstName && (
-            <p className="text-red-500 text-sm flex items-center gap-1">
+            <p id="firstName-error" className="text-red-500 text-sm flex items-center gap-1" role="alert">
               <AlertCircle className="h-4 w-4" /> {errors.firstName}
             </p>
           )}
         </div>

Apply this pattern to all validated inputs and Select components throughout lines 217-625. For Select components, pass aria-invalid as a prop to SelectTrigger.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Label htmlFor="firstName">First Name <span className="text-red-500">*</span></Label>
<Input
id="firstName"
placeholder="John"
className="border border-gray-300"
value={formData.influencer.firstName}
onChange={(e) => handleInputChange("firstName", e.target.value)}
className={`border ${errors.firstName ? "border-red-500" : "border-gray-300"}`}
/>
{errors.firstName && (
<p className="text-red-500 text-sm flex items-center gap-1">
<AlertCircle className="h-4 w-4" /> {errors.firstName}
</p>
)}
<Label htmlFor="firstName">First Name <span className="text-red-500">*</span></Label>
<Input
id="firstName"
placeholder="John"
value={formData.influencer.firstName}
onChange={(e) => handleInputChange("firstName", e.target.value)}
className={`border ${errors.firstName ? "border-red-500" : "border-gray-300"}`}
aria-invalid={!!errors.firstName}
aria-describedby={errors.firstName ? "firstName-error" : undefined}
/>
{errors.firstName && (
<p id="firstName-error" className="text-red-500 text-sm flex items-center gap-1" role="alert">
<AlertCircle className="h-4 w-4" /> {errors.firstName}
</p>
)}
🤖 Prompt for AI Agents
In Frontend/src/pages/BasicDetails.tsx around lines 217 to 229 (and apply across
lines 217-625), the inputs and Selects only provide visual error feedback; add
accessibility attributes so screen readers announce validation state. For each
validated input: add aria-invalid={Boolean(errors.fieldName)} and
aria-describedby referencing a unique id for the error message (e.g.,
`${fieldName}-error`) and ensure the error <p> has that id. For Select
components, pass aria-invalid to the SelectTrigger and use aria-describedby on
the underlying trigger input (or a wrapper) pointing to the error id. Repeat
this pattern for every validated field and Select between lines 217–625.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BUG:The BasicDetails form component has no input validation for user-submitted data

1 participant