Skip to content

Refactor auth system: extract forms to dedicated components#39

Merged
Ross1116 merged 1 commit into
mainfrom
staging
Feb 26, 2026
Merged

Refactor auth system: extract forms to dedicated components#39
Ross1116 merged 1 commit into
mainfrom
staging

Conversation

@Ross1116

@Ross1116 Ross1116 commented Feb 26, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Added smooth entrance animations to login, registration, and password reset forms for improved visual polish.
  • Improvements

    • Streamlined authentication experience by removing unnecessary loading spinners from the flow.
    • Enhanced form validation feedback and error messaging across all authentication pages.

@vercel

vercel Bot commented Feb 26, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
sitespace-app Building Building Preview, Comment Feb 26, 2026 3:53am

@coderabbitai

coderabbitai Bot commented Feb 26, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR refactors the authentication system by extracting form handling logic from page components into dedicated, reusable form components (ForgotPasswordForm, LoginForm, RegisterForm). Auth pages are converted to lightweight server-side components that render these forms. The AuthContext no longer displays a loading UI, and the auth/loading route is removed. A new AuthFormMotion component adds entrance animations to forms. Landing page imports are consolidated via a ClientDynamics barrel export.

Changes

Cohort / File(s) Summary
Auth Page Refactoring
src/app/(auth)/forgot-password/page.tsx, src/app/(auth)/login/page.tsx, src/app/(auth)/register/page.tsx
Converted to server-side components that delegate form rendering to external form components, removing inline state management, form handling, and submission logic from pages.
Auth Form Components
src/components/auth/ForgotPasswordForm.tsx, src/components/auth/LoginForm.tsx, src/components/auth/RegisterForm.tsx
New client-side form components extracted from pages, each managing form state, validation, submission, error handling, and UI rendering with integration to AuthContext and API calls.
Form Animation & Context
src/components/auth/AuthFormMotion.tsx, src/app/context/AuthContext.tsx, src/app/(auth)/loading.tsx
Added AuthFormMotion wrapper for entrance animations using Framer Motion; removed loading UI from AuthContext and deleted the auth/loading route component entirely.
Landing Page Optimization
src/components/landing/ClientDynamics.tsx, src/components/landing/LandingPage.tsx
Created ClientDynamics barrel file for dynamic imports of client-only components (ScrollAnimations, HeroOrbs, LookaheadDashboard, ShowcaseSection); consolidated imports in LandingPage and removed Suspense wrapper around HeroOrbs.
Dashboard Styling
src/app/(dashboard)/layout.tsx
Updated auth-loading state styling to use CSS variables (bg-[var(--page-bg)] and text-[var(--teal)]) instead of hardcoded utility classes.

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly Related PRs

Poem

🐰 Forms take flight with graceful ease,
Server pages dance with tranquil breeze,
AuthFormMotion spins them 'round and 'round,
Loading spinners quietly bound—
Clean, composed, a refactored delight! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ 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%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed Title check skipped as CodeRabbit has written the PR title.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch staging

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.

@coderabbitai coderabbitai Bot changed the title @coderabbitai Refactor auth system: extract forms to dedicated components Feb 26, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (4)
src/components/landing/ClientDynamics.tsx (1)

6-24: Consider adding loading fallbacks for content-heavy components.

The dynamic imports work correctly, but LookaheadDashboard and ShowcaseSection appear to be content-heavy sections. Without a loading fallback, users may see empty space or layout shifts while these components load on the client.

For decorative components like HeroOrbs and ScrollAnimations, omitting the fallback is fine.

