Skip to content

Conversation

@jason-duong4509
Copy link
Contributor

@jason-duong4509 jason-duong4509 commented Dec 24, 2025

  • Completed SANC-48
  • Added a loading screen while the Google Maps API loads (feedback from SANC-39). Found in \src\app_components\agencycomponents\agency-interactive-area.tsx

Attached is a video demonstrating the login process, starting when the user has a name (directs them to /dashboard) and then when the user has no name (directs them to /fill-out-name).

In the video, /dashboard was a copy-paste of the agency-interative-area.tsx file. It was only added since the endpoint does not yet exist. It is not included in the final branch (/dashboard remains non-existent)

SANC-48.Video.mp4

Summary by CodeRabbit

  • New Features

    • Added a "Fill Out Name" page where users can enter and save their profile name and be redirected after saving.
    • New server endpoint to change a user's name and support the post-save redirect flow.
  • Improvements

    • Users without a name are routed to the name entry page before dashboard access.
    • Loading states now display a styled, centered loading card instead of an empty placeholder.
  • Validation

    • Name input enforces format rules to prevent invalid entries.

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

- Completed SANC-48
- Added a loading screen while the Google Maps API loads (feedback from SANC-39). Found in \src\app\_components\agencycomponents\agency-interactive-area.tsx
@coderabbitai
Copy link

coderabbitai bot commented Dec 24, 2025

📝 Walkthrough

Walkthrough

Adds a name-collection page and API to set a user's name, updates dashboard redirect logic to guard against empty names and validate agency slugs, and replaces an empty Google Maps loading placeholder with a styled Mantine Paper containing a centered "Loading..." title.

Changes

Cohort / File(s) Summary
Validation
src/types/validation.ts
Add nameRegex export to enforce no consecutive spaces and require alphanumeric start/end.
Loading State Enhancement
src/app/_components/agencycomponents/agency-interactive-area.tsx
Replace empty loading placeholder with a small centered Mantine Paper containing a Title "Loading...".
New Name Input Page
src/app/fill-out-name/page.tsx
Add client-side FillOutNamePage using Mantine useForm with nameRegex validation; two-step submit: changeName then redirectToDashboard; notifications and router navigation.
API Router Updates
src/server/api/routers/organizations.ts
Add changeName protectedProcedure (validates nameRegex, updates user via eq), and enhance redirectToDashboard to guard empty ctx.session.user.name, validate agency slug and construct slug-based redirect; improved error handling and messages.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Client as FillOutName Page
    participant API as organizations.router
    participant DB as Database
    participant Router as Next Router

    User->>Client: Submit name
    Client->>API: changeName(newName)
    API->>API: Validate nameRegex
    API->>DB: UPDATE user SET name = newName WHERE id = ctx.session.user.id
    DB-->>API: Success/Error
    API-->>Client: changeName result
    Client->>API: redirectToDashboard()
    API->>API: Check ctx.session.user.name, role, slug
    API->>DB: Query organization by slug (if needed)
    DB-->>API: Organization / Not found
    API-->>Client: redirectUrl or error
    Client->>Router: router.push(redirectUrl)
    Router-->>User: Navigate
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • promatty
  • burtonjong
  • themaxboucher
  • JustinTan-1
  • Yemyam
  • Lujarios

Poem

🐰 I nibble names from tip to tail,
A paper nest where forms prevail,
Loading paper snug and bright,
Names set true, redirects take flight,
Hop—into dashboards with 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 The PR title directly references ticket SANC-48 and describes the feature: allowing users who complete registration to input their name, which is the main objective of this changeset.

✏️ 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

@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: 5

🧹 Nitpick comments (1)
src/app/login/page.tsx (1)

12-15: Document the RedirectLink type.

The custom type declaration is necessary but lacks context. Consider adding a comment explaining that this matches the return value from the better-auth sign-in callback hook defined in src/lib/auth.ts.

🔎 Suggested documentation
-//Custom type declaration fo result.data after logging in.
+// Custom type declaration for result.data after logging in.
-//Needed as the better auth hook will return one of two URLs
-//to redirect to.
+// The better-auth sign-in hook returns a redirect URL via the after middleware
+// defined in src/lib/auth.ts (either /fill-out-name or /dashboard).
 type RedirectLink = { newLink: string };
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 42ecab9 and fcf42ab.

📒 Files selected for processing (5)
  • src/app/_components/agencycomponents/agency-interactive-area.tsx
  • src/app/fill-out-name/page.tsx
  • src/app/login/page.tsx
  • src/lib/auth.ts
  • src/server/api/routers/organizations.ts
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-23T05:44:35.017Z
Learnt from: tanvimahal
Repo: Code-the-Change-YYC/salvationarmy PR: 25
File: src/server/api/routers/organizations.ts:38-38
Timestamp: 2025-12-23T05:44:35.017Z
Learning: In this codebase's TRPC protectedProcedure context, ctx.session has a nested structure containing both a session object and a user object. To access activeOrganizationId, use ctx.session.session.activeOrganizationId (not ctx.session.activeOrganizationId).

Applied to files:

  • src/server/api/routers/organizations.ts
🧬 Code graph analysis (3)
src/app/fill-out-name/page.tsx (4)
src/app/login/page.tsx (1)
  • LoginPage (17-96)
src/trpc/react.tsx (1)
  • api (25-25)
src/lib/notifications.ts (1)
  • notify (13-58)
src/app/_components/common/button/Button.tsx (1)
  • Button (41-80)
src/server/api/routers/organizations.ts (2)
src/server/api/trpc.ts (1)
  • protectedProcedure (122-132)
src/server/db/auth-schema.ts (1)
  • user (5-19)
src/app/login/page.tsx (1)
src/lib/auth-client.ts (2)
  • authClient (4-7)
  • authClient (9-9)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: ci
🔇 Additional comments (3)
src/app/_components/agencycomponents/agency-interactive-area.tsx (1)

3-3: LGTM! Nice loading UI improvement.

The addition of a styled loading card using Mantine's Paper and Title components is a good UX enhancement over the previous empty div. The implementation is clean and consistent with the existing Mantine design system usage.

Also applies to: 169-176

src/app/login/page.tsx (2)

50-56: Good error handling with proper cleanup.

The error handling correctly shows user-facing messages via alert() and the finally block ensures the loading state is always reset regardless of success or failure.


40-49: The type assertion is safe but consider formalizing the custom type.

The double assertion pattern (result.data as unknown as RedirectLink) is a valid workaround for better-auth's type limitations. The server-side middleware (in src/lib/auth.ts lines 21 and 24) explicitly returns { newLink: ... } for /sign-in/email requests, which correctly flows back to the client in result.data. However, since this custom property is not in better-auth's type definitions, the assertion is necessary.

To improve type safety without the workaround, consider creating a type guard or a safer wrapper around authClient.signIn.email() that validates the newLink property exists before using it.

<Stack gap="md">
<TextInput
label="Name"
placeholder="Alphanumeric, 3+ Characters"
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Update placeholder to match actual validation.

The placeholder says "3+ Characters" but the regex pattern actually requires 5+ characters (though it should be corrected to 3+ as per the intended design).

-              placeholder="Alphanumeric, 3+ Characters"
+              placeholder="Your full name"
📝 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
placeholder="Alphanumeric, 3+ Characters"
placeholder="Your full name"
🤖 Prompt for AI Agents
In src/app/fill-out-name/page.tsx around line 61, the input placeholder
currently reads "Alphanumeric, 3+ Characters" which mismatches the actual regex
validation requiring 5+ characters; update the code so the placeholder matches
the intended validation by either changing the regex to require 3+ characters or
changing the placeholder to state "Alphanumeric, 5+ Characters" — choose the
intended design (preferably correct the regex to 3+ if that was intended) and
ensure placeholder text and the validation pattern are consistent.

src/lib/auth.ts Outdated
Comment on lines 15 to 27
hooks: {
after: createAuthMiddleware(async (ctx) => {
if (ctx.path.startsWith("/sign-in/email")) {
const accountName = ctx.context.newSession?.user.name; //Get the account name
if (accountName === "") {
//Account name not set
return { newLink: "/fill-out-name" };
}
//TODO V: change later when we know where to send the user
return { newLink: "/dashboard" };
}
}),
},
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, let's find the database schema file(s)
find . -type f -name "*schema*" -o -name "*db*" | grep -E "\.(ts|js)$" | head -20

Repository: Code-the-Change-YYC/salvationarmy

Length of output: 167


🏁 Script executed:

