diff --git a/apps/builder/src/features/results/components/ResultsTableContainer.tsx b/apps/builder/src/features/results/components/ResultsTableContainer.tsx index ef3464004..89c53cdfa 100644 --- a/apps/builder/src/features/results/components/ResultsTableContainer.tsx +++ b/apps/builder/src/features/results/components/ResultsTableContainer.tsx @@ -1,12 +1,14 @@ import { Stack } from '@chakra-ui/react' -import React, { useState } from 'react' +import React, { useEffect, useState } from 'react' import { LogsModal } from './LogsModal' import { useTypebot } from '@/features/editor/providers/TypebotProvider' import { useResults } from '../ResultsProvider' import { ResultModal } from './ResultModal' import { ResultsTable } from './table/ResultsTable' +import { useRouter } from 'next/router' export const ResultsTableContainer = () => { + const { query } = useRouter() const { flatResults: results, fetchNextPage, @@ -34,6 +36,10 @@ export const ResultsTableContainer = () => { setExpandedResultId(results[index].id) } + useEffect(() => { + if (query.id) setExpandedResultId(query.id as string) + }, [query.id]) + return ( {publishedTypebot && ( diff --git a/apps/docs/docs/editor/blocks/integrations/chatwoot.md b/apps/docs/docs/editor/blocks/integrations/chatwoot.md index bf2bf7b65..b06e9b109 100644 --- a/apps/docs/docs/editor/blocks/integrations/chatwoot.md +++ b/apps/docs/docs/editor/blocks/integrations/chatwoot.md @@ -31,3 +31,16 @@ To find your website token, head over to Chatwoot in your Inbox settings: You can prefill user information by adding collected variables to the "Set user details" inputs. For example, if you set the "Email" input to "john@gmail.com" then Chatwoot will automatically associate this email to the current user. + +## Custom attributes + +You can add these custom attributes that Typebot will automatically fill in for you: + +### Result URL + +You can link the current result URL to the Chatwoot conversation by creating this custom attribute: + +Chatwoot custom attribute diff --git a/apps/docs/static/img/blocks/integrations/chatwoot/custom-attribute.png b/apps/docs/static/img/blocks/integrations/chatwoot/custom-attribute.png new file mode 100644 index 000000000..e4dad38be Binary files /dev/null and b/apps/docs/static/img/blocks/integrations/chatwoot/custom-attribute.png differ diff --git a/apps/viewer/src/features/blocks/integrations/chatwoot/executeChatwootBlock.ts b/apps/viewer/src/features/blocks/integrations/chatwoot/executeChatwootBlock.ts index 9218ddd86..c95b7547e 100644 --- a/apps/viewer/src/features/blocks/integrations/chatwoot/executeChatwootBlock.ts +++ b/apps/viewer/src/features/blocks/integrations/chatwoot/executeChatwootBlock.ts @@ -2,32 +2,47 @@ import { ExecuteIntegrationResponse } from '@/features/chat/types' import { extractVariablesFromText } from '@/features/variables/extractVariablesFromText' import { parseGuessedValueType } from '@/features/variables/parseGuessedValueType' import { parseVariables } from '@/features/variables/parseVariables' +import { isDefined } from '@typebot.io/lib' import { ChatwootBlock, ChatwootOptions, SessionState, } from '@typebot.io/schemas' -const parseSetUserCode = (user: ChatwootOptions['user']) => ` -window.$chatwoot.setUser("${user?.id ?? ''}", { - email: ${user?.email ? `"${user.email}"` : 'undefined'}, - name: ${user?.name ? `"${user.name}"` : 'undefined'}, - avatar_url: ${user?.avatarUrl ? `"${user.avatarUrl}"` : 'undefined'}, - phone_number: ${user?.phoneNumber ? `"${user.phoneNumber}"` : 'undefined'}, -}); +const parseSetUserCode = (user: ChatwootOptions['user'], resultId: string) => + user?.email || user?.id + ? ` +window.$chatwoot.setUser(${user?.id ?? `"${resultId}"`}, { + email: ${user?.email ? user.email : 'undefined'}, + name: ${user?.name ? user.name : 'undefined'}, + avatar_url: ${user?.avatarUrl ? user.avatarUrl : 'undefined'}, + phone_number: ${user?.phoneNumber ? user.phoneNumber : 'undefined'}, +});` + : '' -` const parseChatwootOpenCode = ({ baseUrl, websiteToken, user, -}: ChatwootOptions) => ` -if (window.$chatwoot) { - if(${Boolean(user)}) { - ${parseSetUserCode(user)} - } + resultId, + typebotId, +}: ChatwootOptions & { typebotId: string; resultId: string }) => { + const openChatwoot = `${parseSetUserCode(user, resultId)} + window.$chatwoot.setCustomAttributes({ + typebot_result_url: "${ + process.env.NEXTAUTH_URL + }/typebots/${typebotId}/results?id=${resultId}", + }); window.$chatwoot.toggle("open"); -} else { + ` + + return ` + window.addEventListener("chatwoot:error", function (error) { + console.log(error); + }); + + if (window.$chatwoot) {${openChatwoot}} + else { (function (d, t) { var BASE_URL = "${baseUrl}"; var g = d.createElement(t), @@ -41,15 +56,11 @@ if (window.$chatwoot) { websiteToken: "${websiteToken}", baseUrl: BASE_URL, }); - window.addEventListener("chatwoot:ready", function () { - if(${Boolean(user?.id || user?.email)}) { - ${parseSetUserCode(user)} - } - window.$chatwoot.toggle("open"); - }); + window.addEventListener("chatwoot:ready", function () {${openChatwoot}}); }; })(document, "script"); }` +} const chatwootCloseCode = ` if (window.$chatwoot) { @@ -59,17 +70,20 @@ if (window.$chatwoot) { ` export const executeChatwootBlock = ( - { typebot: { variables }, result }: SessionState, + { typebot, result }: SessionState, block: ChatwootBlock, lastBubbleBlockId?: string ): ExecuteIntegrationResponse => { - const isPreview = !result.id const chatwootCode = block.options.task === 'Close widget' ? chatwootCloseCode - : isPreview - ? '' - : parseChatwootOpenCode(block.options) + : isDefined(result.id) + ? parseChatwootOpenCode({ + ...block.options, + typebotId: typebot.id, + resultId: result.id, + }) + : '' return { outgoingEdgeId: block.outgoingEdgeId, clientSideActions: [ @@ -77,10 +91,10 @@ export const executeChatwootBlock = ( lastBubbleBlockId, chatwoot: { scriptToExecute: { - content: parseVariables(variables, { fieldToParse: 'id' })( + content: parseVariables(typebot.variables, { fieldToParse: 'id' })( chatwootCode ), - args: extractVariablesFromText(variables)(chatwootCode).map( + args: extractVariablesFromText(typebot.variables)(chatwootCode).map( (variable) => ({ id: variable.id, value: parseGuessedValueType(variable.value), diff --git a/apps/viewer/src/features/variables/extractVariablesFromText.ts b/apps/viewer/src/features/variables/extractVariablesFromText.ts index 029f14b55..c74d8876b 100644 --- a/apps/viewer/src/features/variables/extractVariablesFromText.ts +++ b/apps/viewer/src/features/variables/extractVariablesFromText.ts @@ -9,7 +9,11 @@ export const extractVariablesFromText = const variable = variables.find( (variable) => variable.name === variableName ) - if (!variable) return acc + if ( + !variable || + acc.find((accVariable) => accVariable.id === variable.id) + ) + return acc return [...acc, variable] }, []) }