Skip to content

Component Name: subscriptions

Last Updated: 2025-09-29 Source Code: https://bitbucket.org/i2cinc/i2c.salesforce.metadata/src/STAGING/force-app/main/default/lwc/subscriptions

API Name: c-subscriptions Type: Form/Display Component Target: Not exposed (embedded in parent components)

Business Purpose

This component displays and manages a user's active subscriptions, allowing them to view renewal dates, amounts, and cancel future auto-renewals. It enforces a 90-day restriction preventing cancellation of newly-purchased subscriptions. Used within account management interfaces to give members control over their recurring purchases.

User Interface

Visual Description

  • Layout: Modal dialog with subscription list
  • Key UI Elements: "View My Subscriptions" link, modal with subscription table, checkboxes, cancel button
  • Responsive: Modal adapts to screen size

Component Structure

Files

  • subscriptions.html - Template (83 lines)
  • subscriptions.js - Controller (160 lines)
  • subscriptions.js-meta.xml - Metadata (not exposed)

HTML Template Structure

<template>
    <div class="row">
        <a onclick={openModal} data-item="subscriptions">View My Subscriptions</a>
    </div>

    <div class="modal" data-id="subscriptions">
        <div class="modal-dialog">
            <div class="modal-header">
                <h5>My Subscriptions</h5>
                <button onclick={closeModal}>Close</button>
            </div>

            <div class="modal-body">
                <template lwc:if={isLoading}>
                    <lightning-spinner />
                </template>

                <template lwc:elseif={showSubscriptions}>
                    <template if:true={subscriptions.length}>
                        <div for:each={subscriptions}>
                            <input type="checkbox" onchange={handleSubscriptionSelection}
                                   disabled={subscription.preventCancel} />
                            <strong>Product:</strong> {subscription.ProductName}
                            <strong>Renewal Date:</strong> {subscription.EndtDate}
                        </div>

                        <button onclick={handleCancelSubscription}>
                            Cancel Future Auto-Renewal(s)
                        </button>

                        <div if:true={showErrorMessage} class={messageClass}>
                            {messageText}
                        </div>
                    </template>

                    <template if:false={subscriptions.length}>
                        <p>You don't have any subscriptions.</p>
                    </template>
                </template>
            </div>
        </div>
    </div>
</template>

Key Template Features: - Modal dialog pattern with backdrop - Lightning spinner during loading/operations - Checkboxes with preventCancel logic (90-day restriction) - Alert messages for user feedback - Conditional rendering for empty state

JavaScript Controller

Properties (API)

@api accountId

  • Type: String
  • Required: Yes
  • Description: Account ID to load subscriptions for

@api refreshData()

  • Type: Function
  • Returns: Promise
  • Description: Public method to refresh subscription data

Tracked Properties

@track selectedSubscriptions

  • Type: Set
  • Purpose: Tracks which subscriptions user has selected for cancellation

@track showErrorMessage, messageClass, messageText

  • Type: Boolean, String, String
  • Purpose: Controls display and styling of user feedback messages

isLoading

  • Type: Boolean
  • Purpose: Shows/hides loading spinner

Wire Adapters

@wire(getActiveSubscriptions, {accountId: '$accountId'})

@wire(getActiveSubscriptions, {accountId: '$accountId'})
wiredSubscriptions(response) {
    this.subscriptionsResponse = response;
    if(response.data) {
        this.subscriptions = response.data.map((subscription) => ({
            Id, ProductName, StartDate, EndtDate, formattedAmount,
            preventCancel: this.computePreventCancel(subscription.Start_Date__c)
        }));
    }
}

Purpose: Loads active subscriptions for account Fields Retrieved: Subscription with Product, dates, Order Product price Error Handling: Logs to console


Event Handlers

handleSubscriptionSelection(event)

Triggered By: Checkbox change Action: Adds/removes subscription from selectedSubscriptions Set

handleCancelSubscription()

Triggered By: Click "Cancel Future Auto-Renewal(s)" button Action: Validates selection, calls cancelSubscriptions Apex, refreshes data

openModal(event) / closeModal(event)

Triggered By: Click link/button Action: Shows/hides modal and backdrop


Private Methods

computePreventCancel(startRaw)

Purpose: Calculates if subscription is within 90-day restriction Returns: Boolean (true if within 90 days) Logic: Compares subscription.Start_Date__c to today

formatDate(dateString)

Purpose: Formats date as "DD Mon YYYY" (e.g., "15 Jan 2025") Returns: Formatted string

getCurrencySymbol(currencyIsoCode)

Purpose: Maps currency codes to symbols Returns: Currency symbol (e.g., "$", "€")

showMessage(type, message)

Purpose: Displays alert message for 8 seconds Parameters: type ("alert-warning"), message (String)

toggleModalVisibility(modal, isVisible)

Purpose: Shows/hides modal and backdrop


Events

None dispatched to parent

Styling (CSS)

Custom CSS Classes

  • .cancel-subscription-btn-bg: Cancel button styling
  • .order-row: Subscription row styling
  • .alert, .alert-warning: Alert message styling
  • .spinner-section: Loading spinner positioning
  • .my-sybscriptions-link: Link styling

SLDS Classes

  • slds-backdrop, slds-backdrop_open: Modal backdrop

Dependencies

Lightning Web Components (Base)

  • lightning-spinner

Custom LWC Components

None

Apex Classes

  • SubscriptionController.getActiveSubscriptions(): Returns active subscriptions
  • SubscriptionController.cancelSubscriptions(): Cancels selected subscriptions

Salesforce Objects & Fields

  • Subscription__c: Product__c, Start_Date__c, Renew_On__c, Order_Product__r.TotalPrice, etc.
  • Chargent_Order__c: ChargentOrders__Next_Scheduled_Payment__c

Configuration

Not exposed - embedded component

User Interactions

Actions Available to Users

  1. View Subscriptions:
  2. Trigger: Click "View My Subscriptions" link
  3. Result: Opens modal with subscription list

  4. Select Subscriptions to Cancel:

  5. Trigger: Check checkboxes (if not within 90-day restriction)
  6. Result: Adds to selection

  7. Cancel Future Auto-Renewals:

  8. Trigger: Click "Cancel Future Auto-Renewal(s)" button
  9. Result: Cancels selected subscriptions, refreshes list, shows confirmation

Validation & Error Handling

Client-Side Validation: - Prevents cancellation within 90 days of purchase (preventCancel flag) - Requires at least one subscription selected

Error Messages: - "Please select at least one subscription." (if none selected) - Apex errors logged to console, may show blank on failure

Loading States: - Spinner during initial load - Spinner during cancellation operation - Disabled backdrop prevents interaction during loading

Data Flow

Input Data Flow

accountId from parent
@wire getActiveSubscriptions
Map to subscription objects with preventCancel
Display in modal

Output Data Flow

User selects subscriptions
handleCancelSubscription
cancelSubscriptions Apex
refreshApex(subscriptionsResponse)
List updates automatically

Performance Considerations

  • Uses @wire for automatic caching
  • refreshApex reuses wire cache (efficient)
  • Set data structure for O(1) selection lookups

Accessibility (a11y)

ARIA Labels: - Modal needs aria-modal, aria-labelledby attributes - Checkboxes need labels (currently only visual)

Keyboard Navigation: - Modal trap focus needs implementation - Checkboxes keyboard accessible

Screen Reader Support: - Modal title announced - Checkbox labels needed - Alert messages announced (auto-dismisses may be too fast)

Color Contrast: - Depends on custom CSS classes

Testing

Jest Tests

None

Manual Testing Checklist

  • [ ] Subscriptions load correctly
  • [ ] 90-day restriction prevents cancellation
  • [ ] Multiple selections work
  • [ ] Cancellation succeeds
  • [ ] Empty state displays
  • [ ] Loading states show
  • [ ] Error messages display
  • [ ] Auto-dismissal timing
  • [ ] Modal open/close
  • [ ] Refresh after cancellation

Usage Examples

In Parent Component

<!-- In account management component -->
<c-subscriptions account-id={accountId}></c-subscriptions>

Programmatic Refresh

// In parent component
const subsComponent = this.template.querySelector('c-subscriptions');
await subsComponent.refreshData();

Changes & History

  • 2025-09-29: Latest version

⚠️ Pre-Go-Live Concerns

CRITICAL - Fix Before Go-Live

  • 90-day calculation uses local time: computePreventCancel (lines 76-88) uses Date() which varies by timezone - should use UTC
  • No confirmation dialog: Users can accidentally cancel subscriptions with one click
  • No undo: Once cancelled, no way to undo (before closing modal)

HIGH - Address Soon After Go-Live

  • No unit tests: Zero coverage for business-critical cancellation logic
  • Checkbox labels missing: Accessibility violation - checkboxes have no associated labels
  • Modal not accessible: Missing aria-modal, aria-labelledby, focus trap
  • Error handling weak: Apex errors don't show user-friendly messages
  • Alert auto-dismisses: 8-second timeout may be too fast for users to read (line 126-128)

MEDIUM - Future Enhancement

  • Add cancellation reason: Collect feedback on why cancelling
  • Add pause option: Allow pausing instead of cancelling
  • Show cancellation effective date: Clarify when renewal stops
  • Add reactivation: Allow un-cancelling within grace period
  • Bulk actions: Select all/deselect all checkboxes

LOW - Monitor

  • Currency symbol hardcoded: getCurrencySymbol supports limited currencies
  • Date format hardcoded: "en-GB" format may not suit all locales
  • Console.log statements: Lines 112, 124 log to console
  • Commented-out code: Lines 45, 54-57 have commented JSX

Maintenance Notes

Complexity: Medium Recommended Review Schedule: Quarterly

Key Maintainer Notes: - CRITICAL: 90-day restriction calculation must account for timezones - Component manages auto-renewal cancellations - very sensitive user action - No confirmation dialog - users can accidentally cancel with one click - Cancellation is permanent within this UI (no undo) - preventCancel logic prevents cancellation within 90 days of Start_Date__c - Refresh uses refreshApex which is efficient (reuses wire cache) - Modal visibility managed via CSS classes and backdrop div - selectedSubscriptions uses Set for efficient lookups - Alert messages auto-dismiss after 8 seconds - Component embedded in parent (not standalone page) - Consider adding analytics to track cancellation rates

Browser Compatibility: - Chrome: Latest - Firefox: Latest - Safari: Latest - Mobile: iOS 12+, Android 8+