Skip to content

Conversation

@mfts
Copy link
Owner

@mfts mfts commented Nov 26, 2025

Summary by CodeRabbit

New Features

  • Visitor and viewer records now display names (when available) instead of showing email addresses only
  • Email addresses appear as secondary information beneath visitor names
  • Falls back to email address when visitor name data is unavailable
  • Visitor name information now available in updated API responses

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

@vercel
Copy link

vercel bot commented Nov 26, 2025

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

Project Deployment Preview Comments Updated (UTC)
papermark Ready Ready Preview Comment Nov 26, 2025 5:43pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 26, 2025

Walkthrough

The PR adds optional viewerName field support across visitor and viewer tables. Components display viewer names when available, falling back to email addresses. API endpoints are enhanced to compute and return viewer names derived from the most recent view data.

Changes

Cohort / File(s) Summary
Visitor Display Components
components/analytics/visitors-table.tsx, components/visitors/contacts-table.tsx, components/visitors/dataroom-viewers.tsx, components/visitors/dataroom-visitors-table.tsx, components/visitors/visitors-table.tsx
Added optional viewerName?: string | null field to Visitor/Viewer types. Updated rendering to display viewerName when available, otherwise falling back to email. Secondary line shows email in muted style when both viewerName and email exist.
API Endpoints - viewerName Computation
pages/api/analytics/index.ts, pages/api/teams/[teamId]/datarooms/[id]/viewers/index.ts, pages/api/teams/[teamId]/viewers/index.ts
Added logic to compute viewerName field derived from the most recent view containing a non-null viewerName. Response objects now include viewerName: string | null for each viewer record. SQL queries enhanced to select and derive the viewerName field through subqueries.

Possibly related PRs

Pre-merge checks

❌ 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 (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add viewerName if available' clearly and accurately describes the main change across the pull request—adding an optional viewerName field to viewer/visitor types and updating UI display logic to show viewerName when available.

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


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)
components/analytics/visitors-table.tsx (1)

252-273: Include viewerName in exported data.

The export functionality doesn't include the viewerName field, which means exported CSV files won't contain visitor names even when available.

Apply this diff:

 const exportData = visitors.map((visitor) => ({
+  Name: visitor.viewerName || "",
   Email: visitor.email,
   "Total Views": visitor.totalViews,
   "Unique Documents": visitor.uniqueDocuments,
   "Total Duration": durationFormat(visitor.totalDuration),
   "Last Active": new Date(visitor.lastActive).toISOString(),
   Verified: visitor.verified ? "Yes" : "No",
 }));
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 32a88c1 and 0f0a5e2.

