feat(integration): ✨ Add Google Analytics integration
This commit is contained in:
37
packages/bot-engine/lib/gtag.ts
Normal file
37
packages/bot-engine/lib/gtag.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { GoogleAnalyticsOptions } from 'models'
|
||||
|
||||
declare const gtag: any
|
||||
|
||||
const initGoogleAnalytics = (id: string): Promise<void> =>
|
||||
new Promise((resolve) => {
|
||||
const existingScript = document.getElementById('gtag')
|
||||
if (!existingScript) {
|
||||
const script = document.createElement('script')
|
||||
script.src = `https://www.googletagmanager.com/gtag/js?id=${id}`
|
||||
script.id = 'gtag'
|
||||
const initScript = document.createElement('script')
|
||||
initScript.innerHTML = `window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', '${id}');
|
||||
`
|
||||
document.body.appendChild(script)
|
||||
document.body.appendChild(initScript)
|
||||
script.onload = () => {
|
||||
resolve()
|
||||
}
|
||||
}
|
||||
if (existingScript) resolve()
|
||||
})
|
||||
|
||||
export const sendGaEvent = (options: GoogleAnalyticsOptions) => {
|
||||
if (!options) return
|
||||
gtag('event', options.action, {
|
||||
event_category: options.category,
|
||||
event_label: options.label,
|
||||
value: options.value,
|
||||
})
|
||||
}
|
||||
|
||||
export default initGoogleAnalytics
|
@ -26,7 +26,8 @@ export const HostMessageBubble = ({
|
||||
const [isTyping, setIsTyping] = useState(true)
|
||||
|
||||
const content = useMemo(
|
||||
() => parseVariables(step.content.html, typebot.variables),
|
||||
() =>
|
||||
parseVariables({ text: step.content.html, variables: typebot.variables }),
|
||||
[typebot.variables]
|
||||
)
|
||||
|
||||
|
@ -9,10 +9,12 @@ import {
|
||||
GoogleSheetsUpdateRowOptions,
|
||||
Cell,
|
||||
GoogleSheetsGetOptions,
|
||||
GoogleAnalyticsStep,
|
||||
} from 'models'
|
||||
import { stringify } from 'qs'
|
||||
import { sendRequest } from 'utils'
|
||||
import { parseVariables } from './variable'
|
||||
import { sendGaEvent } from '../../lib/gtag'
|
||||
import { parseVariables, parseVariablesInObject } from './variable'
|
||||
|
||||
export const executeIntegration = (
|
||||
step: IntegrationStep,
|
||||
@ -22,9 +24,21 @@ export const executeIntegration = (
|
||||
switch (step.type) {
|
||||
case IntegrationStepType.GOOGLE_SHEETS:
|
||||
return executeGoogleSheetIntegration(step, variables, updateVariableValue)
|
||||
case IntegrationStepType.GOOGLE_ANALYTICS:
|
||||
return executeGoogleAnalyticsIntegration(step, variables)
|
||||
}
|
||||
}
|
||||
|
||||
export const executeGoogleAnalyticsIntegration = async (
|
||||
step: GoogleAnalyticsStep,
|
||||
variables: Table<Variable>
|
||||
) => {
|
||||
if (!step.options?.trackingId) return
|
||||
const { default: initGoogleAnalytics } = await import('../../lib/gtag')
|
||||
await initGoogleAnalytics(step.options.trackingId)
|
||||
sendGaEvent(parseVariablesInObject(step.options, variables))
|
||||
}
|
||||
|
||||
const executeGoogleSheetIntegration = async (
|
||||
step: GoogleSheetsStep,
|
||||
variables: Table<Variable>,
|
||||
@ -73,7 +87,10 @@ const updateRowInGoogleSheets = async (
|
||||
values: parseCellValues(options.cellsToUpsert, variables),
|
||||
referenceCell: {
|
||||
column: options.referenceCell.column,
|
||||
value: parseVariables(options.referenceCell.value ?? '', variables),
|
||||
value: parseVariables({
|
||||
text: options.referenceCell.value ?? '',
|
||||
variables,
|
||||
}),
|
||||
},
|
||||
},
|
||||
})
|
||||
@ -90,7 +107,10 @@ const getRowFromGoogleSheets = async (
|
||||
credentialsId: options.credentialsId,
|
||||
referenceCell: {
|
||||
column: options.referenceCell.column,
|
||||
value: parseVariables(options.referenceCell.value ?? '', variables),
|
||||
value: parseVariables({
|
||||
text: options.referenceCell.value ?? '',
|
||||
variables,
|
||||
}),
|
||||
},
|
||||
columns: options.cellsToExtract.allIds.map(
|
||||
(id) => options.cellsToExtract?.byId[id].column
|
||||
@ -117,5 +137,8 @@ const parseCellValues = (
|
||||
const cell = cells.byId[id]
|
||||
return !cell.column || !cell.value
|
||||
? row
|
||||
: { ...row, [cell.column]: parseVariables(cell.value, variables) }
|
||||
: {
|
||||
...row,
|
||||
[cell.column]: parseVariables({ text: cell.value, variables }),
|
||||
}
|
||||
}, {})
|
||||
|
@ -22,7 +22,7 @@ export const executeLogic = (
|
||||
return
|
||||
const expression = step.options.expressionToEvaluate
|
||||
const evaluatedExpression = isMathFormula(expression)
|
||||
? evaluateExpression(parseVariables(expression, variables))
|
||||
? evaluateExpression(parseVariables({ text: expression, variables }))
|
||||
: expression
|
||||
updateVariableValue(step.options.variableId, evaluatedExpression)
|
||||
return
|
||||
|
@ -6,11 +6,14 @@ const safeEval = eval
|
||||
export const stringContainsVariable = (str: string): boolean =>
|
||||
/\{\{(.*?)\}\}/g.test(str)
|
||||
|
||||
export const parseVariables = (
|
||||
text: string,
|
||||
export const parseVariables = ({
|
||||
text,
|
||||
variables,
|
||||
}: {
|
||||
text?: string
|
||||
variables: Table<Variable>
|
||||
): string => {
|
||||
if (text === '') return text
|
||||
}): string => {
|
||||
if (!text || text === '') return ''
|
||||
return text.replace(/\{\{(.*?)\}\}/g, (_, fullVariableString) => {
|
||||
const matchedVarName = fullVariableString.replace(/{{|}}/g, '')
|
||||
const matchedVariableId = variables.allIds.find((variableId) => {
|
||||
@ -44,3 +47,18 @@ const countDecimals = (value: number) => {
|
||||
if (value % 1 != 0) return value.toString().split('.')[1].length
|
||||
return 0
|
||||
}
|
||||
|
||||
export const parseVariablesInObject = (
|
||||
object: { [key: string]: string | number },
|
||||
variables: Table<Variable>
|
||||
) =>
|
||||
Object.keys(object).reduce((newObj, key) => {
|
||||
const currentValue = object[key]
|
||||
return {
|
||||
...newObj,
|
||||
[key]:
|
||||
typeof currentValue === 'string'
|
||||
? parseVariables({ text: currentValue, variables })
|
||||
: currentValue,
|
||||
}
|
||||
}, {})
|
||||
|
@ -1,12 +1,15 @@
|
||||
import { StepBase } from '.'
|
||||
import { Table } from '../..'
|
||||
|
||||
export type IntegrationStep = GoogleSheetsStep
|
||||
export type IntegrationStep = GoogleSheetsStep | GoogleAnalyticsStep
|
||||
|
||||
export type IntegrationStepOptions = GoogleSheetsOptions
|
||||
export type IntegrationStepOptions =
|
||||
| GoogleSheetsOptions
|
||||
| GoogleAnalyticsOptions
|
||||
|
||||
export enum IntegrationStepType {
|
||||
GOOGLE_SHEETS = 'Google Sheets',
|
||||
GOOGLE_ANALYTICS = 'Google Analytics',
|
||||
}
|
||||
|
||||
export type GoogleSheetsStep = StepBase & {
|
||||
@ -14,6 +17,19 @@ export type GoogleSheetsStep = StepBase & {
|
||||
options?: GoogleSheetsOptions
|
||||
}
|
||||
|
||||
export type GoogleAnalyticsStep = StepBase & {
|
||||
type: IntegrationStepType.GOOGLE_ANALYTICS
|
||||
options?: GoogleAnalyticsOptions
|
||||
}
|
||||
|
||||
export type GoogleAnalyticsOptions = {
|
||||
trackingId?: string
|
||||
category?: string
|
||||
action?: string
|
||||
label?: string
|
||||
value?: number
|
||||
}
|
||||
|
||||
export enum GoogleSheetsAction {
|
||||
GET = 'Get data from sheet',
|
||||
INSERT_ROW = 'Insert a row',
|
||||
|
@ -73,4 +73,4 @@ export const isConditionStep = (step: Step): step is ConditionStep =>
|
||||
step.type === LogicStepType.CONDITION
|
||||
|
||||
export const isIntegrationStep = (step: Step): step is IntegrationStep =>
|
||||
step.type === IntegrationStepType.GOOGLE_SHEETS
|
||||
(Object.values(IntegrationStepType) as string[]).includes(step.type)
|
||||
|
Reference in New Issue
Block a user