Skip to content

Add ActivityRing component and update to program owner activity#3342

Merged
steven-tey merged 3 commits intomainfrom
program-owner-activity
Jan 13, 2026
Merged

Add ActivityRing component and update to program owner activity#3342
steven-tey merged 3 commits intomainfrom
program-owner-activity

Conversation

@marcusljf
Copy link
Collaborator

@marcusljf marcusljf commented Jan 12, 2026

Introduces a new ActivityRing component for visualizing positive and negative metrics. Refactors PartnerCrossProgramSummary to use ActivityRing and improves loading and row presentation.

Component is also used in the fraud review drawer.

Neutral

CleanShot 2026-01-12 at 15 28 21@2x

Trustworthy leading

CleanShot 2026-01-12 at 15 27 58@2x

Removed leading

CleanShot 2026-01-12 at 15 28 10@2x

Summary by CodeRabbit

  • New Features
    • New circular ring visualization for showing positive vs. negative metrics.
    • Consolidated partner cross-program summary layout with visual indicator and compact stat rows.
    • Loading placeholder to improve UX while summary data loads.

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

Introduces a new ActivityRing component for visualizing positive and negative metrics. Refactors PartnerCrossProgramSummary to use ActivityRing and improves loading and stat row presentation. Exports ActivityRing from the UI package.
@vercel
Copy link
Contributor

vercel bot commented Jan 12, 2026

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

Project Deployment Review Updated (UTC)
dub Ready Ready Preview Jan 13, 2026 2:08am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 12, 2026

📝 Walkthrough

Walkthrough

Replaces per-item cross-program metric rendering with a consolidated ActivityRing visualization and two StatRow entries, adds a LoadingSkeleton early return, and exports the new ActivityRing from the UI package. Data is destructured into totalPrograms, trustedPrograms, and removedPrograms.

Changes

Cohort / File(s) Summary
ActivityRing component & export
packages/ui/src/activity-ring.tsx, packages/ui/src/index.tsx
Adds new ActivityRing React component rendering SVG arcs for positive/negative/neutral values (props: positiveValue, negativeValue, size, positiveIcon, negativeIcon, neutralIcon, className) and geometric helpers; re-exported from UI barrel.
Partner cross-program summary UI
apps/web/ui/partners/fraud-risks/partner-cross-program-summary.tsx
Replaces prior per-item metric list with an ActivityRing plus two StatRow components, introduces LoadingSkeleton early return when isLoading or data missing, and destructures crossProgramSummary into totalPrograms, trustedPrograms, removedPrograms.

Sequence Diagram(s)

(omitted)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • devkiran

Poem

🐰 I hopped through arcs of color bright,
Trust and removals in looped flight,
SVG whiskers, stats in a row,
A tiny ring to make data glow —
Hooray! 🥕✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main changes: introducing a new ActivityRing component and refactoring the program owner activity UI to use it.

✏️ 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
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/ui/partners/fraud-risks/partner-cross-program-summary.tsx (1)

4-4: Remove unused User import.

User is imported but not used anywhere in this file.

Suggested fix
-import { ActivityRing, User, UserCheck, UserXmark } from "@dub/ui";
+import { ActivityRing, UserCheck, UserXmark } from "@dub/ui";
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between de33a63 and 76f5843.

📒 Files selected for processing (3)
  • apps/web/ui/partners/fraud-risks/partner-cross-program-summary.tsx
  • packages/ui/src/activity-ring.tsx
  • packages/ui/src/index.tsx
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-11-24T16:36:36.196Z
Learnt from: CR
Repo: dubinc/dub PR: 0
File: packages/hubspot-app/CLAUDE.md:0-0
Timestamp: 2025-11-24T16:36:36.196Z
Learning: Applies to packages/hubspot-app/app/cards/**/*.{js,jsx,ts,tsx} : Only components exported from the `hubspot/ui-extensions` npm package can be used in card components

Applied to files:

  • packages/ui/src/index.tsx
📚 Learning: 2025-05-29T04:45:18.504Z
Learnt from: devkiran
Repo: dubinc/dub PR: 2448
File: packages/email/src/templates/partner-program-summary.tsx:0-0
Timestamp: 2025-05-29T04:45:18.504Z
Learning: In the PartnerProgramSummary email template (packages/email/src/templates/partner-program-summary.tsx), the stat titles are hardcoded constants ("Clicks", "Leads", "Sales", "Earnings") that will always match the ICONS object keys after toLowerCase() conversion, so icon lookup failures are not possible.

Applied to files:

  • apps/web/ui/partners/fraud-risks/partner-cross-program-summary.tsx
⏰ 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 (9)
packages/ui/src/index.tsx (1)

6-6: LGTM!

The new activity-ring export follows the established alphabetical ordering pattern in this barrel file.

apps/web/ui/partners/fraud-risks/partner-cross-program-summary.tsx (2)

6-45: Clean refactor with proper loading state handling.

The component correctly handles loading states, destructures data cleanly, and integrates well with the new ActivityRing component. The separation between the visual ring and the textual StatRow components provides good information density.


47-83: LGTM!

The StatRow and LoadingSkeleton helpers are clean and well-structured. The skeleton dimensions appropriately match the loaded content layout.

packages/ui/src/activity-ring.tsx (6)

6-20: Well-documented props interface.

The JSDoc comments on each prop provide clear guidance for consumers of this component.


37-88: LGTM!

The geometry helper functions are mathematically sound. The -90 degree offset in polarToCartesian correctly positions 0° at the top, and the arc path generation follows standard SVG conventions.


108-156: Arc calculation logic is sound.

The minimum arc visibility enforcement correctly handles edge cases where one value is very small relative to the other. The sequential checks work correctly because with the current constants (MIN_ARC_DEGREES=30, availableSweep=330), it's impossible for both sweeps to be below the minimum simultaneously.


158-162: LGTM!

The radius calculations correctly account for SVG stroke positioning, and the proportional fillInnerRadius ensures the component scales consistently.


164-188: LGTM!

The memoization is appropriately used for the icon selection and color determination.


190-299: Clean SVG rendering with proper layering.

The SVG structure correctly layers filled arcs behind strokes, and the conditional rendering based on state is well-organized. The centered icon implementation is clean.

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)
packages/ui/src/activity-ring.tsx (1)

158-188: Consider simplifying unused intermediate variables.

positiveColor and negativeColor (lines 187-188) are assigned from COLORS but could be inlined directly in the JSX since they never change. This is a minor nitpick—the current approach is also fine if you anticipate future dynamic color logic.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 76f5843 and 5d3e0f3.

📒 Files selected for processing (2)
  • apps/web/ui/partners/fraud-risks/partner-cross-program-summary.tsx
  • packages/ui/src/activity-ring.tsx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-05-29T04:45:18.504Z
Learnt from: devkiran
Repo: dubinc/dub PR: 2448
File: packages/email/src/templates/partner-program-summary.tsx:0-0
Timestamp: 2025-05-29T04:45:18.504Z
Learning: In the PartnerProgramSummary email template (packages/email/src/templates/partner-program-summary.tsx), the stat titles are hardcoded constants ("Clicks", "Leads", "Sales", "Earnings") that will always match the ICONS object keys after toLowerCase() conversion, so icon lookup failures are not possible.

Applied to files:

  • apps/web/ui/partners/fraud-risks/partner-cross-program-summary.tsx
🧬 Code graph analysis (1)
apps/web/ui/partners/fraud-risks/partner-cross-program-summary.tsx (1)
packages/ui/src/activity-ring.tsx (1)
  • ActivityRing (92-270)
⏰ 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 (9)
packages/ui/src/activity-ring.tsx (4)

1-35: LGTM! Well-structured type definitions and constants.

The props interface is well-documented with JSDoc comments, and the color constants are clearly named. The GAP_ANGLE and MIN_ARC_DEGREES constants provide good configurability for the visual appearance.


37-88: LGTM! Clean SVG path generation helpers.

The polar-to-cartesian conversion and arc path generation functions are mathematically correct. The describeFilledArc function properly creates a closed donut-slice path by drawing the outer arc, connecting to the inner arc, and closing the path.


101-156: Verify behavior when both values are at the minimum arc threshold.

The minimum arc visibility logic at lines 135-142 handles each value independently. If both positiveValue and negativeValue are non-zero but have extremely skewed ratios (e.g., 1:1000), the first condition adjusts the minority arc to MIN_ARC_DEGREES, leaving plenty of room for the majority arc. However, consider adding a comment explaining why the conditions can't conflict (after expanding one arc, the remaining sweep is always > MIN_ARC_DEGREES).

Also, when one value is exactly 0, the stroke arc still renders with zero sweep (start === end), which may produce a tiny dot with strokeLinecap="round" in some browsers—though this is likely imperceptible.


190-269: LGTM! Clean SVG rendering with proper conditional logic.

The component correctly renders filled arcs only when values are positive, ensuring the neutral state (both values = 0) shows only stroke arcs. The icon overlay is properly centered and responds to the computed state. Good use of the cn utility for className composition.

apps/web/ui/partners/fraud-risks/partner-cross-program-summary.tsx (5)

4-4: LGTM! Clean import of new UI components.

The ActivityRing and icon components are properly imported from the shared UI package.


15-20: LGTM! Good defensive loading check.

The early return handles both the loading state and the case where crossProgramSummary is undefined/null, preventing runtime errors during data fetching.


22-45: LGTM! Clean integration of ActivityRing with StatRow layout.

The component properly wires up the trusted/removed values to the positive/negative props of ActivityRing, with appropriate icons for each state. The flex layout with min-w-0 grow ensures proper text truncation behavior if needed.


47-65: LGTM! Simple and effective StatRow component.

The component is well-typed and renders a clean label-value pair layout. The typography classes provide appropriate visual hierarchy.


67-89: LGTM! LoadingSkeleton properly mirrors the actual content layout.

The skeleton dimensions match the rendered content structure—size-10 (40px) matches ActivityRing's default size, and the placeholder widths approximate the stat row content. The consistent use of animate-pulse and bg-neutral-200 follows common loading state patterns.

@steven-tey steven-tey merged commit ac98e03 into main Jan 13, 2026
7 checks passed
@steven-tey steven-tey deleted the program-owner-activity branch January 13, 2026 02:20
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