Skip to content

fix: normalize cta#1092

Merged
asanehisa merged 21 commits intomainfrom
cta
Mar 17, 2026
Merged

fix: normalize cta#1092
asanehisa merged 21 commits intomainfrom
cta

Conversation

@asanehisa
Copy link
Copy Markdown
Contributor

@asanehisa asanehisa commented Mar 13, 2026

Adds a normalize link prop for users to set as true or false, migration and default has it set to true for most cases (not in email or phone).

If link type is email or phone, normalizeLink is false and the field is hidden.

https://jam.dev/c/25d6f9b3-b15b-4bc2-89cc-ce8be0042f34

@asanehisa asanehisa marked this pull request as ready for review March 16, 2026 13:44
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 16, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This PR introduces a new boolean normalizeLink flag across the visual editor CTA system: it adds the field to CTA props/types/docs, wires it into CTA rendering (via a new getResolvedLink helper), updates many CTA usages and default slot data to include the flag, adds editor fields to expose per-item control, and registers a migration to backfill defaults. Separately, many locale files were extended with kilometer_zero and mile_zero translation keys.

Sequence Diagram

sequenceDiagram
    participant Parent as Parent Component (e.g., HeaderLinks)
    participant CTA as CTA Component
    participant Helper as getResolvedLink Helper
    participant Resolver as Link Resolution Logic

    Parent->>CTA: pass normalizeLink (true/false) + link data
    CTA->>CTA: extract shouldNormalizeLink
    CTA->>Helper: getResolvedLink(link, linkType, shouldNormalizeLink)
    alt shouldNormalizeLink = true
        Helper->>Resolver: normalize link
        Resolver-->>Helper: return normalized link
    else
        Helper->>Resolver: return raw/synthetic link
        Resolver-->>Helper: return resolved link
    end
    Helper-->>CTA: resolved link
    CTA->>Parent: render CTA with resolved link
Loading

Possibly related PRs

Suggested labels

create-dev-release

Suggested reviewers

  • benlife5
  • mkilpatrick
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix: normalize cta' directly describes the main change - adding a normalize link property for CTA components, which is the core objective of this PR.
Description check ✅ Passed The pull request description clearly relates to the changeset, explaining the addition of a normalizeLink prop across CTA components with appropriate defaults and special handling for email/phone link types.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cta
📝 Coding Plan
  • Generate coding plan for human review comments

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.

Tip

You can generate walkthrough in a markdown collapsible section to save space.

Enable the reviews.collapse_walkthrough setting to generate walkthrough in a markdown collapsible section.

Copy link
Copy Markdown
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: 13

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/visual-editor/src/components/atoms/maybeLink.tsx (1)

29-34: ⚠️ Potential issue | 🟠 Major

MaybeLink should not disable normalization for generic URL links.

Line 33 sets normalizeLink={false} for a linkType="URL" CTA (Line 32). That can regress links like example.com by skipping normalization.

💡 Suggested fix
-        normalizeLink={false}
+        normalizeLink={true}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/visual-editor/src/components/atoms/maybeLink.tsx` around lines 29 -
34, The CTA invocation inside MaybeLink should not force normalizeLink={false}
for generic URLs; remove the hardcoded normalizeLink={false} (or set
normalizeLink to true/omit it) when linkType is "URL" so that links like
"example.com" are normalized correctly; update the CTA call in the MaybeLink
component (look for the CTA props: link={href}, label={children},
linkType="URL", normalizeLink={false}, eventName={eventName}) to either omit
normalizeLink or conditionally pass normalizeLink only for non-URL linkTypes.
packages/visual-editor/src/components/footer/Footer.tsx (1)

197-205: ⚠️ Potential issue | 🟠 Major

Don't opt every legacy footer link out of normalization.

site.footer.links renders generic CTAs, so forcing normalizeLink={false} changes behavior for normal URL entries as well. This exception should stay limited to phone/email-style links; otherwise let the CTA use the normal default.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/visual-editor/src/components/footer/Footer.tsx` around lines 197 -
205, The Footer is forcing normalizeLink={false} for every site.footer.links
CTA; change the prop to be conditional so only phone/email-style links opt out
of normalization. Update the CTA usage in Footer.tsx to pass
normalizeLink={item.linkType === 'phone' || item.linkType === 'email'} (or
equivalent check against item.linkType) so generic URL entries use the default
normalization behavior while phone/email links remain unnormalized.
🧹 Nitpick comments (1)
packages/visual-editor/locales/platform/zh-TW/visual-editor.json (1)

544-546: Consider using one mile term consistently across zero/one/other forms.

mile_zero uses 英哩, while mile_one/mile_other use 英里. Aligning them avoids UI wording drift.

Suggested consistency tweak
-  "mile_zero": "英哩",
+  "mile_zero": "英里",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/visual-editor/locales/platform/zh-TW/visual-editor.json` around
lines 544 - 546, The three localization keys mile_zero, mile_one, and mile_other
are inconsistent (mile_zero uses "英哩" while the others use "英里"); pick the
preferred term and make all three values identical to prevent UI wording drift —
update mile_zero, mile_one, and mile_other so they all use the same Chinese term
(either "英里" or "英哩") across the file.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/visual-editor/locales/components/en-GB/visual-editor.json`:
- Around line 40-42: The en-GB locale has an inconsistency: the key
"kilometer_zero" uses American spelling "kilometer" while "kilometer_one" and
"kilometer_other" use British "kilometre"/"kilometres"; update the value of
"kilometer_zero" to "kilometre" so all three keys ("kilometer_zero",
"kilometer_one", "kilometer_other") consistently use British English.

In `@packages/visual-editor/locales/components/sv/visual-editor.json`:
- Line 56: Replace the incorrect Swedish string for the "mile_zero" key so it
uses "mil" to match the existing "mile_one" and "mile_other" entries; locate the
"mile_zero" key in the visual-editor.json and change its value from "mile" to
"mil" to ensure consistent Swedish copy for zero-distance cases across the
locale file.

In `@packages/visual-editor/locales/components/zh-TW/visual-editor.json`:
- Around line 54-56: The three i18n keys mile_one, mile_other, and mile_zero use
inconsistent Chinese characters for "mile" (mile_zero uses "英哩" while mile_one
and mile_other use "英里"); pick the correct variant (e.g., change mile_zero to
"英里" to match mile_one and mile_other) and update the value for the mile_zero
key so all three keys (mile_one, mile_other, mile_zero) use the same character
form.

In `@packages/visual-editor/locales/platform/en-GB/visual-editor.json`:
- Line 516: The en-GB locale entry "kilometer_zero" uses American spelling
("kilometer") while nearby keys use British spelling ("kilometre"/"kilometres");
update the value of "kilometer_zero" to "kilometre" so zero-form matches the
other distance keys (keep the key name "kilometer_zero" unchanged).

In `@packages/visual-editor/locales/platform/it/visual-editor.json`:
- Line 516: The Italian locale uses singular forms for zero-count distance keys;
update the translation values for the keys "kilometer_zero" and "mile_zero" to
use the plural forms ("chilometri" and "miglia" respectively) so zero counts
render as "0 chilometri" and "0 miglia"; locate and edit the entries named
kilometer_zero and mile_zero in the visual-editor.json and replace their string
values with the correct plural words.

In `@packages/visual-editor/locales/platform/lt/visual-editor.json`:
- Line 516: The Lithuanian zero-form unit strings are incorrect; update the
locale keys kilometer_zero and mile_zero to use the proper zero/count-0 forms —
set kilometer_zero to "kilometrų" and mile_zero to "mylių" so zero counts render
grammatically correctly in the UI.

In `@packages/visual-editor/locales/platform/sv/visual-editor.json`:
- Line 544: The localization key "mile_zero" currently uses the English form
"mile"; change its value to the Swedish unit form "mil" so it matches the
adjacent keys (e.g., the nearby "mile_one"/"mile_other" entries that use "mil"),
ensuring consistent zero-count rendering for distance units.

In `@packages/visual-editor/src/components/atoms/cta.tsx`:
- Line 31: The normalizeLink prop should default to true when omitted: update
the handling of normalizeLink (and the derived shouldNormalizeLink) so it uses
true as the fallback (e.g., coerce via nullish coalescing), and ensure
getResolvedLink treats undefined as true rather than false; locate references to
normalizeLink, shouldNormalizeLink and getResolvedLink and change their checks
to use normalizeLink ?? true (or equivalent) so incomplete/migrated CTA payloads
have normalization enabled by default.

In
`@packages/visual-editor/src/components/footer/FooterExpandedLinkSectionSlot.tsx`:
- Line 67: The current defaulting of normalizeLink in
FooterExpandedLinkSectionSlot (normalizeLink={linkData.normalizeLink ?? true})
forces normalization for all unset cases, incorrectly affecting Phone and Email
links; change the fallback so that when linkData.normalizeLink is undefined it
chooses true for standard URL/link types but false for linkData.type values
'Phone' and 'Email' (i.e., use linkData.normalizeLink if present, otherwise set
normalizeLink to false when linkData.type === 'Phone' or 'Email', and true
otherwise).

