feat(account): always-visible Renew on yearly licences, deep-linked to checkout#270
Conversation
…o checkout Show a "Renew" button on every renewable (yearly) licence on the account page, not only when it is expiring-soon or already expired. Lifetime licences (null expiry) show no Renew — there is nothing to renew. The button deep-links to the pre-filled yearly checkout (/pro/checkout?product=<handle>) instead of the generic /pro; on payment the existing order-completed subscriber extends the SAME licence key using the locked max(expiry, now) + 1yr rule (see wcpos-medusa#63). Falls back to /pro when the plan handle cannot be resolved. Renew is styled primary when expired (needed to regain access) and secondary when active (an optional early renewal — no days lost). To avoid two identical CTAs on one card, the footer Renew is suppressed while the expiring-soon banner already offers one, so exactly one Renew is ever present. Tests updated for the new always-visible behaviour + a deep-link assertion.
There was a problem hiding this comment.
kilbot has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughLicensesClient now derives per-license renewal behavior from policy IDs, uses that state to render the expiring-soon Renew link and card CTAs, and updates tests and e2e coverage to match the new checkout deep-linking. ChangesRenew Link Deep-Linking
Estimated code review effort: 2 (Simple) | ~15 minutes Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
src/components/account/licenses-client.tsx (1)
429-431: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRedundant outer condition.
showRenewis already gated ondisplayStatus === 'active' || displayStatus === 'expired'(Line 273), soshowRenew ||in this outer condition never changes the outcome — the wrapper renders wheneverdisplayStatusis'active'or'expired', with or without theshowRenewdisjunct. Simplifying to just thedisplayStatuscheck would be clearer.🤖 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 `@src/components/account/licenses-client.tsx` around lines 429 - 431, The outer conditional around the renewal UI is redundant because showRenew is already derived from the active/expired displayStatus logic in licenses-client.tsx. Update the JSX condition near the wrapper to rely only on displayStatus === 'active' || displayStatus === 'expired', and remove the unnecessary showRenew disjunct while keeping the existing rendering behavior unchanged.src/components/account/licenses-client.test.tsx (1)
264-282: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConfirm test policy ID matches
DEFAULT_YEARLY_POLICY_ID.The hardcoded UUID
'261cb7e2-6e80-476e-98bd-fe7f406f258d'is asserted to resolve to the yearly plan's handle. This test will silently start failing (or worse, pass for the wrong reason) ifDEFAULT_YEARLY_POLICY_IDinsrc/lib/plans.tsever changes without updating this literal in lockstep. Consider importing the constant directly rather than duplicating the literal, to keep the test coupled to the source of truth.🤖 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 `@src/components/account/licenses-client.test.tsx` around lines 264 - 282, The Renew-link test is duplicating the yearly policy UUID instead of using the source of truth. Update the test in LicensesClient to reference DEFAULT_YEARLY_POLICY_ID from src/lib/plans.ts (or otherwise derive the policy ID from the shared constant) so the assertion stays aligned with the yearly plan mapping. Keep the existing deep-link expectation in the LicensesClient Renew button test, but remove the hardcoded UUID literal.
🤖 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.
Nitpick comments:
In `@src/components/account/licenses-client.test.tsx`:
- Around line 264-282: The Renew-link test is duplicating the yearly policy UUID
instead of using the source of truth. Update the test in LicensesClient to
reference DEFAULT_YEARLY_POLICY_ID from src/lib/plans.ts (or otherwise derive
the policy ID from the shared constant) so the assertion stays aligned with the
yearly plan mapping. Keep the existing deep-link expectation in the
LicensesClient Renew button test, but remove the hardcoded UUID literal.
In `@src/components/account/licenses-client.tsx`:
- Around line 429-431: The outer conditional around the renewal UI is redundant
because showRenew is already derived from the active/expired displayStatus logic
in licenses-client.tsx. Update the JSX condition near the wrapper to rely only
on displayStatus === 'active' || displayStatus === 'expired', and remove the
unnecessary showRenew disjunct while keeping the existing rendering behavior
unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: a0e2916d-4823-4a4b-9f7d-4fe43950a406
📒 Files selected for processing (2)
src/components/account/licenses-client.test.tsxsrc/components/account/licenses-client.tsx
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ea97f307fc
ℹ️ 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".
Fix triage
Working through 1–3 now; detail on #4 in-thread. |
The e2e-expired fixture is a yearly policy, so its card Renew now points at /pro/checkout?product=wcpos-pro-yearly instead of /pro. Updates the assertion to match the intended deep-link (Codex P2 / E2E CI failure).
showRenew already implies displayStatus is active|expired, so the outer condition simplifies to the displayStatus check alone. No behaviour change (CodeRabbit nitpick).
Import the constant from @/lib/plans instead of duplicating the yearly policy UUID literal, so the test stays coupled to the source of truth (also the existing Yearly-label test). CodeRabbit nitpick.
Resolution
Local validation: licenses-client unit tests 30/30, |
There was a problem hiding this comment.
kilbot has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
|
🚀 Preview: https://wcpos-ibt1w34s7-wcpos.vercel.app |
What
Phase 2 of the manual-renewal work: an always-visible "Renew" button on each renewable (yearly) licence on the account page.
Before, "Renew" only appeared when a licence was expiring-soon (banner) or already expired, and it linked to the generic
/pro. Now:/pro/checkout?product=wcpos-pro-yearly(falls back to/proif the plan handle can't be resolved).On payment, the existing
order-completedsubscriber extends the same licence key — no backend change needed here — using the renewal-date rule locked in wcpos-medusa#63 (max(expiry, now) + 1yr: active renewers lose no days, lapsed ones start today).Details
expiry != null(robust; independent of policy-id resolution).t('renew')i18n key — no new locale strings, so no 10-locale parity impact.Validation
vitest— 1206 unit tests (licenses-client: 30, +2: deep-link assertion + lifetime shows-no-renew); updated the "beyond-30-day" test since active non-expiring licences now show Renew.eslint,tsc --noEmit,next build— clean.Scope
Frontend only. Independent of #264/#265 (attach-customer / save-card) and works with today's checkout. Next up (Phase 3): the one-click off-session charge (consent checkbox → charge saved card) so this button can skip checkout entirely for customers with a saved card.
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes
Tests