Skip to content

Conversation

thesmithdao
Copy link
Collaborator

@thesmithdao thesmithdao commented Oct 8, 2025

Summary

  • Instrument LocalizedLink so clicks to https://app.shapeshift.com trigger the Addressable Pixel conversion event.
  • Forward any provided onClick, open app links in a new tab
  • Updated TypeScript config to exclude auxiliary scripts from compilation.
  • Some ESLint/TS fixes (curly, typings) applied and local production build verified.

Acceptance

  • Successfully tested at Addressable dashboard.
image

Output:

  },
  "server_timestamp": 1759944953,
  "headers": {
    "accept": "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8",
    "accept-encoding": "gzip, deflate, br, zstd",
    "accept-language": "en-US,en;q=0.9",
    "Host": "tag.adrsbl.io",
    "priority": "i",
    "referer": "https://shapeshift-mkt-git-addrsbl-pixel-v2-defismith.vercel.app/",
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
    "X-Forwarded-Port": "443",
    "X-Forwarded-Proto": "https"
  },
  "is_conversion": "true"
}

Summary by CodeRabbit

  • New Features

    • Internal links now auto-include the current language (excluding the default) and preserve programmatic URL objects (queries/fragments).
    • External app links open in a new tab with analytics/ad-tracking support and allow custom onClick behavior.
  • Bug Fixes

    • Preserves query strings and fragments during navigation.
    • Maintains default behavior for external, anchor, mailto, tel, and non-root routes to avoid unintended rewrites.
  • Chores

    • TypeScript config updated to exclude the scripts directory.

Copy link
Contributor

coderabbitai bot commented Oct 8, 2025

📝 Walkthrough

Walkthrough

Extends LocalizedLink to preserve string and UrlObject hrefs (pathname, query, hash), detect and bypass external/anchor/mailto/tel/non-root links, prepend language for internal root links (except default), add app.shapeshift.com analytics + new-tab handling, and update tsconfig exclude to include scripts.

Changes

Cohort / File(s) Summary of Changes
Link localization & external handling
app/[lang]/_components/LocalizedLink.tsx
Reimplemented LocalizedLink to accept string and UrlObject hrefs; preserve pathname, query, and hash; detect and skip external/anchor/mailto/tel/non-root links; prepend current language for internal root links (except default) and return UrlObject when appropriate; add special handling for app.shapeshift.com that calls global __adrsbl hook, attempts window.open(fullUrl, "_blank") and falls back to router navigation; propagate onClick and keep displayName.
Build configuration
tsconfig.json
Added scripts to exclude alongside node_modules and .next.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant LocalizedLink
  participant Analytics as __adrsbl
  participant Router
  participant Window

  User->>LocalizedLink: click(href)
  alt href is anchor/mailto/tel/external host/non-root internal
    LocalizedLink->>Router: no localization / default behavior
  else host == app.shapeshift.com
    LocalizedLink->>Analytics: invoke __adrsbl (if present)
    Analytics-->>LocalizedLink: ack?
    LocalizedLink->>Window: window.open(fullUrl, "_blank")
    alt open blocked/error
      LocalizedLink->>Router: navigate(fullUrl) (fallback)
    end
  else internal root-relative
    LocalizedLink->>LocalizedLink: prepend lang (if not default), preserve query/hash
    LocalizedLink->>Router: navigate(localized href)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • 0xApotheosis

Poem

A rabbit hops through paths and strings,
Keeps queries snug and mends the wings.
When distant apps call with a click,
It logs the leap and opens quick.
Languages wrapped — a tidy trick. 🥕

Pre-merge checks and finishing touches

✅ 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 succinctly highlights the new click_app event and the firing of a pixel on app clicks, which captures the core functionality introduced by this pull request. It directly references the intended analytics instrumentation for app.shapeshift.com link interactions, aligning with the PR’s objective. The phrasing is concise, avoids irrelevant details, and follows a single clear sentence structure while using the conventional commit prefix.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between bfed48e and 2faf556.

📒 Files selected for processing (1)
  • app/[lang]/_components/LocalizedLink.tsx (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: thesmithdao
PR: shapeshift/website-frontend#66
File: app/[lang]/page.tsx:262-296
Timestamp: 2025-09-02T02:04:59.408Z
Learning: User thesmithdao prefers to avoid refactoring to LocalizedLink components for landing info cards in app/[lang]/page.tsx, preferring to keep the implementation clean with plain anchor tags.
📚 Learning: 2025-09-02T02:04:59.408Z
Learnt from: thesmithdao
PR: shapeshift/website-frontend#66
File: app/[lang]/page.tsx:262-296
Timestamp: 2025-09-02T02:04:59.408Z
Learning: User thesmithdao prefers to avoid refactoring to LocalizedLink components for landing info cards in app/[lang]/page.tsx, preferring to keep the implementation clean with plain anchor tags.

Applied to files:

  • app/[lang]/_components/LocalizedLink.tsx
🧬 Code graph analysis (1)
app/[lang]/_components/LocalizedLink.tsx (1)
app/[lang]/_utils/i18nconfig.ts (2)
  • getLanguageFromPath (59-64)
  • DEFAULT_LANGUAGE (52-52)
🔇 Additional comments (2)
app/[lang]/_components/LocalizedLink.tsx (2)

85-110: Verify event name consistency.

The duplicate URL computation concern from previous reviews has been resolved—absolute is now computed once at lines 96-98 and reused in both the try and catch blocks.

However, line 90 uses the event name 'app_click', while the PR title references 'click_app event'. Please confirm this is the correct event name for the Addressable dashboard configuration.


24-159: LGTM! Solid implementation with proper handling of edge cases.

The component correctly:

  • Preserves UrlObject structure with query and hash parameters
  • Detects app.shapeshift.com links for both string and UrlObject hrefs
  • Fires the analytics pixel with appropriate error handling
  • Opens app links in new tabs with security attributes (noopener, noreferrer)
  • Propagates custom onClick handlers
  • Bypasses localization for external, anchor, mailto, tel, and non-root links
  • Applies language prefixing only to internal root paths (excluding DEFAULT_LANGUAGE)

All concerns raised in previous reviews have been addressed: string query support has been added (lines 47-50), null/undefined query values are properly skipped (lines 59-60), and URL computation is no longer duplicated.


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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 29665de and 905db99.

📒 Files selected for processing (2)
  • app/[lang]/_components/LocalizedLink.tsx (1 hunks)
  • tsconfig.json (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-02T02:04:59.408Z
Learnt from: thesmithdao
PR: shapeshift/website-frontend#66
File: app/[lang]/page.tsx:262-296
Timestamp: 2025-09-02T02:04:59.408Z
Learning: User thesmithdao prefers to avoid refactoring to LocalizedLink components for landing info cards in app/[lang]/page.tsx, preferring to keep the implementation clean with plain anchor tags.

Applied to files:

  • app/[lang]/_components/LocalizedLink.tsx
🧬 Code graph analysis (1)
app/[lang]/_components/LocalizedLink.tsx (1)
app/[lang]/_utils/i18nconfig.ts (2)
  • getLanguageFromPath (59-64)
  • DEFAULT_LANGUAGE (52-52)

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)
app/[lang]/_components/LocalizedLink.tsx (1)

93-101: Previous critical issue resolved; consider minor optimization.

The past issue with UrlObject navigation has been correctly fixed—both window.open and the fallback window.location.assign now use fullUrlFromObj(hrefObj) to generate the complete absolute URL. Well done!

Minor optimization: the absolute URL is computed twice (lines 93-95 and line 98). You could compute it once before the outer try block to reduce duplication:

 			}
 			e.preventDefault()
