Skip to content

Conversation

rohitpaulk
Copy link
Member

@rohitpaulk rohitpaulk commented Jul 28, 2025

  • Created PricingPlanCard component for displaying pricing information.
  • Updated pricing plan cards to enhance UI and call-to-action elements.
  • Implemented membership plan selection modal and cards on the payment page.
  • Added discounted pricing and amortization details to the plan card.

Summary by CodeRabbit

  • New Features

    • Introduced a new modal for selecting membership plans, offering multiple plan options and a streamlined checkout process.
    • Added interactive membership plan cards with clear pricing, discount details, and selection indicators.
    • Enhanced pricing plan cards with improved layout, feature lists, and call-to-action buttons.
  • Refactor

    • Updated the pay page layout for better clarity and user experience, including a new grid arrangement for plan cards.
    • Simplified modal interactions and plan selection flow.
  • Bug Fixes

    • Improved accessibility for interactive elements within the membership selection and pricing cards.

Copy link
Contributor

coderabbitai bot commented Jul 28, 2025

Walkthrough

A new membership plan selection and checkout modal system was introduced, including reusable plan card and pricing card components. The pay page template was refactored to use these new components and updated state management. Controller logic was simplified, with plan features and modal state now managed through new properties and actions.

Changes

Cohort / File(s) Change Summary
Membership Plan Modal Components
app/components/pay-page/choose-membership-plan-modal.hbs, app/components/pay-page/choose-membership-plan-modal.ts
Introduced a new modal component for choosing membership plans, including UI logic, state management (previewType), and event handlers for plan selection, invoice details, and checkout. Modal disables manual close and uses animated transitions.
Plan Card Subcomponent
app/components/pay-page/choose-membership-plan-modal/plan-card.hbs, app/components/pay-page/choose-membership-plan-modal/plan-card.ts
Added a plan card subcomponent for displaying selectable membership plans, with dynamic styling, discount logic, monthly price calculation, and accessibility support.
Pricing Plan Card Component
app/components/pay-page/pricing-plan-card.hbs, app/components/pay-page/pricing-plan-card.ts
Added a new pricing plan card component for displaying plan summaries, features, and CTA buttons, supporting recommended styling and feature links.
Pay Page Controller
app/controllers/pay.ts
Refactored state management for the modal, removed the old checkout session logic, and added computed properties for plan feature descriptions. Simplified CTA handling for opening the membership plan modal.
Pay Page Template
app/templates/pay.hbs
Refactored to use new pricing plan card components and updated modal logic. Replaced old pricing cards, updated modal state and component usage, and revised layout to a grid.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant PayPage
    participant PayController
    participant ChooseMembershipPlanModal
    participant PlanCard

    User->>PayPage: Clicks "Membership" CTA
    PayPage->>PayController: handleMembershipPlanCTAClick()
    PayController->>PayPage: Set chooseMembershipPlanModalIsOpen = true
    PayPage->>ChooseMembershipPlanModal: Render modal
    ChooseMembershipPlanModal->>PlanCard: Render plan options
    User->>ChooseMembershipPlanModal: Selects plan, proceeds to checkout
    ChooseMembershipPlanModal->>PayPage: (onClose or checkout)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

In the meadow of code, a modal appears,
With plans for all rabbits—three months or years!
Cards hop in grids, with features to show,
Discounts and details in a tidy new flow.
A checkout adventure, so easy and bright—
This bunny’s delighted: the pay page feels right!
🐇✨

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch create-pricing-plan-card-component

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@rohitpaulk rohitpaulk changed the title create-pricing-plan-card-component Design preview for /pay overhaul Jul 28, 2025
Copy link

Test Results

  1 files  ±0    1 suites  ±0   8m 23s ⏱️ -14s
640 tests ±0  583 ✅  -  9  48 💤 ±0  0 ❌ ±0  9 🔥 +9 
640 runs  ±0  574 ✅  - 18  48 💤 ±0  9 ❌ +9  9 🔥 +9 

For more details on these errors, see this check.

Results for commit db4e404. ± Comparison against base commit 1d6cc1d.

Copy link

codecov bot commented Jul 28, 2025

❌ 9 Tests Failed:

