import React, { useState, useCallback, useEffect, useRef } from "react"; import { Linking, SafeAreaView } from "react-native"; import { GiftedChat, IAccordionMessage, IButtonMessage, IInfoMessage, IListMessage, IMessage, Reply, User, } from "./ui"; //import { DialogFlowAPI } from './tests/mockApi'; import { DialogFlowAPI } from "./api"; import { dialogFlowMessagesToGiftMessages, repluToGiftMessage } from "./util"; import { v4 as uuidv4 } from "uuid"; import { styles } from "./styles"; import { AccordionElement, ButtonElement, DialogFlowMessengerProps, ListElement, } from "./types"; const agentUser: User = { _id: 2, avatar: null, }; export function DialogFlowMessenger({ location, agent, language, dfMessengerBotMessage, dfMessengerUserMessage, dfMessengerFontColor = "black", dfAccordionClicked, dfButtonClicked, dfChipClicked, dfInfoCardClicked, dfListElementClicked, dfMessengerError, dfRequestSent, dfResponseReceived, dfUserInputEntered, }: DialogFlowMessengerProps) { const [session, setSession] = useState(uuidv4()); const [messages, setMessages] = useState>([]); const api = new DialogFlowAPI({ location, agent, language, session, onSend: dfRequestSent, onError: dfMessengerError, }); const chat = useRef(); const onSend = useCallback( async (messages = []) => { try { // Add message to chat log setMessages((previousMessages) => GiftedChat.append(previousMessages, messages), ); // Call Dialogflow messages.forEach(async (message) => { try { const response = await api.detectIntent(message.text); processResponse(response); scrollToBottom(); } catch (e) {} }); } catch (e) {} }, [messages], ); const scrollToBottom = useCallback(() => { chat.current.scrollToBottom(); }, [chat]); const processResponse = useCallback( (response) => { const reponseMessages = dialogFlowMessagesToGiftMessages( response.queryResult.responseMessages, agentUser, ); setMessages((previousMessages) => GiftedChat.append(previousMessages, reponseMessages), ); }, [messages], ); const clearQuickReplies = useCallback(() => { const newMessages = messages.splice(0); newMessages.shift(); setMessages(newMessages); }, [messages]); const processChip = useCallback( async (replies: Reply[]) => { for (let reply of replies) { if (reply.link) { dfChipClicked(reply.title); const supported = await Linking.canOpenURL(reply.link); if (supported) { await Linking.openURL(reply.link); //clearQuickReplies() return; } } } const messages = replies.map(repluToGiftMessage); if (messages) { await onSend(messages); } }, [messages], ); const processInfo = useCallback(async (message: IInfoMessage) => { if (dfInfoCardClicked) { dfInfoCardClicked(message.raw); } if (message.link) { const supported = await Linking.canOpenURL(message.link); if (supported) { await Linking.openURL(message.link); return; } } }, []); const processButton = useCallback(async (message: IButtonMessage) => { if (dfButtonClicked) { const element = message.raw as ButtonElement; dfButtonClicked({ element: element, }); } if (message.link) { const supported = await Linking.canOpenURL(message.link); if (supported) { await Linking.openURL(message.link); return; } } else if (message.event) { try { const response = await api.detectIntentEvent( message.event, message.parameters, ); processResponse(response); } catch (e) {} } }, []); const processList = useCallback(async (message: IListMessage) => { if (dfListElementClicked) { const element = message.raw as ListElement; dfListElementClicked({ element }); } if (message.event) { try { const response = await api.detectIntentEvent( message.event, message.parameters, ); processResponse(response); } catch (e) {} } }, []); const processAccordion = useCallback(async (message: IAccordionMessage) => { if (dfAccordionClicked) { const element = message.raw as AccordionElement; dfAccordionClicked({ element }); } }, []); return ( onSend(messages)} placeholder={"Ask something..."} user={{ _id: 1, avatar: null, }} onQuickReply={(replies) => processChip(replies)} onInfoPress={(message) => processInfo(message)} onButtonPress={(message) => processButton(message)} onListPress={(message) => processList(message)} onAccordionPress={(message) => processAccordion(message)} /> ); }