Skip to content

Improved gift subscription Portal screens across selection, preview, and mobile#27770

Merged
minimaluminium merged 10 commits intomainfrom
gift-subs-design-iteration-4
May 7, 2026
Merged

Improved gift subscription Portal screens across selection, preview, and mobile#27770
minimaluminium merged 10 commits intomainfrom
gift-subs-design-iteration-4

Conversation

@minimaluminium
Copy link
Copy Markdown
Member

ref https://linear.app/ghost/issue/BER-3600/design-iteration

  • Simplified the selection screen when only one paid tier is available
  • Surfaced tier descriptions in the selection and details views
  • Pinned the gift card preview while details scroll
  • Removed "Powered by Ghost" branding from gift screens
  • Tightened spacing on the selection screen
  • Improved mobile styling across the 50/50 layouts
  • Replaced the expiry date on the gift card with gift value

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 7, 2026

Review Change Stack
No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3a987a6e-665d-48b0-8466-693b6927ba89

📥 Commits

Reviewing files that changed from the base of the PR and between edae610 and 51feab8.

📒 Files selected for processing (1)
  • apps/portal/src/components/pages/gift-page.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/portal/src/components/pages/gift-page.js

Walkthrough

This PR adds a new pricing helper export formatGiftValue, replaces expiry displays with formatted gift value across gift-page, gift-redemption-page, gift-success-page, and magic-link-page, adds tier descriptions and expands the details container to show description or benefits, implements single-tier-aware tier picker semantics (AR/visual changes), updates popup-modal to suppress PoweredBy on gift layouts, and includes multiple styling/layout and responsive adjustments. Package version bump to 2.68.33.

Possibly related PRs

  • TryGhost/Ghost#27705: Both PRs modify the same gifting components (gift-page, gift-redemption-page, gift-success-page, magic-link-page and package.json) and implement overlapping UI/logic changes to the tier picker and right-panel gift card.
  • TryGhost/Ghost#27668: Both PRs touch the same gift flow files (gift-page, gift-redemption, gift-success, magic-link, popup-modal, package.json) and make overlapping code-level changes to gift card/preview behavior (pricing/expiry display and layout).

Suggested labels

preview

Suggested reviewers

  • sagzy
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main changes: improvements to gift subscription Portal screens involving selection, preview, and mobile layouts.
Description check ✅ Passed The description is directly related to the changeset, listing specific improvements made to gift subscription screens that align with the actual code modifications.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch gift-subs-design-iteration-4

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Microsoft Presidio Analyzer (2.2.362)
apps/portal/src/components/pages/gift-page.js

Microsoft Presidio Analyzer failed to scan this file


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
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.

Caution

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

⚠️ Outside diff range comments (1)
apps/portal/src/components/pages/gift-page.js (1)

645-672: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical: window.matchMedia is not available in the JSDOM test env — breaks unit tests.

Static analysis reports TypeError: window.matchMedia is not a function originating at line 654, surfaced via test/portal-links.test.js ("opens gift page when giftSubscriptions labs flag is enabled"). JSDOM does not implement matchMedia by default, so any test that mounts GiftPage will throw inside the useLayoutEffect.

Guard the call so the layout effect degrades gracefully when matchMedia is unavailable.

