-
Notifications
You must be signed in to change notification settings - Fork 18
Add a billing tab to the settings #2811
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
## Walkthrough
This update migrates the membership management functionality from the standalone `/membership` route to a new, consolidated billing section under `/settings/billing`. It introduces new Ember components and templates for membership status, renewal, support, and payment history, all organized within the billing settings page. The routing structure, navigation destinations, and UI flows are updated accordingly, with redirects and controller logic adjusted to support the new organization. Associated tests and page objects are refactored or replaced to align with the new billing page, and legacy membership files and tests are removed.
## Changes
| File(s) / Path(s) | Change Summary |
|-----------------------------------------------------------------------------------|---------------|
| `app/components/settings/billing-page/membership-section.hbs`, `.ts`<br>`app/components/settings/billing-page/payment-history-section.hbs`, `.ts`<br>`app/components/settings/billing-page/renewal-section.hbs`, `.ts`<br>`app/components/settings/billing-page/support-section.hbs`, `.ts`<br>`app/components/settings/billing-page/membership-section/status-pill.hbs`, `.ts` | Added new Ember components and templates for membership status, payment history, renewal, support sections, and a status pill UI element on the billing page, each with typed arguments and UI logic. |
| `app/templates/settings/billing.hbs` | Added new billing settings page template, organizing the new billing-related components and layout. |
| `app/controllers/settings/billing.ts` | Added new controller for the billing settings route with typed model including charges. |
| `app/controllers/settings.ts` | Added 'Billing' tab to settings page navigation. |
| `app/router.ts` | Added nested 'billing' route under 'settings'. |
| `app/components/billing-status-badge/member-badge.hbs`<br>`app/components/header/account-dropdown.ts` | Changed navigation targets from 'membership' to 'settings.billing' for member badge and account dropdown actions. |
| `app/routes/pay.ts` | Updated post-payment route transition from 'membership' to 'settings.billing'. |
| `vercel.json` | Added permanent redirect from `/membership` to `/settings/billing`. |
| `app/routes/membership.js`<br>`app/templates/membership.hbs` | Deleted legacy membership route and template. |
| `app/components/membership-page/*` (all files) | Removed all legacy membership page components and templates, including actions, plan section, payment method section, recent payments, upcoming payment, and section wrapper components. |
| `tests/acceptance/settings-page/billing-test.js`<br>`tests/pages/settings/billing-page.ts` | Added new acceptance tests and page objects for the billing settings page. |
| `tests/acceptance/manage-membership-test.js`<br>`tests/pages/membership-page.js` | Removed legacy membership acceptance tests and page object. |
| `tests/acceptance/course-page/view-course-stages-test.js`<br>`tests/acceptance/header-test.js`<br>`tests/acceptance/pay-test.js` | Updated tests to expect billing page (`/settings/billing`) instead of membership page. |
| `tests/support/authentication-helpers.js` | Added helper for signing in as a VIP user for tests. |
## Sequence Diagram(s)
```mermaid
sequenceDiagram
participant User
participant AppRouter
participant SettingsController
participant BillingController
participant BillingPageComponents
User->>AppRouter: Navigates to /settings/billing
AppRouter->>SettingsController: Loads settings context
AppRouter->>BillingController: Loads billing model (user, charges)
BillingController->>BillingPageComponents: Passes user and charges
BillingPageComponents->>User: Renders Membership, Renewal, Support, Payment History sections sequenceDiagram
participant User
participant MemberBadge
participant Router
User->>MemberBadge: Clicks member badge
MemberBadge->>Router: Transitions to 'settings.billing'
Router->>User: Displays billing settings page
Poem
|
Test Results 1 files ±0 1 suites ±0 9m 22s ⏱️ -1s Results for commit 263cab5. ± Comparison against base commit 8f14f91. This pull request removes 9 and adds 10 tests. Note that renamed tests count towards both.
♻️ This comment has been updated with latest results. |
Codecov ReportAttention: Patch coverage is ✅ All tests successful. No failed tests found.
📢 Thoughts on this report? Let us know! |
Bundle ReportChanges will decrease total bundle size by 2.02kB (-0.01%) ⬇️. This is within the configured threshold ✅ Detailed changes
Affected Assets, Files, and Routes:view changes for bundle: client-array-pushAssets Changed:
Files in
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
🧹 Nitpick comments (5)
app/templates/settings/billing.hbs (1)
20-23
: Add handling for empty payment historyThe PaymentHistorySection should handle the case where a user has no payment history. Consider adding a conditional to display an appropriate message when the charges array is empty.
<Settings::FormSection @title="Payment history" @description="Details of your previous payments"> {{#let this.model.charges as |charges|}} - <Settings::BillingPage::PaymentHistorySection @charges={{charges}} /> + {{#if charges.length}} + <Settings::BillingPage::PaymentHistorySection @charges={{charges}} /> + {{else}} + <div class="text-gray-500 py-4"> + No payment history available. + </div> + {{/if}} {{/let}} </Settings::FormSection>app/components/settings/billing-page/payment-history-section.hbs (1)
14-21
: Consider adding a tooltip for refund information.For partially refunded charges, consider adding a tooltip that provides additional context about when/why the refund was processed to improve user experience.
{{#if (gt charge.amountRefunded 0)}} {{#if charge.isFullyRefunded}} - <span data-test-refund-text>(refunded)</span> + <span data-test-refund-text title="Fully refunded on {{date-format charge.refundedAt format='PPP'}}">(refunded)</span> {{else}} - <span data-test-refund-text>(<span class="font-semibold">{{charge.refundedAmountDisplayString}}</span> + <span data-test-refund-text title="Partially refunded on {{date-format charge.refundedAt format='PPP'}}">(<span class="font-semibold">{{charge.refundedAmountDisplayString}}</span> refunded)</span> {{/if}} {{/if}}app/components/settings/billing-page/membership-section.hbs (1)
63-65
: Consider adding tracking for membership conversions.The "Start membership" buttons are key conversion points. Consider adding analytics tracking to measure user engagement with these buttons.
-<PrimaryLinkButton @size="small" @route="pay" class="mt-3"> +<PrimaryLinkButton @size="small" @route="pay" class="mt-3" data-test-start-membership-button {{on "click" this.trackMembershipButtonClick}}> Start membership → </PrimaryLinkButton>Also applies to: 80-82
tests/acceptance/settings-page/billing-test.js (1)
67-69
: Consider mocking email client interaction.Instead of commenting out the contact button test, consider mocking the email client interaction or testing that the correct mailto URL is generated.
- // await billingPage.supportSection.clickContactButton(); - // Commented out because it opens the email client, if behavior changes, uncomment + // Test that the correct mailto URL is used + const contactButton = document.querySelector('[data-test-support-contact-button]'); + assert.ok(contactButton.href.startsWith('mailto:'), 'Contact button has mailto link'); + assert.ok(contactButton.href.includes('subject='), 'Contact button includes subject');mirage/models/charge.js (1)
1-14
: Charge model structure looks goodThe model correctly defines the user relationship and includes appropriate fields for a payment charge record.
Consider these improvements:
- Add more detailed documentation about valid values for the
status
field- Consider whether 'succeeded' is the most appropriate default status (versus 'pending')
- Clarify the comment on line 9 to better explain the specific linting issue
import { Model, belongsTo } from 'miragejs'; export default Model.extend({ user: belongsTo(), amount: 0, amountRefunded: 0, currency: 'usd', createdAt() { - return new Date(); // Done this way due to linting error and shared objects + return new Date(); // Returns a new Date object each time to avoid shared reference issues across instances }, invoiceId: null, - status: 'succeeded', + status: 'succeeded', // Possible values: 'succeeded', 'pending', 'failed', etc. });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (17)
app/components/settings/billing-page/membership-section.hbs
(1 hunks)app/components/settings/billing-page/membership-section.ts
(1 hunks)app/components/settings/billing-page/payment-history-section.hbs
(1 hunks)app/components/settings/billing-page/payment-history-section.ts
(1 hunks)app/components/settings/billing-page/renewal-section.hbs
(1 hunks)app/components/settings/billing-page/renewal-section.ts
(1 hunks)app/components/settings/billing-page/support-section.hbs
(1 hunks)app/components/settings/billing-page/support-section.ts
(1 hunks)app/controllers/settings.ts
(1 hunks)app/controllers/settings/billing.ts
(1 hunks)app/router.ts
(1 hunks)app/routes/settings/billing.ts
(1 hunks)app/templates/settings/billing.hbs
(1 hunks)mirage/models/charge.js
(1 hunks)tests/acceptance/settings-page/billing-test.js
(1 hunks)tests/pages/settings/billing-page.ts
(1 hunks)tests/support/authentication-helpers.js
(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (5)
app/components/settings/billing-page/renewal-section.ts (3)
app/components/settings/billing-page/membership-section.ts (1)
Registry
(15-17)app/components/settings/billing-page/payment-history-section.ts (1)
Registry
(15-17)app/components/settings/billing-page/support-section.ts (1)
Registry
(14-16)
tests/acceptance/settings-page/billing-test.js (1)
tests/support/authentication-helpers.js (4)
signInAsSubscriber
(51-61)signIn
(1-14)signInAsVipUser
(63-69)user
(102-102)
app/components/settings/billing-page/payment-history-section.ts (3)
app/components/settings/billing-page/membership-section.ts (1)
Registry
(15-17)app/components/settings/billing-page/renewal-section.ts (1)
Registry
(10-12)app/components/settings/billing-page/support-section.ts (1)
Registry
(14-16)
app/components/settings/billing-page/membership-section.ts (4)
app/models/user.ts (1)
UserModel
(28-218)app/components/settings/billing-page/payment-history-section.ts (1)
Registry
(15-17)app/components/settings/billing-page/renewal-section.ts (1)
Registry
(10-12)app/components/settings/billing-page/support-section.ts (1)
Registry
(14-16)
app/components/settings/billing-page/support-section.ts (3)
app/components/settings/billing-page/membership-section.ts (1)
Registry
(15-17)app/components/settings/billing-page/payment-history-section.ts (1)
Registry
(15-17)app/components/settings/billing-page/renewal-section.ts (1)
Registry
(10-12)
🔇 Additional comments (13)
app/controllers/settings.ts (1)
18-18
: LGTM! The billing tab is correctly added to the settings controller.This change properly integrates the new billing route into the settings interface navigation, maintaining consistency with the existing tab structure.
app/components/settings/billing-page/renewal-section.ts (1)
1-13
: RenewalSectionComponent setup looks solidThe component class and its Glint registry declaration follow the established pattern, matching other billing‐page sections and providing correct typing for the root
<div>
. No changes needed here.app/controllers/settings/billing.ts (1)
1-11
: BillingController model typing is correctThe
BillingController
properly extendsController
and declares a strongly typedmodel
combiningSettingsModelType
withcharges: ChargeModel[]
. This aligns with the route and ensures type safety.app/components/settings/billing-page/payment-history-section.ts (1)
1-18
: PaymentHistorySectionComponent matches the patternThe component signature correctly types
Args.charges
and the registry declaration mirrors other billing‐page sections. Everything is consistent and ready for use in the template.app/components/settings/billing-page/support-section.hbs (1)
1-12
: Support section template is well-structuredThe Handlebars markup cleanly renders the mailto link with dynamic
@username
and the styled support message. It follows accessibility and styling conventions in use elsewhere.app/components/settings/billing-page/membership-section.ts (1)
1-18
: MembershipSectionComponent conforms to conventionsThe component signature properly types
Args.user: UserModel
and the registry entry is consistent with other billing‐page sections. No further updates required.app/components/settings/billing-page/support-section.ts (1)
3-17
: LGTM! Well-structured component signatureThe component signature is well-defined with proper typing for the username argument and correct Glint registry setup for type safety.
app/components/settings/billing-page/payment-history-section.hbs (1)
1-45
: Well-structured payment history section with appropriate conditional rendering.The payment history section effectively handles different states (no charges, succeeded/failed charges, and refund scenarios) with clear visual indicators. The conditional logic for displaying "Download Invoice" links or failure messages is implemented correctly.
app/components/settings/billing-page/membership-section.hbs (1)
1-83
: Complete and well-structured membership section with clear visual indicators.The membership section effectively handles all user states (VIP, active, inactive, and no membership) with appropriate visual indicators and messaging.
tests/pages/settings/billing-page.ts (1)
1-30
: Well-structured page object with appropriate test selectors.The page object correctly implements the necessary selectors and properties for testing the billing page components.
tests/acceptance/settings-page/billing-test.js (1)
1-126
: Comprehensive test coverage for billing functionality.The tests cover all major scenarios for the billing page including different membership states and payment history display. Good use of test helpers and Mirage models.
app/router.ts (1)
84-84
: LGTM: Clean addition of the billing routeThe addition of the billing route under settings is well-placed and follows the existing routing pattern. This aligns perfectly with the PR objective of adding a billing tab to the settings section.
tests/support/authentication-helpers.js (1)
63-69
: LGTM: Well-implemented VIP user authentication helperThe new helper function follows the same pattern as other authentication helpers in the file. It correctly sets the VIP status and expiration date, which will be useful for testing the billing features with different user states.
I've updated to test but window mock isn't working because it doesn't actually change the window location just opens the related app, but this should cover it decently |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added one round of comments + more detailed spec for the membership section
<div class="inline-flex items-center gap-2 rounded-full bg-teal-50 dark:bg-teal-900 px-2 py-1 border border-teal-500 dark:border-teal-400"> | ||
{{svg-jar "check-circle" class="h-5 w-5 text-teal-500"}} | ||
<div class="text-teal-500 font-semibold uppercase text-sm"> | ||
VIP Access + Membership Active |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is going to look pretty long & ugly - I'll share a spec on how to refine shortly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- If a user has an active membership
- Pill is green, says "Membership active"
- Text says "You have access to all CodeCrafters content, valid until XYZ"
- If (a) the user also has VIP access and (b) The VIP access date is longer than the subscription end date, let's keep the above text but cross it out and also say "🎉 You have VIP access to all CodeCrafters content, valid until XYZ".
- Else, If a user is VIP
- Pill is green, says "VIP Access"
- Text says "You have VIP access to...."
- Else, If a user has an expired subscription:
- Pill is red and says "Membership inactive"
- Else, if a user doesn't have any memberships, active or expired
- Pill is yellow and says "No membership found"
We won't use any icons inside the pills - rely solely on color and text to convey meaning.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me know if you think there any cases where this logic would result in confusion from the user's POV btw - can discuss
</p> | ||
</div> | ||
{{else if @user.hasActiveSubscription}} | ||
<div class="inline-flex items-center gap-2 rounded-full bg-teal-50 px-2 py-1 border border-teal-500 has-active-plan"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we still using has-active-plan
?
</PrimaryLinkButton> | ||
{{else}} | ||
<div class="inline-flex items-center gap-2 rounded-full bg-yellow-50 px-2 py-1 border border-yellow-500"> | ||
{{svg-jar "question-mark-circle" class="h-5 w-5 text-yellow-500"}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Arpan-206 the design for this didn't have SVGs if I'm not wrong, we were relying on just color & text to convey meaning
</div> | ||
{{else if @user.expiredSubscription}} | ||
<div class="inline-flex items-center gap-2 rounded-full bg-red-50 px-2 py-1 border border-red-500"> | ||
{{svg-jar "x-circle" class="h-5 w-5 text-red-500"}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as previous comment, we don't need SVGs here - the color & text is enough to convey the meaning we want, icons would just be distracting here
</div> | ||
{{else if this.errorMessage}} | ||
<div class="bg-red-50 dark:bg-red-900 border border-red-200 dark:border-red-400 rounded-md p-4"> | ||
<div class="flex"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<div class="flex"> | |
<div class="flex gap-3"> |
Instead of using ml-3
on the second child, prefer doing this instead - it's cleaner and prevents mistakes
<div class="bg-red-50 dark:bg-red-900 border border-red-200 dark:border-red-400 rounded-md p-4"> | ||
<div class="flex"> | ||
<div class="flex-shrink-0"> | ||
{{svg-jar "x-circle" class="h-5 w-5 text-red-400 dark:text-red-300"}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Arpan-206 this doesn't seem consistent - below I see text-red-700 dark:text-red-300
, and here it's text-red-400 dark:text-red-300
. Which are we going with?
Usually the direct inverse brightness works for dark mode (300 vs. 700, 800 vs 200), we've only had to make minor +/- 100 changes based on some situations so far.
</div> | ||
</div> | ||
{{else if (gt this.charges.length 0)}} | ||
<div class="grid grid-cols-3 gap-y-3" data-test-payment-history-section> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<div class="grid grid-cols-3 gap-y-3" data-test-payment-history-section> | |
<div class="grid grid-cols-3 gap-y-3"> |
(This can go in the outer FormSection component rather than be duplicated)
} | ||
|
||
export default class SupportSectionComponent extends Component<Signature> { | ||
get supportEmail() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Arpan-206 what is this used for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
tests/pages/settings/billing-page.ts (1)
4-24
: 🛠️ Refactor suggestionAdd missing renewalSection to the page object
There appears to be a
renewal-section
component in the application, but it's not represented in this page object.Add the renewalSection to the page object:
export default createPage({ membershipSection: { scope: '[data-test-membership-section]', }, paymentHistorySection: { charges: collection('[data-test-payment-history-item]', { amount: text('[data-test-amount]'), failed: hasClass('text-red-600'), }), scope: '[data-test-payment-history-section]', }, + renewalSection: { + scope: '[data-test-renewal-section]', + }, + supportSection: { clickOnContactButton: clickable('[data-test-support-contact-button]'), scope: '[data-test-support-section]', }, visit: visitable('/settings/billing'), });Make sure to add the appropriate
data-test-renewal-section
attribute to the renewal section component's template if it's not already there.🧰 Tools
🪛 ESLint
[error] 15-16: Delete
··⏎··
(prettier/prettier)
🧹 Nitpick comments (6)
tests/pages/settings/billing-page.ts (3)
4-7
: Consider adding properties to the membershipSectionThe
membershipSection
is currently only scoped but doesn't expose any properties for testing elements within this section. If there are membership status badges or other elements that need testing, consider adding them with appropriate data-test attributes.
9-16
: Remove extra whitespace on line 15There's unnecessary whitespace that should be removed to maintain consistent formatting.
charges: collection('[data-test-payment-history-item]', { amount: text('[data-test-amount]'), failed: hasClass('text-red-600'), }), scope: '[data-test-payment-history-section]', - },
🧰 Tools
🪛 ESLint
[error] 15-16: Delete
··⏎··
(prettier/prettier)
4-24
: Consider alphabetical ordering of page object sectionsFor better maintainability and consistency with other files, consider arranging the sections in alphabetical order.
export default createPage({ membershipSection: { scope: '[data-test-membership-section]', }, paymentHistorySection: { charges: collection('[data-test-payment-history-item]', { amount: text('[data-test-amount]'), failed: hasClass('text-red-600'), }), scope: '[data-test-payment-history-section]', }, + renewalSection: { + scope: '[data-test-renewal-section]', + }, + supportSection: { clickOnContactButton: clickable('[data-test-support-contact-button]'), scope: '[data-test-support-section]', }, visit: visitable('/settings/billing'), });🧰 Tools
🪛 ESLint
[error] 15-16: Delete
··⏎··
(prettier/prettier)
app/components/settings/billing-page/membership-section.hbs (3)
26-30
: Add dark mode support for VIP section badgeThe active subscription badge has dark mode classes but the VIP badge is missing them. For UI consistency, dark mode classes should be added to match other sections.
-<div class="inline-flex items-center gap-2 rounded-full bg-teal-50 px-2 py-1 border border-teal-500"> +<div class="inline-flex items-center gap-2 rounded-full bg-teal-50 dark:bg-teal-900 px-2 py-1 border border-teal-500 dark:border-teal-400">
42-46
: Add dark mode support for inactive membership badgeThe inactive membership badge is missing dark mode support classes. For consistency with the active membership section, dark mode classes should be added.
-<div class="inline-flex items-center gap-2 rounded-full bg-red-50 px-2 py-1 border border-red-500"> +<div class="inline-flex items-center gap-2 rounded-full bg-red-50 dark:bg-red-900 px-2 py-1 border border-red-500 dark:border-red-400">
61-65
: Add dark mode support for no membership badgeThe "No membership found" badge is missing dark mode support classes. For consistency across all membership status badges, dark mode classes should be added.
-<div class="inline-flex items-center gap-2 rounded-full bg-yellow-50 px-2 py-1 border border-yellow-500"> +<div class="inline-flex items-center gap-2 rounded-full bg-yellow-50 dark:bg-yellow-900 px-2 py-1 border border-yellow-500 dark:border-yellow-400">
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)
📒 Files selected for processing (6)
app/components/settings/billing-page/membership-section.hbs
(1 hunks)app/components/settings/billing-page/payment-history-section.hbs
(1 hunks)app/components/settings/billing-page/payment-history-section.ts
(1 hunks)app/components/settings/billing-page/support-section.ts
(1 hunks)tests/acceptance/settings-page/billing-test.js
(1 hunks)tests/pages/settings/billing-page.ts
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
- app/components/settings/billing-page/payment-history-section.hbs
- app/components/settings/billing-page/support-section.ts
- app/components/settings/billing-page/payment-history-section.ts
- tests/acceptance/settings-page/billing-test.js
🧰 Additional context used
🪛 ESLint
tests/pages/settings/billing-page.ts
[error] 15-16: Delete ··⏎··
(prettier/prettier)
🔇 Additional comments (2)
tests/pages/settings/billing-page.ts (1)
1-24
: Good foundation for the billing settings page object!The page object defines the basic structure needed for testing the billing page, with proper data-test selectors for the main sections.
🧰 Tools
🪛 ESLint
[error] 15-16: Delete
··⏎··
(prettier/prettier)
app/components/settings/billing-page/membership-section.hbs (1)
1-76
: Membership section looks good overallThe membership section correctly implements the requirements from previous review comments:
- Uses the proper conditional logic for different membership states
- Handles the interaction between membership and VIP status appropriately
- Uses color-coded badges and text to convey membership status
- Provides clear calls to action for users without active memberships
The implementation follows the design guidelines and addresses all the feedback from previous reviews.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added one more round of comments - think this can be the last, let's aim to wrap up and ship for the next review! Make sure to self-review in detail before opening for review, ensure that there are no inconsistencies.
Also, I still don't see the change where we remove the components used in the old membership page
<Settings::FormSection @title="Membership" @description="Your CodeCrafters membership details" data-test-membership-section> | ||
{{#if @user.hasActiveSubscription}} | ||
<div class="inline-flex items-center gap-2 rounded-full bg-teal-50 dark:bg-teal-900 px-2 py-1 border border-teal-500 dark:border-teal-400"> | ||
{{svg-jar "circle" class="h-5 w-5 text-teal-500"}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of svg let's just do HTML (h-5 w-5 rounded-full
), that's what we use for simple cases like this
{{/if}} | ||
</div> | ||
{{else if @user.isVip}} | ||
<div class="inline-flex items-center gap-2 rounded-full bg-teal-50 px-2 py-1 border border-teal-500"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Arpan-206 no dark mode styles. The same green pill above has different styles added.
Maybe you'd want to extract this into a component? Something like BillingPage::MembershipSection::StatusPill
?
Start membership → | ||
</PrimaryLinkButton> | ||
{{else}} | ||
<div class="inline-flex items-center gap-2 rounded-full bg-yellow-50 px-2 py-1 border border-yellow-500"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No dark mode styles (bg-yellow-50
will look extremely bright in dark mode)
@@ -0,0 +1,63 @@ | |||
<Settings::FormSection @title="Payment history" @description="Details of your previous payments" data-test-payment-history-section> | |||
{{#if this.isLoading}} | |||
<div class="flex justify-center py-8"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
app/components/settings/billing-page/payment-history-section.ts
Outdated
Show resolved
Hide resolved
@@ -0,0 +1,14 @@ | |||
<Settings::FormSection @title="Support" @description="How to get help with billing"> | |||
<a href="mailto:[email protected]?subject=Billing help (account: {{@user.username}})" class="inline-block rounded" data-test-support-section> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<a href="mailto:[email protected]?subject=Billing help (account: {{@user.username}})" class="inline-block rounded" data-test-support-section> | |
<a href="mailto:[email protected]?subject=Billing help (account: {{@user.username}})" class="inline-block rounded"> |
(Place on the outer FormSection
, to be consistent with other components)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This shouldn't be needed, just use HTML with rounded-full
await billingPage.visit(); | ||
|
||
assert.ok(billingPage.supportSection.isVisible, 'support section is visible'); | ||
assert.ok(billingPage.supportSection.clickOnContactButton, 'click on contact button'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't asserting anything clickOnContactButton
is a function and hence will always be truthy
|
||
assert.ok(billingPage.supportSection.isVisible, 'support section is visible'); | ||
assert.ok(billingPage.supportSection.clickOnContactButton, 'click on contact button'); | ||
assert.dom('[data-test-support-section]').hasAttribute('href', /^mailto:[email protected]/); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this just an attribute on the button? Why are we asserting against data-test-support-section
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, page objects do support checking attributes: https://ember-cli-page-object.js.org/docs/v2.3.x/api/attribute. So you could use that to define something like contactButtonLink
or contactButtonHref
Co-authored-by: Paul Kuruvilla <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (1)
tests/pages/settings/billing-page.ts (1)
4-23
: Add missing renewalSection to page objectThe billing page includes a renewal section component that needs test coverage, but it's missing from this page object.
#!/bin/bash # Verify the renewal section exists in the template rg -A 3 "data-test-renewal-section" --type hbsAdd a
renewalSection
entry to the page object, matching the structure of other sections:export default createPage({ membershipSection: { scope: '[data-test-membership-section]', }, + renewalSection: { + scope: '[data-test-renewal-section]', + }, + paymentHistorySection: { charges: collection('[data-test-payment-history-item]', { amount: text('[data-test-amount]'), failed: hasClass('text-red-600'), }), scope: '[data-test-payment-history-section]', },
🧹 Nitpick comments (3)
app/components/settings/billing-page/membership-section/status-pill.hbs (1)
15-15
: Fix trailing whitespace at end of fileThe file has a formatting issue - there's a trailing space at the end of the last line.
-</div> +</div>🧰 Tools
🪛 GitHub Actions: Test
[warning] Prettier formatting warning: Code style issues found. Run Prettier with --write to fix.
tests/pages/settings/billing-page.ts (1)
4-23
: Organize page object properties alphabeticallyPer project convention, properties in page objects should be arranged alphabetically.
export default createPage({ membershipSection: { scope: '[data-test-membership-section]', }, paymentHistorySection: { charges: collection('[data-test-payment-history-item]', { amount: text('[data-test-amount]'), failed: hasClass('text-red-600'), }), scope: '[data-test-payment-history-section]', }, supportSection: { scope: '[data-test-support-section]', contactButtonHref: attribute('href', '[data-test-support-contact-button]'), }, visit: visitable('/settings/billing'), });Should be organized as:
export default createPage({ membershipSection: { scope: '[data-test-membership-section]', }, paymentHistorySection: { charges: collection('[data-test-payment-history-item]', { amount: text('[data-test-amount]'), failed: hasClass('text-red-600'), }), scope: '[data-test-payment-history-section]', }, supportSection: { contactButtonHref: attribute('href', '[data-test-support-contact-button]'), scope: '[data-test-support-section]', }, visit: visitable('/settings/billing'), });tests/acceptance/settings-page/billing-test.js (1)
58-58
: Fix formatting for multi-line assertionThe assertion on line 58 needs to be formatted according to the project's Prettier configuration.
- assert.strictEqual(billingPage.supportSection.contactButtonHref, 'mailto:[email protected]?subject=Billing help (account: rohitpaulk)', 'contact button href is correct'); + assert.strictEqual( + billingPage.supportSection.contactButtonHref, + 'mailto:[email protected]?subject=Billing help (account: rohitpaulk)', + 'contact button href is correct', + );🧰 Tools
🪛 ESLint
[error] 58-58: Replace
billingPage.supportSection.contactButtonHref,·'mailto:[email protected]?subject=Billing·help·(account:·rohitpaulk)',·'contact·button·href·is·correct'
with⏎······billingPage.supportSection.contactButtonHref,⏎······'mailto:[email protected]?subject=Billing·help·(account:·rohitpaulk)',⏎······'contact·button·href·is·correct',⏎····
(prettier/prettier)
🪛 GitHub Actions: Test
[error] 58-58: Prettier formatting error: Replace line with properly formatted code. Run 'prettier --write' to fix.
[warning] Prettier formatting warning: Code style issues found. Run Prettier with --write to fix.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)
📒 Files selected for processing (19)
app/components/membership-page/actions-section.hbs
(0 hunks)app/components/membership-page/actions-section.js
(0 hunks)app/components/membership-page/membership-plan-section.hbs
(0 hunks)app/components/membership-page/membership-plan-section.js
(0 hunks)app/components/membership-page/payment-method-section.hbs
(0 hunks)app/components/membership-page/payment-method-section.js
(0 hunks)app/components/membership-page/recent-payments-section.hbs
(0 hunks)app/components/membership-page/recent-payments-section.js
(0 hunks)app/components/membership-page/section.hbs
(0 hunks)app/components/membership-page/section.js
(0 hunks)app/components/membership-page/upcoming-payment-section.hbs
(0 hunks)app/components/membership-page/upcoming-payment-section.js
(0 hunks)app/components/settings/billing-page/membership-section.hbs
(1 hunks)app/components/settings/billing-page/membership-section/status-pill.hbs
(1 hunks)app/components/settings/billing-page/payment-history-section.hbs
(1 hunks)app/components/settings/billing-page/payment-history-section.ts
(1 hunks)app/components/settings/billing-page/support-section.hbs
(1 hunks)tests/acceptance/settings-page/billing-test.js
(1 hunks)tests/pages/settings/billing-page.ts
(1 hunks)
💤 Files with no reviewable changes (12)
- app/components/membership-page/section.js
- app/components/membership-page/upcoming-payment-section.hbs
- app/components/membership-page/membership-plan-section.js
- app/components/membership-page/section.hbs
- app/components/membership-page/payment-method-section.hbs
- app/components/membership-page/upcoming-payment-section.js
- app/components/membership-page/recent-payments-section.js
- app/components/membership-page/payment-method-section.js
- app/components/membership-page/recent-payments-section.hbs
- app/components/membership-page/actions-section.js
- app/components/membership-page/actions-section.hbs
- app/components/membership-page/membership-plan-section.hbs
🚧 Files skipped from review as they are similar to previous changes (4)
- app/components/settings/billing-page/support-section.hbs
- app/components/settings/billing-page/payment-history-section.hbs
- app/components/settings/billing-page/membership-section.hbs
- app/components/settings/billing-page/payment-history-section.ts
🧰 Additional context used
🪛 GitHub Actions: Test
app/components/settings/billing-page/membership-section/status-pill.hbs
[error] 2-2: TS2339: Property 'variant' does not exist on type '{}'.
[error] 3-4: TS2339: Property 'variant' does not exist on type '{}'.
[error] 5-5: TS2345: Argument of type 'void' is not assignable to parameter of type 'Element'.
[error] 8-10: TS2339: Property 'variant' does not exist on type '{}'.
[error] 13-13: TS2345: Argument of type '"default"' and '[]' is not assignable to parameter of type 'never'.
[warning] Prettier formatting warning: Code style issues found. Run Prettier with --write to fix.
tests/acceptance/settings-page/billing-test.js
[error] 58-58: Prettier formatting error: Replace line with properly formatted code. Run 'prettier --write' to fix.
[warning] Prettier formatting warning: Code style issues found. Run Prettier with --write to fix.
🪛 ESLint
tests/acceptance/settings-page/billing-test.js
[error] 58-58: Replace billingPage.supportSection.contactButtonHref,·'mailto:[email protected]?subject=Billing·help·(account:·rohitpaulk)',·'contact·button·href·is·correct'
with ⏎······billingPage.supportSection.contactButtonHref,⏎······'mailto:[email protected]?subject=Billing·help·(account:·rohitpaulk)',⏎······'contact·button·href·is·correct',⏎····
(prettier/prettier)
🔇 Additional comments (1)
tests/acceptance/settings-page/billing-test.js (1)
59-59
: Add window mock test for contact buttonThe test verifies the href attribute but doesn't test the actual click behavior.
Since this is a mailto link, add a test using ember-window-mock to verify that clicking the button triggers the expected behavior:
test('clicking support contact button opens email client', async function (assert) { testScenario(this.server); signInAsSubscriber(this.owner, this.server); await billingPage.visit(); await billingPage.supportSection.clickOnContactButton(); // Assert that window.location would have changed to the mailto link const window = this.owner.lookup('service:window'); assert.true( window.location.href.includes('mailto:[email protected]'), 'email client should open with correct recipient' ); });You'll need to add a
clickOnContactButton
action to the supportSection in the page object.🧰 Tools
🪛 GitHub Actions: Test
[warning] Prettier formatting warning: Code style issues found. Run Prettier with --write to fix.
Checklist:
[percy]
in the message to trigger)Summary by CodeRabbit
New Features
Bug Fixes
Chores
/membership
to/settings/billing
.Tests