#!/bin/bash
# Look for pgTable definitions related to users
rg "pgTable.*user" -A 10 -B 2

Repository: Code-the-Change-YYC/salvationarmy

Length of output: 917


🏁 Script executed:

#!/bin/bash
# Search for user table/schema definition
rg "name.*:" -t ts | grep -i "user\|account" | head -20

Repository: Code-the-Change-YYC/salvationarmy

Length of output: 631


🏁 Script executed:

#!/bin/bash
# Find better-auth configuration and type definitions
find . -type f \( -name "auth.ts" -o -name "auth.config.*" -o -name "*auth*" \) | grep -v node_modules | head -20

Repository: Code-the-Change-YYC/salvationarmy

Length of output: 229


🏁 Script executed:

#!/bin/bash
# Check the actual import and usage of user.name in the auth.ts file
cat -n src/lib/auth.ts | head -50

Repository: Code-the-Change-YYC/salvationarmy

Length of output: 2107


Handle null/undefined values in the name check.

The after middleware correctly implements conditional routing based on user profile completion. However, the name check on line 19 only handles empty strings. Since ctx.context.newSession?.user.name uses optional chaining, accountName can be undefined if either newSession or user is falsy. Update the condition to catch both cases:

if (!accountName || accountName === "") {
  // Account name not set
  return { newLink: "/fill-out-name" };
}
🤖 Prompt for AI Agents
In src/lib/auth.ts around lines 15 to 27, the middleware only checks for an
empty string when determining if the account name is set, but accountName can be
undefined/null due to optional chaining; update the condition to treat falsy
values as unset (e.g., check if accountName is falsy or empty) so the branch
returns { newLink: "/fill-out-name" } when name is undefined, null, or an empty
string.

@jason-duong4509 jason-duong4509 changed the title SANC-48: Completed Ticket SANC-48-When-the-user-completes-registration-they-should-be-able-to-input-their-name Dec 24, 2025
- Changed the function name in /src/app/fill-out-name from LoginPage to FillOutNamePage because that was missed earlier
- Added a comment in /src/app/fill-out-name because that was missed earlier
- Changed an HTTP error code from 500 to 400 because of the coderabbitai suggestion
Copy link

@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: 0

♻️ Duplicate comments (3)
src/app/fill-out-name/page.tsx (2)

34-48: Validation issues remain unresolved.

The regex validation logic still has the problems identified in the previous review:

  1. Incorrect minimum length: The regex pattern requires 5 characters minimum, contradicting the comment and placeholder claiming ">=3 characters."
  2. Code duplication: This exact regex and validation logic is duplicated in src/server/api/routers/organizations.ts (lines 235-243).
  3. Suboptimal UX: Client-side validation should be in the useForm hook's validate property for inline error feedback, not in the submit handler.

Please refer to the detailed refactoring suggestions in the previous review comment on lines 36-42, which proposed creating a shared validation utility in src/lib/validation.ts to eliminate duplication and fix the minimum length requirement.


50-74: UI structure is clean, but placeholder text remains inconsistent.

The form UI is well-structured with appropriate Mantine components. However, the placeholder text issue from the previous review persists:

The placeholder states "Alphanumeric, 3+ Characters" but the actual regex validation requires 5+ characters minimum. This misleads users about the actual requirements.

src/server/api/routers/organizations.ts (1)

230-243: Validation error code fixed, but duplication remains.

Good fix changing the validation error to BAD_REQUEST (line 240) as recommended in the previous review. However, the core validation issues remain unresolved:

  1. Regex duplication: This exact regex pattern and validation logic is duplicated from src/app/fill-out-name/page.tsx (line 37), violating DRY principles.
  2. Incorrect minimum length: The regex requires 5 characters minimum, not 3 as documented in the comment (line 235).

As suggested in the previous review, please create a shared validation utility (e.g., src/lib/validation.ts) with a validateName function and constants that both the client and server can import. This will ensure consistency and make it easier to fix the minimum length requirement in one place.

🧹 Nitpick comments (1)
src/app/fill-out-name/page.tsx (1)

11-19: Component setup is functional.

The function naming issue from the previous review has been resolved. However, consider adding validation to the useForm configuration (in the validate property) rather than performing it in handleSubmit for better UX with inline error messages.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fcf42ab and a3d8349.