🛡️ Proposed fix
-        if (window.matchMedia('(max-width: 880px)').matches) {
+        if (typeof window.matchMedia === 'function' && window.matchMedia('(max-width: 880px)').matches) {
             inner.style.marginTop = '';
             centeringDoneRef.current = true;
             return;
         }

Alternatively, mock window.matchMedia in the test setup file. The runtime guard is preferable since it also protects any non-browser embedding.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/portal/src/components/pages/gift-page.js` around lines 645 - 672, The
useLayoutEffect that centers the inner element calls window.matchMedia and
breaks in JSDOM; update the guard around that call in the effect (the block
using useLayoutEffect, centeringDoneRef, innerRef, leftRef) to first check that
window.matchMedia exists (e.g. typeof window.matchMedia === 'function' or
window.matchMedia != null) before calling .matches, and if it's unavailable
treat it as the mobile case (clear inner.style.marginTop / skip centering) so
the effect degrades gracefully in tests and non-browser environments.
🧹 Nitpick comments (1)
apps/portal/src/components/pages/gift-page.js (1)

613-623: ⚡ Quick win

Naming nit: helper name vs. responsibility.

formatGiftValue is now a generic price-object formatter ({amount, currency} → "$X") used wherever a price needs to render — not specifically tied to a gift. Consider renaming to something like formatPriceAmount (and re-exporting) so callers in gift-redemption-page.js / magic-link-page.js / gift-success-page.js aren't misled into passing a gift object (which appears to already have caused the shape mismatch flagged in gift-redemption-page.js line 221).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/portal/src/components/pages/gift-page.js` around lines 613 - 623, Rename
the helper formatGiftValue to a more accurate name like formatPriceAmount and
update its export so it reflects that it formats a generic price object
({amount, currency} → "$X"); change the function declaration from
formatGiftValue to formatPriceAmount, update all internal callers (e.g.,
getTierPriceLabel uses formatPriceAmount), and export it under the new name
while optionally re-exporting the old name (export { formatPriceAmount as
formatGiftValue }) to maintain backwards compatibility for callers in
gift-redemption-page.js, magic-link-page.js and gift-success-page.js; ensure
imports in those modules are updated or keep the alias export so existing
imports continue to work.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@apps/portal/src/components/pages/gift-page.js`:
- Around line 645-672: The useLayoutEffect that centers the inner element calls
window.matchMedia and breaks in JSDOM; update the guard around that call in the
effect (the block using useLayoutEffect, centeringDoneRef, innerRef, leftRef) to
first check that window.matchMedia exists (e.g. typeof window.matchMedia ===
'function' or window.matchMedia != null) before calling .matches, and if it's
unavailable treat it as the mobile case (clear inner.style.marginTop / skip
centering) so the effect degrades gracefully in tests and non-browser
environments.

---

Nitpick comments:
In `@apps/portal/src/components/pages/gift-page.js`:
- Around line 613-623: Rename the helper formatGiftValue to a more accurate name
like formatPriceAmount and update its export so it reflects that it formats a
generic price object ({amount, currency} → "$X"); change the function
declaration from formatGiftValue to formatPriceAmount, update all internal
callers (e.g., getTierPriceLabel uses formatPriceAmount), and export it under
the new name while optionally re-exporting the old name (export {
formatPriceAmount as formatGiftValue }) to maintain backwards compatibility for
callers in gift-redemption-page.js, magic-link-page.js and gift-success-page.js;
ensure imports in those modules are updated or keep the alias export so existing
imports continue to work.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6fd5a581-614d-4328-af7b-61060a8b195b

📥 Commits

Reviewing files that changed from the base of the PR and between 1dd3f89 and a86a129.

📒 Files selected for processing (6)
  • apps/portal/package.json
  • apps/portal/src/components/pages/gift-page.js
  • apps/portal/src/components/pages/gift-redemption-page.js
  • apps/portal/src/components/pages/gift-success-page.js
  • apps/portal/src/components/pages/magic-link-page.js
  • apps/portal/src/components/popup-modal.js

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

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/portal/src/components/pages/gift-page.js`:
- Around line 613-618: The exported helper formatGiftValue currently
destructures its parameter directly, so calling formatGiftValue(null) throws;
change it to first coalesce the incoming argument to an empty object before
destructuring (e.g., accept a single param and do const { amount, currency } =
param ?? {}), then keep the existing null/undefined checks and return logic;
update the function signature referencing formatGiftValue and ensure all
internal references use the coalesced values so both undefined and null inputs
are safely handled.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 934fcc72-2706-459b-906b-bee00975a904

📥 Commits

Reviewing files that changed from the base of the PR and between a86a129 and edae610.

📒 Files selected for processing (1)
  • apps/portal/src/components/pages/gift-page.js

Comment thread apps/portal/src/components/pages/gift-page.js Outdated
@minimaluminium minimaluminium enabled auto-merge (squash) May 7, 2026 14:21
@minimaluminium minimaluminium merged commit 9c0edb7 into main May 7, 2026
41 checks passed
@minimaluminium minimaluminium deleted the gift-subs-design-iteration-4 branch May 7, 2026 14:29
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.

1 participant