In `@packages/visual-editor/src/components/footer/FooterExpandedLinksWrapper.tsx`:
- Line 83: The current prop normalizeLink={linkData.normalizeLink ?? true}
treats Phone/Email items as normalized by default; update
FooterExpandedLinksWrapper to compute a type-aware default (e.g., const
defaultNormalize = linkData.normalizeLink ?? !(linkData.type === 'Phone' ||
linkData.type === 'Email')) and pass normalizeLink={defaultNormalize} wherever
normalizeLink is set (including the occurrence around line 83 and the block at
137-152) so tel:/mailto: values bypass URL normalization for Phone/Email types
while preserving explicit linkData.normalizeLink when provided.

In `@packages/visual-editor/src/components/footer/FooterLinksSlot.tsx`:
- Line 92: The code forces normalizeLink to true unconditionally; update
FooterLinksSlot.tsx to derive the fallback from the link type instead of always
defaulting to true: replace the prop assignment
normalizeLink={linkData.normalizeLink ?? true} with logic that uses
linkData.normalizeLink when present, otherwise sets normalizeLink to false for
Phone and Email link types and true for others (e.g.
normalizeLink={linkData.normalizeLink ?? !(linkData.linkType === 'Phone' ||
linkData.linkType === 'Email')}); ensure you reference linkData.normalizeLink
and linkData.linkType (or the local linkType) so Phone/Email behave as intended.

In
`@packages/visual-editor/src/components/migrations/0067_cta_normalize_link_default.ts`:
- Around line 3-12: The migration currently forces normalizeLink: true for every
CTA in applyNormalizeLinkDefault, which incorrectly rewrites Phone/Email CTAs;
update applyNormalizeLinkDefault to only default normalizeLink to true when
value.linkType is not "phone" or "email" (i.e., keep it undefined/unchanged for
phone/email), and apply the same conditional change to the other similar helper
referenced around lines 43-55 so Phone/Email CTA shapes do not get the wrong
default.

In `@packages/visual-editor/src/docs/components.md`:
- Around line 154-158: Update the documentation for the `data.normalizeLink`
property in the `data` prop entry to explicitly state the default semantics:
when `actionType` is a URL/link CTA normalizeLink defaults to true, and when the
CTA is an email (`mailto:`) or phone (`tel:`) link it defaults to false;
reference the `data` prop and its `normalizeLink` field as well as `actionType`
(`"link" | "button"`) so readers understand which CTA types the defaults apply
to.

---

Outside diff comments:
In `@packages/visual-editor/src/components/atoms/maybeLink.tsx`:
- Around line 29-34: The CTA invocation inside MaybeLink should not force
normalizeLink={false} for generic URLs; remove the hardcoded
normalizeLink={false} (or set normalizeLink to true/omit it) when linkType is
"URL" so that links like "example.com" are normalized correctly; update the CTA
call in the MaybeLink component (look for the CTA props: link={href},
label={children}, linkType="URL", normalizeLink={false}, eventName={eventName})
to either omit normalizeLink or conditionally pass normalizeLink only for
non-URL linkTypes.

In `@packages/visual-editor/src/components/footer/Footer.tsx`:
- Around line 197-205: The Footer is forcing normalizeLink={false} for every
site.footer.links CTA; change the prop to be conditional so only
phone/email-style links opt out of normalization. Update the CTA usage in
Footer.tsx to pass normalizeLink={item.linkType === 'phone' || item.linkType ===
'email'} (or equivalent check against item.linkType) so generic URL entries use
the default normalization behavior while phone/email links remain unnormalized.

---

Nitpick comments:
In `@packages/visual-editor/locales/platform/zh-TW/visual-editor.json`:
- Around line 544-546: The three localization keys mile_zero, mile_one, and
mile_other are inconsistent (mile_zero uses "英哩" while the others use "英里");
pick the preferred term and make all three values identical to prevent UI
wording drift — update mile_zero, mile_one, and mile_other so they all use the
same Chinese term (either "英里" or "英哩") across the file.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 17d8af4f-7e1b-494b-b1c0-3ab5332e234e

📥 Commits

Reviewing files that changed from the base of the PR and between da68454 and 2576246.

📒 Files selected for processing (80)
  • packages/visual-editor/locales/components/cs/visual-editor.json
  • packages/visual-editor/locales/components/da/visual-editor.json
  • packages/visual-editor/locales/components/de/visual-editor.json
  • packages/visual-editor/locales/components/en-GB/visual-editor.json
  • packages/visual-editor/locales/components/en/visual-editor.json
  • packages/visual-editor/locales/components/es/visual-editor.json
  • packages/visual-editor/locales/components/et/visual-editor.json
  • packages/visual-editor/locales/components/fi/visual-editor.json
  • packages/visual-editor/locales/components/fr/visual-editor.json
  • packages/visual-editor/locales/components/hr/visual-editor.json
  • packages/visual-editor/locales/components/hu/visual-editor.json
  • packages/visual-editor/locales/components/it/visual-editor.json
  • packages/visual-editor/locales/components/ja/visual-editor.json
  • packages/visual-editor/locales/components/lt/visual-editor.json
  • packages/visual-editor/locales/components/nb/visual-editor.json
  • packages/visual-editor/locales/components/nl/visual-editor.json
  • packages/visual-editor/locales/components/pl/visual-editor.json
  • packages/visual-editor/locales/components/pt/visual-editor.json
  • packages/visual-editor/locales/components/ro/visual-editor.json
  • packages/visual-editor/locales/components/sk/visual-editor.json
  • packages/visual-editor/locales/components/sv/visual-editor.json
  • packages/visual-editor/locales/components/tr/visual-editor.json
  • packages/visual-editor/locales/components/zh-TW/visual-editor.json
  • packages/visual-editor/locales/components/zh/visual-editor.json
  • packages/visual-editor/locales/platform/cs/visual-editor.json
  • packages/visual-editor/locales/platform/da/visual-editor.json
  • packages/visual-editor/locales/platform/de/visual-editor.json
  • packages/visual-editor/locales/platform/en-GB/visual-editor.json
  • packages/visual-editor/locales/platform/en/visual-editor.json
  • packages/visual-editor/locales/platform/es/visual-editor.json
  • packages/visual-editor/locales/platform/et/visual-editor.json
  • packages/visual-editor/locales/platform/fi/visual-editor.json
  • packages/visual-editor/locales/platform/fr/visual-editor.json
  • packages/visual-editor/locales/platform/hr/visual-editor.json
  • packages/visual-editor/locales/platform/hu/visual-editor.json
  • packages/visual-editor/locales/platform/it/visual-editor.json
  • packages/visual-editor/locales/platform/ja/visual-editor.json
  • packages/visual-editor/locales/platform/lt/visual-editor.json
  • packages/visual-editor/locales/platform/lv/visual-editor.json
  • packages/visual-editor/locales/platform/nb/visual-editor.json
  • packages/visual-editor/locales/platform/nl/visual-editor.json
  • packages/visual-editor/locales/platform/pl/visual-editor.json
  • packages/visual-editor/locales/platform/pt/visual-editor.json
  • packages/visual-editor/locales/platform/ro/visual-editor.json
  • packages/visual-editor/locales/platform/sk/visual-editor.json
  • packages/visual-editor/locales/platform/sv/visual-editor.json
  • packages/visual-editor/locales/platform/tr/visual-editor.json
  • packages/visual-editor/locales/platform/zh-TW/visual-editor.json
  • packages/visual-editor/locales/platform/zh/visual-editor.json
  • packages/visual-editor/src/components/LocatorResultCard.tsx
  • packages/visual-editor/src/components/atoms/cta.tsx
  • packages/visual-editor/src/components/atoms/maybeLink.tsx
  • packages/visual-editor/src/components/atoms/phone.tsx
  • packages/visual-editor/src/components/contentBlocks/Address.tsx
  • packages/visual-editor/src/components/contentBlocks/CTAGroup.tsx
  • packages/visual-editor/src/components/contentBlocks/CtaWrapper.tsx
  • packages/visual-editor/src/components/contentBlocks/Emails.tsx
  • packages/visual-editor/src/components/contentBlocks/GetDirections.tsx
  • packages/visual-editor/src/components/footer/ExpandedFooter.tsx
  • packages/visual-editor/src/components/footer/Footer.tsx
  • packages/visual-editor/src/components/footer/FooterExpandedLinkSectionSlot.tsx
  • packages/visual-editor/src/components/footer/FooterExpandedLinksWrapper.tsx
  • packages/visual-editor/src/components/footer/FooterLinksSlot.tsx
  • packages/visual-editor/src/components/footer/FooterSocialLinksSlot.tsx
  • packages/visual-editor/src/components/header/Header.tsx
  • packages/visual-editor/src/components/header/HeaderLinks.tsx
  • packages/visual-editor/src/components/header/PrimaryHeaderSlot.tsx
  • packages/visual-editor/src/components/migrations/0067_cta_normalize_link_default.ts
  • packages/visual-editor/src/components/migrations/migrationRegistry.ts
  • packages/visual-editor/src/components/pageSections/EventSection/EventCard.tsx
  • packages/visual-editor/src/components/pageSections/HeroSection.tsx
  • packages/visual-editor/src/components/pageSections/InsightSection/InsightCard.tsx
  • packages/visual-editor/src/components/pageSections/ProductSection/ProductCard.tsx
  • packages/visual-editor/src/components/pageSections/ProfessionalHeroSection.tsx
  • packages/visual-editor/src/components/pageSections/PromoSection/PromoSection.tsx
  • packages/visual-editor/src/components/pageSections/TeamSection/TeamCard.tsx
  • packages/visual-editor/src/docs/ai/components.d.ts
  • packages/visual-editor/src/docs/components.md
  • packages/visual-editor/src/types/types.ts
  • packages/visual-editor/src/vite-plugin/defaultLayoutData.ts