📒 Files selected for processing (8)
  • components/analytics/visitors-table.tsx (2 hunks)
  • components/visitors/contacts-table.tsx (2 hunks)
  • components/visitors/dataroom-viewers.tsx (2 hunks)
  • components/visitors/dataroom-visitors-table.tsx (2 hunks)
  • components/visitors/visitors-table.tsx (3 hunks)
  • pages/api/analytics/index.ts (2 hunks)
  • pages/api/teams/[teamId]/datarooms/[id]/viewers/index.ts (2 hunks)
  • pages/api/teams/[teamId]/viewers/index.ts (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
components/analytics/visitors-table.tsx (1)
components/ui/tooltip.tsx (1)
  • BadgeTooltip (53-107)
components/visitors/visitors-table.tsx (2)
components/ui/table.tsx (1)
  • TableCell (116-116)
components/visitors/visitor-avatar.tsx (1)
  • VisitorAvatar (10-95)
🔇 Additional comments (14)
pages/api/analytics/index.ts (1)

482-493: LGTM!

The logic correctly derives viewerName from the most recent view containing a name and includes proper null handling.

components/analytics/visitors-table.tsx (2)

54-54: LGTM!

The optional viewerName field is properly typed.


67-78: LGTM!

The rendering logic correctly prioritizes viewerName over email and conditionally displays both when available.

components/visitors/contacts-table.tsx (2)

42-42: LGTM!

The optional viewerName field is properly typed.


153-159: LGTM!

The rendering logic correctly displays viewerName with proper fallback to email and conditional secondary line.

pages/api/teams/[teamId]/datarooms/[id]/viewers/index.ts (2)

68-73: LGTM!

The viewerName field is correctly included in the view selection.


102-110: LGTM!

The logic correctly derives viewerName from the most recent view and includes it in the response with proper null handling.

components/visitors/dataroom-visitors-table.tsx (2)

106-106: LGTM!

The display logic correctly prioritizes viewerName over viewerEmail.


144-148: LGTM!

The conditional rendering properly displays the email as a secondary line when both viewerName and viewerEmail exist.

components/visitors/visitors-table.tsx (3)

179-189: LGTM!

The archived view correctly displays viewerName with proper fallback and conditional email line.


287-287: LGTM!

The display logic in the collapsible row correctly prioritizes viewerName.


346-350: LGTM!

The conditional rendering properly shows the email as a secondary line when both fields exist.

pages/api/teams/[teamId]/viewers/index.ts (2)

87-102: Verify query performance with large datasets.

The correlated subquery for viewerName could have performance implications when dealing with a large number of views. Each row in the outer query triggers a separate subquery execution.

Consider monitoring query performance or testing with realistic data volumes. If performance becomes an issue, you might want to use a window function or a different join strategy:

-- Alternative approach using window function
(
  SELECT "viewerId", 
         "viewerName",
         ROW_NUMBER() OVER (PARTITION BY "viewerId" ORDER BY "viewedAt" DESC) as rn
  FROM "View"
  WHERE "viewerName" IS NOT NULL
) as recent_names ON v.id = recent_names."viewerId" AND recent_names.rn = 1

However, the current implementation is correct and may be sufficient for typical dataset sizes.


121-141: LGTM!

The type definition and response mapping correctly include viewerName with proper null handling.

{viewer.email ? (
<>
{viewer.email}{" "}
{(viewer as any).viewerName || viewer.email}{" "}
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

Add proper type definition instead of using any cast.

The type assertion (viewer as any).viewerName bypasses TypeScript's type safety. Consider defining a proper type or extending the viewer interface to include the optional viewerName field.

Apply this pattern (similar to other components in this PR):

// At the top of the file or in a types file
interface ViewerWithName {
  viewerName?: string | null;
  // ... other viewer properties
}

Then use:

-{(viewer as any).viewerName || viewer.email}{" "}
+{(viewer as ViewerWithName).viewerName || viewer.email}{" "}

Or better yet, ensure the useDataroomViewers hook returns viewers with the proper type that includes viewerName.

🤖 Prompt for AI Agents
In components/visitors/dataroom-viewers.tsx around line 80, the code uses
(viewer as any).viewerName which bypasses TypeScript safety; define a proper
interface (e.g., ViewerWithName with optional viewerName?: string | null plus
existing viewer fields) either at the top of this file or in a shared types
file, update the component and the useDataroomViewers hook to return viewers
typed as ViewerWithName (or narrow the local viewer variable to that type) and
replace the any cast with viewer.viewerName so TypeScript enforces the optional
field correctly.

Comment on lines +110 to +114
{(viewer as any).viewerName && viewer.email && (
<p className="text-xs text-muted-foreground/60">
{viewer.email}
</p>
)}
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

Use proper type definition for consistency.

The same type safety concern applies here as on Line 80.

🤖 Prompt for AI Agents
components/visitors/dataroom-viewers.tsx around lines 110 to 114: currently the
code uses (viewer as any).viewerName which bypasses type checking; replace the
any cast by updating the viewer prop/type so viewer has a proper interface that
includes viewerName and email (or use a narrowed union type) and then reference
viewer.viewerName directly; alternatively add a small type guard function
(isViewerWithName) to narrow the union before accessing viewerName; update the
component/prop type definitions where viewer is declared so the compiler knows
viewerName exists and remove the unsafe any cast.

@mfts mfts merged commit 4f13e8d into main Nov 26, 2025
9 checks passed
@github-actions github-actions bot locked and limited conversation to collaborators Nov 26, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants