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

Skip to content

Conversation

@steven-tey
Copy link
Collaborator

@steven-tey steven-tey commented Sep 24, 2025

Summary by CodeRabbit

  • New Features

    • Added a Copy button next to each short link in Partners > Links.
    • Introduced per-link "Conversions" data and renamed the “Sales” column to “Conversions”.
    • Search expanded to match partner ID as well as name/email; placeholder updated to "Search by ID, name, email, or link" and input is now responsive.
  • Style

    • Simplified the sticky bottom action bar styling for a cleaner look.

@vercel
Copy link
Contributor

vercel bot commented Sep 24, 2025

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

Project Deployment Preview Updated (UTC)
dub Ready Ready Preview Sep 24, 2025 4:57am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 24, 2025

Walkthrough

Adds link conversions to partner APIs and validation, surfaces conversions and a Copy button in the partners links UI, changes link cache invalidation from deleteMany to expireMany across partner account flows, and removes border/background styling from a bounty action bar.

Changes

Cohort / File(s) Summary
Partners links UI
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/[partnerId]/links/page-client.tsx
Added CopyButton beside each short link; renamed “Sales” column to “Conversions” and switched data to row.original.conversions; adjusted Link cell layout to a horizontal flex.
Bounty submission sheet styling
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/[bountyId]/bounty-submission-details-sheet.tsx
Removed border-t border-neutral-200 classes from the sticky bottom action bar inner div (visual styling only).
Partner link cache behavior (expire vs delete)
apps/web/lib/actions/partners/ban-partner.ts, apps/web/lib/actions/partners/bulk-ban-partners.ts, apps/web/lib/actions/partners/revoke-program-invite.ts, apps/web/lib/actions/partners/unban-partner.ts
Replaced linkCache.deleteMany(...) with linkCache.expireMany(...) to mark partner link cache entries expired instead of removing them.
API and validation for conversions field
apps/web/lib/api/partners/get-partner-for-program.ts, apps/web/lib/zod/schemas/programs.ts
Added conversions to the JSON-aggregated link objects in the API and included conversions in ProgramPartnerLinkSchema validation.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant UI as Partners Links Page
  participant API as get-partner-for-program
  participant DB as Database

  UI->>API: GET partner links (workspaceId, includeExpandedFields)
  API->>DB: SELECT ... url, clicks, leads, sales, saleAmount, conversions
  DB-->>API: Rows with conversions
  API-->>UI: JSON links array (includes conversions)
  UI->>UI: Render table (Conversions column)
  UI->>UI: CopyButton copies short link to clipboard
Loading
sequenceDiagram
  autonumber
  participant Admin as Admin Action
  participant Service as Partner Actions Service
  participant Cache as linkCache

  rect rgba(230,250,230,0.4)
    note over Admin,Service: Ban / Bulk-ban / Revoke Invite / Unban flows
    Admin->>Service: Trigger partner state change
    Service->>Cache: expireMany(links)
    note right of Cache: Entries marked expired (not deleted)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • TWilson023

Poem

I hop through links with nimble cheer,
A copy click—your short is near.
Conversions counted, tidy and bright,
The cache now sleeps instead of flight.
This rabbit ships the changes light. 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
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.
Title Check ❓ Inconclusive The title "Small partners fixes" indicates the PR touches partner-related code but is overly generic and does not summarize the primary change or impact. The changeset includes several distinct updates (adding conversions to APIs and schemas, UI changes like CopyButton and column rename, and switching cache invalidation to expireMany), so the title fails to convey the most important change. Because it is vague, it is not sufficiently informative for reviewers or future history. Please update the title to a concise single sentence that highlights the primary change, for example "partners: expose link conversions and add CopyButton" or "partners: switch partner link cache to expireMany and add CopyButton to links UI". If multiple changes are equally important, pick the most user-visible change for the title and summarize the rest clearly in the PR description. This will make the PR more useful to reviewers and clearer in the commit history.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch small-partners-fixes

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

🧹 Nitpick comments (2)
apps/web/lib/api/partners/get-partner-for-program.ts (1)

41-44: Per-link conversions added — LGTM

Aligns with UI and schema. If Link.conversions can be NULL in DB, consider COALESCE for robustness (optional).

