Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@steven-tey
Copy link
Collaborator

@steven-tey steven-tey commented Dec 4, 2025

Summary by CodeRabbit

  • New Features

    • Email field now included in user profile information and displayed across fraud event tracking and payout interfaces.
  • Refactor

    • Improved user display logic with enhanced fallback handling (name → email → ID) for better visibility.
    • Strengthened data consistency and type definitions across partner fraud and payout management features.

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

@vercel
Copy link
Contributor

vercel bot commented Dec 4, 2025

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

Project Deployment Preview Updated (UTC)
dub Ready Ready Preview Dec 4, 2025 3:17am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 4, 2025

Walkthrough

This PR renames the public type fraudEventGroupProps to FraudEventGroupProps following PascalCase conventions, expands fraud and payout schemas to include email fields, and broadens user schema references from narrowed subsets to full UserSchema across fraud-related components and utilities.

Changes

Cohort / File(s) Change Summary
Type System & Schema Definitions
apps/web/lib/types.ts, apps/web/lib/zod/schemas/fraud.ts, apps/web/lib/zod/schemas/users.ts, apps/web/lib/zod/schemas/payouts.ts
Renamed fraudEventGroupProps to FraudEventGroupProps; broadened groupedFraudEventSchema.user from UserSchema.pick({ id, name, image }) to full UserSchema.nullable(); added email field to UserSchema; updated PayoutResponseSchema.user to reference UserSchema.nullish()
Fraud Component Type Updates
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/fraud-event-groups-table.tsx, apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/resolve-fraud-events-modal.tsx, apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/resolved/resolved-fraud-event-groups-table.tsx
Updated all type annotations and imports to use FraudEventGroupProps; adjusted row typing and hook parameter types throughout
Fraud Risk UI Components
apps/web/ui/partners/fraud-risks/commissions-on-hold-table.tsx, apps/web/ui/partners/fraud-risks/fraud-events-tables/index.tsx, apps/web/ui/partners/fraud-risks/fraud-review-sheet.tsx
Updated imports and prop types from fraudEventGroupProps to FraudEventGroupProps; adjusted avatar fallback logic to use user.id instead of user.name and alt text to chain user.name ?? user.email ?? user.id
SWR & API Updates
apps/web/lib/swr/use-fraud-event-groups.ts, apps/web/lib/api/fraud/get-grouped-fraud-events.ts
Updated SWR hook generic type to FraudEventGroupProps[]; added userEmail propagation from SQL query into returned fraud event objects
User & Payout Components
apps/web/ui/users/user-row-item.tsx, apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/payouts/payout-paid-cell.tsx
Expanded UserRowItem props to accept full UserProps instead of narrowed subset; added optional email field to PayoutPaidCellUser; adjusted avatar and name fallback logic
Tests
apps/web/tests/fraud/index.test.ts
Updated type imports and generic parameters to use FraudEventGroupProps

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Type consistency verification: Ensure all downstream consumers of FraudEventGroupProps correctly handle the broader schema (particularly the expanded user object).
  • Schema broadening impact: Review that the change from narrowed UserSchema.pick() to full UserSchema doesn't introduce unexpected data or breaking contract changes.
  • Fallback logic changes: Verify avatar image fallback (user.id) and name/email nullish coalescing chains work as intended across fraud and payout components.
  • Propagated email field: Confirm SQL query changes in get-grouped-fraud-events.ts and email usage in UI remain aligned.

Possibly related PRs

  • Fraud detection improvements #3153: Directly overlaps—modifies fraud types, schema, and get-grouped-fraud-events with user/email field propagation.
  • Fraud improvements #3159: Related—modifies the same groupedFraudEventSchema and fraud type exports that underlie this refactor.
  • Fraud & Risk #3089: Related—initially introduces/modifies fraud UI files and types that this PR now updates with naming and schema conventions.

Suggested reviewers

  • devkiran
  • TWilson023

Poem

🐰 A name befits its noble form,
From camelCase to PascalCase—reform!
The schema blooms with email's grace,
And avatars now know their place.
Hop through types with pride so bright! 📧✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.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 'Standardize UserRowItem' accurately reflects the primary change: updating UserRowItem and related type definitions to use standardized, full types instead of narrowed subsets.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch standardize-user-row-item

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: 1