💡 Optional: Add skeleton/placeholder for content components
 export const LookaheadDashboard = dynamic(
   () => import("./LookaheadPreview").then((m) => m.LookaheadDashboard),
-  { ssr: false },
+  { ssr: false, loading: () => <div className="h-96 animate-pulse bg-white/5 rounded-xl" /> },
 );

 export const ShowcaseSection = dynamic(
   () => import("./ShowcaseSection").then((m) => m.ShowcaseSection),
-  { ssr: false },
+  { ssr: false, loading: () => <div className="h-96 animate-pulse bg-white/5 rounded-xl" /> },
 );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/landing/ClientDynamics.tsx` around lines 6 - 24,
LookaheadDashboard and ShowcaseSection are dynamically imported without a
loading fallback, causing empty space/layout shifts while they load; update the
dynamic(...) calls for LookaheadDashboard and ShowcaseSection to include a
loading prop that returns a lightweight skeleton/placeholder component (or
simple placeholder element) to render during client load, e.g., add loading: ()
=> <YourSkeleton /> to the dynamic options and create or reuse a small
Skeleton/Placeholder component to keep layout stable while LookaheadDashboard
and ShowcaseSection hydrate.
src/components/auth/RegisterForm.tsx (1)

112-131: Consider making inputs fully controlled by adding value prop.

The Input components use onChange to update state but don't bind the value prop back to formData. This makes them partially uncontrolled, which can lead to state sync issues (e.g., if state is reset programmatically, the UI won't reflect it).

Proposed fix to make inputs controlled
             <Input
               id="firstName"
               name="firstName"
               placeholder="John"
+              value={formData.firstName}
               onChange={handleChange}
               required
               className="h-11 border-slate-200 focus-visible:ring-[var(--navy)]"
             />
           </div>
           <div className="space-y-2">
             <Label htmlFor="lastName">Last Name</Label>
             <Input
               id="lastName"
               name="lastName"
               placeholder="Doe"
+              value={formData.lastName}
               onChange={handleChange}
               required
               className="h-11 border-slate-200 focus-visible:ring-[var(--navy)]"
             />

Apply the same pattern to all other inputs (email, phone, password, confirmPassword).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/auth/RegisterForm.tsx` around lines 112 - 131, The Input
elements (e.g., the Input with id/name "firstName" and "lastName") are currently
updated via onChange/handleChange but lack a bound value, making them partially
uncontrolled; update each Input to include value={formData.firstName} and
value={formData.lastName} respectively (and similarly bind value for email,
phone, password, confirmPassword) so the components are fully controlled by the
formData state managed by handleChange and any programmatic resets will reflect
in the UI.
src/components/auth/LoginForm.tsx (1)

37-40: Consider refactoring to avoid eslint-disable.

The suppressed react-hooks/exhaustive-deps warning indicates a potential issue. The effect reads error and calls clearError but neither is in the dependency array. While the intent (clear error on input change) is valid, this can be achieved more cleanly.

Alternative approach without eslint-disable
-  // eslint-disable-next-line react-hooks/exhaustive-deps
-  useEffect(() => {
-    if (error) clearError();
-  }, [email, password]);
+  const handleEmailChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+    setEmail(e.target.value);
+    if (error) clearError();
+  };
+
+  const handlePasswordChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+    setPassword(e.target.value);
+    if (error) clearError();
+  };

Then use handleEmailChange and handlePasswordChange in the respective Input onChange handlers instead of inline setters.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/auth/LoginForm.tsx` around lines 37 - 40, The useEffect
currently reads error and calls clearError but suppresses
react-hooks/exhaustive-deps; refactor by removing the effect and instead clear
errors inside the input change handlers: add or update handleEmailChange and
handlePasswordChange to call setEmail/setPassword and then call clearError()
when error is present, and wire those handlers to the Input onChange props;
remove the useEffect and the eslint-disable comment so clearError is invoked
deterministically without missing dependencies.
src/components/auth/ForgotPasswordForm.tsx (1)

60-65: Consider allowing retry after error.

Currently, the form remains functional after an error, which is good. However, after success, the form is permanently disabled. Consider whether users should be able to request another email if they didn't receive the first one (perhaps after a delay/cooldown).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/auth/ForgotPasswordForm.tsx` around lines 60 - 65, The success
branch in ForgotPasswordForm currently shows a success Alert and leaves the form
permanently disabled because the UI relies on status.type === "success"; change
the behavior so users can request another email by (1) removing permanent
disablement tied directly to status.type === "success" in the submit/button
disabled logic (update the condition in the component where form submission is
blocked), (2) implement a cooldown/resend flow by adding a resend action or
timer that resets status (use setStatus or the existing status state) after a
configurable delay, and (3) optionally surface a "Resend email" button that
calls the same submit handler (or a dedicated resendEmail function) and respects
the cooldown to prevent spamming; reference the ForgotPasswordForm component,
status (and setStatus) state, and the submit handler to locate and update the
code.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/components/auth/ForgotPasswordForm.tsx`:
- Around line 60-65: The success branch in ForgotPasswordForm currently shows a
success Alert and leaves the form permanently disabled because the UI relies on
status.type === "success"; change the behavior so users can request another
email by (1) removing permanent disablement tied directly to status.type ===
"success" in the submit/button disabled logic (update the condition in the
component where form submission is blocked), (2) implement a cooldown/resend
flow by adding a resend action or timer that resets status (use setStatus or the
existing status state) after a configurable delay, and (3) optionally surface a
"Resend email" button that calls the same submit handler (or a dedicated
resendEmail function) and respects the cooldown to prevent spamming; reference
the ForgotPasswordForm component, status (and setStatus) state, and the submit
handler to locate and update the code.

In `@src/components/auth/LoginForm.tsx`:
- Around line 37-40: The useEffect currently reads error and calls clearError
but suppresses react-hooks/exhaustive-deps; refactor by removing the effect and
instead clear errors inside the input change handlers: add or update
handleEmailChange and handlePasswordChange to call setEmail/setPassword and then
call clearError() when error is present, and wire those handlers to the Input
onChange props; remove the useEffect and the eslint-disable comment so
clearError is invoked deterministically without missing dependencies.

In `@src/components/auth/RegisterForm.tsx`:
- Around line 112-131: The Input elements (e.g., the Input with id/name
"firstName" and "lastName") are currently updated via onChange/handleChange but
lack a bound value, making them partially uncontrolled; update each Input to
include value={formData.firstName} and value={formData.lastName} respectively
(and similarly bind value for email, phone, password, confirmPassword) so the
components are fully controlled by the formData state managed by handleChange
and any programmatic resets will reflect in the UI.

In `@src/components/landing/ClientDynamics.tsx`:
- Around line 6-24: LookaheadDashboard and ShowcaseSection are dynamically
imported without a loading fallback, causing empty space/layout shifts while
they load; update the dynamic(...) calls for LookaheadDashboard and
ShowcaseSection to include a loading prop that returns a lightweight
skeleton/placeholder component (or simple placeholder element) to render during
client load, e.g., add loading: () => <YourSkeleton /> to the dynamic options
and create or reuse a small Skeleton/Placeholder component to keep layout stable
while LookaheadDashboard and ShowcaseSection hydrate.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8738005 and 5810c08.

📒 Files selected for processing (12)
  • src/app/(auth)/forgot-password/page.tsx
  • src/app/(auth)/loading.tsx
  • src/app/(auth)/login/page.tsx
  • src/app/(auth)/register/page.tsx
  • src/app/(dashboard)/layout.tsx
  • src/app/context/AuthContext.tsx
  • src/components/auth/AuthFormMotion.tsx
  • src/components/auth/ForgotPasswordForm.tsx
  • src/components/auth/LoginForm.tsx
  • src/components/auth/RegisterForm.tsx
  • src/components/landing/ClientDynamics.tsx
  • src/components/landing/LandingPage.tsx
💤 Files with no reviewable changes (2)
  • src/app/(auth)/loading.tsx
  • src/app/context/AuthContext.tsx

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.

1 participant