+			const absolute = hrefObj
+				? fullUrlFromObj(hrefObj)
+				: hrefString || (typeof href === 'string' ? href : '')
 			try {
-				const absolute = hrefObj
-					? fullUrlFromObj(hrefObj)
-					: hrefString || (typeof href === 'string' ? href : '')
 				window.open(absolute, '_blank', 'noopener,noreferrer')
 			} catch {
-				const absolute = hrefObj ? fullUrlFromObj(hrefObj) : hrefString
 				if (absolute) {
 					window.location.assign(absolute)
 				}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 905db99 and 1e90018.

📒 Files selected for processing (1)
  • app/[lang]/_components/LocalizedLink.tsx (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: thesmithdao
PR: shapeshift/website-frontend#66
File: app/[lang]/page.tsx:262-296
Timestamp: 2025-09-02T02:04:59.408Z
Learning: User thesmithdao prefers to avoid refactoring to LocalizedLink components for landing info cards in app/[lang]/page.tsx, preferring to keep the implementation clean with plain anchor tags.
📚 Learning: 2025-09-02T02:04:59.408Z
Learnt from: thesmithdao
PR: shapeshift/website-frontend#66
File: app/[lang]/page.tsx:262-296
Timestamp: 2025-09-02T02:04:59.408Z
Learning: User thesmithdao prefers to avoid refactoring to LocalizedLink components for landing info cards in app/[lang]/page.tsx, preferring to keep the implementation clean with plain anchor tags.

Applied to files:

  • app/[lang]/_components/LocalizedLink.tsx
🧬 Code graph analysis (1)
app/[lang]/_components/LocalizedLink.tsx (1)
app/[lang]/_utils/i18nconfig.ts (2)
  • getLanguageFromPath (59-64)
  • DEFAULT_LANGUAGE (52-52)
🔇 Additional comments (3)
app/[lang]/_components/LocalizedLink.tsx (3)

48-57: Verify undefined/null query parameter handling.

When a query parameter value is undefined or null, line 56 appends an empty string (e.g., ?key=). Confirm this is the intended behavior—typically, such values are omitted from query strings entirely. If omission is preferred, remove the else clause:

 					for (const [k, v] of Object.entries(obj.query as Record<string, unknown>)) {
 						if (Array.isArray(v)) {
 							for (const item of v) {
 								params.append(k, String(item))
 							}
 						} else if (v !== undefined && v !== null) {
 							params.append(k, String(v))
-						} else {
-							params.append(k, '')
 						}
 					}

109-130: LGTM: External link detection is comprehensive.

The logic correctly identifies external links, anchors, mailto, tel, and non-root paths, bypassing localization for these cases. The conditional onClick on line 126 properly applies handleClick only for app links while preserving the original onClick for other external links.


132-145: LGTM: Localization preserves URL structure correctly.

The localization logic correctly:

  • Detects existing language prefixes (line 133)
  • Prepends the current language only when needed and not default (lines 138-140)
  • Preserves UrlObject properties (query, hash) by returning a modified UrlObject (lines 142-144) instead of stringifying

This ensures Next.js Link receives the appropriate href format and all URL components are maintained.

Copy link
Member

@0xApotheosis 0xApotheosis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both internal and external links seem to be working as expected. Some minor tweaks requested.

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 (1)
app/[lang]/_components/LocalizedLink.tsx (1)

93-103: Simplify the fallback chain for consistency.

Line 96 includes a redundant fallback (typeof href === 'string' ? href : '') since hrefString is already set to href when it's a string (line 33). The catch block (line 99) doesn't include this fallback, creating an inconsistency.

Consider simplifying line 96 to match line 99:

 			try {
-				const absolute = hrefObj
-					? fullUrlFromObj(hrefObj)
-					: hrefString || (typeof href === 'string' ? href : '')
+				const absolute = hrefObj ? fullUrlFromObj(hrefObj) : hrefString
 				window.open(absolute, '_blank', 'noopener,noreferrer')
 			} catch {
 				const absolute = hrefObj ? fullUrlFromObj(hrefObj) : hrefString
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 1e90018 and c3a80ae.

📒 Files selected for processing (1)
  • app/[lang]/_components/LocalizedLink.tsx (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: thesmithdao
PR: shapeshift/website-frontend#66
File: app/[lang]/page.tsx:262-296
Timestamp: 2025-09-02T02:04:59.408Z
Learning: User thesmithdao prefers to avoid refactoring to LocalizedLink components for landing info cards in app/[lang]/page.tsx, preferring to keep the implementation clean with plain anchor tags.
📚 Learning: 2025-09-02T02:04:59.408Z
Learnt from: thesmithdao
PR: shapeshift/website-frontend#66
File: app/[lang]/page.tsx:262-296
Timestamp: 2025-09-02T02:04:59.408Z
Learning: User thesmithdao prefers to avoid refactoring to LocalizedLink components for landing info cards in app/[lang]/page.tsx, preferring to keep the implementation clean with plain anchor tags.

Applied to files:

  • app/[lang]/_components/LocalizedLink.tsx
🧬 Code graph analysis (1)
app/[lang]/_components/LocalizedLink.tsx (1)
app/[lang]/_utils/i18nconfig.ts (2)
  • getLanguageFromPath (59-64)
  • DEFAULT_LANGUAGE (52-52)
🔇 Additional comments (4)
app/[lang]/_components/LocalizedLink.tsx (4)

70-80: LGTM! App link detection is comprehensive.

The detection logic correctly handles both string hrefs and UrlObject with host information. The regex pattern appropriately matches app.shapeshift.com links with case-insensitive matching.


105-107: LGTM! onClick propagation is handled correctly.

The user-provided onClick handler is properly forwarded after the analytics and navigation logic, ensuring compatibility with existing click handlers.


110-131: LGTM! External link handling is well-structured.

The logic correctly identifies external links (including anchors, mailto, tel, and UrlObject with host/protocol) and bypasses localization for them. The conditional onClick on line 127 ensures app links get the analytics + new-tab behavior while other external links retain their original click handlers.


133-146: LGTM! Localization logic correctly preserves UrlObject structure.

The implementation properly:

  • Detects existing language prefixes to avoid double-prefixing
  • Only adds language prefix when not using the default language
  • Preserves the original type (string or UrlObject) which maintains query and hash parameters

Based on coding guidelines (relevant_code_snippets show DEFAULT_LANGUAGE and getLanguageFromPath usage).

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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c3a80ae and bfed48e.

📒 Files selected for processing (1)
  • app/[lang]/_components/LocalizedLink.tsx (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: thesmithdao
PR: shapeshift/website-frontend#66
File: app/[lang]/page.tsx:262-296
Timestamp: 2025-09-02T02:04:59.408Z
Learning: User thesmithdao prefers to avoid refactoring to LocalizedLink components for landing info cards in app/[lang]/page.tsx, preferring to keep the implementation clean with plain anchor tags.
📚 Learning: 2025-09-02T02:04:59.408Z
Learnt from: thesmithdao
PR: shapeshift/website-frontend#66
File: app/[lang]/page.tsx:262-296
Timestamp: 2025-09-02T02:04:59.408Z
Learning: User thesmithdao prefers to avoid refactoring to LocalizedLink components for landing info cards in app/[lang]/page.tsx, preferring to keep the implementation clean with plain anchor tags.

Applied to files:

  • app/[lang]/_components/LocalizedLink.tsx
🧬 Code graph analysis (1)
app/[lang]/_components/LocalizedLink.tsx (1)
app/[lang]/_utils/i18nconfig.ts (2)
  • getLanguageFromPath (59-64)
  • DEFAULT_LANGUAGE (52-52)
🔇 Additional comments (8)
app/[lang]/_components/LocalizedLink.tsx (8)

13-14: LGTM!

The ESLint disable and global declaration are appropriate for integrating with the Addressable pixel library.


16-19: LGTM!

The type definition properly combines Next.js Link props with standard anchor attributes.


24-33: LGTM!

The component properly supports both string and UrlObject hrefs, extracting the pathname for processing while preserving the original object structure.


75-85: LGTM!

The app link detection correctly handles both string and UrlObject hrefs with appropriate pattern matching.


110-112: Verify onClick propagation behavior is intentional.

When isAppLink is true, the handler calls preventDefault() and opens the link in a new tab, but still invokes the original onClick afterward. Confirm this is the intended behavior, as users might expect their onClick to control navigation. If the onClick is meant only for side effects (e.g., analytics), this is fine; otherwise, consider calling onClick before preventDefault() to allow it to cancel the action.


115-136: LGTM!

The external link detection correctly handles both string patterns (http, #, mailto, tel, non-root paths) and UrlObject indicators (host, hostname, protocol), ensuring only internal root paths are localized.


138-151: LGTM!

The language prefix logic correctly handles both string and UrlObject hrefs, preserving query and hash parameters when returning a UrlObject for localized internal links.


153-165: LGTM!

The final return properly renders the localized link with all props forwarded, and the displayName is set for debugging.

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