🧹 Nitpick comments (4)
apps/web/lib/zod/schemas/users.ts (1)

3-7: UserSchema email addition looks good; consider optional format validation

Adding email: z.string().nullable() cleanly extends the shared user shape and stays consistent with name/image. If you want to guarantee proper email formatting at this layer, you could switch to z.string().email().nullable(), but that’s optional depending on how strict you want this schema to be.

apps/web/ui/partners/fraud-risks/fraud-events-tables/index.tsx (1)

1-1: Type rename is correct; consider typing tables to accept fraudEventGroup

The switch to FraudEventGroupProps for fraudEventGroup is consistent with the new shared type. As a follow‑up, you might consider tightening the table mapping to ensure each table component explicitly receives this prop, e.g.:

-const FRAUD_EVENTS_TABLES: Partial<Record<FraudRuleType, React.ComponentType>> = {
+const FRAUD_EVENTS_TABLES: Partial<
+  Record<FraudRuleType, React.ComponentType<{ fraudEventGroup: FraudEventGroupProps }>>
+> = {
   // ...
 };
 
 // ...
-  return <TableComponent />;
+  return <TableComponent fraudEventGroup={fraudEventGroup} />;

That would let TypeScript enforce that all fraud event tables accept the same fraudEventGroup shape.

Also applies to: 21-33

apps/web/ui/users/user-row-item.tsx (1)

31-31: Consider adding fallback for tooltip display name.

The tooltip displays user.name directly without the fallback chain used elsewhere (line 18). If name is null, this will render as empty. Consider using the same fallback for consistency:

-            <p className="text-sm font-medium">{user.name}</p>
+            <p className="text-sm font-medium">{name}</p>
apps/web/ui/partners/fraud-risks/fraud-review-sheet.tsx (1)

202-206: Avatar fallback logic improved; consider consistent display name handling.

The avatar source fallback to user.id and alt text fallback chain are correctly implemented. However, similar to user-row-item.tsx, line 206 uses user.name directly without the fallback chain. Consider extracting the display name to a variable for consistency:

+                          const displayName = user.name ?? user.email ?? user.id;
                           <img
                              src={user.image || `${OG_AVATAR_URL}${user.id}`}
-                             alt={user.name ?? user.email ?? user.id}
+                             alt={displayName}
                              className="size-6 shrink-0 rounded-full"
                            />
-                           <p className="text-sm font-medium">{user.name}</p>
+                           <p className="text-sm font-medium">{displayName}</p>

Also applies to: 223-224

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a6e3965 and a514366.

📒 Files selected for processing (15)
  • apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/fraud-event-groups-table.tsx (5 hunks)
  • apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/resolve-fraud-events-modal.tsx (3 hunks)
  • apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/resolved/resolved-fraud-event-groups-table.tsx (6 hunks)
  • apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/payouts/payout-paid-cell.tsx (3 hunks)
  • apps/web/lib/api/fraud/get-grouped-fraud-events.ts (3 hunks)
  • apps/web/lib/swr/use-fraud-event-groups.ts (2 hunks)
  • apps/web/lib/types.ts (2 hunks)
  • apps/web/lib/zod/schemas/fraud.ts (1 hunks)
  • apps/web/lib/zod/schemas/payouts.ts (2 hunks)
  • apps/web/lib/zod/schemas/users.ts (1 hunks)
  • apps/web/tests/fraud/index.test.ts (2 hunks)
  • apps/web/ui/partners/fraud-risks/commissions-on-hold-table.tsx (2 hunks)
  • apps/web/ui/partners/fraud-risks/fraud-events-tables/index.tsx (2 hunks)
  • apps/web/ui/partners/fraud-risks/fraud-review-sheet.tsx (4 hunks)
  • apps/web/ui/users/user-row-item.tsx (1 hunks)
🧰 Additional context used
🧠 Learnings (9)
📚 Learning: 2025-11-24T09:10:12.536Z
Learnt from: devkiran
Repo: dubinc/dub PR: 3089
File: apps/web/lib/api/fraud/fraud-rules-registry.ts:17-25
Timestamp: 2025-11-24T09:10:12.536Z
Learning: In apps/web/lib/api/fraud/fraud-rules-registry.ts, the fraud rules `partnerCrossProgramBan` and `partnerDuplicatePayoutMethod` intentionally have stub implementations that return `{ triggered: false }` because they are partner-scoped rules handled separately during partner application/onboarding flows (e.g., in detect-record-fraud-application.ts), rather than being evaluated per conversion event like other rules in the registry. The stubs exist only to satisfy the `Record<FraudRuleType, ...>` type constraint.

Applied to files:

  • apps/web/tests/fraud/index.test.ts
  • apps/web/ui/partners/fraud-risks/fraud-events-tables/index.tsx
  • apps/web/lib/zod/schemas/fraud.ts
  • apps/web/ui/partners/fraud-risks/commissions-on-hold-table.tsx
  • apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/resolved/resolved-fraud-event-groups-table.tsx
  • apps/web/lib/types.ts
  • apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/resolve-fraud-events-modal.tsx
  • apps/web/lib/swr/use-fraud-event-groups.ts
  • apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/fraud-event-groups-table.tsx
  • apps/web/ui/partners/fraud-risks/fraud-review-sheet.tsx
📚 Learning: 2025-12-03T09:19:48.164Z
Learnt from: devkiran
Repo: dubinc/dub PR: 3175
File: apps/web/lib/actions/partners/bulk-reject-partner-applications.ts:14-21
Timestamp: 2025-12-03T09:19:48.164Z
Learning: In apps/web/lib/actions/partners/bulk-reject-partner-applications.ts, the bulkRejectPartnerApplicationsAction does not need explicit plan capability checks for fraud operations (when reportFraud is true) because the authorization is handled automatically by the underlying fraud operation functions (resolveFraudGroups, createFraudEvents) or through other automated mechanisms in the system.

Applied to files:

  • apps/web/tests/fraud/index.test.ts
  • apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/resolved/resolved-fraud-event-groups-table.tsx
  • apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/resolve-fraud-events-modal.tsx
  • apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/fraud-event-groups-table.tsx
  • apps/web/ui/partners/fraud-risks/fraud-review-sheet.tsx
📚 Learning: 2025-11-24T08:55:31.332Z
Learnt from: devkiran
Repo: dubinc/dub PR: 3089
File: apps/web/app/(ee)/api/fraud-rules/route.ts:71-87
Timestamp: 2025-11-24T08:55:31.332Z
Learning: In apps/web/app/(ee)/api/fraud-rules/route.ts, fraud rules cannot be created in a disabled state. When using prisma.fraudRule.upsert, the create branch intentionally omits the disabledAt field (defaulting to null, meaning enabled), while the update branch allows toggling enabled/disabled state via the disabledAt field. This is a business logic constraint.

Applied to files:

  • apps/web/tests/fraud/index.test.ts
📚 Learning: 2025-08-16T11:14:00.667Z
Learnt from: devkiran
Repo: dubinc/dub PR: 2754
File: apps/web/lib/partnerstack/schemas.ts:47-52
Timestamp: 2025-08-16T11:14:00.667Z
Learning: The PartnerStack API always includes the `group` field in partner responses, so the schema should use `.nullable()` rather than `.nullish()` since the field is never omitted/undefined.

Applied to files:

  • apps/web/lib/zod/schemas/fraud.ts
📚 Learning: 2025-10-15T01:05:43.266Z
Learnt from: steven-tey
Repo: dubinc/dub PR: 2958
File: apps/web/app/app.dub.co/(dashboard)/[slug]/settings/members/page-client.tsx:432-457
Timestamp: 2025-10-15T01:05:43.266Z
Learning: In apps/web/app/app.dub.co/(dashboard)/[slug]/settings/members/page-client.tsx, defer refactoring the custom MenuItem component (lines 432-457) to use the shared dub/ui MenuItem component to a future PR, as requested by steven-tey.

Applied to files:

  • apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/resolved/resolved-fraud-event-groups-table.tsx
  • apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/resolve-fraud-events-modal.tsx
  • apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/fraud-event-groups-table.tsx
📚 Learning: 2025-07-30T15:25:13.936Z
Learnt from: TWilson023
Repo: dubinc/dub PR: 2673
File: apps/web/ui/partners/rewards/add-edit-reward-sheet.tsx:56-66
Timestamp: 2025-07-30T15:25:13.936Z
Learning: In apps/web/ui/partners/rewards/add-edit-reward-sheet.tsx, the form schema uses partial condition objects to allow users to add empty/unconfigured condition fields without type errors, while submission validation uses strict schemas to ensure data integrity. This two-stage validation pattern improves UX by allowing progressive completion of complex forms.

Applied to files:

  • apps/web/lib/zod/schemas/payouts.ts
📚 Learning: 2025-07-17T06:41:45.620Z
Learnt from: devkiran
Repo: dubinc/dub PR: 2637
File: apps/web/app/(ee)/api/singular/webhook/route.ts:0-0
Timestamp: 2025-07-17T06:41:45.620Z
Learning: In the Singular integration (apps/web/app/(ee)/api/singular/webhook/route.ts), the event names in the singularToDubEvent object have intentionally different casing: "Copy GAID" and "copy IDFA". This casing difference is valid and should not be changed, as these are the correct event names expected from Singular.

Applied to files:

  • apps/web/lib/types.ts
  • apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/resolve-fraud-events-modal.tsx
📚 Learning: 2025-10-15T01:52:37.048Z
Learnt from: steven-tey
Repo: dubinc/dub PR: 2958
File: apps/web/app/(ee)/partners.dub.co/(dashboard)/profile/members/page-client.tsx:270-303
Timestamp: 2025-10-15T01:52:37.048Z
Learning: In React components with dropdowns or form controls that show modals for confirmation (e.g., role selection, delete confirmation), local state should be reverted to match the prop value when the modal is cancelled. This prevents the UI from showing an unconfirmed change. The solution is to either: (1) pass an onClose callback to the modal that resets the local state, or (2) observe modal visibility state and reset on close. Example context: RoleCell component in apps/web/app/(ee)/partners.dub.co/(dashboard)/profile/members/page-client.tsx where role dropdown should revert to user.role when UpdateUserModal is cancelled.

Applied to files:

  • apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/resolve-fraud-events-modal.tsx
📚 Learning: 2025-08-26T15:05:55.081Z
Learnt from: TWilson023
Repo: dubinc/dub PR: 2736
File: apps/web/lib/swr/use-bounty.ts:11-16
Timestamp: 2025-08-26T15:05:55.081Z
Learning: In the Dub codebase, workspace authentication and route structures prevent endless loading states when workspaceId or similar route parameters are missing, so gating SWR loading states on parameter availability is often unnecessary.

Applied to files:

  • apps/web/lib/swr/use-fraud-event-groups.ts
🧬 Code graph analysis (13)
apps/web/tests/fraud/index.test.ts (1)
apps/web/lib/types.ts (1)
  • FraudEventGroupProps (676-676)
apps/web/ui/partners/fraud-risks/fraud-events-tables/index.tsx (1)
apps/web/lib/types.ts (1)
  • FraudEventGroupProps (676-676)
apps/web/lib/zod/schemas/fraud.ts (1)
apps/web/lib/zod/schemas/users.ts (1)
  • UserSchema (3-8)
apps/web/ui/partners/fraud-risks/commissions-on-hold-table.tsx (1)
apps/web/lib/types.ts (1)
  • FraudEventGroupProps (676-676)
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/resolved/resolved-fraud-event-groups-table.tsx (2)
packages/email/src/react-email.d.ts (1)
  • Row (9-9)
apps/web/lib/types.ts (1)
  • FraudEventGroupProps (676-676)
apps/web/lib/zod/schemas/payouts.ts (1)
apps/web/lib/zod/schemas/users.ts (1)
  • UserSchema (3-8)
apps/web/lib/types.ts (1)
apps/web/lib/zod/schemas/fraud.ts (1)
  • groupedFraudEventSchema (12-28)
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/resolve-fraud-events-modal.tsx (1)
apps/web/lib/types.ts (1)
  • FraudEventGroupProps (676-676)
apps/web/lib/swr/use-fraud-event-groups.ts (1)
apps/web/lib/types.ts (1)
  • FraudEventGroupProps (676-676)
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/fraud-event-groups-table.tsx (2)
apps/web/lib/types.ts (1)
  • FraudEventGroupProps (676-676)
packages/ui/src/table/table.tsx (1)
  • useTable (51-243)
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/payouts/payout-paid-cell.tsx (1)
packages/utils/src/constants/misc.ts (1)
  • OG_AVATAR_URL (29-29)
apps/web/ui/users/user-row-item.tsx (2)
apps/web/lib/types.ts (1)
  • UserProps (244-256)
packages/utils/src/constants/misc.ts (1)
  • OG_AVATAR_URL (29-29)
apps/web/ui/partners/fraud-risks/fraud-review-sheet.tsx (2)
apps/web/lib/types.ts (1)
  • FraudEventGroupProps (676-676)
packages/utils/src/constants/misc.ts (1)
  • OG_AVATAR_URL (29-29)
⏰ 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: build
🔇 Additional comments (15)
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/payouts/payout-paid-cell.tsx (1)

8-8: LGTM! Email field addition improves fallback options.

The addition of the optional email field to PayoutPaidCellUser enables a better fallback chain for displaying user information when the name is unavailable.

apps/web/lib/zod/schemas/payouts.ts (1)

8-8: Good reuse of UserSchema; verify all payout responses now include user.email

Switching user to UserSchema.nullish() nicely centralizes the shape and allows email to propagate through payout responses. The only caveat is that any place constructing PayoutResponseSchema must now include an email field on user when present; otherwise Zod parsing will start failing where it previously passed with just { id, name, image }.

Please double‑check the APIs/actions that produce PayoutResponseSchema to ensure they populate user.email wherever a user object is returned.

Also applies to: 69-77

apps/web/tests/fraud/index.test.ts (1)

1-1: FraudEventGroupProps rename in tests is consistent

The test now imports and uses FraudEventGroupProps[] in waitForFraudEvent, which matches the new exported alias in @/lib/types. No behavioral change; just a clean type rename.

Also applies to: 237-253

apps/web/lib/api/fraud/get-grouped-fraud-events.ts (1)

13-31: User email propagation in grouped fraud events is wired correctly

Adding userEmail to QueryResult, selecting u.email AS userEmail, and threading it into the user object (email: event.userEmail) keeps the SQL, TypeScript type, and UserSchema (with nullable email) all in sync. This should satisfy the updated groupedFraudEventSchema without changing existing behavior for events where userId is null.

Also applies to: 66-86, 123-130

apps/web/ui/partners/fraud-risks/commissions-on-hold-table.tsx (1)

2-3: CommissionsOnHoldTable now correctly typed against FraudEventGroupProps

Wiring fraudEventGroup: FraudEventGroupProps into the props and using it to derive partnerId keeps this table aligned with the canonical groupedFraudEventSchema type and the rest of the fraud UI.

Also applies to: 23-27, 39-44

apps/web/lib/types.ts (1)

62-65: FraudEventGroupProps alias is correctly defined from groupedFraudEventSchema

Importing groupedFraudEventSchema and exporting FraudEventGroupProps = z.infer<typeof groupedFraudEventSchema> gives a single canonical type for grouped fraud events, matching the PascalCase convention you’re standardizing on.

Also applies to: 676-677

apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/resolve-fraud-events-modal.tsx (1)

7-7: Modal + hook now correctly use FraudEventGroupProps

Typing fraudEventGroup as FraudEventGroupProps in both the modal component and useResolveFraudEventsModal keeps this flow aligned with the shared grouped fraud event schema while preserving existing behavior around groupKey, count, and partner.

Also applies to: 29-39, 168-174

apps/web/lib/swr/use-fraud-event-groups.ts (1)

5-5: LGTM!

The type rename from fraudEventGroupProps to FraudEventGroupProps correctly follows PascalCase conventions for TypeScript types, and the usage is consistent throughout the hook.

Also applies to: 29-29

apps/web/ui/users/user-row-item.tsx (1)

17-18: LGTM - Improved fallback logic.

Using user.id for avatar fallback is more reliable than user.name since id is non-nullable in the schema, while name can be null. The display name fallback chain (name ?? email ?? id) provides progressively useful information.

apps/web/ui/partners/fraud-risks/fraud-review-sheet.tsx (1)

4-4: LGTM - Type rename applied consistently.

The import and interface prop type are correctly updated to use FraudEventGroupProps.

Also applies to: 28-28

apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/resolved/resolved-fraud-event-groups-table.tsx (3)

6-6: LGTM - Import updated consistently.


86-86: LGTM - Table column row types updated consistently.

All Row<FraudEventGroupProps> type annotations are correctly applied across the column definitions.

Also applies to: 124-124, 138-138, 153-153


296-307: LGTM - Hook parameter type correctly updated.

The useCurrentFraudEventGroup function parameter type is correctly updated to FraudEventGroupProps[], maintaining consistency with the rest of the codebase.

apps/web/lib/zod/schemas/fraud.ts (1)

27-27: LGTM - Schema expanded to include full user data with proper data source support.

Broadening from UserSchema.pick({ id, name, image }) to the full UserSchema enables the email fallback chain used in UI components. The data source (get-grouped-fraud-events.ts) already fetches and provides the email field from the User table (line 84), so this schema change is fully supported by the underlying data layer.

apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/fraud/fraud-event-groups-table.tsx (1)

7-7: LGTM! Type renaming follows PascalCase convention.

The consistent rename from fraudEventGroupProps to FraudEventGroupProps across all type annotations, generic parameters, and import statements properly follows TypeScript naming conventions for types.

Also applies to: 87-87, 91-91, 103-103, 372-372, 468-468

Comment on lines +37 to +43
src={user.image || `${OG_AVATAR_URL}${user.id}`}
alt={user.name ?? user.email ?? user.id}
className="size-6 shrink-0 rounded-full"
/>
<p className="text-sm font-medium">{user.name}</p>
<p className="text-sm font-medium">
{user.name ?? user.email ?? user.id}
</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 safeguards for undefined user.id in fallback chain.

The type definition allows id to be optional (id?: string), but the fallback logic assumes at least user.id will always be present. If all three fields (name, email, id) are undefined or null, this will result in:

  • Avatar URL: https://api.dub.co/og/avatar/undefined (broken image)
  • Alt text: undefined (accessibility violation)
  • Display text: undefined (blank/confusing UI)

Consider one of these approaches:

Option 1: Add a guard to ensure at least id exists

-        {user && (
+        {user?.id && (
          <img
            src={user.image || `${OG_AVATAR_URL}${user.id}`}
            alt={user.name ?? user.email ?? user.id}
            className="size-5 shrink-0 rounded-full"
          />
        )}

Option 2: Add a fallback string constant

-            src={user.image || `${OG_AVATAR_URL}${user.id}`}
-            alt={user.name ?? user.email ?? user.id}
+            src={user.image || `${OG_AVATAR_URL}${user.id ?? 'unknown'}`}
+            alt={user.name ?? user.email ?? user.id ?? 'Unknown user'}

Apply similar changes to lines 41-43 for the display text.

Also applies to: 84-85

🤖 Prompt for AI Agents
In
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/payouts/payout-paid-cell.tsx
around lines 37-43 (and also apply to 84-85), the fallback chain assumes user.id
exists which can yield "undefined" in the avatar URL, alt text, and display
text; fix this by adding a safe fallback constant (e.g., const FALLBACK_NAME =
"Unknown user") and use it for alt and display text when name, email, and id are
all falsy, and build the avatar src only when user.image exists or user.id is
defined (otherwise use a default avatar URL without interpolating undefined);
update the three usages (src, alt, and visible text) to use these guarded
fallbacks.

@steven-tey steven-tey merged commit ef98bb5 into main Dec 4, 2025
9 of 10 checks passed
@steven-tey steven-tey deleted the standardize-user-row-item branch December 4, 2025 03:31
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