Skip to content

fix(frontend): clarify expired trial plans state - #2927

Open
WcaleNieWolny wants to merge 12 commits into
mainfrom
wolny/expired-trial-plans-state
Open

fix(frontend): clarify expired trial plans state#2927
WcaleNieWolny wants to merge 12 commits into
mainfrom
wolny/expired-trial-plans-state

Conversation

@WcaleNieWolny

@WcaleNieWolny WcaleNieWolny commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Summary

  • show neutral expired-trial heading and subtext only for organizations that never paid
  • suppress the failed-payment banner until billing history resolves, while preserving the existing fallback on lookup errors
  • remove selected and recommended plan styling from the expired-trial state
  • preserve existing behavior and CTA order for previously paid, canceled, and ended subscriptions
  • fix current main-branch type and CLI test-fixture regressions that blocked CI

Test Plan

  • bun lint
  • bun test:unit (200 files, 1,446 tests)
  • bun run typecheck:frontend
  • CHOKIDAR_USEPOLLING=true bun run build

Summary by CodeRabbit

  • New Features

    • Added a dedicated plans experience for expired trials that have never had a paid subscription.
    • Updated headings, descriptions, plan cards, recommendations, and actions to help customers choose a plan and continue using the service.
    • Added localized text for plan selection and expired-trial guidance.
    • Improved billing-state handling across the plans page and payment-required modal.
  • Bug Fixes

    • Prevented outdated billing responses from affecting the current organization’s plan state.
    • Preserved existing behavior for paid, native, canceled, and unresolved billing states.
  • Tests

    • Added coverage for expired-trial, billing lookup, failure-banner, and bypass scenarios.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The pull request adds shared billing-history state and expired-trial handling for the organization plans page. It updates the payment-required modal, plan presentation, translations, helper predicates, tests, and implementation documentation.

Changes

Expired trial plans

Layer / File(s) Summary
Billing state resolution and predicates
src/composables/useBillingPaidAt.ts, src/services/paymentRequired.ts, tests/payment-required-copy.unit.test.ts
Adds billing-date resolution, stale-response protection, lookup failure state, expired-trial predicates, and coverage for unresolved, native, paid, and never-paid organizations.
Shared composable integration
src/components/PaymentRequiredModal.vue, src/auto-imports.d.ts
Replaces the modal’s local billing lookup with useBillingPaidAt and registers the composable for auto-import and Vue template use.
Plans page expired-trial presentation
src/pages/settings/organization/Plans.vue, messages/en.json
Adds expired-trial copy, plan-specific actions, neutral card styling, failure-banner logic, CTA reordering, and related translations.
Implementation plan and scope documentation
docs/superpowers/plans/..., docs/superpowers/specs/...
Documents the billing-state model, UI behavior, validation steps, preserved behavior, and excluded lifecycle changes.
Test mock support
tests/cli-app-permission-helper.test.ts
Adds the missing appAddHintMessage mock implementation.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant PlansPage
  participant useBillingPaidAt
  participant Supabase
  participant PaymentRequiredModal
  PlansPage->>useBillingPaidAt: provide organization ID
  PaymentRequiredModal->>useBillingPaidAt: provide organization GID and disabled flag
  useBillingPaidAt->>Supabase: query stripe_info(paid_at)
  Supabase-->>useBillingPaidAt: paid timestamp or lookup error
  useBillingPaidAt-->>PlansPage: paidAt and billingLookupFailed
  useBillingPaidAt-->>PaymentRequiredModal: paidAt
Loading

Possibly related PRs

Suggested labels: codex

Suggested reviewers: riderx

🚥 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 describes the main change to the expired trial plans state.
Description check ✅ Passed The description provides a clear summary and reports relevant validation results, although screenshots and checklist items are omitted.
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.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands.

@codspeed-hq

codspeed-hq Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 43 untouched benchmarks
⏩ 2 skipped benchmarks1


Comparing wolny/expired-trial-plans-state (5b34c65) with main (e82dd01)

Open in CodSpeed

Footnotes

  1. 2 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Review completed against the latest diff

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread src/pages/settings/organization/Plans.vue Outdated
Comment thread docs/superpowers/plans/2026-08-07-expired-trial-plans-state.md Outdated
Comment thread src/pages/settings/organization/Plans.vue Outdated
Comment thread src/pages/settings/organization/Plans.vue Outdated
@WcaleNieWolny

Copy link
Copy Markdown
Contributor Author

