Share a Connect post in Cliq channel or in direct message

Share a Connect post in Cliq channel or in direct message

Let us consider a custom menu to share the link of a connect post either in a channel or to individual users as a direct message.
 
Handlers used
  1. Menu click handler
  2. Form change handler
  3. Form submit handler
 
Breaking down the workflow of this 'Share in Cliq' custom menu
  • The user selects the 'Share in Cliq' option from the post menu.
  • The menu click handler is triggered.
  • The link between Zoho Connect and Cliq is established using 'zohocliqoauth' connection.
  • The form is built and displayed to the user.
  • When the user provides their input (channel / user) in the 'share in' field, the form change handler will be triggered and the fields in the form gets updated.
  • Once the user enters all the required details and hits the Share button, the form submit handler will be triggered.
  • The form details are validated and are sent to the Cliq API which then shares the link in the selected channel or user's chat box. 
In the menu click handler, the form object is built with the following fields:
 
Field name
Field Type
Description
Share in
Select
The user should select where they want to share the URL. Either in a channel or another user's direct message.
 
The value of 'trigger on change' attribute of this field should be set as 'true'. Based on the user input in this field, the next field (channel name / user name) should be displayed.
Users
multiSelect
Select the people to share the URL with.
 
Channels 
multiSelect
The user should select the Cliq channels in which the URL should be shared
Message          
textArea
The content for the message to be shared.
 
Step by step implementation of field objects:
 
1. Share in  
 
The user should select where they want to share the post link. The options are either in a channel or an individual's DM. Based on the user input, the user field or channel field is displayed next . Hence, the `triggerOnChange` attribute of this field is set as true.
fields.add({"type":"select","label":"Share in","name":"sharein",
"hint":"Select where you’d like to share this post",
"mandatory":"true","triggerOnChange":"true",
"options":{{"label":"Direct Message","id":"private"},
{"label":"Channel","id":"channel"}},"value":"private"});
 
2. Users
 
If the user selects to share the post as a direct message, the field should list user names.  Since the user list is already available in Connect, the same list is used using 'dataSource' attribute.
 
fields.add({"type":"multiSelect","label":"Users",
"name":"users","mandatory":"true",
"triggerOnChange":"false","dataSource":"user"});
3. Channels
 
If the user selects to share the link in a channel, the field should list the channels the user is part of. This information is fetched from Cliq. To do this, the connection `zohocliqoauth` is used for authentication with Zoho Cliq and then the channel derails are fetched.  In this example, the details of first 400 channels are fetched to keep the code execution time less than 20 seconds. If the Cliq API supports searching and fetching channel details by their names, using the field lookup handler is more efficient.
channels = Map();
allChannel = list();
countList = {"1","2","3","4","5"};
//for each  count in countList
{
 parameterMap = Map();
 if(channels.containKey("next_token"))
 {
 parameterMap.put("next_token",channels.get("next_token"));
 }
 channels = invokeurl
 [
  type :GET
  parameters:parameterMap
  connection:"zohocliqoauth"
 ];
 channels = channels.toMap();
 channelsList = channels.get("channels").toList();
 for each  channel in channelsList
 {
  option = Map();
  option.put("id",channel.get("channel_id"));
  option.put("value",channel.get("unique_name"));
  option.put("label",channel.get("name"));
  allChannel.add(option);
 }
 if(channels.containKey("has_more") == false || channels.get("has_more") == false)
 {
  break;
 }
}
 
In this example, the default value of `sharein` field is private, and hence the channels field will not be displayed in the form to provide a better user experience. But, once the user selects 'Channels' in the 'Share in' field, the channel field will be made visible in the form.
fields.add({"type":"multiSelect","label":"Channels","name":"channel",
"mandatory":"true","triggerOnChange":"false","options":allChannel,"hide":"true"});
 
4. Message
 
The following code snippet is to get the user message that has to be shared with the URL:
message = "Look this [connect post](" + entity.get("url") + ")";
fields.add({"type":"textArea","label":"Message",
"name":"message","hint":"Enter your message",
"mandatory":"true","triggerOnChange":"false","value":message,"maxLimit":1000});
 
The completed code of menu click handler with all the above given snippets is as follows:
fields = {};
fields.add({"type":"select","label":"Via","name":"sharein",
"hint":"Select where you’d like to share this post",
"mandatory":"true","triggerOnChange":"true",
"options":{{"label":"Direct Message","id":"private"},
{"label":"Channel","id":"channel"}},"value":"private"});
channels = Map();
allChannel = list();
countList = {"1","2","3","4","5"};
//for each  count in countList
{
 parameterMap = Map();
 if(channels.containKey("next_token"))
 {
  parameterMap.put("next_token",channels.get("next_token"));
 }
 channels = invokeurl
 [
  type :GET
  parameters:parameterMap
  connection:"zohocliqoauth"
 ];
 channels = channels.toMap();
 channelsList = channels.get("channels").toList();
 for each  channel in channelsList
 {
  option = Map();
  option.put("id",channel.get("channel_id"));
  option.put("value",channel.get("unique_name"));
  option.put("label",channel.get("name"));
  allChannel.add(option);
 }
 if(channels.containKey("has_more") == false || channels.get("has_more") == false)
 {
  break;
 }
}
fields.add({"type":"multiSelect","label":"Channels",
"name":"channel","mandatory":"true","triggerOnChange":"false",
"options":allChannel,"hide":"true"});
fields.add({"type":"multiSelect","label":"Users","name":"users",
"mandatory":"true","triggerOnChange":"false","dataSource":"user"});
message = "Look this [connect post](" + entity.get("url") + ")";
fields.add({"type":"textArea","label":"Message","name":"message",
"hint":"Enter your message","mandatory":"true",
"triggerOnChange":"false","value":message,"maxLimit":1000});
form = Map();
form.put("title","Share in Cliq");
form.put("hint","Share a Connect post in Cliq");
form.put("buttonLabel",{"done":"Share"});
form.put("fields",fields);
returnMap = Map();
returnMap.put("form",form);
return returnMap;
 
To keep the CTA's relevant to the action done by the custom menu, the `done` action button is renamed as 'Share' using the `buttonLabel` attribute.
Form Change Handler
Once the user selects an option in the share in field, the form change handler is triggered as the value of its  'triggerOnChange' attribute is set as true.  Based on the user input, the form change handler will display the relevant field (channel/user names). This is done by switching the visibility of the `channel` and 'users' field.
 
 
targetEle = target.get("name");
formValues = form.get("values");
fieldList = form.get("fields").toList();
returnMap = Map();
if(targetEle == "sharein")
{
 cliqMedium = formValues.get("sharein").toMap().get("id");
 fields = list();
 if(cliqMedium == "private")
 {
  fields.add({"name":"channel","hide":true});
  fields.add({"name":"users","hide":false});
 }
 else
 {
  fields.add({"name":"users","hide":true});
  fields.add({"name":"channel","hide":false});
 }
 returnMap.put("fields",fields);
}
return returnMap;
 
 
Form Submit Handler
 
When the form is submitted (i.e. Share button is clicked) the form submit handler is triggered. Since all the fields in the form are mandatory, the form submit handler will not be triggered until the user fills in those fields.
 
The following code snippet is to share the link in Cliq channel and show an error message if the action could not be completed: 
 
message = form.get("values").get("message");
channels = form.get("values").get("channel").toList();
info channels;
errorMsg = "";
joiner = "";
for each  channel in channels
{
  response = zoho.cliq.postToChannel(channel.get("value"),
message,"zohocliqoauth");
  info response;
  if(response == null || response.containKey("status") == false ||
response.get("status") != "success")
  {
  errorMsg = errorMsg + joiner + channel.get("label");
  joiner = ", ";
  info channel.get("value") + " :::: " + response;
  }
}
 
 
The following code snippet is to share the link to individual users as a direct message:
 
Before sending the message to an individual user, a validation is done to check whether the user is trying to share the message to their account as it is not possible in Cliq.
 
users = form.get("values").get("users").toList();
info users;
for each  cliqUser in users
 {
  if(cliqUser.get("id") == user.get("id"))
  {
   fieldError = Map();
   fieldError.put("users","You cannot share a post with yourself.");
   returnMap.put("fieldError",fieldError);
   return returnMap;
  }
 }
 
After validation, the message is sent to the selected users. 
 
for each  cliqUser in users
 {
  response = zoho.cliq.postToUser(cliqUser.get("value"),message,"zohocliqoauth");
  info response;
  if(response == null || response.containKey("status") == false ||
response.get("status") != "success")
  {
   errorMsg = errorMsg + joiner + cliqUser.get("label");
   if(response.containKey("message"))
   {
    info cliqUser.get("value") + " :::: " + response.get("message");
   }
  }
 }
 
If there is a failure in sharing the link, an error message is displayed. In this example, different error messages are used for channels and direct messages.
if(errorMsg != null && errorMsg.length() > 0)
{
msg = "";
 if(cliqMedium == "channel")
 {
  msg = "Sorry, we’re unable to share the post in the following channel(s): "
+ errorMsg;
 }
 else
 {
  msg = "Sorry, we’re unable to share the post with the following user(s): "
+ errorMsg;
 }
 returnMap.put("result","success");
 returnMap.put("message",msg);
}
else
{
 returnMap.put("result","success");
 returnMap.put("message","Message shared successfully");
}
 
The completed code of the form submit handler is as follows:
 
returnMap = Map();
formValues = form.get("values");
cliqMedium = formValues.get("sharein").toMap().get("id");
info cliqMedium;
message = formValues.get("message");
errorMsg = "";
joiner = "";
if(cliqMedium == "channel")
{
 channels = formValues.get("channel").toList();
 info channels;
 for each  channel in channels
 {
  response = zoho.cliq.postToChannel(channel.get("value"),message,"zohocliqoauth");
  info response;
  if(response == null || response.containKey("status") == false ||
response.get("status") != "success")
  {
   errorMsg = errorMsg + joiner + channel.get("label");
   joiner = ", ";
   info channel.get("value") + " :::: " + response;
  }
 }
}
else
{
 users = formValues.get("users").toList();
 info users;
 for each  cliqUser in users
 {
  if(cliqUser.get("id") == user.get("id"))
  {
   fieldError = Map();
   fieldError.put("users","You cannot share a post with yourself.");
   returnMap.put("fieldError",fieldError);
   return returnMap;
  }
 }
 for each  cliqUser in users
 {
  response = zoho.cliq.postToUser(cliqUser.get("value"),message,"zohocliqoauth");
  info response;
  if(response == null || response.containKey("status") == false ||
response.get("status") != "success")
  {
   errorMsg = errorMsg + joiner + cliqUser.get("label");
   if(response.containKey("message"))
   {
    info cliqUser.get("value") + " :::: " + response.get("message");
   }
  }
 }
}
if(errorMsg != null && errorMsg.length() > 0)
{
 msg = "";
 if(cliqMedium == "channel")
 {
  msg = "Sorry, we’re unable to share the post in the following channel(s):
" + errorMsg;
 }
 else
 {
  msg = "Sorry, we’re unable to share the post with the following user(s):
" + errorMsg;
 }
 returnMap.put("result","success");
 returnMap.put("message",msg);
}
else
{
 returnMap.put("result","success");
 returnMap.put("message","Message Shared Successfully");
}
return returnMap;