Skip to content

Component Name: myBusinessAccount

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

API Name: c-myBusinessAccount Type: Page Component Target: lightningCommunity__Page, lightningCommunity__Default, lightning__AppPage, lightning__RecordPage

Business Purpose

This component provides a comprehensive business account management interface for AANP business/corporate members. It allows business account holders to view and update their account information, manage contact details, view orders and receipts, handle data sharing agreements with AANPCB, and manage subscriptions.

User Interface

Visual Description

  • Layout: Single-column responsive layout with expandable accordion sections
  • Key UI Elements: Avatar with photo upload, collapsible information sections, modal dialogs for editing, form inputs with validation
  • Responsive: Fully responsive design adapting from mobile (stacked) to desktop (side-by-side) layouts

Screenshots

  • Desktop view: Full-width accordion with side-by-side field display
  • Mobile view: Stacked layout with full-width sections

Component Structure

Files

  • myBusinessAccount.html - Template/markup
  • myBusinessAccount.js - JavaScript controller (1078 lines)
  • myBusinessAccount.js-meta.xml - Metadata configuration
  • phoneCountryCodes.js - Phone country code mapping utility

HTML Template Structure

<template>
    <section class="container my-account-container">
        <div class="bg-white box">
            <div class="avatar"><!-- Profile photo --></div>
            <h2>Account Name</h2>
            <div>Membership Type and Dues Info</div>
        </div>

        <!-- Accordion Sections -->
        <div class="accordion-item" data-tab="myAccount">
            <!-- My Account Information -->
        </div>
        <div class="accordion-item" data-tab="myAddresses">
            <!-- My Addresses & Phone -->
        </div>
        <div class="accordion-item" data-tab="myOrders">
            <!-- My Orders/Receipts -->
        </div>

        <!-- Modals for editing -->
        <div class="modal" data-id="addCredentials">...</div>
        <div class="modal" data-id="updateDataSharingAgreement">...</div>
        <div class="modal" data-id="addPreferredAddress">...</div>
        <div class="modal" data-id="editPhone">...</div>
    </section>
</template>

Key Template Features: - Conditional rendering with lwc:if for showing/hiding sections - Multiple modal dialogs for different edit operations - Integration with child components (c-my-np-profile-display-field, c-my-np-profile-edit-modal, c-intl-tel-input, c-form-input, c-my-orders-receipts-tab) - File input for photo upload - Country/state picklist fields with dependent logic

JavaScript Controller

Properties (API)

@api userInfo

  • Type: Object
  • Required: No
  • Default: undefined
  • Description: User information object (can be passed in but also loaded via wire)

Example Usage:

<c-my-business-account user-info={userInfo}></c-my-business-account>


@api accountType

  • Type: String
  • Required: No
  • Default: 'Person'
  • Description: Type of account being displayed (defaults to Person but component is designed for Business accounts)

Tracked Properties

@track accountInfo

  • Type: Object
  • Purpose: Stores all account field values for display and editing
  • Updated When: On load from wire, and after successful updates

@track isLoading

  • Type: Boolean
  • Purpose: Controls loading spinner display during save operations
  • Updated When: Set to true before Apex calls, false after completion

@track basePath

  • Type: String
  • Purpose: Stores community base path for navigation
  • Updated When: Set in connectedCallback

Wire Adapters

@wire(getUserInfo, {"accountType":"business"})

@wire(getUserInfo,{"accountType":"business"})
wiredUserInfo({ error, data }) {
    if (data) {
        this.currentUser = data;
        this.userInfoLoaded = true;
        this.initializeComponentProperties();
    }
}

Purpose: Retrieves current user and account information for business accounts Fields Retrieved: Full Account object with all business account fields Error Handling: Logs errors to console, sets userInfoLoaded flag


@wire(getObjectInfo, { objectApiName: ACCOUNT_OBJECT })

@wire(getObjectInfo, { objectApiName: ACCOUNT_OBJECT })
handleObjectInfo({ error, data }) {
    // Retrieves Business Account record type ID
}

Purpose: Gets Account object metadata to find Business Account record type Error Handling: Logs to console


@wire(getPicklistValues, { recordTypeId: "$accountRecordTypeId", fieldApiName: COUNTRY_CODE_FIELD })

@wire(getPicklistValues, { recordTypeId: '$accountRecordTypeId', fieldApiName: COUNTRY_CODE_FIELD })
wiredCountryPicklistValues({ error, data }) {
    // Loads and sorts country picklist values
}

Purpose: Loads country picklist values with US and CA prioritized Error Handling: Logs errors to console


@wire(getPicklistValues, { recordTypeId: "$accountRecordTypeId", fieldApiName: STATE_CODE_FIELD })

@wire(getPicklistValues, { recordTypeId: "$accountRecordTypeId", fieldApiName: STATE_CODE_FIELD })

Purpose: Loads state/province picklist values Dependencies: Depends on country selection


@wire(getPicklistValues, { recordTypeId: "$accountRecordTypeId", fieldApiName: NUMBER_OF_INDIVIDUALS_FIELD })

@wire(getPicklistValues, { recordTypeId: "$accountRecordTypeId", fieldApiName: NUMBER_OF_INDIVIDUALS_FIELD })
numberOfIndividualsResults({ error, data }) {
    // Loads Number of Individuals picklist
}

Purpose: Loads picklist values for Number of Individuals field Error Handling: Sets undefined on error


@wire(getProductCategoryIdByName, { categoryName: 'Communities' })

@wire(getProductCategoryIdByName, { categoryName: 'Communities' })
wiredCategory({ error, data }) {
    // Gets Communities category ID for navigation
}

Purpose: Retrieves product category ID for Communities to enable navigation Error Handling: Logs errors to console


Public Methods

None - component does not expose public methods


Event Handlers

toggleSection

toggleSection(event) {
    const sectionId = event.currentTarget.dataset.tab;
    // Expands/collapses accordion sections
}

Triggered By: Click on accordion header Event Type: click Event Detail: dataset.tab contains section ID Action: Toggles max-height CSS and arrow rotation


openModal

openModal(event) {
    const itemId = event.currentTarget.dataset.item;
    // Opens specific modal dialog
}

Triggered By: Click on edit buttons Event Type: click Event Detail: dataset.item contains modal ID Action: Shows modal and backdrop


closeModal

closeModal(event) {
    const buttonId = event.currentTarget.dataset.close;
    // Closes specific modal dialog
}

Triggered By: Click on cancel/close buttons Event Type: click Event Detail: dataset.close contains modal ID Action: Hides modal and backdrop


handleFileChange

handleFileChange(event) {
    const file = event.target.files[0];
    // Converts file to base64 and uploads
}

Triggered By: File input change Event Type: change Event Detail: File object Action: Reads file, converts to base64, calls uploadFile()


handleInputChange

handleInputChange(event) {
    const value = event.target?.value;
    this.accountInfo[event.target.name] = value;
}

Triggered By: Input field changes Event Type: change Event Detail: Input value Action: Updates accountInfo tracked property


handleCustomInputChange

handleCustomInputChange(event) {
    const { fieldName, value } = event.detail;
    // Handles custom input component events
}

Triggered By: Custom c-form-input component Event Type: inputchange (custom) Event Detail: { fieldName, value } Action: Updates accountInfo, handles multi-line address fields


handleAddressChangeSubmit

handleAddressChangeSubmit(event) {
    event.preventDefault();
    // Validates and saves address changes
}

Triggered By: Address form submission Event Type: submit Action: Validates form, calls upsertAccount, closes modal


handleEditPhoneSubmit

handleEditPhoneSubmit(event) {
    event.preventDefault();
    // Validates and saves phone changes
}

Triggered By: Phone form submission Event Type: submit Action: Validates phone number, calls upsertAccount, closes modal


handleCredentialsSubmit

handleCredentialsSubmit(event) {
    event.preventDefault();
    // Saves credentials
}

Triggered By: Credentials form submission Event Type: submit Action: Calls upsertAccount with credentials, closes modal


handleCountryChange

handleCountryChange(event) {
    // Updates country and resets state options
}

Triggered By: Country combobox selection Event Type: change Event Detail: Selected country code Action: Updates state options, determines if state is required


optInDataSharingAgreement

optInDataSharingAgreement() {
    // Opts user into AANPCB data sharing
}

Triggered By: Button click in data sharing modal Event Type: click Action: Updates Account with opt-in, timestamp, and version


optOutDataSharingAgreement

optOutDataSharingAgreement() {
    // Opts user out of AANPCB data sharing
}

Triggered By: Button click in opt-out modal Event Type: click Action: Updates Account with opt-out, timestamp, and version


Private Methods

initializeComponentProperties

Purpose: Initializes component data from currentUser Called By: wiredUserInfo after successful data load


mapAccountData

Purpose: Maps Account fields to accountInfo tracked property Called By: initializeComponentProperties


handleImage

Purpose: Decodes and displays account photo from Photo__c field Called By: initializeComponentProperties after file server URL is retrieved


decodeImageFromRecord

Purpose: Extracts image URL from Photo__c HTML field Called By: Internal helper


uploadFile

Purpose: Uploads selected profile photo to server Called By: handleFileChange after file is converted to base64


refreshPage

Purpose: Reloads entire page after photo upload Called By: uploadFile after successful upload


displayToastMessage

Purpose: Shows toast notification Called By: Various methods for success/error feedback


validateChangeAddressForm

Purpose: Validates all form inputs in address change modal Called By: handleAddressChangeSubmit


validateComboboxes

Purpose: Validates country and state combobox selections Called By: Internal validation logic


validatePhoneNumber

Purpose: Validates phone number using c-intl-tel-input component Called By: handleEditPhoneSubmit


toggleBackdrop

Purpose: Shows/hides modal backdrop Called By: openModal, closeModal


saveInfo

Purpose: Generic save handler for profile edit modal Called By: onsaveinfo event from c-my-np-profile-edit-modal


closeModalByDataClose

Purpose: Closes modal by data-close ID Called By: saveInfo after successful save


toggleSectionById

Purpose: Toggles specific accordion section by ID Called By: saveInfo to recalculate section height after data update


Events

Events Dispatched

None - component does not dispatch custom events to parent


Events Handled

oninputchange (from c-form-input)

Source: c-form-input child component Purpose: Captures field value changes Handler: handleCustomInputChange


onsaveinfo (from c-my-np-profile-edit-modal)

Source: c-my-np-profile-edit-modal child component Purpose: Saves edited field value Handler: saveInfo


onclosemodal (from c-my-np-profile-edit-modal)

Source: c-my-np-profile-edit-modal child component Purpose: Closes edit modal Handler: closeModal


onphonechange (from c-intl-tel-input)

Source: c-intl-tel-input child component Purpose: Captures phone number changes and validation state Handler: handleInputPhone


Styling (CSS)

CSS Variables Used

Not applicable - uses external stylesheets

Custom CSS Classes

  • .my-account-container: Main container
  • .avatar-icon: Avatar circle with initials or photo
  • .accordion-item: Collapsible section header
  • .description: Collapsible section content
  • .arrow: Chevron icon that rotates
  • .modal-backdrop: Modal overlay
  • Various Bootstrap utility classes

SLDS Classes

  • Lightning combobox uses SLDS internally
  • .slds-combobox__form-element

Responsive Breakpoints

  • Mobile (<768px): Stacked layout, full-width buttons
  • Tablet (768-1024px): Mixed layout
  • Desktop (>1024px): Side-by-side field display

Dependencies

Lightning Web Components (Base)

  • lightning-icon
  • lightning-combobox
  • lightning-spinner
  • lightning-formatted-number

Custom LWC Components

  • c-my-np-profile-display-field: Displays field with edit button
  • c-my-np-profile-edit-modal: Reusable edit modal
  • c-form-input: Custom form input with validation
  • c-intl-tel-input: International phone number input with validation
  • c-my-orders-receipts-tab: Orders and receipts display

Apex Classes

  • AccountController.getUserInfo(): Gets user and account info
  • AccountController.getFileServerUrl(): Gets file server base URL
  • AccountController.uploadImage(): Uploads profile photo
  • AccountController.updateUserEmail(): Updates user email
  • AccountController.upsertAccount(): Saves account changes
  • CategoryController.getProductCategoryIdByName(): Gets category ID

Salesforce Objects & Fields

  • Account: Full business account object
  • BillingStreet, BillingCity, BillingStateCode, BillingCountryCode, BillingPostalCode
  • Business_Main_Email__c, Phone, Phone_Type__c
  • Name, Number_of_Individuals__c, Credentials__c
  • Photo__c, Member_Type__c, Membership_End_Date__c
  • DataSharing_Agreement__c, DataSharing_ArgreementVersion__c, DataSharing_Acceptance_Date__c
  • Exclude_From_Third_Party_Solicitations__c, Business_Region_Territory__c
  • Preferred_Method_of_Communication_Text__c

Static Resources

None

Labels

  • c.AANP_CE_ACTIVITY_URL
  • c.AANP_CE_CENTER_URL
  • c.AANP_CE_TRACKER_URL
  • c.AANP_CE_OPPORTUNITIES_URL
  • c.AANP_CE_EVAL_URL

Configuration

Component Meta XML

<targets>
    <target>lightningCommunity__Page</target>
    <target>lightningCommunity__Default</target>
    <target>lightning__AppPage</target>
    <target>lightning__RecordPage</target>
</targets>

Available On: - Community Page - Community Default - App Page - Record Page

Design Properties

None - no configurable properties in App Builder

User Interactions

Actions Available to Users

  1. Upload Profile Photo:
  2. Trigger: Click on avatar area, select file
  3. Result: Photo uploads and displays immediately, page refreshes

  4. Edit Business Name:

  5. Trigger: Click "Change Name" link
  6. Result: Opens modal with text input, validates on save

  7. Edit Number of Individuals:

  8. Trigger: Click "Change number of Individuals" link
  9. Result: Opens modal with picklist, saves selection

  10. Change Email Address:

  11. Trigger: Click "Change Email Address" link
  12. Result: Opens modal, validates email format, sends verification

  13. Change Business Address:

  14. Trigger: Click "Change Company Address" link
  15. Result: Opens modal with full address form, validates country/state dependency

  16. Edit Phone Number:

  17. Trigger: Click "Change my Phone Number" or "Add my Phone Number"
  18. Result: Opens modal with international phone input, validates format

  19. Manage Data Sharing Agreement:

  20. Trigger: Click data sharing links
  21. Result: Opens modal explaining AANPCB data sharing, allows opt-in/opt-out

  22. View Orders/Receipts:

  23. Trigger: Expand "My Orders/Receipts" accordion
  24. Result: Loads and displays c-my-orders-receipts-tab component

  25. Expand/Collapse Sections:

  26. Trigger: Click accordion headers
  27. Result: Animates section height, rotates chevron

Validation & Error Handling

Client-Side Validation: - Email format validation using regex pattern - Phone number format using c-intl-tel-input component - Required field validation on all inputs - Country-dependent state validation (US/CA require state) - Form input validation via c-form-input components

Error Messages: - Email update: "Error updating email, please try again." - Image upload: "Image upload failed" - Generic: "Form is invalid, please correct the errors." - Country/State validation: "Country is required." / "State is required."

Loading States: - Spinner shown during: photo upload, email update, phone update, address update, data sharing updates - Modal remains open during save with spinner in button

Data Flow

Input Data Flow

Wire Adapters
wiredUserInfo → currentUser
initializeComponentProperties → mapAccountData
accountInfo (tracked) → Template binding
Display to user

Output Data Flow

User edits field
Modal opens → User enters data
handleXXXSubmit validation
upsertAccount Apex call
Success → close modal, refresh wire if needed

Performance Considerations

Render Optimization: - Uses getters for computed values (homeAddressClass, workAddressClass, etc.) - Conditional rendering with lwc:if to reduce DOM size - Accordion collapses unused sections

Data Volume: - Max records displayed: N/A (single account) - No pagination needed

API Call Optimization: - Wire adapters cache data automatically - File upload refreshes entire page (could be optimized to refresh wire instead) - Multiple picklist wires load in parallel

Accessibility (a11y)

ARIA Labels: - Modal dialogs have aria-label on close buttons - Form inputs have associated labels

Keyboard Navigation: - Tab order follows natural DOM flow - Modal dialogs trap focus - All interactive elements keyboard accessible

Screen Reader Support: - Labels properly associated with inputs - Error messages announced when displayed - Modal title announced when opened

Color Contrast: - Passes WCAG AA: Needs verification with accessibility tool

Testing

Jest Tests

Test File: None Coverage: 0%

Test Scenarios: - ✗ No tests currently exist

Manual Testing Checklist

  • [ ] Desktop browser (Chrome, Firefox, Safari)
  • [ ] Mobile browser (iOS Safari, Android Chrome)
  • [ ] Salesforce Mobile App
  • [ ] Tablet view
  • [ ] Accessibility (screen reader, keyboard-only)
  • [ ] Business Account user profile/permissions
  • [ ] Photo upload with various file types and sizes
  • [ ] All modal interactions
  • [ ] Country/state dependency logic
  • [ ] Data sharing opt-in/opt-out workflow
  • [ ] Email update verification workflow

Usage Examples

In App Builder

  1. Add to Community page as full-width component
  2. No configuration needed
  3. Component automatically loads current user's business account

In Parent Component

<!-- Basic usage on community page -->
<c-my-business-account></c-my-business-account>

<!-- With account type specified -->
<c-my-business-account account-type="Business"></c-my-business-account>

Programmatic Access

Not applicable - component does not expose public methods

Changes & History

  • 2025-09-29: Latest changes to business account management
  • Component appears to be actively maintained

⚠️ Pre-Go-Live Concerns

CRITICAL - Fix Before Go-Live

  • Missing error handling on uploadImage: Photo upload fails silently with generic message, no retry mechanism
  • Security: Passwords logged to console: Line 229 logs accountData which may contain sensitive info
  • Full page refresh on photo upload: Very poor UX, should refresh wire data instead
  • No loading state during photo upload: User has no feedback until page refreshes
  • Missing null checks: handleImage assumes Photo__c has specific format (line 285-311)
  • Email update doesn't refresh UI: Success message shown but displayed email doesn't update until manual refresh

HIGH - Address Soon After Go-Live

  • No unit tests: Component has 1078 lines with zero test coverage
  • Phone validation not re-validated on modal open: User could have invalid phone from previous session
  • State picklist wire adapter incomplete: Line 685 has incomplete @wire definition
  • Address parsing brittle: Multi-line address split by comma (lines 249-263) breaks for addresses with commas in street names
  • Modal backdrop z-index issues: No z-index management for multiple modals
  • Memory leak potential: Event listeners added in renderedCallback (lines 581-589) never removed

MEDIUM - Future Enhancement

  • Add address validation service: Validate addresses against USPS or similar
  • Add photo cropping: Allow users to crop/resize before upload
  • Better error messages: More specific error messages for validation failures
  • Add undo/cancel: Changes are saved immediately, no undo option
  • Optimize re-renders: Component re-renders entire tree on any field change
  • Add field-level save: Currently modals save one field at a time, could batch
  • Loading skeleton: Show skeleton UI instead of blank during initial load

LOW - Monitor

  • Unused imports: Several imports may not be used (CE_ACTIVITY_URL labels, etc.)
  • Console.log statements: Many console.log statements in production code (lines 229, 243, etc.)
  • Magic numbers: Data sharing agreement version hardcoded (line 27)
  • Inconsistent error handling: Some methods use try/catch, others use .catch(), others have no error handling
  • Code duplication: phoneCellClass, phoneWorkClass, phoneHomeClass follow same pattern (lines 891-910)

Maintenance Notes

Complexity: High Recommended Review Schedule: Quarterly

Key Maintainer Notes: - Component manages critical business account data including AANPCB data sharing agreements - Photo upload uses custom file server URL - ensure file server remains accessible - Country/state dependency logic is fragile - test thoroughly when updating - Component used on main business account page - any bugs affect all business members - Address parsing splits on commas - document this limitation for users with complex addresses - Phone number validation depends on c-intl-tel-input component - breaking changes there affect this component - Data sharing agreement version is hardcoded - update when agreement version changes (DATA_SHARING_AGREEMENT_VERSION constant)

Browser Compatibility: - Chrome: Latest - Firefox: Latest - Safari: Latest - Mobile: iOS 12+, Android 8+ - IE11: Not supported (uses modern JavaScript)