-              'conversions', CAST(l.conversions AS SIGNED),
+              'conversions', COALESCE(CAST(l.conversions AS SIGNED), 0),
apps/web/lib/actions/partners/revoke-program-invite.ts (1)

71-73: Pass only domain/key to linkCache.expireMany

expireMany signature is async expireMany(links: Pick<LinkProps, "domain" | "key">[]); partnerLinks are full Link records — map to { domain, key } for clarity/consistency.

File: apps/web/lib/actions/partners/revoke-program-invite.ts (lines ~71-73)

-        // Expire the links from Redis
-        linkCache.expireMany(partnerLinks),
+        // Expire the links from Redis
+        linkCache.expireMany(
+          partnerLinks.map(({ domain, key }) => ({ domain, key })),
+        ),
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fb8ed70 and fbfb302.

📒 Files selected for processing (8)
  • apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/[bountyId]/bounty-submission-details-sheet.tsx (1 hunks)
  • apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/[partnerId]/links/page-client.tsx (4 hunks)
  • apps/web/lib/actions/partners/ban-partner.ts (2 hunks)
  • apps/web/lib/actions/partners/bulk-ban-partners.ts (1 hunks)
  • apps/web/lib/actions/partners/revoke-program-invite.ts (1 hunks)
  • apps/web/lib/actions/partners/unban-partner.ts (1 hunks)
  • apps/web/lib/api/partners/get-partner-for-program.ts (1 hunks)
  • apps/web/lib/zod/schemas/programs.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: devkiran
PR: dubinc/dub#2448
File: packages/email/src/templates/partner-program-summary.tsx:254-254
Timestamp: 2025-05-29T04:49:42.842Z
Learning: In the Dub codebase, it's acceptable to keep `partners.dub.co` hardcoded rather than making it configurable for different environments.
📚 Learning: 2025-06-06T07:59:03.120Z
Learnt from: devkiran
PR: dubinc/dub#2177
File: apps/web/lib/api/links/bulk-create-links.ts:66-84
Timestamp: 2025-06-06T07:59:03.120Z
Learning: In apps/web/lib/api/links/bulk-create-links.ts, the team accepts the risk of potential undefined results from links.find() operations when building invalidLinks arrays, because existing links are fetched from the database based on the input links, so matches are expected to always exist.

Applied to files:

  • apps/web/lib/actions/partners/ban-partner.ts
  • apps/web/lib/actions/partners/revoke-program-invite.ts
  • apps/web/lib/actions/partners/bulk-ban-partners.ts
📚 Learning: 2025-09-17T17:44:03.965Z
Learnt from: TWilson023
PR: dubinc/dub#2857
File: apps/web/lib/actions/partners/update-program.ts:96-0
Timestamp: 2025-09-17T17:44:03.965Z
Learning: In apps/web/lib/actions/partners/update-program.ts, the team prefers to keep the messagingEnabledAt update logic simple by allowing client-provided timestamps rather than implementing server-controlled timestamp logic to avoid added complexity.

Applied to files:

  • apps/web/lib/actions/partners/revoke-program-invite.ts
🧬 Code graph analysis (5)
apps/web/lib/actions/partners/unban-partner.ts (1)
apps/web/lib/api/links/cache.ts (1)
  • linkCache (113-113)
apps/web/lib/actions/partners/ban-partner.ts (1)
apps/web/lib/api/links/cache.ts (1)
  • linkCache (113-113)
apps/web/lib/actions/partners/revoke-program-invite.ts (1)
apps/web/lib/api/links/cache.ts (1)
  • linkCache (113-113)
apps/web/lib/actions/partners/bulk-ban-partners.ts (1)
apps/web/lib/api/links/cache.ts (1)
  • linkCache (113-113)
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/[partnerId]/links/page-client.tsx (1)
packages/utils/src/functions/urls.ts (1)
  • getPrettyUrl (130-138)
⏰ 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 (8)
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/bounties/[bountyId]/bounty-submission-details-sheet.tsx (1)

296-298: Border/background cleanup on sticky footer — LGTM

Parent already sets border/background; removing on the inner div prevents double borders.

apps/web/lib/actions/partners/bulk-ban-partners.ts (1)

