Skip to content

init aws rum and sentry events#1837

Merged
simo6529 merged 4 commits intomainfrom
scroll-to-jump
Jan 27, 2026
Merged

init aws rum and sentry events#1837
simo6529 merged 4 commits intomainfrom
scroll-to-jump

Conversation

@simo6529
Copy link
Copy Markdown
Collaborator

@simo6529 simo6529 commented Jan 27, 2026

Summary by CodeRabbit

  • Removed Features

    • Artist submission badge no longer displayed on drops
    • Profile winner badge no longer displayed on drops
  • Enhancements

    • Drop interactions from leaderboard, gallery, and mobile menu now trigger timing telemetry before opening
    • Client-side monitoring added to record when a drop becomes ready and report interaction durations for improved analytics

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

Signed-off-by: Simo <simo@6529.io>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 27, 2026

📝 Walkthrough

Walkthrough

Adds a client-side drop-open telemetry utility and integrates it into several drop UI flows (calls to startDropOpen). Introduces markDropOpenReady in SingleWaveDropWrapper to record readiness. Removes two badge components (ArtistSubmissionBadge, ProfileWinnerBadge).

Changes

Cohort / File(s) Summary
Telemetry utility
utils/monitoring/dropOpenTiming.ts
New module: startDropOpen and markDropOpenReady, pending-entry registry, optional Sentry span handling, AWS RUM event emission, RAF-aligned ready reporting, and a 30s purge timeout.
Leaderboard / Memes click handlers
components/memes/drops/MemesLeaderboardDrop.tsx, components/waves/leaderboard/drops/DefaultWaveLeaderboardDrop.tsx, components/waves/leaderboard/gallery/WaveLeaderboardGalleryItem.tsx
Inserted startDropOpen(...) calls in drop click handlers (source tags: leaderboard_memes, leaderboard_list, leaderboard_grid) before existing onDropClick logic; minor className reorderings.
Mobile menu
components/waves/drops/WaveDropMobileMenuOpen.tsx
Calls startDropOpen(...) with source: "leaderboard_mobile_menu" and isMobile: true before navigation; trivial JSX class ordering tweaks.
Drop readiness marking
components/waves/drop/SingleWaveDropWrapper.tsx
Added readyKeyRef and useEffect to deduplicate and call markDropOpenReady({dropId, waveId}) when drop/wave mounts or IDs change.
Removed badges
components/waves/drops/ArtistSubmissionBadge.tsx, components/waves/drops/ProfileWinnerBadge.tsx
Deleted two tooltip-enabled badge components and their tooltip/interaction logic.

Sequence Diagram

sequenceDiagram
    participant User
    participant UI as "UI Component\n(e.g., leaderboard/memes)"
    participant Start as "startDropOpen\n(utils)"
    participant Registry as "Pending Registry"
    participant Sentry
    participant Single as "SingleWaveDropWrapper"
    participant Mark as "markDropOpenReady\n(utils)"
    participant RUM as "AWS RUM"

    User->>UI: Click/tap drop
    UI->>Start: startDropOpen(dropId, waveId, source, isMobile)
    Start->>Registry: store pending entry (start timestamp)
    Start->>Sentry: start manual span (optional)
    Start-->>UI: return
    UI->>UI: invoke onDropClick / navigation

    Note right of Single: Drop content mounts / renders
    Single->>Mark: markDropOpenReady(dropId, waveId)
    Mark->>Registry: lookup pending entry
    Registry-->>Mark: return entry (start time)
    Mark->>Mark: compute duration_ms (with RAF alignment)
    Mark->>Sentry: update span attrs, end span (if present)
    Mark->>RUM: recordEvent("drop_popup_ready", payload) (if present)
    Mark->>Registry: clear timeout and remove entry
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Suggested reviewers

  • analyticsflowee
  • ragnep
  • GelatoGenesis

Poem

🐰 I hopped to a drop and marked the start,

Timers and spans played their part.
Clicked, then rendered, data set free—
Metrics hop home, safe with me. 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'init aws rum and sentry events' accurately describes the main objective of the PR, which adds telemetry and monitoring for drop-open timing using AWS RUM and Sentry.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

@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 `@package.json`:
- Around line 84-85: The Sentry packages are mismatched and core is directly
imported in utils/monitoring/dropOpenTiming.ts; either align versions in
package.json (set both "@sentry/core" and "@sentry/nextjs" to the same version,
e.g., ^10.37.0) or remove "@sentry/core" and update the import in
dropOpenTiming.ts to import startSpanManual (and any other APIs) from
"@sentry/nextjs" instead; ensure package.json dependencies reflect the chosen
approach and update any imports that referenced "@sentry/core" to
"@sentry/nextjs" to avoid type/runtime inconsistencies.

In `@utils/monitoring/dropOpenTiming.ts`:
- Around line 30-33: getRoute() currently assumes globalThis.window exists;
guard it and return a safe fallback when window or location is unavailable
(e.g., during SSR or tests). Update getRoute to check for globalThis.window (or
use const win = globalThis.window ?? null) and for win.location before accessing
pathname/search, and return a sensible default (empty string or "/") when
missing; keep the function name getRoute and callers unchanged so locating the
change is trivial.
- Around line 71-73: The timeout callback that currently only calls
pendingOpens.delete(dropId) must also end any Sentry span associated with that
entry to avoid orphaned spans: inside the win.setTimeout handler (the one
creating timeoutId), look up the pending entry from pendingOpens using dropId,
if it contains a Sentry span object (e.g., span or sentrySpan) call
span.finish() (or span.end() if your Sentry wrapper uses that) before deleting
the map entry, and guard the call with a null check so you don't throw if the
span is missing.
🧹 Nitpick comments (1)
utils/monitoring/dropOpenTiming.ts (1)

35-38: Avoid the generic Function type.

Using Function loses type safety. Consider a more specific signature.

Suggested fix
 const getRumClient = () => {
   const win = globalThis.window;
-  return (win as unknown as { awsRum?: { recordEvent?: Function } }).awsRum;
+  return (win as unknown as { awsRum?: { recordEvent?: (name: string, data?: Record<string, unknown>) => void } }).awsRum;
 };

Comment thread package.json Outdated
Comment thread utils/monitoring/dropOpenTiming.ts
Comment thread utils/monitoring/dropOpenTiming.ts Outdated
Signed-off-by: Simo <simo@6529.io>
Copy link
Copy Markdown

@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 `@utils/monitoring/dropOpenTiming.ts`:
- Around line 38-41: getRumClient currently assumes globalThis.window exists and
accessing win.awsRum will throw in non‑browser/test environments; update
getRumClient to first check that globalThis.window (win) is defined and return
undefined if not, then safely access awsRum (use optional chaining or a null
check) so calls like awsRum?.recordEvent are protected; modify the function
getRumClient to perform the null guard around globalThis.window and return the
awsRum client only when present.
- Around line 65-111: When startDropOpen is invoked, it currently overwrites
pendingOpens[dropId] without cancelling the previous timeout or ending its span;
before creating the new entry, check pendingOpens.get(dropId) and if present
call clearTimeout on its timeoutId and call endSentrySpan on its span (or
otherwise clean it up) to prevent the old timeout from ending the new span, then
proceed to create the new span via startSpanManual and set the new pendingOpens
entry (references: startDropOpen, pendingOpens, timeoutId, endSentrySpan,
startSpanManual, DROP_OPEN_TIMEOUT_MS).
- Around line 113-164: markDropOpenReady's deferred finish closure uses the
captured `entry` but doesn't verify the map still contains the same active entry
after two rAFs, so it can end/delete a newer start for the same dropId; modify
the `finish` function to re-read `pendingOpens.get(entry.dropId)` and confirm
the returned entry is the same object (or has the same `startMs`/waveId) before
proceeding with recording events, ending the span, clearing timeout and deleting
from `pendingOpens`; keep the existing behavior when it matches and simply
return/do nothing if it does not match.

Comment thread utils/monitoring/dropOpenTiming.ts
Comment thread utils/monitoring/dropOpenTiming.ts
Comment thread utils/monitoring/dropOpenTiming.ts
Signed-off-by: Simo <simo@6529.io>
Copy link
Copy Markdown

@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

🤖 Fix all issues with AI agents
In `@utils/monitoring/dropOpenTiming.ts`:
- Line 74: The code grabs const win = globalThis.window and later calls
win.setTimeout(...) without verifying win exists; update the logic around the
win variable (and the setTimeout usage) to defensively guard for SSR/test
environments by checking that win is not undefined/null and that win.setTimeout
is a function (or fall back to globalThis.setTimeout or a noop). Locate the
const win = globalThis.window and the call to win.setTimeout(...) and wrap the
timeout invocation with this guard (or use an alternative safe timer) so it
never throws when window is absent.
- Around line 88-106: The span returned by startSpanManual is only active inside
its callback, so stop returning the span for later use; instead, move any
deferred work that needs the active span (like storing it on pendingOpens with
dropId and starting the timeout/handler logic) inside the startSpanManual
callback passed to startSpanManual, or use a different API that keeps the span
active for the needed lifecycle; specifically update the startSpanManual usage
(and avoid assigning span = (createdSpan) => createdSpan) so that
pendingOpens.set(dropId, { span: createdSpan, ... }) and the
timeout/timeout-handler that references pendingOpens.get(dropId)?.span are
executed from within the callback while createdSpan is active.

Comment thread utils/monitoring/dropOpenTiming.ts Outdated
Comment thread utils/monitoring/dropOpenTiming.ts Outdated
Signed-off-by: Simo <simo@6529.io>
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Jan 27, 2026

Quality Gate Passed Quality Gate passed

Issues
0 New issues
2 Accepted issues

Measures
0 Security Hotspots
No data about Coverage
0.0% Duplication on New Code

See analysis details on SonarQube Cloud

@simo6529 simo6529 merged commit e9be8f5 into main Jan 27, 2026
7 checks passed
@simo6529 simo6529 deleted the scroll-to-jump branch January 27, 2026 14:22
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