📒 Files selected for processing (2)
  • src/app/fill-out-name/page.tsx
  • src/server/api/routers/organizations.ts
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-23T05:44:35.017Z
Learnt from: tanvimahal
Repo: Code-the-Change-YYC/salvationarmy PR: 25
File: src/server/api/routers/organizations.ts:38-38
Timestamp: 2025-12-23T05:44:35.017Z
Learning: In this codebase's TRPC protectedProcedure context, ctx.session has a nested structure containing both a session object and a user object. To access activeOrganizationId, use ctx.session.session.activeOrganizationId (not ctx.session.activeOrganizationId).

Applied to files:

  • src/server/api/routers/organizations.ts
🧬 Code graph analysis (2)
src/app/fill-out-name/page.tsx (3)
src/trpc/react.tsx (1)
  • api (25-25)
src/lib/notifications.ts (1)
  • notify (13-58)
src/app/_components/common/button/Button.tsx (1)
  • Button (41-80)
src/server/api/routers/organizations.ts (2)
src/server/api/trpc.ts (1)
  • protectedProcedure (122-132)
src/server/db/auth-schema.ts (1)
  • user (5-19)
🔇 Additional comments (4)
src/app/fill-out-name/page.tsx (2)

1-9: LGTM!

Imports are appropriate for a client-side form component with TRPC integration.


21-32: LGTM!

The mutation setup follows TRPC best practices with proper success/error handling and loading state management. The TODO comment is reasonable for tracking future routing decisions.

src/server/api/routers/organizations.ts (2)

2-2: LGTM!

The new imports (eq and user) are necessary for the database update operation in the changeName procedure.

Also applies to: 12-12


245-258: LGTM!

The database update logic is correct:

  • Properly scopes the update to the authenticated user (ctx.session.user.id)
  • Uses .returning() to verify the update succeeded
  • Appropriate error handling with INTERNAL_SERVER_ERROR for the unexpected case where no rows are updated (since protectedProcedure guarantees the user exists)

@promatty
Copy link
Contributor

@burtonjong

- Moved front-end redirect logic from the back-end to the front-end
- Replaced the loading useState
- Moved the name regex to validation.ts
- Simplified form validation in \fill-out-name\page.tsx to streamline code
…-completes-registration-they-should-be-able-to-input-their-name

# Conflicts:
#	src/app/_components/agencycomponents/agency-interactive-area.tsx
Copy link

@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

Fix all issues with AI Agents 🤖
In @src/types/validation.ts:
- Around line 12-13: Replace the current export const nameRegex with a regex
that (1) requires at least two characters, (2) ensures the string contains at
least one letter (so numeric-only names fail), (3) allows letters, single
spaces, hyphens and apostrophes as separators, (4) forbids consecutive spaces,
and (5) ensures any separator is followed by a letter (no trailing separators);
update the nameRegex definition accordingly to implement these rules (target the
export const nameRegex symbol).
🧹 Nitpick comments (1)
src/app/_components/agencycomponents/agency-interactive-area.tsx (1)

177-183: Consider using the existing styles module for consistency.

The inline styles work correctly, but the file already imports and uses a CSS module (styles from ./agency-interactive-area.module.scss) for other layout concerns. For consistency and maintainability, consider extracting these styles into the module.

🔎 Optional refactor to use CSS module

In agency-interactive-area.module.scss, add:

.loadingCardContainer {
  max-width: 250px;
  margin: 4rem auto;
  padding: 0 1rem;
}

Then update the component:

-    return (
-      <div style={{ maxWidth: "250px", margin: "4rem auto", padding: "0 1rem" }}>
-        <Paper shadow="sm" p="xl" radius="md">
-          <Title>Loading...</Title>
-        </Paper>
-      </div>
-    );
+    return (
+      <div className={styles.loadingCardContainer}>
+        <Paper shadow="sm" p="xl" radius="md">
+          <Title>Loading...</Title>
+        </Paper>
+      </div>
+    );
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a3d8349 and 9d5e703.

📒 Files selected for processing (4)
  • src/app/_components/agencycomponents/agency-interactive-area.tsx
  • src/app/fill-out-name/page.tsx
  • src/app/login/page.tsx
  • src/types/validation.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/app/fill-out-name/page.tsx
  • src/app/login/page.tsx
🔇 Additional comments (1)
src/app/_components/agencycomponents/agency-interactive-area.tsx (1)

3-3: LGTM!

The additional Mantine imports support the enhanced loading UI.

Comment on lines +12 to +13
export const nameRegex =
/^(?!.*\s{2})[A-Za-z0-9][A-Za-z0-9\s]*[A-Za-z0-9][A-Za-z0-9\s]*[A-Za-z0-9]$/;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix the name validation regex to support valid names and reject invalid ones.

The current regex has several issues that will impact user experience and data integrity:

  1. Rejects valid short names: The pattern requires a minimum of 3 characters, rejecting legitimate names like "Jo", "Li", "Wu", "Bo", etc.
  2. Accepts numeric-only input: Names like "123" or "007" would pass validation, which is likely unintended.
  3. Overly complex pattern: The repeating [A-Za-z0-9][A-Za-z0-9\s]*[A-Za-z0-9] structure appears redundant.
  4. Missing common name characters: Doesn't support hyphens or apostrophes needed for names like "O'Brien" or "Mary-Jane".
🔎 Proposed fix for the name validation regex
-export const nameRegex =
-  /^(?!.*\s{2})[A-Za-z0-9][A-Za-z0-9\s]*[A-Za-z0-9][A-Za-z0-9\s]*[A-Za-z0-9]$/;
+export const nameRegex = /^(?!.*\s{2})[A-Za-z]+(?:[ '-][A-Za-z]+)*$/;

This improved pattern:

  • Allows names of any length (2+ characters)
  • Requires at least one letter at the start and after each separator
  • Prevents consecutive spaces (maintains your original intent)
  • Supports hyphens and apostrophes for compound names
  • Rejects numeric-only input
  • Simplified and more maintainable

Alternatively, if you want to enforce a minimum length or allow numbers in names, consider:

// Minimum 2 characters, letters only with optional spaces/hyphens/apostrophes
export const nameRegex = /^(?!.*\s{2})[A-Za-z]{2,}(?:[ '-][A-Za-z]+)*$/;
🤖 Prompt for AI Agents
In @src/types/validation.ts around lines 12-13, Replace the current export const
nameRegex with a regex that (1) requires at least two characters, (2) ensures
the string contains at least one letter (so numeric-only names fail), (3) allows
letters, single spaces, hyphens and apostrophes as separators, (4) forbids
consecutive spaces, and (5) ensures any separator is followed by a letter (no
trailing separators); update the nameRegex definition accordingly to implement
these rules (target the export const nameRegex symbol).

…-completes-registration-they-should-be-able-to-input-their-name

# Conflicts:
#	src/app/login/page.tsx
#	src/server/api/routers/organizations.ts
- Changed the way a user is redirected from /login to /fill-out-name to accommodate changes made to main
- Changed the way a user is redirected from /fill-out-name to accommodate changes made to main
Copy link

@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: 0

🧹 Nitpick comments (1)
src/server/api/routers/organizations.ts (1)

306-334: Inconsistency: Regex is defined locally, not imported.

The AI summary states that nameRegex is imported from src/types/validation.ts, but the code shows the regex is defined locally at line 312. The validation logic itself is correct and the error codes have been properly addressed from the previous review.


Optional: Consider returning a success indicator.

The mutation completes successfully but returns void. Consider returning the updated user object or a success status to provide feedback to the caller.

💡 Optional enhancement
       if (listOfUpdatedUsers.length === 0) {
         //Drizzle updated no users (something went wrong)
         throw new TRPCError({
           code: "INTERNAL_SERVER_ERROR",
           message: "Failed to update user's name",
         });
       }
+
+      return {
+        success: true,
+        user: listOfUpdatedUsers[0],
+      };
     }),
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9d5e703 and f859841.

📒 Files selected for processing (2)
  • src/app/fill-out-name/page.tsx
  • src/server/api/routers/organizations.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/app/fill-out-name/page.tsx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-23T05:44:37.925Z
Learnt from: tanvimahal
Repo: Code-the-Change-YYC/salvationarmy PR: 25
File: src/server/api/routers/organizations.ts:38-38
Timestamp: 2025-12-23T05:44:37.925Z
Learning: In this codebase's TRPC protectedProcedure context, ctx.session has a nested structure containing both a session object and a user object. To access activeOrganizationId, use ctx.session.session.activeOrganizationId (not ctx.session.activeOrganizationId).

Applied to files:

  • src/server/api/routers/organizations.ts
🧬 Code graph analysis (1)
src/server/api/routers/organizations.ts (2)
src/server/db/auth-schema.ts (2)
  • organization (72-79)
  • user (6-20)
src/server/api/trpc.ts (1)
  • protectedProcedure (122-132)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: ci
🔇 Additional comments (2)
src/server/api/routers/organizations.ts (2)

2-2: LGTM!

The new imports support the changeName mutation correctly. The eq function and user table reference are properly utilized in the database update operation.

Also applies to: 12-12


34-82: Good defensive programming with proper error handling.

The refactored redirect logic correctly guards against users with empty names and includes thorough validation for the agency role:

  • The organization lookup ensures the slug exists before constructing the redirect URL
  • Error codes are appropriate (NOT_FOUND for missing entities, INTERNAL_SERVER_ERROR for data integrity issues)
  • Properly uses ctx.session.session.activeOrganizationId as per the codebase's session structure

Based on learnings about the session structure in this codebase.

@jason-duong4509
Copy link
Contributor Author

@burtonjong

- Changed a function name for better clarity
- Added additional text to error messages to provide more information
Copy link

@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

🤖 Fix all issues with AI agents
In @src/server/api/routers/organizations.ts:
- Around line 313-321: Replace the duplicated local regex with the shared
exported nameRegex from the validation module: import nameRegex (from the module
that exports it) at the top of this file and remove the local const regex; then
use nameRegex.test(newName) in place of regex.test(newName) in the organizations
update/name validation block so server-side validation matches the client-side
rule and avoids duplication.
🧹 Nitpick comments (2)
src/server/api/routers/organizations.ts (2)

34-36: Consider handling undefined in addition to empty string for name check.

The check ctx.session.user.name === "" only catches empty strings. If the name field could be undefined or null in some authentication scenarios, this condition might not redirect appropriately.

♻️ Suggested fix
-    if (ctx.session.user.name === "") {
+    if (!ctx.session.user.name) {
       redirectUrl = "/fill-out-name";
     } else {

309-309: Consider adding maximum length constraint to input validation.

The input schema only validates that newName is a string. Adding a maximum length constraint provides defense-in-depth validation before the regex check and protects against excessively long inputs.

♻️ Suggested fix
   changeName: protectedProcedure
-    .input(z.object({ newName: z.string() }))
+    .input(z.object({ newName: z.string().max(100) }))
     .mutation(async ({ input, ctx }) => {
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f859841 and d55ca6d.

📒 Files selected for processing (2)
  • src/app/fill-out-name/page.tsx
  • src/server/api/routers/organizations.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/app/fill-out-name/page.tsx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-23T05:44:37.925Z
Learnt from: tanvimahal
Repo: Code-the-Change-YYC/salvationarmy PR: 25
File: src/server/api/routers/organizations.ts:38-38
Timestamp: 2025-12-23T05:44:37.925Z
Learning: In this codebase's TRPC protectedProcedure context, ctx.session has a nested structure containing both a session object and a user object. To access activeOrganizationId, use ctx.session.session.activeOrganizationId (not ctx.session.activeOrganizationId).

Applied to files:

  • src/server/api/routers/organizations.ts
🧬 Code graph analysis (1)
src/server/api/routers/organizations.ts (2)
src/server/db/auth-schema.ts (2)
  • organization (72-79)
  • user (6-20)
src/server/api/trpc.ts (1)
  • protectedProcedure (122-132)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: ci
🔇 Additional comments (3)
src/server/api/routers/organizations.ts (3)

2-2: LGTM!

The imports are correctly added to support the new changeName procedure's database update operation using Drizzle ORM.

Also applies to: 12-12


42-74: LGTM!

The agency role handling is well-implemented with proper organization lookup and comprehensive error handling. The access pattern ctx.session.session.activeOrganizationId correctly follows the nested session structure. Based on learnings, this is the correct pattern for accessing activeOrganizationId in this codebase.


323-336: LGTM!

The database update logic correctly uses Drizzle ORM's update pattern with proper error handling for the edge case where no rows are updated.

- Changed how the back-end validated user name input by relying on an
  imported regex rather than a hardcoded one in-file. Missed this issue
  in previous commits
Copy link

@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

🤖 Fix all issues with AI agents
In @src/server/api/routers/organizations.ts:
- Around line 321-334: The DB update in the mutation updates the user's name
(result in listOfUpdatedUsers) but does not refresh ctx.session.user.name so
downstream logic sees a stale session name; instead of trying to refresh session
here, update redirectToDashboard to read the authoritative name from the
database record (query the users table by ctx.session.user.id and use the
returned user.name) and ensure any post-update logic uses that DB value (refer
to listOfUpdatedUsers, ctx.session.user.name, and redirectToDashboard) so
session staleness is avoided.
- Around line 34-36: The redirect check is using the session value
(ctx.session.user.name) instead of the database user fetched earlier, causing
stale-session redirects; update the condition to use the DB user (the `user`
variable returned from the lookup used before the check) e.g. replace references
to `ctx.session.user.name` with `user.name`, and add a null-safe guard (ensure
`user` exists) so `redirectUrl = "/fill-out-name"` only when the persisted
`user.name` is empty.
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d55ca6d and 30f6a38.

📒 Files selected for processing (1)
  • src/server/api/routers/organizations.ts
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-23T05:44:37.925Z
Learnt from: tanvimahal
Repo: Code-the-Change-YYC/salvationarmy PR: 25
File: src/server/api/routers/organizations.ts:38-38
Timestamp: 2025-12-23T05:44:37.925Z
Learning: In this codebase's TRPC protectedProcedure context, ctx.session has a nested structure containing both a session object and a user object. To access activeOrganizationId, use ctx.session.session.activeOrganizationId (not ctx.session.activeOrganizationId).

Applied to files:

  • src/server/api/routers/organizations.ts
🧬 Code graph analysis (1)
src/server/api/routers/organizations.ts (3)
src/server/db/auth-schema.ts (2)
  • organization (72-79)
  • user (6-20)
src/server/api/trpc.ts (1)
  • protectedProcedure (122-132)
src/types/validation.ts (1)
  • nameRegex (12-13)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: ci
🔇 Additional comments (2)
src/server/api/routers/organizations.ts (2)

2-2: LGTM! Imports are correctly added.

The new imports (eq, user, nameRegex) are all used appropriately in the new changeName procedure and support the required functionality.

Also applies to: 12-12, 14-14


43-74: Good enhancement: Robust organization slug validation.

The AGENCY role handling now includes comprehensive validation for activeOrganizationId, organization existence, and slug presence with clear error messages. The code correctly accesses ctx.session.session.activeOrganizationId per the codebase's nested session structure.

Based on learnings, the nested session access pattern is correct for this codebase.

Comment on lines +313 to +319
if (!nameRegex.test(newName)) {
//User inputted name is not proper
throw new TRPCError({
code: "BAD_REQUEST",
message: "Invalid Name",
});
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, find the validation file and examine nameRegex definition
find . -type f -name "validation.ts" -o -name "validation.js" | head -20

Repository: Code-the-Change-YYC/salvationarmy

Length of output: 102


🏁 Script executed:

# Also look for the organizations router file
find . -type f -path "*/api/routers/organizations.ts" | head -5

Repository: Code-the-Change-YYC/salvationarmy

Length of output: 118


🏁 Script executed:

cat -n src/types/validation.ts | head -100

Repository: Code-the-Change-YYC/salvationarmy

Length of output: 662


🏁 Script executed:

cat -n src/server/api/routers/organizations.ts | sed -n '305,335p'

Repository: Code-the-Change-YYC/salvationarmy

Length of output: 1170


🏁 Script executed:

# Run the test script to verify regex behavior
cat << 'EOF' > test_names.py
import re

# Pattern from validation.ts (exactly as defined)
nameRegex = r"^(?!.*\s{2})[A-Za-z0-9][A-Za-z0-9\s]*[A-Za-z0-9][A-Za-z0-9\s]*[A-Za-z0-9]$"

test_cases = [
    ("Al", "short 2-char name"),
    ("X", "single character"),
    ("John Doe", "standard name"),
    ("John Smith", "2-word name"),
    ("Mary-Jane", "hyphenated"),
    ("O'Brien", "apostrophe"),
    ("José", "accented"),
    ("François", "accented"),
    ("李明", "non-Latin"),
    ("John  Doe", "double space"),
    ("123", "numeric only"),
    ("John123", "alphanumeric"),
    ("A B C", "single letters with spaces"),
]

print("Testing nameRegex pattern:\n")
for name, desc in test_cases:
    matches = bool(re.match(nameRegex, name))
    status = "✓ PASS" if matches else "✗ FAIL"
    print(f"{status} | {name:20} | {desc}")
EOF

python test_names.py

Repository: Code-the-Change-YYC/salvationarmy

Length of output: 163


🏁 Script executed:

# Check if ctx.session is updated after the DB update in changeName
rg -A 20 "changeName:" src/server/api/routers/organizations.ts | head -40

Repository: Code-the-Change-YYC/salvationarmy

Length of output: 782


🏁 Script executed:

# Test regex pattern with a simpler approach using Node.js
node << 'EOF'
const nameRegex = /^(?!.*\s{2})[A-Za-z0-9][A-Za-z0-9\s]*[A-Za-z0-9][A-Za-z0-9\s]*[A-Za-z0-9]$/;

const testCases = [
    ["Al", "short 2-char name"],
    ["X", "single character"],
    ["John Doe", "standard name"],
    ["Mary-Jane", "hyphenated"],
    ["O'Brien", "apostrophe"],
    ["José", "accented"],
    ["123", "numeric only"],
    ["John123", "alphanumeric"],
];

console.log("Testing nameRegex pattern:\n");
testCases.forEach(([name, desc]) => {
    const matches = nameRegex.test(name);
    const status = matches ? "✓ PASS" : "✗ FAIL";
    console.log(`${status} | ${name.padEnd(20)} | ${desc}`);
});
EOF

Repository: Code-the-Change-YYC/salvationarmy

Length of output: 466


🏁 Script executed:

# Check if there's any session update logic after the DB update in changeName or related functions
rg -B 5 -A 15 "ctx.session" src/server/api/routers/organizations.ts | grep -A 15 "changeName"

Repository: Code-the-Change-YYC/salvationarmy

Length of output: 59


🏁 Script executed:

# Search for any session refresh or revalidation logic in the codebase related to user updates
rg -l "session.*refresh|revalidateSession|unstable_getServerSession" src/ | head -10

Repository: Code-the-Change-YYC/salvationarmy

Length of output: 59


Name validation regex is too restrictive and rejects legitimate names.

The nameRegex pattern enforces requirements that block common, valid name formats:

  • Minimum 3 characters required: rejects short names like "Al", "Bo", or single-letter names
  • Hyphens rejected: "Mary-Jane" fails validation
  • Apostrophes rejected: "O'Brien" fails validation
  • Accented characters rejected: "José", "François" fail validation
  • Only allows alphanumeric + spaces: no special characters supported

This creates a poor user experience for people with legitimate names that don't fit this narrow pattern. Additionally, after the database update on line 321–325, ctx.session.user.name is not refreshed, meaning subsequent operations in the same session will reference stale user data.

Comment on lines +321 to +334
const listOfUpdatedUsers = await ctx.db
.update(user)
.set({ name: newName })
.where(eq(user.id, ctx.session.user.id))
.returning(); //Make DB update command to change the user's name

if (listOfUpdatedUsers.length === 0) {
//Drizzle updated no users (something went wrong)
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Failed to update user's name",
});
}
}),
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Session not refreshed after database update.

After updating the user's name in the database, ctx.session.user.name remains unchanged until the session is refreshed. This means subsequent calls within the same session will see the old name value.

Impact: This contributes to the critical issue flagged in redirectToDashboard (line 34), where the session's stale name causes incorrect redirect logic. Once that issue is fixed by using the database user's name instead of the session name, this concern is mitigated.

Note: The recommended fix is to use the database user record consistently in redirectToDashboard rather than attempting to refresh the session here.

🤖 Prompt for AI Agents
In @src/server/api/routers/organizations.ts around lines 321 - 334, The DB
update in the mutation updates the user's name (result in listOfUpdatedUsers)
but does not refresh ctx.session.user.name so downstream logic sees a stale
session name; instead of trying to refresh session here, update
redirectToDashboard to read the authoritative name from the database record
(query the users table by ctx.session.user.id and use the returned user.name)
and ensure any post-update logic uses that DB value (refer to
listOfUpdatedUsers, ctx.session.user.name, and redirectToDashboard) so session
staleness is avoided.

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.

4 participants