126-128: Expiring cached links after bulk ban — LGTM

Consistent with other actions and uses { domain, key } shape.

apps/web/lib/actions/partners/unban-partner.ts (1)

111-114: Expire cache on unban — LGTM

Stale cache busting after re-enabling links is correct.

apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/[partnerId]/links/page-client.tsx (3)

7-7: CopyButton import — LGTM

Consistent with usage elsewhere.


46-55: Link cell with CopyButton — LGTM

Nice UX improvement; concise and accessible.


87-97: Keep event=sales for the Conversions column — 'conversions' maps to sale events

The codebase uses "sales" as the events-page param and tracks/increments "conversions" from sale events, so the current href (event=sales) is correct (see apps/web/ui/analytics/events/events-tabs.tsx and apps/web/lib/api/conversions/track-sale.ts).

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

82-85: Conversions added to ProgramPartnerLinkSchema — LGTM

LinkSchema (apps/web/lib/zod/schemas/links.ts) defines conversions: z.number().default(0).

apps/web/lib/actions/partners/ban-partner.ts (1)

99-109: Switch to cache expiration is sensible — expireMany signature verified

Expiring cached links after DB updates avoids stale reads. apps/web/lib/api/links/cache.ts defines LinkCache.expireMany(links: Pick<LinkProps, "domain" | "key">[]) — matches { domain, key }[].

@steven-tey
Copy link
Collaborator Author

/bug0 run

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

🧹 Nitpick comments (1)
apps/web/lib/api/partners/get-partners.ts (1)

140-151: Make link search truly case-insensitive and add an exact ID fast-path

  • Apply LOWER() to the column side for link search to avoid case mismatches.
  • Add an exact p.id = ${search} branch to leverage the index when users paste a full ID; retain the LIKE for partials.
       ${
         search
           ? Prisma.sql`AND (
-        LOWER(p.id) LIKE LOWER(${`%${search}%`})
+        LOWER(p.id) LIKE LOWER(${`%${search}%`})
+        OR p.id = ${search}
         OR LOWER(p.name) LIKE LOWER(${`%${search}%`}) 
         OR LOWER(p.email) LIKE LOWER(${`%${search}%`})
         OR EXISTS (
           SELECT 1 FROM Link searchLink 
           WHERE searchLink.programId = ${programId}
           AND searchLink.partnerId = p.id 
-          AND searchLink.shortLink LIKE LOWER(${`%${search}%`})
+          AND LOWER(searchLink.shortLink) LIKE LOWER(${`%${search}%`})
         )
       )`
           : Prisma.sql``
       }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fbfb302 and dc3d91b.

📒 Files selected for processing (3)
  • apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/partners-table.tsx (2 hunks)
  • apps/web/lib/api/partners/get-partners.ts (1 hunks)
  • apps/web/lib/zod/schemas/partners.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • apps/web/lib/zod/schemas/partners.ts
⏰ 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 (3)
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/partners/partners-table.tsx (2)

394-396: Placeholder/UI copy aligns with backend search capabilities

Matches the new ID-aware and link search server-side behavior. LGTM.


122-125: Verify API support for workspaceId/includeExpandedFields in /api/partners

The fetch now sends workspaceId and includeExpandedFields: true. Ensure the API route maps workspaceId -> tenant/program correctly and respects includeExpandedFields; otherwise counts/sorting may desync or the request could be rejected if the endpoint still expects programId or tenantId.

apps/web/lib/api/partners/get-partners.ts (1)

158-159: sortBy/sortOrder validated — ORDER BY usage OK

getPartnersQuerySchema (apps/web/lib/zod/schemas/partners.ts) defines sortBy as a z.enum([...]) and sortOrder as z.enum(["asc","desc"]), so Prisma.raw(sortColumnsMap[sortBy]) and Prisma.raw(sortOrder) are protected.

@steven-tey steven-tey merged commit 277a89a into main Sep 24, 2025
7 of 8 checks passed
@steven-tey steven-tey deleted the small-partners-fixes branch September 24, 2025 05:00
@coderabbitai coderabbitai bot mentioned this pull request Oct 17, 2025
@coderabbitai coderabbitai bot mentioned this pull request Nov 8, 2025
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