Tuesday, April 28, 2020

Developing Suggested Cases Component using Lightning Web Components firing SOSL query

Motivation behind this


Today, I have received a requirement to build a suggested cases or similar cases functionality which will help Business to refer during resolving a case. Since this functionality is not by-default available as part of Case Management so tried to build from my own.

There are few approaches I have followed which might be helpful to learn and explore to build this simple component. For example, why should I use SOSL query instead of SOQL.

Let's get started.

Use Case


Business wants a have a functionality to show suggested cases or similar cases in the case detail page. This will help to refer previously closed cases and to resolve current cases quickly. 

It will have following functionality:
  • Based on current case subject, system will pull all the occurrences of matching keywords from any fields from Case object.
  • It will display case records which has been created recently and closed.
  • It might filter based on other criteria like, Case Types
  • In the datatable, clicking on the Case Number (URL), it will open the case record.

Possible End Result


The component will look like as highlighted.


Solution Approach


Based on the above diagram, need to create component which will show data in datatable.

suggestedCases.html


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<template>
    <lightning-card>      
        <p class="slds-p-horizontal_large">Suggested Cases</p>        
        <div style="height: 200px;">
            <lightning-datatable 
                key-field="Id"
                data={records}
                columns={columns}>
            </lightning-datatable>
        </div>
    </lightning-card>
</template>

suggestedCases.js

This js controller is most important for implementing this functionality and some of the key points have been highlighted below:


  • Defining a column as Case Number which will act as hyperlink. Refer type and typeAttributes
{
        label: 'Case Number', 
        fieldName: 'URLField',
        fixedWidth: 120,
        type: 'url', 
        typeAttributes: { 
            label: {
                fieldName: 'CaseNumber'
            },
            target: '_blank'
        },
        sortable: true 
}

  • Use recordId with @api to capture record Id of the Case Detail Record.
  • Since the Case Number column to be created and not readily available like that formatted way so elements to be created on the fly and to be pushed into the records array.
Entire code is as follows:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import { LightningElement, track, wire, api} from 'lwc';
import getSuggestedCases from '@salesforce/apex/CaseController.getSuggestedCases';

//define datatable columns with customized Case Number URL column
const columns = [
    {
        label: 'Case Number', 
        fieldName: 'URLField',
        fixedWidth: 120,
        type: 'url', 
        typeAttributes: { 
            label: {
                fieldName: 'CaseNumber'
            },
            target: '_blank'
        },
        sortable: true 
    },
    { label: 'Subject', fieldName: 'Subject' }       
];
export default class SuggestedCases extends LightningElement {

    @api recordId; //it will be passed from the screen
    @track records; //datatable records
    @track columns; //datatable columns

    //retrieve suggested cases based on case recordId
    @wire(getSuggestedCases,{caseId: '$recordId'})
    wiredCases({ error, data }) {
        if (data) {
            let URLField;
            //retrieve Id, create URL with Id and push it into the array
            this.records = data.map(item=>{
                URLField = '/lightning/r/Case/' + item.Id + '/view';
                return {...item,URLField};                
            });
            this.columns = columns;
            this.error = undefined;
        } else if (error) {
            this.error = error;
            this.records = undefined;
        }
    }
    
}

CaseController.cls

In the class, as keyword occurrences need to be search on multiple fields, so SOSL (Salesforce Object Search Language) query has been used.

Since, it needs to be searched on Case Description field which is LongTextArea so SOQL search is not possible, it cannot be used in WHERE condition.

As it should include all the keywords for search taking from Case's subject, so all the keywords to be separated by OR operator (this is tricky).

Rest of the code is simple.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public with sharing class CaseController {
    @AuraEnabled (cacheable=true)
    public static List<Case> getSuggestedCases(String caseId){
        List<Case> lstCase = new List<Case>(); 
        //retrieve case subject of existing case       
        Case caseObj = [SELECT Subject, Type FROM Case WHERE Id=:caseId];

        //since all the keywords need to searched so, need to put 'OR' condition between the keywords
        List<String> strList = caseObj.Subject.split(' ');
        String strSearch = String.join(strList, '\' OR \'') + '*';
        
        System.debug('strSearch=' + strSearch);
        //strSearch=Seeking' OR 'guidance' OR 'on' OR 'electrical' OR 'wiring' OR 'installation' OR 'for' OR 'GC5060*                                 

        //retrieve cases which are already closed, created recently and eliminating current case
        List<List<SObject>> searchList = [FIND :strSearch IN ALL FIELDS 
                                         RETURNING Case(Id,CaseNumber, Subject 
                                         WHERE Id!=:caseId
                                         AND Status = 'Closed'
                                         AND Type =:caseObj.Type
                                         ORDER BY CreatedDate DESC
                                         LIMIT 20) 
                                        ];

        if(searchList.size()>0){
            return searchList[0];
        }
        return lstCase;
    }
}

suggestedCases.js-meta.xml

Define where this component to be exposed.


<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>48.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__RecordPage</target>
        <target>lightning__AppPage</target>
        <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>

After developing this component, expose it to Case Detail Page as shown in the picture.

Overall, it is a small piece of work but good to explore new things in Javascript and LWC. Thanks for reading!


References



Further Reading

No comments:

Post a Comment