Skip to content

feat: add analytics to PromotionalBanner#5898

Merged
idoshamun merged 1 commit intomainfrom
feat/promotional-banner-analytics
Apr 21, 2026
Merged

feat: add analytics to PromotionalBanner#5898
idoshamun merged 1 commit intomainfrom
feat/promotional-banner-analytics

Conversation

@nimrodkra
Copy link
Copy Markdown
Member

@nimrodkra nimrodkra commented Apr 21, 2026

Summary

Wires impression, click, and dismiss analytics on the top-of-page PromotionalBanner (Title / Subtitle / CTA / URL / Theme) so marketing can measure campaigns.

  • Reuses existing LogEvent.Impression, LogEvent.Click, and LogEvent.MarketingCtaDismiss — no new event names.
  • Adds one TargetType.PromotionalBanner = 'promotion_banner' alongside the other promotion_* target types.
  • target_id = banner.timestamp (the Banner entity's primary key) — unique per campaign.
  • Follows the same pattern as MarketingCtaCard, MarketingCtaPopoverSmall, PlusMobileEntryBanner, etc.

Impression uses useLogEventOnce and is gated on !isTesting && !!banner so it fires exactly once when a banner actually renders.

Test plan

  • Trigger a banner in staging and verify impression / click / dismiss promotion events are emitted with target_type = promotion_banner and target_id = <banner timestamp>.
  • Confirm no events are sent when no banner is active or in Jest/test environment.

Made with Cursor

Preview domain

https://feat-promotional-banner-analytic.preview.app.daily.dev

Track impression, CTA click, and dismiss events on the top
announcement bar using the existing marketing-CTA pattern.
Events are keyed by banner.timestamp (the Banner entity PK)
so analytics can slice by individual campaign.

Made-with: Cursor
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 21, 2026

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

Project Deployment Actions Updated (UTC)
daily-webapp Ready Ready Preview Apr 21, 2026 6:43am
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
storybook Ignored Ignored Apr 21, 2026 6:43am

Request Review

@nimrodkra
Copy link
Copy Markdown
Member Author

@claude please review this pr

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Apr 21, 2026

Claude finished @nimrodkra's task in 1m 13s —— View job


PR Review: feat: add analytics to PromotionalBanner

  • Read changed files
  • Analyze analytics implementation
  • Check consistency with existing patterns
  • Post review feedback

Overall: Clean, focused change. Correctly follows existing conventions. No bugs found. A couple of minor nits below.


packages/shared/src/lib/log.ts

TargetType.PromotionalBanner = 'promotion_banner' is inserted in the right spot — grouped alongside the other promotion_* sibling entries (PromotionCard, MarketingCtaPopover, etc.). ✅


packages/shared/src/components/PromotionalBanner.tsx

✅ What's done well

  • Uses useLogEventOnce (the newer, cleaner pattern) for the impression, rather than the older useRef + useEffect pattern still used in MarketingCtaCard. This is the right direction.
  • All hook calls happen before the two early returns — rules of hooks are respected.
  • condition: !isTesting && !!banner correctly gates the impression so it can never fire in the test environment or when no banner is present.
  • The onDismiss callback correctly calls dismiss() unconditionally even when the log branch is skipped (better than some existing patterns).

Minor nits

  1. Optional chaining on banner?.timestamp inside useLogEventOnce is misleading

    PromotionalBanner.tsx line 48

    target_id: banner?.timestamp,

    The condition: !!banner guarantee means banner is always non-null when this callback is executed, so ?. implies a nullable target_id that can never actually be undefined. The click/dismiss handlers both use banner.timestamp (non-optional) for consistency. Use the same form here:

    target_id: banner!.timestamp,

    or restructure the factory function to avoid the awkwardness entirely. Fix this →

  2. useLogContext is called twice in the same component

    useLogEventOnce internally calls useLogContext(), and the component also calls it directly on line 42 for onCtaClick/onDismiss. This works fine (both calls resolve to the same context value), but it's a minor redundancy. Not worth a refactor to the hook API for this PR alone, just worth noting.

  3. Redundant if (!banner) guard inside onDismiss

    PromotionalBanner.tsx lines 64–67

    The CloseButton that calls onDismiss is only rendered inside a branch that already asserts banner !== null (after the if (!banner) return <></> guard). The if (banner) inside the callback is therefore unreachable in practice. It's harmless, but it reads as though there's a realistic null path when there isn't.


No blocking issues. The nits above are code-quality observations; the logic itself is correct. LGTM pending those (or dismissing them as acceptable).

@idoshamun idoshamun merged commit 6b86542 into main Apr 21, 2026
12 checks passed
@idoshamun idoshamun deleted the feat/promotional-banner-analytics branch April 21, 2026 06:48
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