Addressed all four Cubic findings in c542524: the red banner is suppressed while billing history is unresolved, lookup failures are logged and retain the existing failure fallback, Plans now uses resolveBillingPaidAt, and Credits/Expert CTAs render once with state-dependent ordering. Added banner-state coverage; lint, frontend typecheck, 200 unit files / 1,446 tests, and production build pass locally.

@WcaleNieWolny

Copy link
Copy Markdown
Contributor Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Aug 7, 2026

Copy link
Copy Markdown

@cubic-dev-ai review this PR

@WcaleNieWolny I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 issue found across 8 files

Confidence score: 5/5

  • In src/pages/settings/organization/Plans.vue, the new billing-history watcher duplicates the Supabase fetch and billingLookupRun stale-response guard, which raises maintenance risk: future fixes could land in one path but not the other and cause inconsistent billing timestamps or race-handling behavior — extract this logic into a shared helper/composable and call it from both watchers.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/pages/settings/organization/Plans.vue">

<violation number="1" location="src/pages/settings/organization/Plans.vue:68">
P3: This new billing-history watcher duplicates the exact Supabase query and stale-response guard (`.from('orgs').select('stripe_info(paid_at)').eq('id', orgId).maybeSingle()` plus the `billingLookupRun` token) that already exists inline in `src/components/PaymentRequiredModal.vue` (lines ~21-38). The PR adds a second copy of the same lookup rather than sharing it, so any future change to the query (e.g., RLS shape, added fields, or the never-paid/missing-relation semantics) has to be applied in two places and can drift. Consider extracting the lookup into a small shared helper (or composable) alongside the pure predicates in `src/services/paymentRequired.ts`, which is exactly what the implementation plan describes as "shared billing-history predicates used by dashboard and plans-page presentation."</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread docs/superpowers/plans/2026-08-07-expired-trial-plans-state.md Outdated
Comment thread src/pages/settings/organization/Plans.vue Outdated
@WcaleNieWolny

Copy link
Copy Markdown
Contributor Author

Addressed both follow-up Cubic findings in c046ffd: the implementation plan now defines every referenced predicate and the shared composable workflow, and PaymentRequiredModal plus Plans now consume one useBillingPaidAt implementation for the Supabase query, lookup-error state, and stale-response guard. Local lint, frontend typecheck, 200 unit files / 1,446 tests, and production build pass.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 `@tests/cli-app-permission-helper.test.ts`:
- Line 6: Remove the earlier duplicate appAddHintMessage property from the test
fixture, keeping the later definition that intentionally overwrites it so Biome
no longer reports a duplicate key.
🪄 Autofix

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: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 94d0e6b4-b345-44b1-bd66-cee9d5a6b367

📥 Commits

Reviewing files that changed from the base of the PR and between e82dd01 and 479c1a8.

📒 Files selected for processing (10)
  • docs/superpowers/plans/2026-08-07-expired-trial-plans-state.md
  • docs/superpowers/specs/2026-08-07-expired-trial-plans-state-design.md
  • messages/en.json
  • src/auto-imports.d.ts
  • src/components/PaymentRequiredModal.vue
  • src/composables/useBillingPaidAt.ts
  • src/pages/settings/organization/Plans.vue
  • src/services/paymentRequired.ts
  • tests/cli-app-permission-helper.test.ts
  • tests/payment-required-copy.unit.test.ts
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • Cap-go/capacitor-updater (manual)

Comment thread tests/cli-app-permission-helper.test.ts Outdated
@WcaleNieWolny

Copy link
Copy Markdown
Contributor Author

Addressed the post-merge CodeRabbit finding in 5b34c65 by removing the earlier duplicate appAddHintMessage mock and retaining main’s complete hint implementation. The focused CLI permission-helper test passes (2/2), and the repository lint/typecheck/unit gates had passed on the merged head.

@sonarqubecloud

sonarqubecloud Bot commented Aug 8, 2026

Copy link
Copy Markdown

posthog-eu Bot added a commit that referenced this pull request Aug 8, 2026
Unpaid organizations that land on a gated app page (devices, bundles,
channels, builds, notifications) saw a blurred empty table behind the
payment modal, with no page-level reason and no visible route to the
plans page. Add a shared UnpaidState empty state that explains why the
list is hidden and links to the plans page, and stop the layout overlay
from covering those pages so the explanation is visible.

The block itself is unchanged: the pages still render no data when the
organization has no active subscription. The payment-modal copy flip is
handled separately by PR #2927 and is left untouched.

Generated-By: PostHog Code
Task-Id: 21fb1bad-b78a-4701-803d-0571de027a1f
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant