Skip to content

Fixed gift members unable to redeem or continue when tier is archived#27561

Merged
sagzy merged 2 commits intomainfrom
gift-subscriptions/gift-to-paid-upgrade-for-archived-tiers
Apr 27, 2026
Merged

Fixed gift members unable to redeem or continue when tier is archived#27561
sagzy merged 2 commits intomainfrom
gift-subscriptions/gift-to-paid-upgrade-for-archived-tiers

Conversation

@sagzy
Copy link
Copy Markdown
Contributor

@sagzy sagzy commented Apr 27, 2026

closes https://linear.app/ghost/issue/BER-3566

We validate that a tier is active at the time a gift is purchased. After purchase, gifts should remain redeemable even if the tier is later archived, since they have already been paid for already. This change allows gifts to be redeemed on an archived tier.

Additionally, gift members can currently only continue their subscription on the same tier/cadence so remaining gift time can be carried over as trial days. If that tier has since been archived, this results in a checkout error, as we don't allow paid subscriptions on archived tiers. With this change, the UI renders the standard upgrade flow when the gifted tier is no longer available, letting the member pick from current active tiers. The trade-off is that the remaining gift days can't be preserved in that case; archived tiers are expected to be an edge case in practice.

What changed

Portal:

  • New isArchivedTier({member, site}) helper that follows the existing isActiveOffer pattern (a tier id missing from site.products means the tier has been archived).
  • The gift "Continue subscription" banner and the gift-specific Continue button on the account page are gated on the tier still being available; otherwise the regular Change button takes over and routes the member through the standard upgrade screen.

Backend:

  • MemberRepository.create / update previously rejected any product that wasn't active with "Cannot use archived Tiers", which also blocked the gift-redemption path (creating a member on the gifted tier). The check is now skipped when status === 'gift'. Non-gift paths (comped, paid) keep the archived-tier block.
  • In create(), the products validation block was moved below the status defaulting block so the gift carve-out can read the resolved status.

@sagzy sagzy force-pushed the gift-subscriptions/gift-to-paid-upgrade-for-archived-tiers branch from ca28c5f to 8545da3 Compare April 27, 2026 13:21
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 27, 2026

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: 3faa63f1-2749-40cc-a2eb-25d239d30fcf

📥 Commits

Reviewing files that changed from the base of the PR and between 8545da3 and 36f2432.

📒 Files selected for processing (8)
  • apps/portal/package.json
  • apps/portal/src/components/pages/AccountHomePage/components/continue-gift-subscription-banner.js
  • apps/portal/src/components/pages/AccountHomePage/components/paid-account-actions.js
  • apps/portal/src/utils/helpers.js
  • apps/portal/test/unit/components/pages/AccountHomePage/paid-account-actions.test.js
  • apps/portal/test/utils/helpers.test.js
  • ghost/core/core/server/services/members/members-api/repositories/member-repository.js
  • ghost/core/test/unit/server/services/members/members-api/repositories/member-repository.test.js
✅ Files skipped from review due to trivial changes (1)
  • apps/portal/package.json
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/portal/test/utils/helpers.test.js
  • apps/portal/src/components/pages/AccountHomePage/components/paid-account-actions.js
  • apps/portal/src/components/pages/AccountHomePage/components/continue-gift-subscription-banner.js

Walkthrough

The pull request adds an isArchivedTier helper to detect when a member's subscription tier is not present among site products. Portal components are updated to hide the gift-subscription continuation UI for archived tiers. Member repository validation is reordered and adjusted so archived tiers are allowed for members with status: 'gift' but rejected for non-gift members. Tests are added for the new helper and the repository behavior. The portal package version is incremented from 2.68.17 to 2.68.18.

🚥 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 clearly and concisely summarizes the main change: enabling gift members to redeem or continue subscriptions on archived tiers.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, explaining the problem, solution, and trade-offs across portal and backend changes.
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-subscriptions/gift-to-paid-upgrade-for-archived-tiers

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.

🔧 ast-grep (0.42.1)
ghost/core/test/unit/server/services/members/members-api/repositories/member-repository.test.js

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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ca28c5fd5b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

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 the current code and only fix it if needed.

Inline comments:
In `@apps/portal/src/utils/helpers.js`:
- Around line 116-117: The archived-tier check currently calls getProductFromId
which uses getAllProductsForSite and can return false positives due to portal
plan filters; change the logic to directly inspect site.products instead:
replace the call to getProductFromId({site, productId: tierId}) with a direct
search in site.products (e.g., find or some equivalent) to determine if the
tierId exists on the site, so archived detection relies only on site.products
rather than filtered getAllProductsForSite/getProductFromId.
🪄 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: 4e14d588-1a95-4dc6-8fa6-ca0c2aa17cc3

📥 Commits

Reviewing files that changed from the base of the PR and between a4a79e6 and 8545da3.

📒 Files selected for processing (7)
  • apps/portal/package.json
  • apps/portal/src/components/pages/AccountHomePage/components/continue-gift-subscription-banner.js
  • apps/portal/src/components/pages/AccountHomePage/components/paid-account-actions.js
  • apps/portal/src/utils/helpers.js
  • apps/portal/test/utils/helpers.test.js
  • ghost/core/core/server/services/members/members-api/repositories/member-repository.js
  • ghost/core/test/unit/server/services/members/members-api/repositories/member-repository.test.js

Comment thread apps/portal/src/utils/helpers.js
sagzy added 2 commits April 27, 2026 17:24
We validate that a tier is active at the time a gift is purchased. After purchase, gifts should remain redeemable even if the tier is later archived, since it has already been paid for already. This change allows gifts to be redeemed on an archived tier.

Additionally, this creates a dead end when a gift subscriber chooses to continue as a paid member. The current UI only allows continuation on the same tier/cadence so remaining gift time can be carried over as trial days. If that tier has since been archived, this results in users trying to continue onto an unavailable tier. With this change, we now render the standard upgrade flow when the gifted tier is no longer available, letting the member pick from current
active tiers. The trade-off is that the remaining gift days can't be preserved in that case; archived tiers are expected to be an edge case in practice.

Portal:
- New `isArchivedTier({member, site})` helper that follows the existing
  `isActiveOffer` pattern (a tier id missing from `site.products` means
  the tier has been archived).
- The gift "Continue subscription" banner and the gift-specific
  Continue button on the account page are gated on the tier still
  being available; otherwise the regular Change button takes over and
  routes the member through the standard upgrade screen.

Backend:
- `MemberRepository.create` / `update` previously rejected any product
  that wasn't `active` with "Cannot use archived Tiers", which also
  blocked the gift-redemption path (creating a member on the gifted
  tier). The check is now skipped when `status === 'gift'`. Non-gift
  paths (comped, paid) keep the archived-tier block.
- In `create()`, the products validation block was moved below the
  status defaulting block so the gift carve-out can read the resolved
  status.
@sagzy sagzy force-pushed the gift-subscriptions/gift-to-paid-upgrade-for-archived-tiers branch from 8545da3 to 36f2432 Compare April 27, 2026 15:24
@sagzy sagzy enabled auto-merge (squash) April 27, 2026 15:26
@sagzy sagzy disabled auto-merge April 27, 2026 15:51
@sagzy sagzy enabled auto-merge (squash) April 27, 2026 15:52
@sagzy sagzy merged commit b119490 into main Apr 27, 2026
73 of 83 checks passed
@sagzy sagzy deleted the gift-subscriptions/gift-to-paid-upgrade-for-archived-tiers branch April 27, 2026 16:06
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