Example #1
0
        public void RemoveOldCenterSectionsFromThread()
        {
            var sectionsToRemove = ChatThread.Where(x => x.Direction == MessageDirection.AwkwardCenter && ChatThread.LastOrDefault() != x).ToList();

            foreach (var section in sectionsToRemove)
            {
                ChatThread.Remove(section);
            }
        }
        public void ToggleTyping(bool show)
        {
            var incommingChat  = ChatThread.Where(x => x.Direction == MessageDirection.In);
            var alreadyVisible = incommingChat.Count() > 0 && incommingChat.Last().SectionType == SectionTypeEnum.Typing;

            if (!alreadyVisible && show)
            {
                ChatThread.Add(new Section()
                {
                    SectionType = SectionTypeEnum.Typing, _id = Guid.NewGuid().ToString()
                });
            }
            if (alreadyVisible && !show)
            {
                ChatThread.Remove(incommingChat.Last());
            }
        }
        public async void ProcessNode(JToken node, JToken section = null)
        {
            if (node == null)
            {
                return;
            }
            ClearButtonTimer();

            //Replaceing verbs
            node = JToken.Parse(VerbProcessor.Process(node.ToString()));

            var parsedNode = node.ToObject <ChatNode>();

            if (parsedNode.Buttons != null && parsedNode.Buttons.Count > 0)
            {
                ClearButtons();
            }

            if (parsedNode.NodeType == NodeTypeEnum.ApiCall)
            {
                ToggleTyping(true);
                try
                {
                    var paramDict = new Dictionary <string, object>();
                    foreach (var reqParam in parsedNode.RequiredVariables)
                    {
                        if (reqParam == "HISTORY") //Custom Variable
                        {
                            paramDict[reqParam] = ChatThread.Where(x => x.SectionType != SectionTypeEnum.Typing).ToArray();
                        }
                        else
                        {
                            paramDict[reqParam] = ButtonActionHelper.GetSavedValue(reqParam);
                        }
                    }
                    var nextNodeId = parsedNode.NextNodeId; //Default
                    switch (parsedNode.ApiMethod.ToUpper())
                    {
                    case "GET":
                    {
                        var query = string.Join("&", paramDict.Select(x => $"{x.Key}={Uri.EscapeDataString(x.Value + "")}"));
                        var api   = string.IsNullOrWhiteSpace(query) ? parsedNode.ApiUrl : parsedNode.ApiUrl + "?" + query;

                        var resp = await APIHelper.HitAsync <Dictionary <string, object> >(api);

                        if (resp.ContainsKey("NextNodeId"))
                        {
                            nextNodeId = resp["NextNodeId"] + "";
                        }
                        ButtonActionHelper.HandleSaveMultiple(resp);
                    }
                    break;

                    case "POST":
                    {
                        var resp = await APIHelper.HitPostAsync <Dictionary <string, object>, Dictionary <string, object> >(parsedNode.ApiUrl, paramDict);

                        if (resp.ContainsKey("NextNodeId"))
                        {
                            nextNodeId = resp["NextNodeId"] + "";
                        }
                    }
                    break;

                    default:
                        Utils.ShowDialog($"{parsedNode.ApiMethod} ApiType Unknown!");
                        break;
                    }
                    NavigateToNode(nextNodeId);
                }
                catch (HttpRequestException ex)
                {
                    ToggleTyping(false);
                    Utils.ShowDialog(ex.ToString());
                    NavigateToNode(parsedNode.NextNodeId);
                }
                catch (Exception ex)
                {
                    ToggleTyping(false);
                    Utils.ShowDialog(ex.ToString());
                    NavigateToNode(parsedNode.NextNodeId);
                }
            }
            else if (node["Sections"] == null || node["Sections"].Children().Count() == 0)
            {
                ToggleTyping(false);
                await ProcessButtonsAsync(node);
            }
            else if (node["Sections"] != null && node["Sections"].Children().Count() > 0)
            {
                var sectionsSource       = node["Sections"];
                var currentSectionSource = section ?? sectionsSource.First;

                //Replaceing verbs
                currentSectionSource = JToken.Parse(VerbProcessor.Process(currentSectionSource.ToString()));

                SectionTypeEnum secType       = (SectionTypeEnum)Enum.Parse(typeof(SectionTypeEnum), currentSectionSource["SectionType"].ToString());
                Section         parsedSection = null;
                bool            showTyping    = false;
                switch (secType)
                {
                case SectionTypeEnum.Image:
                    parsedSection = currentSectionSource.ToObject <ImageSection>();
                    showTyping    = true;
                    break;

                case SectionTypeEnum.Text:
                    parsedSection = currentSectionSource.ToObject <TextSection>();
                    break;

                case SectionTypeEnum.Gif:
                    parsedSection = currentSectionSource.ToObject <GifSection>();
                    showTyping    = true;
                    break;

                case SectionTypeEnum.Video:
                    parsedSection = currentSectionSource.ToObject <VideoSection>();
                    break;

                case SectionTypeEnum.Audio:
                    parsedSection = currentSectionSource.ToObject <AudioSection>();
                    break;

                case SectionTypeEnum.EmbeddedHtml:
                    parsedSection = currentSectionSource.ToObject <EmbeddedHtmlSection>();
                    break;

                case SectionTypeEnum.Link:
                case SectionTypeEnum.Graph:
                case SectionTypeEnum.Carousel:
                    Utils.ShowDialog($"{secType} Coming soon!");
                    break;

                default:
                    break;
                }
                if (parsedSection != null)
                {
                    if (parsedSection.DelayInMs > 50 || showTyping) //Add 'typing' bubble if delay is grather than 50 ms
                    {
                        ToggleTyping(true);
                    }

                    //Wait for delay MilliSeconds and then continue with chat
                    Dispatcher.Dispatch(async() =>
                    {
                        var precacheSucess = await PrecacheSection(parsedSection);
                        //Remove 'typing' bubble
                        ToggleTyping(false);
                        var sectionIndex = (sectionsSource.Children().ToList().FindIndex(x => x["_id"].ToString() == parsedSection._id));
                        if (precacheSucess)
                        {
                            if (sectionIndex == 0) //First section in node, send View Event
                            {
                                await Task.Run(async() =>
                                {
                                    try
                                    {
                                        await APIHelper.TrackEvent(Utils.GetViewEvent(parsedNode.Id, Utils.DeviceId));
                                    }
                                    catch (Exception ex)
                                    {
                                        await Utils.ShowDialogAsync(ex.ToString());
                                    }
                                });
                            }
                            AddIncommingSection(parsedSection);
                        }
                        var remainingSections = sectionsSource.Children().Count() - (sectionIndex + 1);
                        if (remainingSections > 0)
                        {
                            var nextSection = sectionsSource.ElementAt(sectionIndex + 1);
                            ProcessNode(node, nextSection);
                        }
                        else
                        {
                            await ProcessButtonsAsync(node);
                        }
                    }, parsedSection.DelayInMs);
                }
            }
        }
Example #4
0
        public async void ProcessNode(JToken node, JToken section = null)
        {
            if (node == null)
            {
                Utils.ShowDialog("Node not found!");
                return;
            }
            ClearButtonTimer();

            //Replacing verbs
            node = JToken.Parse(VerbProcessor.Process(node.ToString()));

            var parsedNode = node.ToObject <ChatNode>();

            if (parsedNode.Buttons != null && parsedNode.Buttons.Count > 0)
            {
                ClearButtons();
            }

            if (parsedNode.NodeType == NodeTypeEnum.HandoffToAgent)
            {
                await Utils.ShowDialogAsync("'HandoffToAgent' not supported in simulator");
            }
            else if (parsedNode.NodeType == NodeTypeEnum.ApiCall)
            {
                ToggleTyping(true);
                try
                {
                    var paramDict = new Dictionary <string, object>();
                    if (parsedNode.RequiredVariables != null)
                    {
                        foreach (var reqParam in parsedNode.RequiredVariables)
                        {
                            if (reqParam == "HISTORY")                             //Custom Variable
                            {
                                paramDict[reqParam] = ChatThread.Where(x => x.SectionType != SectionTypeEnum.Typing).ToArray();
                            }
                            else
                            {
                                paramDict[reqParam] = ButtonActionHelper.GetSavedValue(reqParam);
                            }
                        }
                    }
                    var nextNodeId = parsedNode.NextNodeId;                     //Default
                    switch (parsedNode.ApiMethod.ToUpper())
                    {
                    case "GET":
                    {
                        var query = string.Join("&", paramDict.Select(x => $"{x.Key}={Uri.EscapeDataString(x.Value + "")}"));
                        var api   = string.IsNullOrWhiteSpace(query) ? parsedNode.ApiUrl : parsedNode.ApiUrl + (parsedNode.ApiUrl?.Contains("?") == true ? "&" : "?") + query;

                        var resp = await APIHelper.HitAsync <JObject>(api);

                        if (!string.IsNullOrWhiteSpace(resp["NextNodeId"] + ""))
                        {
                            nextNodeId = resp["NextNodeId"] + "";
                        }

                        ButtonActionHelper.HandleSaveMultiple(resp.ToObject <Dictionary <string, object> >());
                        var apiNextNodeId = ExtractNextNodeIdFromAPIResp(parsedNode, resp);
                        if (!string.IsNullOrWhiteSpace(apiNextNodeId))
                        {
                            nextNodeId = apiNextNodeId;
                        }
                    }
                    break;

                    case "POST":
                    {
                        var resp = await APIHelper.HitPostAsync <Dictionary <string, object>, JObject>(parsedNode.ApiUrl, paramDict);

                        if (!string.IsNullOrWhiteSpace(resp["NextNodeId"] + ""))
                        {
                            nextNodeId = resp["NextNodeId"] + "";
                        }
                        var apiNextNodeId = ExtractNextNodeIdFromAPIResp(parsedNode, resp);
                        if (!string.IsNullOrWhiteSpace(apiNextNodeId))
                        {
                            nextNodeId = apiNextNodeId;
                        }
                    }
                    break;

                    default:
                        Utils.ShowDialog($"{parsedNode.ApiMethod} ApiMethod Unsupported!");
                        break;
                    }
                    NavigateToNode(nextNodeId);
                }
                catch (Exception ex)
                {
                    ToggleTyping(false);
                    Utils.ShowDialog($"API[{parsedNode.ApiMethod}]: {parsedNode.ApiUrl }\r\nRequired Vars: {(parsedNode.RequiredVariables == null ? "" : string.Join(",", parsedNode.RequiredVariables))}\r\nError: " + ex.Message);
                    NavigateToNode(parsedNode.NextNodeId);
                }
            }
            else if (node["Sections"] == null || node["Sections"].Children().Count() == 0)
            {
                ToggleTyping(false);
                await ProcessButtonsAsync(node);
            }
            else if (node["Sections"] != null && node["Sections"].Children().Count() > 0)
            {
                var sectionsSource       = node["Sections"];
                var currentSectionSource = section ?? sectionsSource.First;

                //Replacing verbs
                currentSectionSource = JToken.Parse(VerbProcessor.Process(currentSectionSource.ToString()));

                SectionTypeEnum secType       = (SectionTypeEnum)Enum.Parse(typeof(SectionTypeEnum), currentSectionSource["SectionType"].ToString());
                Section         parsedSection = null;
                bool            showTyping    = false;
                switch (secType)
                {
                case SectionTypeEnum.Image:
                    parsedSection = currentSectionSource.ToObject <ImageSection>();
                    showTyping    = true;
                    break;

                case SectionTypeEnum.Text:
                    parsedSection = currentSectionSource.ToObject <TextSection>();
                    break;

                case SectionTypeEnum.Gif:
                    parsedSection = currentSectionSource.ToObject <GifSection>();
                    showTyping    = true;
                    break;

                case SectionTypeEnum.Video:
                    parsedSection = currentSectionSource.ToObject <VideoSection>();
                    break;

                case SectionTypeEnum.Audio:
                    parsedSection = currentSectionSource.ToObject <AudioSection>();
                    break;

                case SectionTypeEnum.EmbeddedHtml:
                    parsedSection = currentSectionSource.ToObject <EmbeddedHtmlSection>();
                    break;

                case SectionTypeEnum.PrintOTP:
                    parsedSection = currentSectionSource.ToObject <PrintOTPSection>();
                    break;

                case SectionTypeEnum.Carousel:
                {
                    parsedSection = currentSectionSource.ToObject <CarouselSection>();
                    (parsedSection as CarouselSection).Items = VerbProcessor.ProcessCarousalItems((parsedSection as CarouselSection).Items, parsedNode);
                }
                break;

                case SectionTypeEnum.Link:
                case SectionTypeEnum.Graph:
                    Utils.ShowDialog($"{secType} Coming soon!");
                    break;

                default:
                    break;
                }
#if DEBUG
                if (Debugger.IsAttached)
                {
                    if (parsedSection != null)
                    {
                        parsedSection.DelayInMs = 0;
                    }
                }
                else
                {
                    if (parsedSection != null && parsedSection.DelayInMs <= 0)
                    {
                        parsedSection.DelayInMs = 2000;
                    }
                }
#endif
                if (parsedSection != null)
                {
                    if (parsedSection.DelayInMs > 50 || showTyping)                     //Add 'typing' bubble if delay is greater than 50 ms
                    {
                        ToggleTyping(true);
                    }

                    //Wait for delay MilliSeconds and then continue with chat
                    Dispatcher.Dispatch(async() =>
                    {
                        var precacheSucess = await PrecacheSection(parsedSection);
                        //Remove 'typing' bubble
                        ToggleTyping(false);
                        var sectionIndex = (sectionsSource.Children().ToList().FindIndex(x => x["_id"].ToString() == parsedSection._id));
                        if (precacheSucess)
                        {
                            if (parsedNode.NodeType == NodeTypeEnum.Card)
                            {
                                parsedSection.Title   = VerbProcessor.Process(parsedNode.CardHeader);
                                parsedSection.Caption = VerbProcessor.Process(parsedNode.CardFooter);

                                if (parsedNode.Placement == null || parsedNode.Placement == Placement.Incoming)
                                {
                                    AddIncommingSection(parsedSection);
                                }
                                else if (parsedNode.Placement == Placement.Outgoing)
                                {
                                    AddOutgoingSection(parsedSection);
                                }
                                else if (parsedNode.Placement == Placement.Center)
                                {
                                    AddCenterSection(parsedSection);
                                }
                            }
                            else
                            {
                                AddIncommingSection(parsedSection);
                            }
                        }
                        var remainingSections = sectionsSource.Children().Count() - (sectionIndex + 1);
                        if (remainingSections > 0)
                        {
                            var nextSection = sectionsSource.ElementAt(sectionIndex + 1);
                            ProcessNode(node, nextSection);
                        }
                        else
                        {
                            await ProcessButtonsAsync(node);
                        }
                    }, parsedSection.DelayInMs);
                }
            }
        }