Skip to content

Simplify Premium A/B test integration - #152

Merged
AlejandroAkbal merged 3 commits into
mainfrom
simplify-premium-ab-test
Jul 27, 2026
Merged

AlejandroAkbal merged 3 commits into
mainfrom
simplify-premium-ab-test

Conversation

@AlejandroAkbal

@AlejandroAkbal AlejandroAkbal commented Jul 27, 2026 •

Copy link
Copy Markdown
Member

What changed

  • restore the pre-experiment defineNuxtPlugin lifecycle
  • adapt the existing loadAbTesting hook for PremiumLandingV1
  • reduce /premium/index.vue to an 11-line lazy component selector
  • move the original landing page into PremiumLandingOriginal.vue
  • keep OfferFirst and YearlyFocus together because they differ only by ordering and emphasis

Intentional tradeoff

Matomo remains interaction-gated exactly as before. This avoids special tracker lifecycle behavior on Premium routes, but assignment can occur after the first interaction.

Validation

  • focused Vitest passed
  • Nuxt typecheck passed
  • production build passed (247 prerendered routes)
  • git diff --check passed

Summary by CodeRabbit

  • New Features

    • Launched a refreshed Premium landing experience with localized hero content, testimonials, FAQs, trust details, and plan tiers.
    • Added a tier-driven payment dialog offering both card and cryptocurrency checkout links.
    • Improved Premium page SEO with richer structured data and enhanced navigation metadata.
  • Performance

    • Premium landing content is now lazy-loaded to reduce upfront rendering work.
  • Bug Fixes / Tracking

    • Adjusted Premium-page analytics behavior so tracking loads via the existing interaction/idle flow while keeping experiment pageview tracking consistent.
  • Tests

    • Updated monetization and tracking-related assertions for the new landing behavior.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 691763a8-f85b-4151-8bad-7ee6998222b5

📥 Commits

Reviewing files that changed from the base of the PR and between 236a4df and d90a735.

📒 Files selected for processing (2)
  • app/components/pages/premium/PremiumLandingOriginal.vue
  • app/components/pages/premium/PremiumOfferLanding.vue
📜 Recent review details
🧰 Additional context used
📓 Path-based instructions (6)
app/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

app/**/*.{vue,ts,tsx}: Use Nuxt 4 with Vue 3 and TypeScript for the frontend application
Use useLazyToast() to lazy-load vue-sonner; wait for ClientToaster to mount before calling toast.* using a proper async wait instead of plain nextTick()
Build reordered array synchronously instead of reading VueUse moveArrayElement() result before nextTick for state immediately persisted

Files:

  • app/components/pages/premium/PremiumOfferLanding.vue
  • app/components/pages/premium/PremiumLandingOriginal.vue
**/*.{vue,ts,tsx,js,jsx,json,css,scss}

📄 CodeRabbit inference engine (AGENTS.md)

Use Prettier for formatting with 120-char print width, no semicolons, single quotes, trailing commas removed, and single attribute per line in Vue templates

Files:

  • app/components/pages/premium/PremiumOfferLanding.vue
  • app/components/pages/premium/PremiumLandingOriginal.vue
**/*.{ts,tsx,js,jsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

Use Nuxt flat ESLint via @nuxt/eslint for linting

Files:

  • app/components/pages/premium/PremiumOfferLanding.vue
  • app/components/pages/premium/PremiumLandingOriginal.vue
app/components/**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

app/components/**/*.vue: Register Vue components without path prefix using pathPrefix: false in nuxt.config.ts; import them as not <Input/DomainSelector>
Auto-import components from app/components/ flat structure without folder prefix
Use custom imgproxy provider for images; generate images at 1x density only in webp format to reduce bandwidth
Use @nuxt/image v2 preload API (preload: { fetchPriority: 'high' }) for image preload priority instead of patching rendered HTML in Nitro
Use Nuxt Lazy* components, dynamic imports, or similarly deferred boundaries for components and composables only needed after user interaction (menu, sheet, dialog)

Files:

  • app/components/pages/premium/PremiumOfferLanding.vue
  • app/components/pages/premium/PremiumLandingOriginal.vue
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,vue}: Define locales in config/i18n.ts as the single source of truth; do not hardcode locale lists in application code
Use PocketBase batch writes for multi-record replacement/reorder operations instead of one HTTP write per changed row

Files:

  • app/components/pages/premium/PremiumOfferLanding.vue
  • app/components/pages/premium/PremiumLandingOriginal.vue
app/**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

app/**/*.vue: Use project.urls.production for canonical URLs to point to production (https://r34.app/...) even when served from clone domains
Keep breadcrumb Schema.org source item URLs local/locale-relative; do not convert to project.urls.production since nuxt-schema-org resolves against site.url
When triggering a premium prompt from a nested dialog/bottom sheet, let the sheet owner close local UI, open the prompt, and restore UI after prompt closes
Premium auth transitions are reload-backed in dashboard/sign-in flow; rely on page reload to clear memory state instead of tracking PocketBase user ids in useState

Files:

  • app/components/pages/premium/PremiumOfferLanding.vue
  • app/components/pages/premium/PremiumLandingOriginal.vue
🔇 Additional comments (2)
app/components/pages/premium/PremiumLandingOriginal.vue (1)

21-38: LGTM!

Also applies to: 266-266, 302-302, 386-386, 395-395, 413-413

app/components/pages/premium/PremiumOfferLanding.vue (1)

17-17: LGTM!


📝 Walkthrough

Walkthrough

The premium page now lazy-loads dedicated landing components. The original landing component contains localized content, pricing, payment selection, FAQs, SEO metadata, and structured data. Matomo loading and page-view experiment ordering are updated, with source-based tests covering rendering and tracking behavior.

Changes

Premium landing experience

Layer / File(s) Summary
Landing content and pricing
app/components/pages/premium/PremiumLandingOriginal.vue
Adds localized landing content, hero sections, testimonials, pricing intervals, feature lists, FAQs, SEO metadata, and structured data.
Payment selection dialog
app/components/pages/premium/PremiumLandingOriginal.vue
Adds plan-click tracking and a modal that groups payment links by payment method.
Lazy landing composition
app/pages/premium/index.vue, app/components/pages/premium/PremiumOfferLanding.vue, test/assets/monetization-measurement.test.ts
Replaces embedded original markup with lazy-loaded original or offer landing components and adds source assertions for rendering and tracking.
Matomo loading and page tracking
app/plugins/040.matomo.client.ts, test/assets/monetization-measurement.test.ts
Removes eager Matomo loading for premium routes and ensures experiment loading precedes the page-view command, with updated ordering assertions.

Sequence Diagram(s)

sequenceDiagram
  participant Visitor
  participant PremiumPage
  participant LandingComponent
  participant Matomo
  participant PaymentDialog
  Visitor->>PremiumPage: Open premium page
  PremiumPage->>LandingComponent: Render selected lazy landing variant
  LandingComponent->>Matomo: Track plan selection
  LandingComponent->>PaymentDialog: Open selected payment interval
  PaymentDialog-->>Visitor: Display payment links
Loading

Possibly related PRs

  • Rule-34/App#151: Modifies the premium landing A/B flow and related Matomo and monetization assertions.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main refactor to simplify Premium A/B test integration across the landing page and Matomo flow.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch simplify-premium-ab-test
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch simplify-premium-ab-test

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.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install timed out. The project may have too many dependencies for the sandbox.


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.

@AlejandroAkbal
AlejandroAkbal marked this pull request as ready for review July 27, 2026 07:43

@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: 3

🤖 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 `@app/components/pages/premium/PremiumLandingOriginal.vue`:
- Around line 400-409: Remove the commented-out dead template blocks in the
premium landing markup, including the unused anchor with QuestionMarkCircleIcon
and the duplicate CTA NuxtLink. Leave the active template and any intentional
TODOs unchanged.
- Around line 199-201: Update the useSeoMeta configuration in
PremiumLandingOriginal.vue to include a page-specific description alongside the
existing computed title, using the appropriate localized translation key from
the premium landing-page SEO translations.
- Around line 267-269: Define a single computed value or constant named
trustpilotUrl in the Premium landing component using the existing Trustpilot URL
expression, then replace the duplicated inline template literals in all three
NuxtLink instances with trustpilotUrl.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1ed8f49f-d4a9-4bff-9bb7-49b880c1ce80

📥 Commits

Reviewing files that changed from the base of the PR and between 017bd6b and 236a4df.

📒 Files selected for processing (4)
  • app/components/pages/premium/PremiumLandingOriginal.vue
  • app/pages/premium/index.vue
  • app/plugins/040.matomo.client.ts
  • test/assets/monetization-measurement.test.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (9)
test/**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

test/**/*.{test,spec}.{ts,tsx}: Use Vitest with @nuxt/test-utils and Playwright browser mode for testing
Use @nuxt/test-utils with Playwright inside describe blocks calling await setup({ browser: true })
Mock server-side API calls via test-only Nitro plugin at test/server-mocks/plugin.ts injected through nuxt.config.ts $test.nitro.plugins
Use debugBrowserOptions from test/helper.ts for headful Playwright playback with slowMo in tests
Keep repository/pure modules importable through relative paths in plain Vitest suites that do not get Nuxt's runtime alias resolution
Use fetch from @nuxt/test-utils with { redirect: 'manual' } to access redirect status and Location headers; @nuxt/test-utils $fetch has no .raw method
Import localeCodes, prefixedLocaleCodes, and removedLocaleCodes from config/i18n in tests instead of hardcoding locale lists

Files:

  • test/assets/monetization-measurement.test.ts
**/*.{vue,ts,tsx,js,jsx,json,css,scss}

📄 CodeRabbit inference engine (AGENTS.md)

Use Prettier for formatting with 120-char print width, no semicolons, single quotes, trailing commas removed, and single attribute per line in Vue templates

Files:

  • test/assets/monetization-measurement.test.ts
  • app/pages/premium/index.vue
  • app/components/pages/premium/PremiumLandingOriginal.vue
  • app/plugins/040.matomo.client.ts
**/*.{ts,tsx,js,jsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

Use Nuxt flat ESLint via @nuxt/eslint for linting

Files:

  • test/assets/monetization-measurement.test.ts
  • app/pages/premium/index.vue
  • app/components/pages/premium/PremiumLandingOriginal.vue
  • app/plugins/040.matomo.client.ts
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,vue}: Define locales in config/i18n.ts as the single source of truth; do not hardcode locale lists in application code
Use PocketBase batch writes for multi-record replacement/reorder operations instead of one HTTP write per changed row

Files:

  • test/assets/monetization-measurement.test.ts
  • app/pages/premium/index.vue
  • app/components/pages/premium/PremiumLandingOriginal.vue
  • app/plugins/040.matomo.client.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: For URL validation/parsing, prefer URL.canParse() or URL.parse() over constructor try/catch
Use URL.parse() when the parsed URL object is needed, with URL.canParse() fallback in browser code if compatibility matters

Files:

  • test/assets/monetization-measurement.test.ts
  • app/plugins/040.matomo.client.ts
app/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

app/**/*.{vue,ts,tsx}: Use Nuxt 4 with Vue 3 and TypeScript for the frontend application
Use useLazyToast() to lazy-load vue-sonner; wait for ClientToaster to mount before calling toast.* using a proper async wait instead of plain nextTick()
Build reordered array synchronously instead of reading VueUse moveArrayElement() result before nextTick for state immediately persisted

Files:

  • app/pages/premium/index.vue
  • app/components/pages/premium/PremiumLandingOriginal.vue
  • app/plugins/040.matomo.client.ts
app/**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

app/**/*.vue: Use project.urls.production for canonical URLs to point to production (https://r34.app/...) even when served from clone domains
Keep breadcrumb Schema.org source item URLs local/locale-relative; do not convert to project.urls.production since nuxt-schema-org resolves against site.url
When triggering a premium prompt from a nested dialog/bottom sheet, let the sheet owner close local UI, open the prompt, and restore UI after prompt closes
Premium auth transitions are reload-backed in dashboard/sign-in flow; rely on page reload to clear memory state instead of tracking PocketBase user ids in useState

Files:

  • app/pages/premium/index.vue
  • app/components/pages/premium/PremiumLandingOriginal.vue
app/pages/**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

app/pages/**/*.vue: Use useSeoMeta in page components for page-specific tags (title, description)
Use flat bracket keys (filter[sort], filter[rating], etc.) with Vue Router's default query handling; do not re-add qs for nested route.query.filter objects unless URL contract changes
Keep @formkit/auto-animate route-scoped unless used broadly; use local vAutoAnimate imports on specific pages instead of global directive
Keep TanStack infinite-query data raw and apply blocklist hiding in page-level computed rows; do not mutate query pages in select with selectedBlockList
Query filters use flat bracket keys (filter[sort], filter[rating]) with Vue Router default query handling

Files:

  • app/pages/premium/index.vue
app/components/**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

app/components/**/*.vue: Register Vue components without path prefix using pathPrefix: false in nuxt.config.ts; import them as not <Input/DomainSelector>
Auto-import components from app/components/ flat structure without folder prefix
Use custom imgproxy provider for images; generate images at 1x density only in webp format to reduce bandwidth
Use @nuxt/image v2 preload API (preload: { fetchPriority: 'high' }) for image preload priority instead of patching rendered HTML in Nitro
Use Nuxt Lazy* components, dynamic imports, or similarly deferred boundaries for components and composables only needed after user interaction (menu, sheet, dialog)

Files:

  • app/components/pages/premium/PremiumLandingOriginal.vue
🧠 Learnings (1)
📚 Learning: 2026-06-22T07:50:54.935Z
Learnt from: AlejandroAkbal
Repo: Rule-34/App PR: 144
File: test/server/fix-canonical-queries.test.ts:174-178
Timestamp: 2026-06-22T07:50:54.935Z
Learning: In this Nuxt 3/4 project using `nuxt-schema-org` (v6.2.1), breadcrumb `source`/`itemListElement` URL values may be provided via `localePath()` (locale-relative in source code), but `nuxt-schema-org` renders JSON-LD with production-absolute URLs using `site.url` during schema rendering. When asserting JSON-LD breadcrumb `itemListElement` URLs in tests, expect production-absolute URLs (e.g., prefix with `project.urls.production.origin`), not the locale-relative `localePath()` forms. Do not flag production-absolute URL strings in JSON-LD breadcrumb tests as incorrect.

Applied to files:

  • test/assets/monetization-measurement.test.ts
🔇 Additional comments (6)
app/components/pages/premium/PremiumLandingOriginal.vue (3)

1-219: LGTM!


49-144: 🎯 Functional Correctness | ⚡ Quick win

Dead code path: link.instructions is never populated.

The template checks 'instructions' in link && link.instructions (lines 684-693) to render extra steps for a payment link, but none of the link objects defined in paymentIntervals (lines 49-144) ever set an instructions field. This branch can never render. If this dropped a feature during the move from the old page (e.g. bank-transfer/manual-payment steps), it should be restored with the missing data; otherwise this dead branch should be removed.

Also applies to: 679-694


220-577: LGTM!

Also applies to: 578-714

app/pages/premium/index.vue (1)

1-11: LGTM!

test/assets/monetization-measurement.test.ts (1)

11-11: LGTM!

Also applies to: 22-27, 37-39

app/plugins/040.matomo.client.ts (1)

24-50: Ordering fix matches Matomo's official SPA integration pattern.

Calling loadAbTesting (which pushes AbTesting::create) before _paq.push(['trackPageView']) on every route change matches Matomo's documented SPA guidance, which shows the experiment-create call alongside setCustomUrl/trackPageView on every virtual pageview, placed before the trackPageView push. Removal of the eager premium-route Matomo load is consistent with the PR objective that Matomo stays interaction-gated.

I verified this against Matomo's official documentation via web search, since the pattern initially looked like it could cause redundant re-registration of the same experiment on every navigation.

Also applies to: 84-93

Comment thread app/components/pages/premium/PremiumLandingOriginal.vue
Comment thread app/components/pages/premium/PremiumLandingOriginal.vue
Comment thread app/components/pages/premium/PremiumLandingOriginal.vue Outdated
@AlejandroAkbal

Copy link
Copy Markdown
Member Author

Validated all CodeRabbit findings against the current branch:

  • Fixed the repeated Trustpilot URL.
  • Removed the commented markup and its now-unused feature metadata.
  • Removed the unreachable payment-link instructions branch; no plan defines instructions.
  • Did not add an SEO description because no localized Premium landing seoDescription key exists. That requires a separate copy/i18n change rather than inventing a key in this refactor.

Revalidated with focused Vitest, Nuxt typecheck, production build (247 routes), and git diff --check.

@AlejandroAkbal

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 27, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@AlejandroAkbal

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 27, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@AlejandroAkbal
AlejandroAkbal merged commit f509f91 into main Jul 27, 2026
1 check passed
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