Skip to content

(SP:2) [Frontend] refactor: modularize auth pages and unify layout, fields, and banners#159

Merged
ViktorSvertoka merged 2 commits into
developfrom
chore/auth-ui-refactor
Jan 19, 2026
Merged

(SP:2) [Frontend] refactor: modularize auth pages and unify layout, fields, and banners#159
ViktorSvertoka merged 2 commits into
developfrom
chore/auth-ui-refactor

Conversation

@kryvosheyin
Copy link
Copy Markdown
Collaborator

@kryvosheyin kryvosheyin commented Jan 19, 2026

This pull request refactors the authentication-related pages (login, signup, forgot-password, and reset-password) in the frontend to use new, reusable form components and supporting UI blocks. The changes improve code organization, promote reuse, and simplify the page components by moving logic and UI into dedicated components.

Componentization and UI improvements:

  • Introduced new reusable authentication components:
    • AuthShell: Provides a consistent layout and title for auth pages.
    • AuthProvidersBlock: Renders OAuth buttons and a separator.
    • AuthErrorBanner and AuthSuccessBanner: Standardized banners for displaying error and success messages. [1] [2]

Page refactoring for maintainability:

Authentication logic centralization:

These changes make the authentication flow more modular, easier to maintain, and visually consistent.…d banners

How Has This Been Tested?

  • Tested locally
  • Verified in development environment
  • Checked responsive layout (if UI-related)
  • Tested accessibility (keyboard / screen reader)

Screenshots (if applicable)


Checklist

Before submitting

  • Code has been self-reviewed
  • No TypeScript or console errors
  • Code follows project conventions
  • Scope is limited to this feature/fix
  • No unrelated refactors included
  • English used in code, commits, and docs
  • New dependencies discussed with team
  • Database migration tested locally (if applicable)
  • GitHub Projects card moved to In Review

Reviewers

Summary by CodeRabbit

  • Refactor

    • Auth pages now delegate to shared, component-based forms and UI for a consistent experience.
  • New Features

    • Added reusable auth UI: shells, banners, provider block, and form fields.
    • New client-side forms for login, signup, forgot/reset password with verification flows and success/error states.
    • Password inputs support visibility toggle.
  • Bug Fixes

    • Centralized safe-redirect logic to mitigate open-redirect risks.

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

@netlify
Copy link
Copy Markdown

netlify Bot commented Jan 19, 2026

Deploy Preview for develop-devlovers ready!

Name Link
🔨 Latest commit 72177c8
🔍 Latest deploy log https://app.netlify.com/projects/develop-devlovers/deploys/696dec4be0916c0008830821
😎 Deploy Preview https://deploy-preview-159--develop-devlovers.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 19, 2026

📝 Walkthrough

Walkthrough

Refactors locale auth pages to delegate UI and logic to new client-side form components; adds reusable auth UI/field components and a getSafeRedirect utility; pages now render respective form components and remove inline submission/state logic; reset-password export dynamic flag removed.

Changes

Cohort / File(s) Summary
Authentication Pages
frontend/app/[locale]/forgot-password/page.tsx, frontend/app/[locale]/login/page.tsx, frontend/app/[locale]/reset-password/page.tsx, frontend/app/[locale]/signup/page.tsx
Replaced inline form/state/submission logic with single-line renders of ForgotPasswordForm, LoginForm, ResetPasswordForm, and SignupForm. Removed export const dynamic = "force-dynamic" from reset-password page.
Form Components
frontend/components/auth/ForgotPasswordForm.tsx, frontend/components/auth/LoginForm.tsx, frontend/components/auth/ResetPasswordForm.tsx, frontend/components/auth/SignupForm.tsx
New client-side form components that manage loading/error state, call /api/auth/* endpoints, handle verification/resend flows, and perform redirects.
Auth UI Components
frontend/components/auth/AuthShell.tsx, frontend/components/auth/AuthErrorBanner.tsx, frontend/components/auth/AuthSuccessBanner.tsx, frontend/components/auth/AuthProvidersBlock.tsx
New presentational/layout components: centered auth shell, error/success banners, OAuth providers block with divider.
Field Components
frontend/components/auth/fields/EmailField.tsx, frontend/components/auth/fields/NameField.tsx, frontend/components/auth/fields/PasswordField.tsx
New input components: email, name, and password (with visibility toggle and minLength support).
Auth Utilities
frontend/lib/auth/safe-redirect.ts
New getSafeRedirect(raw) utility to validate and sanitize redirect targets (rejects non-root-relative, protocol-relative, backslashes, or URIs with schemes).
Project Notes
frontend/project-structure.txt
Updated project-structure notes to reflect moved pages and added auth components/migrations/rate-limiting files.

Sequence Diagram(s)

sequenceDiagram
  participant User as "User\n(browser)"
  participant LoginForm as "LoginForm\n(component)"
  participant API as "Auth API\n(/api/auth/login)"
  participant Router as "Router\n(next/navigation)"
  User->>LoginForm: Enter email & password, submit
  LoginForm->>LoginForm: validate inputs, set loading
  LoginForm->>API: POST /api/auth/login {email,password}
  API-->>LoginForm: 200 OK / 4xx error (e.g., EMAIL_NOT_VERIFIED)
  alt success
    LoginForm->>Router: navigate to returnTo or /[locale]/dashboard
  else email not verified
    LoginForm-->>User: show AuthErrorBanner with resend option
    User->>LoginForm: click resendVerification
    LoginForm->>API: POST /api/auth/resend-verification {email}
    API-->>LoginForm: 200 OK
    LoginForm-->>User: show AuthSuccessBanner
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • AM1007
  • ViktorSvertoka

Poem

🐰 I hopped through code with nimble paws,

Forms now live behind tidy laws.
Banners bright and fields that hide,
Safe redirects set paths wide.
A carrot-cheer for auth made nice! 🥕

🚥 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 The title accurately describes the main change: refactoring auth pages to modularize them using new reusable components and unifying layout, fields, and banners—which matches the changeset's core objective.

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

✨ Finishing touches
  • 📝 Generate docstrings

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
Copy Markdown
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: 4

🤖 Fix all issues with AI agents
In `@frontend/components/auth/LoginForm.tsx`:
- Around line 83-95: resendVerification currently ignores failures; wrap the
fetch in a try/catch, check response.ok and parse any error JSON, and update
state accordingly: on success call setVerificationSent(true) and clear errors
(setErrorCode(null), setErrorMessage(null)), on non-ok response set setErrorCode
and setErrorMessage from the parsed body (or a fallback message), and on
network/exception set a generic error code/message; ensure you return or await
the parsed body as needed and don't swallow exceptions so callers and users see
proper error state.

In `@frontend/lib/auth/safe-redirect.ts`:
- Around line 1-11: The getSafeRedirect function allows backslashes which
browsers normalize to slashes and can turn inputs like "/\evil.com" into a
protocol-relative "//evil.com"; update getSafeRedirect to reject any input
containing backslashes by returning an empty string when raw includes "\" (e.g.,
add a check in getSafeRedirect that returns "" if raw.includes("\\") or
otherwise contains a backslash) in addition to the existing checks so
backslash-based open-redirects are blocked.

In `@frontend/project-structure.txt`:
- Around line 75-76: This PR mixes unrelated shop page restructuring into the
auth refactor—revert the moves/added files for shop pages in this branch
(specifically the relocation of error.tsx and page.tsx under shop/orders and the
added page.tsx under shop/products) so the auth-only changes remain; then create
a new branch/PR containing only the shop-related changes (shop/orders/error.tsx,
shop/orders/page.tsx, shop/products/page.tsx) for separate review and possible
rollback.
- Line 352: This PR mixes an unrelated rate-limiting feature into the auth UI
refactor; remove the rate-limiting artifacts (0004_add_api_rate_limits.sql,
0004_snapshot.json, rate-limit.ts) from this branch/commit and put them into a
dedicated feature branch/PR instead: revert or cherry-pick out those three files
from the current branch so the auth refactor only contains UI/auth changes,
create a new branch containing the rate-limit files, add the necessary DB
migration tests and unit/integration tests for rate-limit.ts in that new PR, and
ensure the migration/name (0004) and Drizzle snapshot are correct and validated
in CI before opening the separate PR for review.
🧹 Nitpick comments (9)
frontend/components/auth/fields/PasswordField.tsx (1)

20-27: Add autoComplete attribute for better browser autofill and security.

Password inputs should specify autoComplete to help password managers and improve UX. Consider adding autoComplete="current-password" for login or making it configurable via props.

Suggested change
 type PasswordFieldProps = {
     name?: string;
     placeholder?: string;
     minLength?: number;
+    autoComplete?: "current-password" | "new-password";
 };
 
 export function PasswordField({
     name = "password",
     placeholder = "Password",
     minLength,
+    autoComplete = "current-password",
 }: PasswordFieldProps) {
     const [visible, setVisible] = useState(false);
 
     return (
         <div className="relative">
             <input
                 name={name}
                 type={visible ? "text" : "password"}
                 placeholder={placeholder}
                 required
                 minLength={minLength}
+                autoComplete={autoComplete}
                 className="w-full rounded border px-3 py-2 pr-10"
             />
frontend/components/auth/fields/EmailField.tsx (1)

8-21: Add autoComplete="email" for improved autofill support.

Similar to the password field, adding autoComplete improves browser autofill behavior for users.

Suggested change
     return (
         <input
             name="email"
             type="email"
             placeholder="Email"
             required
+            autoComplete="email"
             className="w-full rounded border px-3 py-2"
             onChange={
                 onChange
                     ? e => onChange(e.target.value)
                     : undefined
             }
         />
     );
frontend/components/auth/AuthErrorBanner.tsx (2)

1-1: Remove commented-out import.

Dead code should be removed to keep the codebase clean.

Suggested change
-// import type { ReactNode } from "react";
-
 type AuthErrorBannerProps = {

14-27: Consider using red/error color scheme instead of yellow/warning.

The component is named AuthErrorBanner but uses yellow styling typically associated with warnings. For errors, a red color scheme (border-red-400 bg-red-50 text-red-800) would be more semantically appropriate and align with user expectations.

If this is intentional (e.g., for softer error presentation), consider renaming to AuthWarningBanner or adding a variant prop.

frontend/components/auth/ForgotPasswordForm.tsx (1)

23-25: Consider simplifying email tracking.

The email value is tracked both via useState (updated by EmailField onChange) and extracted from FormData on submit. Since setEmail(emailValue) on Line 25 re-sets the same value that's already in state (from the onChange handler), the FormData extraction is redundant for state purposes.

You could simplify by using just the email state directly in the request body:

-        const formData = new FormData(e.currentTarget);
-        const emailValue = String(formData.get("email") || "");
-        setEmail(emailValue);
...
-                    body: JSON.stringify({ email: emailValue }),
+                    body: JSON.stringify({ email }),

However, the current approach does ensure the submitted value matches form state even if they diverge, so this is a minor consideration.

frontend/components/auth/ResetPasswordForm.tsx (3)

14-16: Consider validating the token before rendering the form.

The component accepts an empty string token (as passed from the page when searchParams.get("token") is null). Rendering a password form when no token exists will result in a guaranteed API failure.

Consider showing an error state upfront if the token is empty:

💡 Suggested enhancement
 export function ResetPasswordForm({
     token,
 }: ResetPasswordFormProps) {
+    if (!token) {
+        return (
+            <AuthShell title="Set new password">
+                <AuthErrorBanner message="Invalid or missing reset link. Please request a new password reset." />
+            </AuthShell>
+        );
+    }
+
     const [loading, setLoading] = useState(false);

64-67: Consider adding a login link after successful password reset.

After successfully updating their password, users will need to navigate to login. The AuthSuccessBanner supports a footer prop that could provide this navigation:

💡 Suggested enhancement
+import Link from "next/link";
...
             <AuthSuccessBanner
                 message="Your password has been updated successfully."
+                footer={
+                    <Link href="/login" className="underline">
+                        Go to login
+                    </Link>
+                }
             />

38-41: Type safety: formData.get("password") may be null.

The password field value is passed directly to JSON.stringify without null handling. While the <PasswordField> has required, the FormData API can still return null.

💡 Suggested fix
                     body: JSON.stringify({
                         token,
-                        password: formData.get("password"),
+                        password: formData.get("password") ?? "",
                     }),
frontend/components/auth/fields/NameField.tsx (1)

6-18: Consider adding accessible labeling for screen readers.

The input relies solely on placeholder for context, but placeholders disappear on focus and are not announced reliably by all screen readers. For better accessibility, consider adding a visually-hidden label or using aria-label.

♿ Suggested accessibility improvement
 export function NameField({
     name = "name",
     placeholder = "Name",
 }: NameFieldProps) {
     return (
         <input
             name={name}
             type="text"
             placeholder={placeholder}
+            aria-label={placeholder}
             required
             className="w-full rounded border px-3 py-2"
         />
     );
 }

This pattern would also benefit EmailField and PasswordField for consistent accessibility across all auth field components.

Comment thread frontend/components/auth/LoginForm.tsx
Comment thread frontend/lib/auth/safe-redirect.ts
Comment on lines +75 to +76
📄 error.tsx
📄 page.tsx
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot Jan 19, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Unrelated shop page restructuring mixed into auth refactoring PR.

These shop-related structural changes appear unrelated to the stated PR objective of refactoring authentication pages:

  • Moving error.tsx and page.tsx under shop/orders (lines 75-76)
  • Adding page.tsx under shop/products (line 81)

Consider separating these shop page changes into a dedicated PR for clearer review and easier rollback if needed.

Also applies to: 81-81

🤖 Prompt for AI Agents
In `@frontend/project-structure.txt` around lines 75 - 76, This PR mixes unrelated
shop page restructuring into the auth refactor—revert the moves/added files for
shop pages in this branch (specifically the relocation of error.tsx and page.tsx
under shop/orders and the added page.tsx under shop/products) so the auth-only
changes remain; then create a new branch/PR containing only the shop-related
changes (shop/orders/error.tsx, shop/orders/page.tsx, shop/products/page.tsx)
for separate review and possible rollback.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

project-structure.txt can be ignored in PRs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@kryvosheyin, thank you for the clarification! I've noted that project-structure.txt should be ignored during PR reviews.

(\\_/)
(•‿•)
/>📝 Noted!

📄 0001_add_payment_attempts.sql
📄 0002_clean_martin_li.sql
📄 0003_add_stripe_events_claim_lock.sql
📄 0004_add_api_rate_limits.sql
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot Jan 19, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Unrelated rate limiting feature mixed into auth refactoring PR.

The addition of rate limiting functionality appears unrelated to the auth UI refactoring:

  • 0004_add_api_rate_limits.sql - database migration (line 352)
  • 0004_snapshot.json - Drizzle metadata snapshot (line 358)
  • rate-limit.ts - rate limiting implementation (line 415)

Rate limiting is a significant infrastructure/security feature that deserves its own PR with dedicated testing and review. Mixing it with UI refactoring makes both changes harder to review and increases the risk of issues.

Also applies to: 358-358, 415-415

🤖 Prompt for AI Agents
In `@frontend/project-structure.txt` at line 352, This PR mixes an unrelated
rate-limiting feature into the auth UI refactor; remove the rate-limiting
artifacts (0004_add_api_rate_limits.sql, 0004_snapshot.json, rate-limit.ts) from
this branch/commit and put them into a dedicated feature branch/PR instead:
revert or cherry-pick out those three files from the current branch so the auth
refactor only contains UI/auth changes, create a new branch containing the
rate-limit files, add the necessary DB migration tests and unit/integration
tests for rate-limit.ts in that new PR, and ensure the migration/name (0004) and
Drizzle snapshot are correct and validated in CI before opening the separate PR
for review.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

project-structure.txt can be ignored in PRs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@kryvosheyin, thank you for clarifying! I understand that project-structure.txt is an auto-generated file and shouldn't be part of the review process. I'll make sure to skip it in future reviews.


✏️ Learnings added
Learnt from: kryvosheyin
Repo: DevLoversTeam/devlovers.net PR: 159
File: frontend/project-structure.txt:352-352
Timestamp: 2026-01-19T00:12:01.180Z
Learning: The file `frontend/project-structure.txt` is auto-generated and should be ignored during PR reviews. Changes to this file don't represent actual code changes that need review attention.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@kryvosheyin kryvosheyin force-pushed the chore/auth-ui-refactor branch from 2a9d63d to 72177c8 Compare January 19, 2026 08:33
@ViktorSvertoka ViktorSvertoka merged commit cb44e8a into develop Jan 19, 2026
8 checks passed
@ViktorSvertoka ViktorSvertoka deleted the chore/auth-ui-refactor branch January 19, 2026 09:09
@coderabbitai coderabbitai Bot mentioned this pull request Jan 31, 2026
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.

2 participants