5

I am working on an utility bar component that displays a form to agents to give feedback (See feedback utility in the left bottom of the picture). I want to open the utility on case closed event (without agent manually clicking the utility component). Workflow is as below:

Agent close case -> auto open the utility -> Agent answer questions and click submit button 
-> minimize utility on submit button click

utilityBarAPI provides a method called openUtility to open the utility. I am having trouble figuring out a way to open the utility when a case is closed. This is in the salesforce lightning experience.

Options I explored:

  1. Create an Apex trigger that captures case closed event and call the openUtility method in it. But I didn't find a way to make UI changes from backend triggers. I am not sure if this is even supported.

  2. Create a custom button to close a case. When the button is clicked, call the openUtility method. The problem here is there are multiple ways to close cases like (change status field directly, button click etc). How would I cover all these options?

  3. Create an Apex trigger and send platform event. UI component would listen on the event and open the form. This seems most achievable but there is a problem:

    Imagine 2 agents in an org working on cases and both have this component. When Agent 1 closes Case 1, the components in both Agent browsers will listen to the event and open the feedback form. But I only want the Agent 1 component to open as he/she closed the case. Agent 2 should not see any changes in his browser/component due to this particular event. Similarly when Agent 2 close a case, only he/she should see the utility bar open up and display the form.

The final solution should work in both Cases page layout and single case layout.

If someone has better ways to solve this problem, I would like to know. Let me know if you need more information. Thank you.

If this use case is not possible with utility bar component, I am open to using other custom components or pop-up modals etc.

Feedback widget

3
+50

Use Streaming API to capture the events from the database.

Create a push topic

First, you need to create a push topic with a specific query, based on that query the event will be fired.

In your case, it will be something like.

Select Name,..., LastModifiedById FROM Case where Status = 'Closed'

As you need to fire this event only when the case is updated you can set NotifyForOperationUpdate to true on Push Topic record. Make sure that the IsActive is set to true.

So the final code to insert the push topic will be like below.

PushTopic pushTopic = new PushTopic();
pushTopic.Name = 'WhenCaseClosed';
pushTopic.Query = 'Select Name,..., LastModifiedById FROM Case where Status = \'Closed\'';
pushTopic.ApiVersion = 49.0;
pushTopic.NotifyForOperationUpdate = true;
pushTopic.NotifyForFields = 'Where'; // as you want to fire this event only when the status field is changed.
insert pushTopic;

Note that you just need a single push topic record in the org.

Use the Streaming API event listener to open the utility.

Add the lightning:empApi in your component and add the event handler in the init handler of the component. Note you will also need lightning:utilityBarAPI.

<lightning:empApi aura:id="empApi" />
<lightning:utilityBarAPI aura:id="utilitybar" />

Now let's see the handler code.

const empApi = component.find('empApi');
const replayId = -1;
const channel = '/topic/WhenCaseClosed'; // note the same name we have set to the push topic.
// Subscribe to an event
    empApi
    .subscribe(
        channel,
        replayId,
        $A.getCallback(eventReceived => {
            // Process event (this is called each time we receive an event)
            if(eventReceived.data && eventReceived.data.sobject){
                // check if the last modifyby id of the current record is same as the logged in user.
                if(eventReceived.data.sobject.LastModifiedById === $A.get("$SObjectType.CurrentUser.Id")){
                    // open the utility here.
                }
            }
        })
    )
    .then(subscription => {});

As we had already added the LastModifiedById in the query, so we are checking if the LastModifiedById is the same as the logged-in user. So we can say that it is the same user who has closed the case.

I hope this will solve all of your problems.

Corner case.

There is a possibility that the LastModifiedById might get changed in between the case is closed and the event is received on the Utility component. To avoid that you can create a custom field to store the user id who has closed the case.

The Platform events

I have not tried but I think this can be also achieved with Platform Events as they also use Streaming Apis and EMP APIs. One advantage using PushTopic over Platform events I see is you don't need to fire the any events from the trigger like we do in Platform Events.

| improve this answer | |
  • 2
    Awesome this seems close to the solution I am looking for. Thank you. If you can think of any other corner cases, please let me know. One other corner case I can think is user running a script to bulk close cases which will refresh the component multiple times without giving chance for the user to give feedback. Do you have any ideas on handling this case? – VK_nandi Aug 13 at 19:18
  • 1
    @VK_nandi in that case, you can check if the utility is already open, and skip the others until the first form is filled. also you can always show a list of cases which are pending for feedback so user fill that one by one. – rahul gawale Aug 14 at 3:52
2

You should use lightning data services in the components. Lightning data services automatically captures records changes and you can get update details(like which field is updated and value of the field). After that you can utilityBarAPI to open the utility.

Code Markup - Cmp

<aura:component implements="force:hasRecordId,flexipage:availableForRecordHome">
<aura:attribute name="caseRecord" type="Object"/>
<aura:attribute name="recordLoadError" type="String"/>

<force:recordData aura:id="recordLoader"
                  recordId="{!v.recordId}"
                  layoutType="{!v.layout}"
                  fields="CaseNumber,Description,Subject,Status"
                  targetFields="{!v.caseRecord}"
                  targetError="{!v.recordLoadError}"
                  recordUpdated="{!c.recordUpdated}"
                  />
<!-- Display a lightning card with details about the case -->
<lightning:card iconName="standard:case" title="{!v.caseRecord.Name}" >
    <div class="slds-p-horizontal--small">
        <p class="slds-text-heading--small">
            <lightning:formattedPhone title="Phone"  value="{!v.caseRecord.CaseNumber}" /></p>
        <p class="slds-text-heading--small">
            <lightning:formattedText title="Description" value="{!v.caseRecord.Description}" /></p>
    </div>
</lightning:card></aura:component>

Component Controller js

({
recordUpdated: function(component, event, helper) {
    var eventParams = event.getParams();
    if(eventParams.changeType === "CHANGED") {
        var changedFields = eventParams.changedFields;
        let fields = Object.keys(changedFields);
        let values = Object.values(changedFields);
        for(let field of Object.keys(changedFields)){
            if(field === 'Status'){
                let value = changedFields[field]['value'];
                if(value === 'Closed'){
                    // Place your Open Utility Code here
                    console.log('Open Utility');
                }
            }
        }
    }
}

})

Refer to the Link:- Lightning Data Services - Record Changes

| improve this answer | |
  • 1
    This sounds like a decent option. Couple of things I noticed: 1) The component won't work on Cases list view page where Agents can change status to Closed. But my component won't be tracking a record as its not a record page. I think I am okay with this limitation. 2) what happens when multiple agents are modifying/viewing the case at same time? Won't the component be displayed to all these agents? Any solution to this problem. – VK_nandi Aug 12 at 5:36
  • 1.) For Point 1. Yeah, I don't think it will work on the list view of cases. 2.) Lightning data services is just handling a record save event that is fired when we save the record. As this event is within the scope of browser current page, only the component that is on the page can catch the event. So,It is only going to open the utility for the user who closed the case. – Manjeet Singh Aug 13 at 6:04
0

If the feedback on Case closure is a hard requirement, you may want to go with a custom Action/Button which calls a custom Lightning Component or Lightning Flow that combines the Case status update and feedback questions. The Action/Button can be added to the Case Page Layouts and the List View Actions as required (just not to the Recently Viewed List View)

To ensure that Cases aren't closed by editing the Status Field directly (or by any other means), you could add a custom Field to flag when the Case is closed (not included on the Page Layouts) that only gets updated when closed by the custom Action/Button. You could then add a Validation Rule to the Case to check for both the closed Status and this new flagged Field, showing a relevant message asking the user to use the Action/Button to close the Case accordingly

Not a super fancy solution, but will ensure the Cases are closed with the required feedback

| improve this answer | |
  • 2
    Thank you for the response. To be clear, there will be new component which will have the "status update" field and feedback questions. And this is the only way that the status can be updated right? Can these changes be achieved programmatically or do they have to be done using UI? – VK_nandi Aug 7 at 16:58
  • Yes, that's the idea, update the Status and the new flag Field in the background as the feedback questions are answered and saved in the new component. A Lightning Flow would probably be the better way to go in the Action/Button (declarative rather than code) – Instread Aug 7 at 17:31
0

Have you tried creating a process builder node on case change checking case closure condition which calls a screenflow which launches your component in it(making your component available for screenflow by implementing the availableforscreenflows interface in lightning)? I think this will solve your issue on simulataneous access by agents as the flow will be shown to only the user who initiated the case closure.

| improve this answer | |
  • 1
    Does this have to be done in UI? Can this be achieved using code? My use case is once I define the process, other salesforce accounts can use this solution by installing it (maybe via app). I want to avoid each salesforce account Admin doing repeated manual work. – VK_nandi Aug 11 at 22:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.