Tests completed Failed Passed Skipped
592 9 583 48
View the top 3 failed test(s) by shortest run time
Chrome 137.0::Acceptance | pay-test: user can create checkout session when extra invoice details is requested
Stack Traces | 0.286s run time
Promise rejected during "user can create checkout session when extra invoice details is requested": Element not found.

PageObject: 'page'
  Selector: '[data-test-yearly-pricing-card] [data-test-start-payment-button]'

PageObject: 'page.clickOnStartPaymentButtonForYearlyPlan()'
  Selector: '[data-test-yearly-pricing-card] [data-test-start-payment-button]'
Chrome 137.0::Acceptance | pay-test: user can create checkout session when extra invoice details is not requested
Stack Traces | 0.287s run time
Promise rejected during "user can create checkout session when extra invoice details is not requested": Element not found.

PageObject: 'page'
  Selector: '[data-test-yearly-pricing-card] [data-test-start-payment-button]'

PageObject: 'page.clickOnStartPaymentButtonForYearlyPlan()'
  Selector: '[data-test-yearly-pricing-card] [data-test-start-payment-button]'
Chrome 137.0::Acceptance | pay-test: user is redirected to login page after clicking on start membership if not logged in
Stack Traces | 0.309s run time
Promise rejected during "user is redirected to login page after clicking on start membership if not logged in": Element not found.

PageObject: 'page.pricingCards[0].startPaymentButton'
  Selector: '[data-test-pricing-card]:eq(0) [data-test-start-payment-button]'

PageObject: 'page.pricingCards[0].startPaymentButton.click()'
  Selector: '[data-test-pricing-card]:eq(0) [data-test-start-payment-button]'

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

</li>
</ul>
</div>
{{/if}}
Copy link

Choose a reason for hiding this comment

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

Bug: Static Discount Data in Template

Hardcoded placeholder discount information, including "50% off — India discount" and "40% off — coding-game's referral offer, expires in 74h:24m:01s", was accidentally committed to the template instead of dynamic data.

Locations (1)
Fix in Cursor Fix in Web

Copy link
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: 5

🧹 Nitpick comments (7)
app/components/pay-page/pricing-plan-card.hbs (2)

1-6: Check the CSS class structure for potential issues.

The container div has some styling inconsistencies:

  • Line 2 has both border and a conditional border class on line 3, which could cause conflicts
  • The filter class on line 4 appears to be standalone without related filter properties

Consider cleaning up the CSS classes:

-  class="flex flex-col items-start rounded-lg bg-gray-50 shadow-md shadow-gray-300/50 border
-    {{if @isRecommended 'border-teal-500' 'border border-gray-100'}}
-    filter relative"
+  class="flex flex-col items-start rounded-lg bg-gray-50 shadow-md shadow-gray-300/50 relative
+    {{if @isRecommended 'border-2 border-teal-500' 'border border-gray-100'}}"

41-59: Consider consolidating the CTA button implementation.

The two button elements share most of their structure and only differ in styling classes. This creates code duplication.

Consider consolidating into a single button with conditional classes:

-    {{#if @isRecommended}}
-      <button
-        class="w-full flex items-center justify-center transition-colors p-3 font-bold rounded-full shadow border-2 border-teal-500 bg-teal-500 text-white hover:bg-teal-600 hover:border-teal-600 px-5 py-3 text-sm"
-        data-test-pricing-plan-card-cta
-        type="button"
-        {{on "click" @onCtaClick}}
-      >
-        {{@ctaText}}&nbsp;→
-      </button>
-    {{else}}
-      <button
-        class="w-full flex items-center justify-center transition-colors p-3 font-bold rounded-full border bg-gray-50 hover:bg-white border-gray-300 text-gray-600 px-5 py-3 text-sm"
-        data-test-pricing-plan-card-cta
-        type="button"
-        {{on "click" @onCtaClick}}
-      >
-        {{@ctaText}}&nbsp;→
-      </button>
-    {{/if}}
+    <button
+      class="w-full flex items-center justify-center transition-colors p-3 font-bold rounded-full px-5 py-3 text-sm
+        {{if @isRecommended 
+          'shadow border-2 border-teal-500 bg-teal-500 text-white hover:bg-teal-600 hover:border-teal-600' 
+          'border bg-gray-50 hover:bg-white border-gray-300 text-gray-600'}}"
+      data-test-pricing-plan-card-cta
+      type="button"
+      {{on "click" @onCtaClick}}
+    >
+      {{@ctaText}}&nbsp;→
+    </button>
app/components/pay-page/pricing-plan-card.ts (1)

23-25: Consider removing unused cta block definition.

The cta block is defined in the Signature but doesn't appear to be used in the corresponding template (app/components/pay-page/pricing-plan-card.hbs).

If the block isn't needed, consider removing it:

-  Blocks: {
-    cta: [];
-  };
app/components/pay-page/choose-membership-plan-modal/plan-card.hbs (2)

1-8: Consider enhancing accessibility for the plan card.

The card has role="button" but lacks keyboard navigation support and screen reader descriptions. Consider adding tabindex="0", aria-label, and keyboard event handlers for better accessibility.

 <div
   class="flex items-start justify-between border
     {{if @isSelected 'border-teal-500' 'border-gray-200 hover:border-gray-300'}}
     rounded p-3
     {{if @isSelected 'bg-teal-50' 'bg-white hover:bg-gray-50'}}"
   role="button"
+  tabindex="0"
+  aria-label="{{@title}} plan card"
   ...attributes
 >

60-81: LGTM! Consider making fallback text configurable.

The pricing display logic correctly handles both discounted and regular pricing scenarios. The use of the computed property amortizedMonthlyPriceInDollars is appropriate.

Consider making the fallback text configurable instead of hardcoding "Limited spots":

 <div class="text-gray-500 text-xxs flex-shrink-0 text-right mt-0.5">
   {{#if this.amortizedMonthlyPriceInDollars}}
     Effectively ${{this.amortizedMonthlyPriceInDollars}}/mo
   {{else}}
-    Limited spots
+    {{or @fallbackText "Limited spots"}}
   {{/if}}
 </div>
app/controllers/pay.ts (1)

50-74: LGTM! Consider externalizing feature descriptions for easier maintenance.

The feature descriptions are well-structured and comprehensive for each plan type. The inclusion of documentation links is helpful for users.

For easier maintenance and potential localization, consider moving these feature descriptions to a configuration file or service:

// utils/plan-features.ts
export const PLAN_FEATURES = {
  free: [
    { text: 'Limited content access' },
    { text: 'Basic community features' }
  ],
  membership: [
    { text: 'Unrestricted content access' },
    // ... rest of features
  ],
  teams: [
    { text: 'All membership features' },
    // ... rest of features
  ]
};
app/components/pay-page/choose-membership-plan-modal.hbs (1)

109-124: Implement checkout functionality.

The checkout button is currently non-functional with {{on "click" (noop)}}. The loading state UI is well-implemented but needs actual checkout logic.

Replace the noop with an actual checkout handler:

-<PrimaryButton class="flex! items-center justify-center" @size="large" {{on "click" (noop)}} data-test-proceed-to-checkout-button>
+<PrimaryButton class="flex! items-center justify-center" @size="large" {{on "click" this.handleProceedToCheckout}} data-test-proceed-to-checkout-button>

Do you want me to help implement the checkout handler logic?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1d6cc1d and db4e404.

📒 Files selected for processing (8)
  • app/components/pay-page/choose-membership-plan-modal.hbs (1 hunks)
  • app/components/pay-page/choose-membership-plan-modal.ts (1 hunks)
  • app/components/pay-page/choose-membership-plan-modal/plan-card.hbs (1 hunks)
  • app/components/pay-page/choose-membership-plan-modal/plan-card.ts (1 hunks)
  • app/components/pay-page/pricing-plan-card.hbs (1 hunks)
  • app/components/pay-page/pricing-plan-card.ts (1 hunks)
  • app/controllers/pay.ts (4 hunks)
  • app/templates/pay.hbs (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{js,ts,hbs,gts,gjs}

📄 CodeRabbit Inference Engine (.rules/no-bugs.md)

**/*.{js,ts,hbs,gts,gjs}: Avoid typos
Don't have really obvious bugs
Follow reasonable conventions of the language we're programming in

Files:

  • app/templates/pay.hbs
  • app/controllers/pay.ts
  • app/components/pay-page/choose-membership-plan-modal.ts
  • app/components/pay-page/pricing-plan-card.ts
  • app/components/pay-page/choose-membership-plan-modal/plan-card.ts
  • app/components/pay-page/pricing-plan-card.hbs
  • app/components/pay-page/choose-membership-plan-modal/plan-card.hbs
  • app/components/pay-page/choose-membership-plan-modal.hbs
app/components/**/*.ts

📄 CodeRabbit Inference Engine (.cursor/rules/formatting-component-files.mdc)

app/components/**/*.ts: Use TypeScript (.ts) files for components in app/components
Import from @glimmer/component when creating components
Use interface Signature { ... } to define the component's signature
class doesn't have to be in Args, Ember automatically forwards native args like class, id etc. to the component
Ensure the component is registered with Glint using declare module ...

Files:

  • app/components/pay-page/choose-membership-plan-modal.ts
  • app/components/pay-page/pricing-plan-card.ts
  • app/components/pay-page/choose-membership-plan-modal/plan-card.ts
🧠 Learnings (3)
app/components/pay-page/choose-membership-plan-modal.ts (3)

Learnt from: CR
PR: codecrafters-io/frontend#0
File: .cursor/rules/formatting-component-files.mdc:0-0
Timestamp: 2025-07-25T04:24:47.305Z
Learning: Applies to app/components/**/*.ts : Ensure the component is registered with Glint using declare module ...

Learnt from: CR
PR: codecrafters-io/frontend#0
File: .cursor/rules/formatting-component-files.mdc:0-0
Timestamp: 2025-07-25T04:24:47.305Z
Learning: Applies to app/components/**/*.ts : Import from @glimmer/component when creating components

Learnt from: CR
PR: codecrafters-io/frontend#0
File: .cursor/rules/formatting-component-files.mdc:0-0
Timestamp: 2025-07-25T04:24:47.305Z
Learning: Applies to app/components/**/*.ts : Use interface Signature { ... } to define the component's signature

app/components/pay-page/pricing-plan-card.ts (3)

Learnt from: CR
PR: codecrafters-io/frontend#0
File: .cursor/rules/formatting-component-files.mdc:0-0
Timestamp: 2025-07-25T04:24:47.305Z
Learning: Applies to app/components/**/*.ts : Use interface Signature { ... } to define the component's signature

Learnt from: CR
PR: codecrafters-io/frontend#0
File: .cursor/rules/formatting-component-files.mdc:0-0
Timestamp: 2025-07-25T04:24:47.305Z
Learning: Applies to app/components/**/*.ts : Import from @glimmer/component when creating components

Learnt from: CR
PR: codecrafters-io/frontend#0
File: .cursor/rules/formatting-component-files.mdc:0-0
Timestamp: 2025-07-25T04:24:47.305Z
Learning: Applies to app/components/**/*.ts : Ensure the component is registered with Glint using declare module ...

app/components/pay-page/choose-membership-plan-modal/plan-card.ts (3)

Learnt from: CR
PR: codecrafters-io/frontend#0
File: .cursor/rules/formatting-component-files.mdc:0-0
Timestamp: 2025-07-25T04:24:47.305Z
Learning: Applies to app/components/**/*.ts : Use interface Signature { ... } to define the component's signature

Learnt from: CR
PR: codecrafters-io/frontend#0
File: .cursor/rules/formatting-component-files.mdc:0-0
Timestamp: 2025-07-25T04:24:47.305Z
Learning: Applies to app/components/**/*.ts : Ensure the component is registered with Glint using declare module ...

Learnt from: CR
PR: codecrafters-io/frontend#0
File: .cursor/rules/formatting-component-files.mdc:0-0
Timestamp: 2025-07-25T04:24:47.305Z
Learning: Applies to app/components/**/*.ts : Import from @glimmer/component when creating components

🧬 Code Graph Analysis (2)
app/controllers/pay.ts (1)
app/components/pay-page/pricing-plan-card.ts (1)
  • FeatureDescription (5-8)
app/components/pay-page/pricing-plan-card.ts (1)
app/services/authenticator.ts (1)
  • AuthenticatorService (11-146)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test
🔇 Additional comments (10)
app/components/pay-page/pricing-plan-card.hbs (1)

22-37: LGTM! Feature list implementation is well-structured.

The feature list iteration correctly handles both linked and plain text features, with appropriate accessibility attributes for external links (target="_blank", rel="noopener noreferrer") and good hover state styling.

app/templates/pay.hbs (2)

28-61: LGTM! Component migration is well-executed.

The transition from PayPage::PricingCard to PayPage::PricingPlanCard is consistent across all three plan cards, with appropriate property mappings and grid layout implementation. The use of controller-provided feature descriptions maintains separation of concerns.


100-107: Confirmed: chooseMembershipPlanModalIsOpen is defined in PayController
The tracked property is declared in app/controllers/pay.ts (@tracked chooseMembershipPlanModalIsOpen = false), so the template reference is valid.

app/components/pay-page/choose-membership-plan-modal.ts (2)

14-27: LGTM! Component implementation follows best practices.

The component correctly uses tracked properties, action decorators, and maintains simple state management for the preview type switching. The fade transition integration is appropriate for modal animations.


29-33: LGTM! Proper Glint registration.

The component is correctly registered with Glint using the expected naming convention for nested components.

app/components/pay-page/choose-membership-plan-modal/plan-card.ts (1)

1-33: LGTM! Well-implemented pricing component.

The component follows all established patterns from the retrieved learnings:

  • Correct Glimmer component import
  • Proper interface Signature definition
  • Appropriate Element type (HTMLDivElement)
  • Correct Glint registration

The pricing calculation logic is sound:

  • effectivePriceInDollars correctly falls back from discounted to actual price
  • amortizedMonthlyPriceInDollars properly handles lifetime plans by returning null when validityInMonths is undefined
  • Math.round ensures clean monthly pricing display
app/components/pay-page/pricing-plan-card.ts (1)

1-36: LGTM! Component follows established patterns.

The component correctly implements all the patterns from the retrieved learnings:

  • Proper import from @glimmer/component
  • Uses interface Signature for component definition
  • Correctly registered with Glint

The FeatureDescription interface is well-defined and the component signature properly covers all necessary arguments for the template usage.

app/controllers/pay.ts (3)

14-14: LGTM!

The import of FeatureDescription type is correctly referenced and used in the new getter methods.


25-25: LGTM!

The property rename from configureCheckoutSessionModalIsOpen to chooseMembershipPlanModalIsOpen correctly reflects the new modal component's purpose.


85-87: LGTM!

The simplified action method correctly delegates complex logic to the modal component, following good separation of concerns. The method name clearly describes its purpose.

Comment on lines +13 to +48
{{#animated-if (eq this.previewType "plan") use=this.transition duration=200}}
<div>
<div class="flex flex-col gap-y-2">
<PayPage::ChooseMembershipPlanModal::PlanCard
@isSelected={{true}}
@title="3 month pass"
@actualPriceInDollars={{120}}
@discountedPriceInDollars={{undefined}}
@validityInMonths={{3}}
/>

<PayPage::ChooseMembershipPlanModal::PlanCard
@isSelected={{false}}
@title="1 year pass"
@actualPriceInDollars={{360}}
@discountedPriceInDollars={{108}}
@validityInMonths={{12}}
/>

<PayPage::ChooseMembershipPlanModal::PlanCard
@isSelected={{false}}
@title="Lifetime pass"
@actualPriceInDollars={{1490}}
@discountedPriceInDollars={{undefined}}
/>

<PrimaryButton @size="large" {{on "click" this.handleChoosePlanButtonClick}}>
Choose 3 month pass&nbsp;→
</PrimaryButton>
</div>
<div class="flex justify-center mt-4">
<div class="inline-block text-gray-500 text-sm border-b border-gray-300 cursor-pointer" {{on "click" @onClose}}>
Back to pricing page
</div>
</div>
</div>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Make plan selection dynamic and interactive.

The plan cards have hardcoded data and selection states, making the component non-functional. The selection logic needs to be implemented.

Apply these changes to make plan selection dynamic:

 <div class="flex flex-col gap-y-2">
   <PayPage::ChooseMembershipPlanModal::PlanCard
-    @isSelected={{true}}
-    @title="3 month pass"
-    @actualPriceInDollars={{120}}
-    @discountedPriceInDollars={{undefined}}
-    @validityInMonths={{3}}
+    @isSelected={{eq this.selectedPlan.id "3-month"}}
+    @title={{this.availablePlans.3month.title}}
+    @actualPriceInDollars={{this.availablePlans.3month.price}}
+    @discountedPriceInDollars={{this.availablePlans.3month.discountedPrice}}
+    @validityInMonths={{this.availablePlans.3month.validityInMonths}}
+    {{on "click" (fn this.handlePlanSelection this.availablePlans.3month)}}
   />

   <PayPage::ChooseMembershipPlanModal::PlanCard
-    @isSelected={{false}}
+    @isSelected={{eq this.selectedPlan.id "12-month"}}
     <!-- similar changes for other plans -->
   />

-  <PrimaryButton @size="large" {{on "click" this.handleChoosePlanButtonClick}}>
-    Choose 3 month pass&nbsp;→
+  <PrimaryButton @size="large" {{on "click" this.handleChoosePlanButtonClick}}>
+    Choose {{this.selectedPlan.title}}&nbsp;→
   </PrimaryButton>
 </div>

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In app/components/pay-page/choose-membership-plan-modal.hbs between lines 13 and
48, the plan cards and selection states are hardcoded, making the UI static and
non-interactive. To fix this, replace the hardcoded plan cards with a dynamic
loop over a plans array from the component's JavaScript/TypeScript file, bind
the @isSelected property based on the currently selected plan state, and update
the selection state when a plan card is clicked. Also, update the button label
and click handler to reflect the selected plan dynamically.

Comment on lines +51 to +58
<div class="relative">
<PayPage::ChooseMembershipPlanModal::PlanCard
@isSelected={{true}}
@title="3 month pass"
@actualPriceInDollars={{120}}
@discountedPriceInDollars={{undefined}}
@validityInMonths={{3}}
/>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Use dynamic plan data in invoice details view.

The selected plan card shows the same hardcoded data as in the plan selection view.

Apply this change to use dynamic data:

 <PayPage::ChooseMembershipPlanModal::PlanCard
   @isSelected={{true}}
-  @title="3 month pass"
-  @actualPriceInDollars={{120}}
-  @discountedPriceInDollars={{undefined}}
-  @validityInMonths={{3}}
+  @title={{this.selectedPlan.title}}
+  @actualPriceInDollars={{this.selectedPlan.price}}
+  @discountedPriceInDollars={{this.selectedPlan.discountedPrice}}
+  @validityInMonths={{this.selectedPlan.validityInMonths}}
 />
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div class="relative">
<PayPage::ChooseMembershipPlanModal::PlanCard
@isSelected={{true}}
@title="3 month pass"
@actualPriceInDollars={{120}}
@discountedPriceInDollars={{undefined}}
@validityInMonths={{3}}
/>
<div class="relative">
<PayPage::ChooseMembershipPlanModal::PlanCard
@isSelected={{true}}
@title={{this.selectedPlan.title}}
@actualPriceInDollars={{this.selectedPlan.price}}
@discountedPriceInDollars={{this.selectedPlan.discountedPrice}}
@validityInMonths={{this.selectedPlan.validityInMonths}}
/>
🤖 Prompt for AI Agents
In app/components/pay-page/choose-membership-plan-modal.hbs around lines 51 to
58, the selected plan card uses hardcoded values for the plan details. Replace
these hardcoded values with dynamic data by passing the actual selected plan's
properties to the PlanCard component, ensuring the invoice details reflect the
user's chosen plan accurately.

Comment on lines +6 to +12
interface Signature {
Element: HTMLAnchorElement;

Args: {
onClose: () => void;
};
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix the Element type in the Signature interface.

The Element type is set to HTMLAnchorElement but this appears to be a modal component that would typically render as a div or other container element, not an anchor element.

 interface Signature {
-  Element: HTMLAnchorElement;
+  Element: HTMLDivElement;

   Args: {
     onClose: () => void;
   };
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
interface Signature {
Element: HTMLAnchorElement;
Args: {
onClose: () => void;
};
}
interface Signature {
Element: HTMLDivElement;
Args: {
onClose: () => void;
};
}
🤖 Prompt for AI Agents
In app/components/pay-page/choose-membership-plan-modal.ts between lines 6 and
12, the Signature interface incorrectly types Element as HTMLAnchorElement,
which is inappropriate for a modal component. Change the Element type to a more
suitable container element type such as HTMLDivElement to accurately reflect the
modal's rendered element.

Comment on lines +42 to +57
{{#if @discountedPriceInDollars}}
<div class="prose prose-xs prose-compact text-gray-500">
<ul class="mt-0">
<li>
<b class="text-teal-500">50% off</b>
— India discount
</li>
<li>
<b class="text-teal-500">40% off</b>
— <span class="text-nowrap">coding-game's</span>
referral offer, expires in
<span class="font-mono">74h:24m:01s</span>
</li>
</ul>
</div>
{{/if}}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Replace hardcoded discount values with dynamic properties.

The discount section contains several hardcoded values that should be made configurable:

  • Discount percentages (50%, 40%)
  • Referral user name ("coding-game's")
  • Static countdown timer ("74h:24m:01s")

Consider passing these as component arguments:

 {{#if @discountedPriceInDollars}}
   <div class="prose prose-xs prose-compact text-gray-500">
     <ul class="mt-0">
       <li>
-        <b class="text-teal-500">50% off</b>
+        <b class="text-teal-500">{{@regionalDiscountPercentage}}% off</b>
         — India discount
       </li>
       <li>
-        <b class="text-teal-500">40% off</b>
-        — <span class="text-nowrap">coding-game's</span>
+        <b class="text-teal-500">{{@referralDiscountPercentage}}% off</b>
+        — <span class="text-nowrap">{{@referralUserName}}'s</span>
         referral offer, expires in
-        <span class="font-mono">74h:24m:01s</span>
+        <span class="font-mono">{{@countdownTimer}}</span>
       </li>
     </ul>
   </div>
 {{/if}}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{{#if @discountedPriceInDollars}}
<div class="prose prose-xs prose-compact text-gray-500">
<ul class="mt-0">
<li>
<b class="text-teal-500">50% off</b>
— India discount
</li>
<li>
<b class="text-teal-500">40% off</b>
— <span class="text-nowrap">coding-game's</span>
referral offer, expires in
<span class="font-mono">74h:24m:01s</span>
</li>
</ul>
</div>
{{/if}}
{{#if @discountedPriceInDollars}}
<div class="prose prose-xs prose-compact text-gray-500">
<ul class="mt-0">
<li>
<b class="text-teal-500">{{@regionalDiscountPercentage}}% off</b>
— India discount
</li>
<li>
<b class="text-teal-500">{{@referralDiscountPercentage}}% off</b>
— <span class="text-nowrap">{{@referralUserName}}'s</span>
referral offer, expires in
<span class="font-mono">{{@countdownTimer}}</span>
</li>
</ul>
</div>
{{/if}}
🤖 Prompt for AI Agents
In app/components/pay-page/choose-membership-plan-modal/plan-card.hbs lines 42
to 57, replace the hardcoded discount percentages, referral user name, and
countdown timer with dynamic properties passed as component arguments. Update
the template to use these arguments instead of fixed values so the discount
details and timer can be configured externally.

}

export default class PricingPlanCardComponent extends Component<Signature> {
@service declare authenticator: AuthenticatorService;
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify authenticator service usage.

The authenticator service is injected but doesn't appear to be used in either the component class or template. Consider whether this injection is necessary.


🏁 Script executed:

#!/bin/bash
# Check if authenticator service is used in the component template
rg -A 3 -B 3 "authenticator" app/components/pay-page/pricing-plan-card.hbs

Length of output: 74


🏁 Script executed:

#!/bin/bash
# Check for any usage of the injected authenticator service in the component class
rg -n "authenticator" app/components/pay-page/pricing-plan-card.ts
rg -n "this.authenticator" .

Length of output: 27968


Remove unused authenticator injection

The authenticator service is declared but never used in app/components/pay-page/pricing-plan-card.ts or its template. Please remove the unused import and decorator:

• In app/components/pay-page/pricing-plan-card.ts

-import AuthenticatorService from 'codecrafters-frontend/services/authenticator';-  @service declare authenticator: AuthenticatorService;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@service declare authenticator: AuthenticatorService;
import Component from '@glimmer/component';
import { inject as service } from '@ember/service';
// … other imports (but no AuthenticatorService import)
export default class PricingPlanCard extends Component<Signature> {
// … other service injections or properties
// (removed unused authenticator injection)
// … rest of the class implementation
}
🤖 Prompt for AI Agents
In app/components/pay-page/pricing-plan-card.ts at line 29, the authenticator
service is injected but never used. Remove the entire line declaring the
authenticator service injection to clean up unused code and imports.

@Arpan-206 Arpan-206 merged commit 16fe2f4 into main Aug 4, 2025
6 of 10 checks passed
@Arpan-206 Arpan-206 deleted the create-pricing-plan-card-component branch August 4, 2025 05: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.

2 participants