Case Close Lightning Component

This is a Lightning Component to show a Case Close button in Salesforce with input fields in a modal box. Case Close solution using Quick Action do not create Case Comment Record and it is not shown in a modal box like quick actions on other objects.

This solution only shows Case Status values which are of Type Closed dynamically using apex in the Status Selection field. Along with that, it creates a Case Comment record based on the comments you add on the UI. Error is Handled via AuraHandledException and Error is displayed in Toast if any.

CaseCloseButton.cmp

<aura:component controller="CaseCloseController" implements="flexipage:availableForAllPageTypes,force:hasRecordId">
    
    <aura:attribute name="recordId" type="Id"/>
    <aura:attribute name="isModalOpen" type="Boolean" default="false"/>
    <aura:attribute name="selectedStatusValue" type="String" />
    <aura:attribute name="caseComment" type="String" />
    <aura:attribute name="closeStatusList" type="List"/>

    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />
    
    <lightning:button class="slds-m-top_xx-small" label="Close Case" name="Close Case" onclick="{!c.openModel}"/>

    <aura:if isTrue="{!v.isModalOpen}">
        <section role="dialog" tabindex="-1" aria-labelledby="modal-heading-01" aria-modal="true" aria-describedby="modal-content-id-1" class="slds-modal slds-fade-in-open">
            <div class="slds-modal__container">
                <header class="slds-modal__header">
                    <lightning:buttonIcon iconName="utility:close"
                                            onclick="{!c.closeModel}"
                                            alternativeText="close"
                                            variant="bare-inverse"
                                            class="slds-modal__close"/>
                    <h2 id="modal-heading-01" class="slds-text-heading_medium slds-hyphenate">Close Case</h2>
                </header>
                <div class="slds-modal__content slds-p-around_medium" id="modal-content-id-1">
                        
                    <lightning:select name="mySelect" label="Status" aura:id="mySelect" value="{!v.selectedStatusValue}">
                        <aura:iteration items="{!v.closeStatusList}" var="item">
                            <option text="{!item.label}" value="{!item.value}" selected="{!item.selected}"/>
                        </aura:iteration>
                    </lightning:select>
                    <br/>
                    <ui:inputTextArea label="Case Comment" value="{!v.caseComment}"></ui:inputTextArea>
                    <br/>                        
                </div>
                <footer class="slds-modal__footer">
                    <lightning:button variant="neutral"
                                        label="Cancel"
                                        title="Cancel"
                                        onclick="{! c.closeModel }"/>
                    <lightning:button variant="brand"
                                        label="Close Case"
                                        title="Close Case"
                                        onclick="{!c.closeCaseAction}"/>
                </footer>
            </div>
        </section>
        <div class="slds-backdrop slds-backdrop_open"></div>
    </aura:if>
</aura:component>

CaseCloseButtonController.js

({
    doInit : function(component, event, helper) {
        var action = component.get("c.getCloseCaseStatus");           
        action.setCallback(this, function(response) {
            var state = response.getState();
            if (state === "SUCCESS") {
                var closeStatusList = [];
                var returnedMap = response.getReturnValue();  console.log(returnedMap);
                for (var key in returnedMap){
                    var item = {};
                    item.label = key;
                    item.value = returnedMap[key];
                    closeStatusList.push(item);
                }
                component.set("v.closeStatusList",closeStatusList);
            }
            component.set("v.showSpinner", false); 
        });
        $A.enqueueAction(action);   
    },
    closeCaseAction : function(component, event, helper) {       
        var action = component.get("c.closeCaseRecord");  
        action.setParams({ 
            recordId : component.get("v.recordId"),
            caseStatus : component.get("v.selectedStatusValue"),
            caseCommentBody : component.get("v.caseComment")
        });      
        action.setCallback(this, function(response) {
            var state = response.getState();
            if (state === "SUCCESS") {
                component.set("v.isModalOpen", false);
                $A.get('e.force:refreshView').fire();
                helper.showToast('Success','success','Case Closed','dismissible');
            }
            else{
                var errors = response.getError();
                if (errors) { console.log(JSON.stringify(errors));
                    if (errors[0] && errors[0].message) {
                        helper.showToast('Error','error',errors[0].message,'sticky');
                        console.log(errors);
                    }
                } else {
                    console.log("Unknown error");
                }
            }
            component.set("v.showSpinner", false); 
        });
        $A.enqueueAction(action);  

    },
    openModel: function(component, event, helper) {
        component.set("v.isModalOpen", true);
     },
     closeModel: function(component, event, helper) {
        component.set("v.isModalOpen", false);
        component.set("v.caseComment",'');
     }
})

CaseCloseButtonHelper.js

({
    callApexControllerMethod : function(component, methodName, params, callback) {
 var action = component.get("c." + methodName);
        if(params) {
            action.setParams(params);
        }
        action.setCallback(this, callback);
        $A.enqueueAction(action);
    },
    showToast: function (title,type,message) {
        var toastEvent = $A.get("e.force:showToast");
        toastEvent.setParams({
            "title": title,
            "type" : type,
            "message": message
        });
        toastEvent.fire();
    }
})

CaseCloseController.cls

public with sharing class CaseCloseController {

    @auraEnabled
    public static Map<String,String> getCloseCaseStatus() {
        Map<String,String> statusMap = new Map<String,String>();
        for(CaseStatus cs : [Select Id, MasterLabel,ApiName From CaseStatus Where IsClosed = true]) {
            statusMap.put(cs.MasterLabel,cs.ApiName);
        }
        return statusMap;        
    }
    
    @auraEnabled
    public static void closeCaseRecord(String recordId, String caseStatus, String caseCommentBody) {
         try{             
            Case objCase = new Case(Id = recordId);
            objCase.status = caseStatus;
            update objCase;

            Database.DMLOptions dlo = new Database.DMLOptions();
            dlo.EmailHeader.triggerUserEmail = true;

            CaseComment cs = new CaseComment();
            cs.parentId = objCase.Id;
            cs.Commentbody = caseCommentBody;
            Database.insert(cs,dlo);
         }catch(Exception e ){
            System.debug(e.getMessage() + ' | Line Number :'+e.getLineNumber()+' | Record ID :'+recordId);
            throw new AuraHandledException(e.getMessage());
        }
    }
}

CaseCloseControllerTest.cls

@isTest
private class CaseCloseControllerTest {

 @testSetup
 public static void testSetupData() {
 Case c = new Case();
 c.Status ='New';
 c.Type ='Other';
 c.Origin ='Email';
 insert c;
 }

 private static testMethod void testCaseCloseController() {
 Case c = [SELECT Id FROM Case LIMIT 1];
 Map<String,String> statusMap = CaseCloseController.getCloseCaseStatus();
 System.assertNotEquals(0,statusMap.keySet().size());
 CaseCloseController.closeCaseRecord(c.Id,statusMap.values().get(0),'Case Close Reason');
 c = [SELECT Id,Status,isClosed FROM Case LIMIT 1];
 System.assertEquals(true,c.isClosed);
 }
}
Close case custom component

Git Repository Link: https://github.com/abhimanyud3dx/Close-Case-Lightning-Component

Was this post useful? If yes then please share.



Comments (2)

  1. Maxime says:

    Hi,
    I’m interested by your lightning component for our organization. I was trying to use it, but how the aura model is set to open ? My close case button isn’t display on Lighning Experience in Salesforce

    Thanks for your help,
    Best

    • Hi Maxime,

      You need to add this component to Lightning Case Record Page and then you can see the button from which you can open the modal box to close the case.

      Thanks

Leave a Comment

All fields marked with an asterisk (*) are required


shares