Comment thread packages/visual-editor/locales/components/en-GB/visual-editor.json Outdated
Comment thread packages/visual-editor/locales/components/sv/visual-editor.json Outdated
Comment thread packages/visual-editor/locales/components/zh-TW/visual-editor.json Outdated
Comment thread packages/visual-editor/locales/platform/en-GB/visual-editor.json Outdated
Comment thread packages/visual-editor/locales/platform/it/visual-editor.json Outdated
Comment thread packages/visual-editor/src/components/footer/FooterExpandedLinkSectionSlot.tsx Outdated
Comment thread packages/visual-editor/src/components/footer/FooterExpandedLinksWrapper.tsx Outdated
Comment thread packages/visual-editor/src/components/footer/FooterLinksSlot.tsx Outdated
Comment thread packages/visual-editor/src/docs/components.md
Copy link
Copy Markdown
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.

♻️ Duplicate comments (1)
packages/visual-editor/src/components/migrations/0067_cta_normalize_link_default.ts (1)

46-58: ⚠️ Potential issue | 🟠 Major

applyCtaNormalizeLinkDefault still unconditionally defaults to true for all link types.

This helper does not check data.linkType, so CTAWrapper and CTASlot components with Email or Phone link types will incorrectly receive normalizeLink: true. The PR description states "default is not true for email or phone."

Apply the same conditional logic used in applyNormalizeLinkDefault:

Proposed fix
 const applyCtaNormalizeLinkDefault = (
   props: { id: string } & Record<string, any>
 ) => {
   const data = props.data ?? {};
+  const shouldNormalizeByDefault =
+    data.linkType !== "Email" && data.linkType !== "Phone";

   return {
     ...props,
     data: {
       ...data,
-      normalizeLink: data.normalizeLink ?? true,
+      normalizeLink: data.normalizeLink ?? shouldNormalizeByDefault,
     },
   };
 };

,

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/visual-editor/src/components/migrations/0067_cta_normalize_link_default.ts`
around lines 46 - 58, applyCtaNormalizeLinkDefault currently always sets
data.normalizeLink to true; modify it to mirror applyNormalizeLinkDefault's
logic so email and phone link types do not get normalizeLink defaulted to true.
In applyCtaNormalizeLinkDefault check props.data.linkType (or data.linkType) and
only default normalizeLink to true when linkType is not 'email' and not 'phone'
(leave existing normalizeLink value if present), otherwise set normalizeLink to
false (or leave undefined per existing pattern); keep the rest of the returned
shape the same so CTAWrapper/CTASlot receive the corrected normalizeLink value.
🧹 Nitpick comments (1)
packages/visual-editor/src/components/footer/FooterExpandedLinksWrapper.tsx (1)

170-174: Make the editor affordance match the per-row render behavior.

resolveFields makes normalizeLink visible for every link row in every section as soon as any URL exists, but Lines 170-174 still ignore that value for Phone/Email rows and always pass false. In mixed sections that exposes a toggle authors can change without any runtime effect. If this shared footer pattern stays collection-level, I’d at least make the control explicitly URL-only so the editor matches what the CTA actually does.

Also applies to: 192-200

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/visual-editor/src/components/footer/FooterExpandedLinksWrapper.tsx`
around lines 170 - 174, The editor is showing a normalizeLink control that has
no effect for non-URL rows because FooterExpandedLinksWrapper currently forces
normalizeLink to false for Phone/Email; update the normalizeLink prop logic in
FooterExpandedLinksWrapper so it uses the per-row value only for URL rows (i.e.,
pass linkData.normalizeLink when linkData.linkType === "URL", otherwise ensure
the control is explicitly URL-only or hidden), and apply the same fix to the
other occurrence mentioned (the block around the 192–200 logic); locate uses of
normalizeLink and linkData.linkType in this component and make the conditional
behavior consistent with resolveFields so the editor affordance matches runtime
behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In
`@packages/visual-editor/src/components/migrations/0067_cta_normalize_link_default.ts`:
- Around line 46-58: applyCtaNormalizeLinkDefault currently always sets
data.normalizeLink to true; modify it to mirror applyNormalizeLinkDefault's
logic so email and phone link types do not get normalizeLink defaulted to true.
In applyCtaNormalizeLinkDefault check props.data.linkType (or data.linkType) and
only default normalizeLink to true when linkType is not 'email' and not 'phone'
(leave existing normalizeLink value if present), otherwise set normalizeLink to
false (or leave undefined per existing pattern); keep the rest of the returned
shape the same so CTAWrapper/CTASlot receive the corrected normalizeLink value.

---

Nitpick comments:
In `@packages/visual-editor/src/components/footer/FooterExpandedLinksWrapper.tsx`:
- Around line 170-174: The editor is showing a normalizeLink control that has no
effect for non-URL rows because FooterExpandedLinksWrapper currently forces
normalizeLink to false for Phone/Email; update the normalizeLink prop logic in
FooterExpandedLinksWrapper so it uses the per-row value only for URL rows (i.e.,
pass linkData.normalizeLink when linkData.linkType === "URL", otherwise ensure
the control is explicitly URL-only or hidden), and apply the same fix to the
other occurrence mentioned (the block around the 192–200 logic); locate uses of
normalizeLink and linkData.linkType in this component and make the conditional
behavior consistent with resolveFields so the editor affordance matches runtime
behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: c5dce1be-1757-481d-9869-9541b9ebc7ec

📥 Commits

Reviewing files that changed from the base of the PR and between 2576246 and 8f72719.

📒 Files selected for processing (11)
  • packages/visual-editor/locales/components/en-GB/visual-editor.json
  • packages/visual-editor/locales/components/it/visual-editor.json
  • packages/visual-editor/locales/components/lt/visual-editor.json
  • packages/visual-editor/locales/components/sv/visual-editor.json
  • packages/visual-editor/locales/platform/en-GB/visual-editor.json
  • packages/visual-editor/locales/platform/sv/visual-editor.json
  • packages/visual-editor/locales/platform/zh-TW/visual-editor.json
  • packages/visual-editor/src/components/footer/FooterExpandedLinkSectionSlot.tsx
  • packages/visual-editor/src/components/footer/FooterExpandedLinksWrapper.tsx
  • packages/visual-editor/src/components/footer/FooterLinksSlot.tsx
  • packages/visual-editor/src/components/migrations/0067_cta_normalize_link_default.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • packages/visual-editor/locales/components/sv/visual-editor.json
  • packages/visual-editor/locales/platform/zh-TW/visual-editor.json
  • packages/visual-editor/locales/components/it/visual-editor.json
  • packages/visual-editor/locales/platform/en-GB/visual-editor.json
  • packages/visual-editor/locales/platform/sv/visual-editor.json

Copy link
Copy Markdown
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.

♻️ Duplicate comments (1)
packages/visual-editor/src/components/migrations/0067_cta_normalize_link_default.ts (1)

50-66: ⚠️ Potential issue | 🟠 Major

applyCtaNormalizeLinkDefault can still mis-default Phone/Email CTAs.

On Line 56-59, the defaulting logic only checks constantCta?.linkType. If data.linkType is "Email" or "Phone" and constantCta is absent, Line 65 will still set normalizeLink to true.

Suggested fix
   const actionType = data.actionType ?? "link";
   const entityField = data.entityField;
   const constantCta =
     entityField?.constantValueEnabled && entityField?.constantValue
       ? entityField.constantValue
       : undefined;
+  const linkType = constantCta?.linkType ?? data.linkType;
   const shouldNormalizeByDefault =
     actionType === "button"
       ? false
-      : constantCta?.linkType !== "Email" && constantCta?.linkType !== "Phone";
+      : linkType !== "Email" && linkType !== "Phone";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/visual-editor/src/components/migrations/0067_cta_normalize_link_default.ts`
around lines 50 - 66, The defaulting logic for normalizeLink can still enable
normalization when data.linkType is "Email" or "Phone" but constantCta is
missing; update the calculation for shouldNormalizeByDefault to consider
data.linkType when constantCta is undefined (e.g., derive a linkType =
constantCta?.linkType ?? data.linkType) and then set shouldNormalizeByDefault =
actionType === "button" ? false : (linkType !== "Email" && linkType !==
"Phone"); adjust the normalizeLink fallback that uses shouldNormalizeByDefault
(identifiers: actionType, entityField, constantCta, shouldNormalizeByDefault,
normalizeLink) so Email/Phone CTAs are not normalized by default.
🧹 Nitpick comments (2)
packages/visual-editor/src/components/footer/footerLinkEditorField.tsx (1)

111-111: Use a deep clone when appending defaultItemProps.

Line 111 currently does a shallow copy. Nested objects (like translatable fields) can stay shared across newly added items if anything mutates in place.

♻️ Suggested change
-              onClick={() => onChange([...links, { ...defaultItemProps }])}
+              onClick={() =>
+                onChange([...links, structuredClone(defaultItemProps)])
+              }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/visual-editor/src/components/footer/footerLinkEditorField.tsx` at
line 111, The onClick handler currently appends a shallow-copied
defaultItemProps (onClick => onChange([...links, { ...defaultItemProps }]))
which allows nested objects to be shared between items; change this to append a
deep-cloned copy of defaultItemProps (e.g., use
structuredClone(defaultItemProps) or a utility like cloneDeep) so newly added
items get independent nested objects and mutations won't affect others; update
the onClick logic to call onChange([...links, deepCloneOf(defaultItemProps)])
referencing the existing onClick, onChange, links, and defaultItemProps
identifiers.
packages/visual-editor/src/components/footer/FooterExpandedLinksWrapper.tsx (1)

115-119: Consider extracting footer CTA normalizeLink resolution into a shared helper.

This logic is now repeated across footer renderers; a shared helper would prevent subtle drift later.

♻️ Example refactor
+const resolveFooterNormalizeLink = (linkData: TranslatableCTA) =>
+  linkData.linkType === "URL" ? (linkData.normalizeLink ?? true) : false;
...
-                    normalizeLink={
-                      linkData.linkType === "URL"
-                        ? (linkData.normalizeLink ?? true)
-                        : false
-                    }
+                    normalizeLink={resolveFooterNormalizeLink(linkData)}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/visual-editor/src/components/footer/FooterExpandedLinksWrapper.tsx`
around lines 115 - 119, The normalizeLink resolution logic repeated in
FooterExpandedLinksWrapper (the ternary using linkData.linkType === "URL" ?
(linkData.normalizeLink ?? true) : false) should be extracted into a small
shared helper (e.g., resolveFooterNormalizeLink(linkData) or
isFooterNormalizeEnabled(linkData)) and exported for reuse by all footer
renderers; replace the inline ternary in FooterExpandedLinksWrapper with a call
to that helper so behavior is centralized and tested once.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In
`@packages/visual-editor/src/components/migrations/0067_cta_normalize_link_default.ts`:
- Around line 50-66: The defaulting logic for normalizeLink can still enable
normalization when data.linkType is "Email" or "Phone" but constantCta is
missing; update the calculation for shouldNormalizeByDefault to consider
data.linkType when constantCta is undefined (e.g., derive a linkType =
constantCta?.linkType ?? data.linkType) and then set shouldNormalizeByDefault =
actionType === "button" ? false : (linkType !== "Email" && linkType !==
"Phone"); adjust the normalizeLink fallback that uses shouldNormalizeByDefault
(identifiers: actionType, entityField, constantCta, shouldNormalizeByDefault,
normalizeLink) so Email/Phone CTAs are not normalized by default.

---

Nitpick comments:
In `@packages/visual-editor/src/components/footer/FooterExpandedLinksWrapper.tsx`:
- Around line 115-119: The normalizeLink resolution logic repeated in
FooterExpandedLinksWrapper (the ternary using linkData.linkType === "URL" ?
(linkData.normalizeLink ?? true) : false) should be extracted into a small
shared helper (e.g., resolveFooterNormalizeLink(linkData) or
isFooterNormalizeEnabled(linkData)) and exported for reuse by all footer
renderers; replace the inline ternary in FooterExpandedLinksWrapper with a call
to that helper so behavior is centralized and tested once.

In `@packages/visual-editor/src/components/footer/footerLinkEditorField.tsx`:
- Line 111: The onClick handler currently appends a shallow-copied
defaultItemProps (onClick => onChange([...links, { ...defaultItemProps }]))
which allows nested objects to be shared between items; change this to append a
deep-cloned copy of defaultItemProps (e.g., use
structuredClone(defaultItemProps) or a utility like cloneDeep) so newly added
items get independent nested objects and mutations won't affect others; update
the onClick logic to call onChange([...links, deepCloneOf(defaultItemProps)])
referencing the existing onClick, onChange, links, and defaultItemProps
identifiers.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 9670c71c-da30-4105-87b2-1a30f3bb68a0

📥 Commits

Reviewing files that changed from the base of the PR and between 8f72719 and 54aedf5.

📒 Files selected for processing (6)
  • packages/visual-editor/locales/components/zh-TW/visual-editor.json
  • packages/visual-editor/src/components/footer/FooterExpandedLinkSectionSlot.tsx
  • packages/visual-editor/src/components/footer/FooterExpandedLinksWrapper.tsx
  • packages/visual-editor/src/components/footer/FooterLinksSlot.tsx
  • packages/visual-editor/src/components/footer/footerLinkEditorField.tsx
  • packages/visual-editor/src/components/migrations/0067_cta_normalize_link_default.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/visual-editor/locales/components/zh-TW/visual-editor.json
  • packages/visual-editor/src/components/footer/FooterLinksSlot.tsx

@asanehisa asanehisa marked this pull request as draft March 16, 2026 16:58
@asanehisa asanehisa marked this pull request as ready for review March 16, 2026 17:32
@asanehisa asanehisa added the create-dev-release Triggers dev release workflow label Mar 16, 2026
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Mar 16, 2026

commit: 02aff4e

Copy link
Copy Markdown
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.

♻️ Duplicate comments (2)
packages/visual-editor/locales/platform/it/visual-editor.json (1)

548-548: ⚠️ Potential issue | 🟡 Minor

Use plural zero form for mile_zero in Italian.

At Line [548], mile_zero is still singular (miglio), but zero-count form should be plural (miglia) for consistency and correct rendering.

💬 Proposed fix
-  "mile_zero": "miglio",
+  "mile_zero": "miglia",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/visual-editor/locales/platform/it/visual-editor.json` at line 548,
The translation key "mile_zero" currently uses the singular Italian form
"miglio"; update its value to the plural zero-count form "miglia" so the key
"mile_zero" maps to "miglia" for correct zero pluralization.
packages/visual-editor/locales/platform/lt/visual-editor.json (1)

552-552: ⚠️ Potential issue | 🟡 Minor

Fix mile_zero to the zero/plural form.

"mile_zero": "mylia" will render 0 in singular form. This should be the plural zero form to avoid incorrect UI text.

Proposed fix
-  "mile_zero": "mylia",
+  "mile_zero": "mylių",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/visual-editor/locales/platform/lt/visual-editor.json` at line 552,
The "mile_zero" localization entry currently uses the singular form ("mylia"),
which renders incorrectly for zero; update the "mile_zero" key in the Lithuanian
locale to use the correct plural/zero form (the Lithuanian genitive plural for
"mile", e.g., "mylių") so zero values render with the proper pluralized text.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@packages/visual-editor/locales/platform/it/visual-editor.json`:
- Line 548: The translation key "mile_zero" currently uses the singular Italian
form "miglio"; update its value to the plural zero-count form "miglia" so the
key "mile_zero" maps to "miglia" for correct zero pluralization.

In `@packages/visual-editor/locales/platform/lt/visual-editor.json`:
- Line 552: The "mile_zero" localization entry currently uses the singular form
("mylia"), which renders incorrectly for zero; update the "mile_zero" key in the
Lithuanian locale to use the correct plural/zero form (the Lithuanian genitive
plural for "mile", e.g., "mylių") so zero values render with the proper
pluralized text.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: f3126770-e1a5-4994-911b-2db71ae40515

📥 Commits

Reviewing files that changed from the base of the PR and between ac32520 and 0901c2c.

📒 Files selected for processing (4)
  • packages/visual-editor/locales/components/it/visual-editor.json
  • packages/visual-editor/locales/components/lt/visual-editor.json
  • packages/visual-editor/locales/platform/it/visual-editor.json
  • packages/visual-editor/locales/platform/lt/visual-editor.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/visual-editor/locales/components/lt/visual-editor.json
  • packages/visual-editor/locales/components/it/visual-editor.json

Comment thread packages/visual-editor/locales/components/en/visual-editor.json Outdated
Comment thread packages/visual-editor/src/components/atoms/cta.tsx Outdated
Comment thread packages/visual-editor/src/components/atoms/maybeLink.tsx
Comment thread packages/visual-editor/src/components/atoms/cta.tsx
Comment thread packages/visual-editor/src/components/contentBlocks/CTAGroup.tsx Outdated
Copy link
Copy Markdown
Contributor

@jwartofsky-yext jwartofsky-yext left a comment

Choose a reason for hiding this comment

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

tiny nitpick, but looks good to me

Copy link
Copy Markdown
Contributor

@jwartofsky-yext jwartofsky-yext left a comment

Choose a reason for hiding this comment

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

LGTM!

@asanehisa asanehisa merged commit 2ed1b3b into main Mar 17, 2026
18 checks passed
@asanehisa asanehisa deleted the cta branch March 17, 2026 17:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

create-dev-release Triggers dev release workflow

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants