Skip to content

@W-20975885 New launch agent location in header component#3606

Merged
sf-tejas-nadkarni merged 8 commits intodevelopfrom
W-20975885-new-launch-agent-header-component
Jan 30, 2026
Merged

@W-20975885 New launch agent location in header component#3606
sf-tejas-nadkarni merged 8 commits intodevelopfrom
W-20975885-new-launch-agent-header-component

Conversation

@sf-tejas-nadkarni
Copy link
Collaborator

@sf-tejas-nadkarni sf-tejas-nadkarni commented Jan 23, 2026

Adds a configurable header button to launch the shopper agent, refactors shopper agent utilities for simplicity, and includes unit tests

Description

  1. Header Component - Agent Button Integration
    File: app/components/header/index.jsx
    Description: Added conditional rendering of the SparkleIcon button in the header based on the enableLaunchAgentFromHeader configuration flag. The button triggers the shopper agent chat when clicked. Integrated with getCommerceAgentConfig utility for centralized configuration management.

  2. Configuration Utility Enhancement
    File: app/utils/config-utils.js
    Description: Added getCommerceAgentConfig() utility function to centralize access to commerce agent configuration settings. Added enableLaunchAgentFromHeader to the default configuration options, providing a single source of truth for commerce agent settings across the application.

  3. App Component - Agent Click Handler
    File: app/components/_app/index.jsx
    Description: Added onAgentClick handler that calls openShopperAgent() to programmatically open the shopper agent chat window when the header button is clicked.

Types of Changes

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Documentation update
  • Breaking change (could cause existing functionality to not work as expected)
  • Other changes (non-breaking changes that does not fit any of the above)

Breaking changes include:

  • Removing a public function or component or prop
  • Adding a required argument to a function
  • Changing the data type of a function parameter or return value
  • Adding a new peer dependency to package.json

Changes

  • Header Component - Agent Button Integration
  • Configuration Utility Enhancement
  • App Component - Agent Click Handler

How to Test-Drive This PR

Header.Launch.Location.mov

Checklists

General

  • Changes are covered by test cases
  • CHANGELOG.md updated with a short description of changes (not required for documentation updates)

Accessibility Compliance

You must check off all items in one of the follow two lists:

  • There are no changes to UI

or...

Localization

  • Changes include a UI text update in the Retail React App (which requires translation)

@sf-tejas-nadkarni sf-tejas-nadkarni requested a review from a team as a code owner January 23, 2026 17:45
@cc-prodsec
Copy link
Collaborator

cc-prodsec commented Jan 23, 2026

Snyk checks have passed. No issues have been found so far.

Status Scanner Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@sf-tejas-nadkarni sf-tejas-nadkarni force-pushed the W-20975885-new-launch-agent-header-component branch from 175a224 to 742b72f Compare January 23, 2026 18:18
@sf-tejas-nadkarni sf-tejas-nadkarni added the skip changelog Skip the "Changelog Check" GitHub Actions step even if the Changelog.md files are not updated label Jan 23, 2026
@sf-tejas-nadkarni sf-tejas-nadkarni force-pushed the W-20975885-new-launch-agent-header-component branch from 742b72f to 4c89336 Compare January 23, 2026 18:41
feat: update the condition to avoid fab enable permission

feat: update files
@sf-tejas-nadkarni sf-tejas-nadkarni force-pushed the W-20975885-new-launch-agent-header-component branch from 4c89336 to 2081fa1 Compare January 23, 2026 18:44
@sf-tejas-nadkarni sf-tejas-nadkarni changed the title W 20975885 new launch agent header component @W-20975885 New launch agent location in header component Jan 23, 2026
@sf-tejas-nadkarni sf-tejas-nadkarni changed the base branch from feature-shopper-agent-launch-locations to develop January 23, 2026 21:18
Copy link
Contributor

@sf-jhalak-maheshwari sf-jhalak-maheshwari left a comment

Choose a reason for hiding this comment

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

Looks good. @sf-tejas-nadkarni qq: will we be adding settings for customer, in the case they want to hide the agent on load and clicking on icon in header only opens it?

@sf-tejas-nadkarni
Copy link
Collaborator Author

@sf-jhalak-maheshwari yes that will be a seperate feature with a new feature flag.

@sf-tejas-nadkarni sf-tejas-nadkarni force-pushed the W-20975885-new-launch-agent-header-component branch from c647115 to c16ea45 Compare January 26, 2026 20:21
@sf-tejas-nadkarni sf-tejas-nadkarni force-pushed the W-20975885-new-launch-agent-header-component branch 3 times, most recently from 6a4fc26 to f5d1bc2 Compare January 29, 2026 17:12
const logout = useAuthHelper(AuthHelpers.Logout)
const navigate = useNavigation()
const storeLocatorEnabled = getConfig()?.app?.storeLocatorEnabled ?? STORE_LOCATOR_IS_ENABLED
const commerceAgentConfig = getCommerceAgentConfig()
Copy link
Contributor

@kevinxh kevinxh Jan 29, 2026

Choose a reason for hiding this comment

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

It appears the code style is slightly inconsistent, most of the component access the global config object via getConfig().xxxxxx, and it seems shopper agent introduced its own utility getCommerceAgentConfig. I wonder if we want to be consistent, either create utilities for all other features (not just shopper agent), otherwise it looks inconsistent coding style

    const storeLocatorEnabled = getConfig()?.app?.storeLocatorEnabled ?? STORE_LOCATOR_IS_ENABLED
    const commerceAgentConfig = getCommerceAgentConfig()

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thats a good point, this is where they decided to change it into utility functions, #3230

enableConversationContext: 'false',
conversationContext: []
conversationContext: [],
enableAgentFromHeader: 'false'
Copy link
Contributor

Choose a reason for hiding this comment

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

any idea why the booleans are implemented as strings? I understand this is already there before your change but I'm curious to know if you happen to know the answer.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Aggreed its cleaner to use boolean, I'm not sure why the API/Config design uses strings for flags.
I just opted for consistency

this is the official help doc Shopper Agent documentation.

Comment on lines +7 to +49
const onClient = typeof window !== 'undefined'

/**
* Launch the chat using the embedded service bootstrap API
*
* @function launchChat
* @returns {void}
*/
export function launchChat() {
if (!onClient) return

try {
// Launch chat using the embedded service bootstrap API
if (
window.embeddedservice_bootstrap &&
typeof window.embeddedservice_bootstrap.utilAPI.launchChat === 'function'
) {
window.embeddedservice_bootstrap.utilAPI.launchChat()
}
} catch (error) {
console.error('Shopper Agent: Error launching chat', error)
}
}

/**
* Open the shopper agent chat window
*
* Programmatically opens the embedded messaging widget by finding and clicking
* the embedded service chat button. This function can be called from custom
* UI elements like header buttons.
*
* @function openShopperAgent
* @returns {void}
*/
export function openShopperAgent() {
if (!onClient) return

try {
launchChat()
} catch (error) {
console.error('Shopper Agent: Error opening agent', error)
}
}
Copy link
Contributor

@kevinxh kevinxh Jan 29, 2026

Choose a reason for hiding this comment

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

Have you considered to make this a React hook? There are many React hooks in this code base and it 's more consistent with the style and the technologies we used. something like below.

import { useCallback } from 'react'

declare global {
    interface Window {
        embeddedservice_bootstrap?: {
            utilAPI: {
                launchChat: () => void
            }
        }
    }
}

/**
 * Hook for launching the Salesforce Embedded Service chat
 */
export function useShopperAgent() {
    const openChat = useCallback(() => {
        if (typeof window === 'undefined') return

        try {
            window.embeddedservice_bootstrap?.utilAPI.launchChat()
        } catch (error) {
            console.error('Shopper Agent: Error launching chat', error)
        }
    }, [])

    return { openChat }
}

usage example

function ChatButton() {
    const { openChat } = useShopperAgent()

    return <button onClick={openChat}>Chat with us</button>
}

Copy link
Contributor

@kevinxh kevinxh left a comment

Choose a reason for hiding this comment

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

Overall looks good, left a few comments. thank you

Comment on lines +16 to +22
export function useOpenShopperAgent() {
const openShopperAgent = useCallback(() => {
launchChat()
}, [])

return openShopperAgent
}
Copy link
Contributor

@kevinxh kevinxh Jan 29, 2026

Choose a reason for hiding this comment

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

I would encourage to update the function signature to make it more generic and return a collection of actions related to shopper agent rather than having "Open" in the hook's name and return a single function, this isn't extendable for future. Imagine we want to add a couple of more functionalities, with this design, we would have to either making a breaking change in terms of the function signature, or create more hooks like useActionOneShopperAgent , useActionTwoShopperAgent , useActionThreeShopperAgent etc.

export function useShopperAgent() {
    const open = useCallback(() => {
        launchChat()
    }, [])
    
    const actions = {
      open,
      // future proof and DRY the implementation
      // this hook can be extended with new functionalities.
    }

    return actions
}

Thoughts?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thats a good pracitce in react, i dont see it happening for this functionality but i can update it to make it simple

Comment on lines +15 to +49
export function launchChat() {
if (!onClient) return

try {
// Launch chat using the embedded service bootstrap API
if (
window.embeddedservice_bootstrap?.utilAPI &&
typeof window.embeddedservice_bootstrap.utilAPI.launchChat === 'function'
) {
window.embeddedservice_bootstrap.utilAPI.launchChat()
}
} catch (error) {
console.error('Shopper Agent: Error launching chat', error)
}
}

/**
* Open the shopper agent chat window
*
* Programmatically opens the embedded messaging widget by finding and clicking
* the embedded service chat button. This function can be called from custom
* UI elements like header buttons.
*
* @function openShopperAgent
* @returns {void}
*/
export function openShopperAgent() {
if (!onClient) return

try {
launchChat()
} catch (error) {
console.error('Shopper Agent: Error opening agent', error)
}
}
Copy link
Contributor

@kevinxh kevinxh Jan 29, 2026

Choose a reason for hiding this comment

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

It doesn't look like we need to separate functions?

the only thing openShopperAgent does is to call launchChat, can we remove one of them and simplify the code?

Copy link
Collaborator Author

@sf-tejas-nadkarni sf-tejas-nadkarni Jan 29, 2026

Choose a reason for hiding this comment

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

There are more feature coming in the next patch where we will need to add more conditions before launchChat thats why i have created it as seperate function

@sf-tejas-nadkarni sf-tejas-nadkarni force-pushed the W-20975885-new-launch-agent-header-component branch from 1f9334c to 0a1f5eb Compare January 30, 2026 00:06
launchChat()
}, [])

return {actions: {open}}
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think you need the key "actions" because it's already an extensible object.

Suggested change
return {actions: {open}}
return { open }

This way you can directly deconstruct it, usage example

const {open} = useShopperAgent()

i'm just nitpicking.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'd prefer to keep the actions wrapper to add explicit namespace for executable functions. What you think?

* @function openShopperAgent
* @returns {void}
*/
export function openShopperAgent() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need both launchChat and openShopperAgent function?
We can remove openShopperAgent and just have launchChat. Post that, renaming launchChat maybe a good option too

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

openShopperAgent will have more conditions once we introduce flag to hide the FAB icon thats why added two seperate functions

"defaultMessage": "View"
},
"header.button.assistive_msg.ask_shopping_agent": {
"defaultMessage": "Ask Shopping Agent"
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we want to add translations for other files as well or is there an automated process?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

translation command should have added more labels, let me look into that

@sf-tejas-nadkarni sf-tejas-nadkarni merged commit bff4b48 into develop Jan 30, 2026
42 checks passed
@sf-tejas-nadkarni sf-tejas-nadkarni deleted the W-20975885-new-launch-agent-header-component branch January 30, 2026 01:23
@sf-tejas-nadkarni sf-tejas-nadkarni restored the W-20975885-new-launch-agent-header-component branch February 3, 2026 23:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip changelog Skip the "Changelog Check" GitHub Actions step even if the Changelog.md files are not updated

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants