@@ -7,6 +7,8 @@ import { TypebotPageProps, TypebotPageV2 } from '@/components/TypebotPageV2'
|
||||
import { TypebotPageV3, TypebotV3PageProps } from '@/components/TypebotPageV3'
|
||||
import { env } from '@typebot.io/env'
|
||||
import prisma from '@typebot.io/lib/prisma'
|
||||
import { defaultTheme } from '@typebot.io/schemas/features/typebot/theme/constants'
|
||||
import { defaultSettings } from '@typebot.io/schemas/features/typebot/settings/constants'
|
||||
|
||||
// Browsers that doesn't support ES modules and/or web components
|
||||
const incompatibleBrowsers = [
|
||||
@@ -61,6 +63,7 @@ export const getServerSideProps: GetServerSideProps = async (
|
||||
const publishedTypebot = isMatchingViewerUrl
|
||||
? await getTypebotFromPublicId(context.query.publicId?.toString())
|
||||
: await getTypebotFromCustomDomain(customDomain)
|
||||
|
||||
return {
|
||||
props: {
|
||||
publishedTypebot,
|
||||
@@ -106,11 +109,14 @@ const getTypebotFromPublicId = async (publicId?: string) => {
|
||||
? ({
|
||||
name: publishedTypebot.typebot.name,
|
||||
publicId: publishedTypebot.typebot.publicId ?? null,
|
||||
background: publishedTypebot.theme.general.background,
|
||||
background:
|
||||
publishedTypebot.theme.general?.background ??
|
||||
defaultTheme.general.background,
|
||||
isHideQueryParamsEnabled:
|
||||
publishedTypebot.settings.general.isHideQueryParamsEnabled ?? null,
|
||||
metadata: publishedTypebot.settings.metadata,
|
||||
} as Pick<
|
||||
publishedTypebot.settings.general?.isHideQueryParamsEnabled ??
|
||||
defaultSettings.general.isHideQueryParamsEnabled,
|
||||
metadata: publishedTypebot.settings.metadata ?? {},
|
||||
} satisfies Pick<
|
||||
TypebotV3PageProps,
|
||||
| 'name'
|
||||
| 'publicId'
|
||||
@@ -148,11 +154,14 @@ const getTypebotFromCustomDomain = async (customDomain: string) => {
|
||||
? ({
|
||||
name: publishedTypebot.typebot.name,
|
||||
publicId: publishedTypebot.typebot.publicId ?? null,
|
||||
background: publishedTypebot.theme.general.background,
|
||||
background:
|
||||
publishedTypebot.theme.general?.background ??
|
||||
defaultTheme.general.background,
|
||||
isHideQueryParamsEnabled:
|
||||
publishedTypebot.settings.general.isHideQueryParamsEnabled ?? null,
|
||||
metadata: publishedTypebot.settings.metadata,
|
||||
} as Pick<
|
||||
publishedTypebot.settings.general?.isHideQueryParamsEnabled ??
|
||||
defaultSettings.general.isHideQueryParamsEnabled,
|
||||
metadata: publishedTypebot.settings.metadata ?? {},
|
||||
} satisfies Pick<
|
||||
TypebotV3PageProps,
|
||||
| 'name'
|
||||
| 'publicId'
|
||||
@@ -214,9 +223,14 @@ const App = ({
|
||||
url={props.url}
|
||||
name={publishedTypebot.name}
|
||||
publicId={publishedTypebot.publicId}
|
||||
isHideQueryParamsEnabled={publishedTypebot.isHideQueryParamsEnabled}
|
||||
background={publishedTypebot.background}
|
||||
metadata={publishedTypebot.metadata}
|
||||
isHideQueryParamsEnabled={
|
||||
publishedTypebot.isHideQueryParamsEnabled ??
|
||||
defaultSettings.general.isHideQueryParamsEnabled
|
||||
}
|
||||
background={
|
||||
publishedTypebot.background ?? defaultTheme.general.background
|
||||
}
|
||||
metadata={publishedTypebot.metadata ?? {}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -8,17 +8,19 @@ import {
|
||||
import { hasValue, isDefined } from '@typebot.io/lib'
|
||||
import { GoogleSpreadsheet, GoogleSpreadsheetRow } from 'google-spreadsheet'
|
||||
import {
|
||||
ComparisonOperators,
|
||||
GoogleSheetsAction,
|
||||
GoogleSheetsGetOptions,
|
||||
GoogleSheetsInsertRowOptions,
|
||||
GoogleSheetsUpdateRowOptions,
|
||||
LogicalOperator,
|
||||
} from '@typebot.io/schemas'
|
||||
import Cors from 'cors'
|
||||
import { getAuthenticatedGoogleClient } from '@/lib/google-sheets'
|
||||
import { saveErrorLog } from '@typebot.io/bot-engine/logs/saveErrorLog'
|
||||
import { saveSuccessLog } from '@typebot.io/bot-engine/logs/saveSuccessLog'
|
||||
import { GoogleSheetsAction } from '@typebot.io/schemas/features/blocks/integrations/googleSheets/constants'
|
||||
import {
|
||||
ComparisonOperators,
|
||||
LogicalOperator,
|
||||
} from '@typebot.io/schemas/features/blocks/logic/condition/constants'
|
||||
|
||||
const cors = initMiddleware(Cors())
|
||||
|
||||
@@ -43,11 +45,12 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
const getRows = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
const sheetId = req.query.sheetId as string
|
||||
const spreadsheetId = req.query.spreadsheetId as string
|
||||
const { resultId, credentialsId, referenceCell, filter, columns } =
|
||||
req.body as GoogleSheetsGetOptions & {
|
||||
resultId?: string
|
||||
columns: string[] | string
|
||||
}
|
||||
const body = req.body as GoogleSheetsGetOptions & {
|
||||
resultId?: string
|
||||
columns: string[] | string
|
||||
}
|
||||
const referenceCell = 'referenceCell' in body ? body.referenceCell : undefined
|
||||
const { resultId, credentialsId, filter, columns } = body
|
||||
|
||||
if (!hasValue(credentialsId)) {
|
||||
badRequest(res)
|
||||
@@ -141,11 +144,13 @@ const insertRow = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
const updateRow = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
const sheetId = req.query.sheetId as string
|
||||
const spreadsheetId = req.query.spreadsheetId as string
|
||||
const { resultId, credentialsId, values, referenceCell } =
|
||||
req.body as GoogleSheetsUpdateRowOptions & {
|
||||
resultId?: string
|
||||
values: { [key: string]: string }
|
||||
}
|
||||
const body = req.body as GoogleSheetsUpdateRowOptions & {
|
||||
resultId?: string
|
||||
values: { [key: string]: string }
|
||||
}
|
||||
const referenceCell = 'referenceCell' in body ? body.referenceCell : undefined
|
||||
const { resultId, credentialsId, values } = body
|
||||
|
||||
if (!hasValue(credentialsId) || !referenceCell) return badRequest(res)
|
||||
const auth = await getAuthenticatedGoogleClient(credentialsId)
|
||||
if (!auth)
|
||||
@@ -181,7 +186,7 @@ const matchFilter = (
|
||||
filter: NonNullable<GoogleSheetsGetOptions['filter']>
|
||||
) => {
|
||||
return filter.logicalOperator === LogicalOperator.AND
|
||||
? filter.comparisons.every(
|
||||
? filter.comparisons?.every(
|
||||
(comparison) =>
|
||||
comparison.column &&
|
||||
matchComparison(
|
||||
@@ -190,7 +195,7 @@ const matchFilter = (
|
||||
comparison.value
|
||||
)
|
||||
)
|
||||
: filter.comparisons.some(
|
||||
: filter.comparisons?.some(
|
||||
(comparison) =>
|
||||
comparison.column &&
|
||||
matchComparison(
|
||||
|
||||
@@ -10,12 +10,13 @@ import Stripe from 'stripe'
|
||||
|
||||
import Cors from 'cors'
|
||||
import {
|
||||
PaymentInputOptions,
|
||||
PaymentInputBlock,
|
||||
StripeCredentials,
|
||||
Variable,
|
||||
} from '@typebot.io/schemas'
|
||||
import prisma from '@typebot.io/lib/prisma'
|
||||
import { parseVariables } from '@typebot.io/bot-engine/variables/parseVariables'
|
||||
import { defaultPaymentInputOptions } from '@typebot.io/schemas/features/blocks/inputs/payment/constants'
|
||||
|
||||
const cors = initMiddleware(Cors())
|
||||
|
||||
@@ -43,11 +44,11 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
const { inputOptions, isPreview, variables } = (
|
||||
typeof req.body === 'string' ? JSON.parse(req.body) : req.body
|
||||
) as {
|
||||
inputOptions: PaymentInputOptions
|
||||
inputOptions: PaymentInputBlock['options']
|
||||
isPreview: boolean
|
||||
variables: Variable[]
|
||||
}
|
||||
if (!inputOptions.credentialsId) return forbidden(res)
|
||||
if (!inputOptions?.credentialsId) return forbidden(res)
|
||||
const stripeKeys = await getStripeInfo(inputOptions.credentialsId)
|
||||
if (!stripeKeys) return forbidden(res)
|
||||
const stripe = new Stripe(
|
||||
@@ -56,9 +57,13 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
: stripeKeys.live.secretKey,
|
||||
{ apiVersion: '2022-11-15' }
|
||||
)
|
||||
|
||||
const currency =
|
||||
inputOptions.currency ?? defaultPaymentInputOptions.currency
|
||||
|
||||
const amount = Math.round(
|
||||
Number(parseVariables(variables)(inputOptions.amount)) *
|
||||
(isZeroDecimalCurrency(inputOptions.currency) ? 1 : 100)
|
||||
(isZeroDecimalCurrency(currency) ? 1 : 100)
|
||||
)
|
||||
if (isNaN(amount)) return badRequest(res)
|
||||
// Create a PaymentIntent with the order amount and currency
|
||||
@@ -68,7 +73,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
try {
|
||||
const paymentIntent = await stripe.paymentIntents.create({
|
||||
amount,
|
||||
currency: inputOptions.currency,
|
||||
currency,
|
||||
receipt_email: receiptEmail === '' ? undefined : receiptEmail,
|
||||
automatic_payment_methods: {
|
||||
enabled: true,
|
||||
@@ -81,10 +86,8 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
isPreview && stripeKeys.test?.publicKey
|
||||
? stripeKeys.test.publicKey
|
||||
: stripeKeys.live.publicKey,
|
||||
amountLabel: `${
|
||||
amount / (isZeroDecimalCurrency(inputOptions.currency) ? 1 : 100)
|
||||
}${
|
||||
currencySymbols[inputOptions.currency] ?? ` ${inputOptions.currency}`
|
||||
amountLabel: `${amount / (isZeroDecimalCurrency(currency) ? 1 : 100)}${
|
||||
currencySymbols[currency] ?? ` ${currency}`
|
||||
}`,
|
||||
})
|
||||
} catch (err) {
|
||||
|
||||
@@ -1,30 +1,33 @@
|
||||
import {
|
||||
defaultWebhookAttributes,
|
||||
KeyValue,
|
||||
PublicTypebot,
|
||||
ResultValues,
|
||||
Typebot,
|
||||
Variable,
|
||||
Webhook,
|
||||
WebhookOptions,
|
||||
WebhookResponse,
|
||||
WebhookBlock,
|
||||
Block,
|
||||
} from '@typebot.io/schemas'
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
import got, { Method, Headers, HTTPError } from 'got'
|
||||
import { byId, omit } from '@typebot.io/lib'
|
||||
import { byId, isEmpty, omit } from '@typebot.io/lib'
|
||||
import { parseAnswers } from '@typebot.io/lib/results'
|
||||
import { initMiddleware, methodNotAllowed, notFound } from '@typebot.io/lib/api'
|
||||
import { stringify } from 'qs'
|
||||
import Cors from 'cors'
|
||||
import prisma from '@typebot.io/lib/prisma'
|
||||
import { HttpMethod } from '@typebot.io/schemas/features/blocks/integrations/webhook/enums'
|
||||
import { fetchLinkedTypebots } from '@typebot.io/bot-engine/blocks/logic/typebotLink/fetchLinkedTypebots'
|
||||
import { getPreviouslyLinkedTypebots } from '@typebot.io/bot-engine/blocks/logic/typebotLink/getPreviouslyLinkedTypebots'
|
||||
import { parseVariables } from '@typebot.io/bot-engine/variables/parseVariables'
|
||||
import { saveErrorLog } from '@typebot.io/bot-engine/logs/saveErrorLog'
|
||||
import { saveSuccessLog } from '@typebot.io/bot-engine/logs/saveSuccessLog'
|
||||
import { parseSampleResult } from '@typebot.io/bot-engine/blocks/integrations/webhook/parseSampleResult'
|
||||
import {
|
||||
HttpMethod,
|
||||
defaultWebhookAttributes,
|
||||
} from '@typebot.io/schemas/features/blocks/integrations/webhook/constants'
|
||||
import { getBlockById } from '@typebot.io/lib/getBlockById'
|
||||
import { IntegrationBlockType } from '@typebot.io/schemas/features/blocks/integrations/constants'
|
||||
|
||||
const cors = initMiddleware(Cors())
|
||||
|
||||
@@ -47,40 +50,36 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
})) as unknown as (Typebot & { webhooks: Webhook[] }) | null
|
||||
if (!typebot) return notFound(res)
|
||||
const block = typebot.groups
|
||||
.flatMap((g) => g.blocks)
|
||||
.find(byId(blockId)) as WebhookBlock
|
||||
.flatMap<Block>((g) => g.blocks)
|
||||
.find(byId(blockId))
|
||||
if (block?.type !== IntegrationBlockType.WEBHOOK)
|
||||
return notFound(res, 'Webhook block not found')
|
||||
const webhookId = 'webhookId' in block ? block.webhookId : undefined
|
||||
const webhook =
|
||||
block.options.webhook ?? typebot.webhooks.find(byId(block.webhookId))
|
||||
block.options?.webhook ??
|
||||
typebot.webhooks.find((w) => {
|
||||
if ('id' in w) return w.id === webhookId
|
||||
return false
|
||||
})
|
||||
if (!webhook)
|
||||
return res
|
||||
.status(404)
|
||||
.send({ statusCode: 404, data: { message: `Couldn't find webhook` } })
|
||||
const preparedWebhook = prepareWebhookAttributes(webhook, block.options)
|
||||
const { group } = getBlockById(blockId, typebot.groups)
|
||||
const result = await executeWebhook(typebot)({
|
||||
webhook: preparedWebhook,
|
||||
webhook,
|
||||
variables,
|
||||
groupId: block.groupId,
|
||||
groupId: group.id,
|
||||
resultValues,
|
||||
resultId,
|
||||
parentTypebotIds,
|
||||
isCustomBody: block.options?.isCustomBody,
|
||||
})
|
||||
return res.status(200).send(result)
|
||||
}
|
||||
return methodNotAllowed(res)
|
||||
}
|
||||
|
||||
const prepareWebhookAttributes = (
|
||||
webhook: Webhook,
|
||||
options: WebhookOptions
|
||||
): Webhook => {
|
||||
if (options.isAdvancedConfig === false) {
|
||||
return { ...webhook, body: '{{state}}', ...defaultWebhookAttributes }
|
||||
} else if (options.isCustomBody === false) {
|
||||
return { ...webhook, body: '{{state}}' }
|
||||
}
|
||||
return webhook
|
||||
}
|
||||
|
||||
const checkIfBodyIsAVariable = (body: string) => /^{{.+}}$/.test(body)
|
||||
|
||||
export const executeWebhook =
|
||||
@@ -92,6 +91,7 @@ export const executeWebhook =
|
||||
resultValues,
|
||||
resultId,
|
||||
parentTypebotIds = [],
|
||||
isCustomBody,
|
||||
}: {
|
||||
webhook: Webhook
|
||||
variables: Variable[]
|
||||
@@ -99,27 +99,29 @@ export const executeWebhook =
|
||||
resultValues?: ResultValues
|
||||
resultId?: string
|
||||
parentTypebotIds: string[]
|
||||
isCustomBody?: boolean
|
||||
}): Promise<WebhookResponse> => {
|
||||
if (!webhook.url || !webhook.method)
|
||||
if (!webhook.url)
|
||||
return {
|
||||
statusCode: 400,
|
||||
data: { message: `Webhook doesn't have url or method` },
|
||||
}
|
||||
const basicAuth: { username?: string; password?: string } = {}
|
||||
const basicAuthHeaderIdx = webhook.headers.findIndex(
|
||||
(h) =>
|
||||
h.key?.toLowerCase() === 'authorization' &&
|
||||
h.value?.toLowerCase()?.includes('basic')
|
||||
)
|
||||
const basicAuthHeaderIdx =
|
||||
webhook.headers?.findIndex(
|
||||
(h) =>
|
||||
h.key?.toLowerCase() === 'authorization' &&
|
||||
h.value?.toLowerCase()?.includes('basic')
|
||||
) ?? -1
|
||||
const isUsernamePasswordBasicAuth =
|
||||
basicAuthHeaderIdx !== -1 &&
|
||||
webhook.headers[basicAuthHeaderIdx].value?.includes(':')
|
||||
webhook.headers?.[basicAuthHeaderIdx].value?.includes(':')
|
||||
if (isUsernamePasswordBasicAuth) {
|
||||
const [username, password] =
|
||||
webhook.headers[basicAuthHeaderIdx].value?.slice(6).split(':') ?? []
|
||||
webhook.headers?.[basicAuthHeaderIdx].value?.slice(6).split(':') ?? []
|
||||
basicAuth.username = username
|
||||
basicAuth.password = password
|
||||
webhook.headers.splice(basicAuthHeaderIdx, 1)
|
||||
webhook.headers?.splice(basicAuthHeaderIdx, 1)
|
||||
}
|
||||
const headers = convertKeyValueTableToObject(webhook.headers, variables) as
|
||||
| Headers
|
||||
@@ -141,6 +143,7 @@ export const executeWebhook =
|
||||
...linkedTypebotsChildren,
|
||||
])({
|
||||
body: webhook.body,
|
||||
isCustomBody,
|
||||
resultValues,
|
||||
groupId,
|
||||
variables,
|
||||
@@ -158,8 +161,8 @@ export const executeWebhook =
|
||||
url: parseVariables(variables)(
|
||||
webhook.url + (queryParams !== '' ? `?${queryParams}` : '')
|
||||
),
|
||||
method: webhook.method as Method,
|
||||
headers,
|
||||
method: (webhook.method ?? defaultWebhookAttributes.method) as Method,
|
||||
headers: headers ?? {},
|
||||
...basicAuth,
|
||||
json:
|
||||
!contentType?.includes('x-www-form-urlencoded') && body && isJson
|
||||
@@ -229,14 +232,15 @@ const getBodyContent =
|
||||
resultValues,
|
||||
groupId,
|
||||
variables,
|
||||
isCustomBody,
|
||||
}: {
|
||||
body?: string | null
|
||||
resultValues?: ResultValues
|
||||
groupId: string
|
||||
variables: Variable[]
|
||||
isCustomBody?: boolean
|
||||
}): Promise<string | undefined> => {
|
||||
if (!body) return
|
||||
return body === '{{state}}'
|
||||
return isEmpty(body) && isCustomBody !== true
|
||||
? JSON.stringify(
|
||||
resultValues
|
||||
? parseAnswers({
|
||||
@@ -260,7 +264,7 @@ const getBodyContent =
|
||||
variables
|
||||
)
|
||||
)
|
||||
: body
|
||||
: body ?? undefined
|
||||
}
|
||||
|
||||
const convertKeyValueTableToObject = (
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
PublicTypebot,
|
||||
ResultValues,
|
||||
SendEmailOptions,
|
||||
SendEmailBlock,
|
||||
SmtpCredentials,
|
||||
} from '@typebot.io/schemas'
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
@@ -56,12 +56,15 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
fileUrls,
|
||||
} = (
|
||||
typeof req.body === 'string' ? JSON.parse(req.body) : req.body
|
||||
) as SendEmailOptions & {
|
||||
) as SendEmailBlock['options'] & {
|
||||
resultValues: ResultValues
|
||||
fileUrls?: string
|
||||
}
|
||||
const { name: replyToName } = parseEmailRecipient(replyTo)
|
||||
|
||||
if (!credentialsId)
|
||||
return res.status(404).send({ message: "Couldn't find credentials" })
|
||||
|
||||
const { host, port, isTlsEnabled, username, password, from } =
|
||||
(await getEmailInfo(credentialsId)) ?? {}
|
||||
if (!from)
|
||||
@@ -186,9 +189,10 @@ const getEmailBody = async ({
|
||||
}: {
|
||||
typebotId: string
|
||||
resultValues: ResultValues
|
||||
} & Pick<SendEmailOptions, 'isCustomBody' | 'isBodyCode' | 'body'>): Promise<
|
||||
{ html?: string; text?: string } | undefined
|
||||
> => {
|
||||
} & Pick<
|
||||
NonNullable<SendEmailBlock['options']>,
|
||||
'isCustomBody' | 'isBodyCode' | 'body'
|
||||
>): Promise<{ html?: string; text?: string } | undefined> => {
|
||||
if (isCustomBody || (isNotDefined(isCustomBody) && !isEmpty(body)))
|
||||
return {
|
||||
html: isBodyCode ? body : undefined,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { authenticateUser } from '@/helpers/authenticateUser'
|
||||
import prisma from '@typebot.io/lib/prisma'
|
||||
import { Group, WebhookBlock } from '@typebot.io/schemas'
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
import { byId, isWebhookBlock } from '@typebot.io/lib'
|
||||
import { isWebhookBlock } from '@typebot.io/lib'
|
||||
import { methodNotAllowed } from '@typebot.io/lib/api'
|
||||
|
||||
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
@@ -28,7 +28,11 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
...blocks.map((b) => ({
|
||||
blockId: b.id,
|
||||
name: `${group.title} > ${b.id}`,
|
||||
url: typebot?.webhooks.find(byId(b.webhookId))?.url ?? undefined,
|
||||
url:
|
||||
typebot?.webhooks.find((w) => {
|
||||
if ('id' in w && 'webhookId' in b) return w.id === b.webhookId
|
||||
return false
|
||||
})?.url ?? undefined,
|
||||
})),
|
||||
]
|
||||
}, [])
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { authenticateUser } from '@/helpers/authenticateUser'
|
||||
import prisma from '@typebot.io/lib/prisma'
|
||||
import { Group, WebhookBlock } from '@typebot.io/schemas'
|
||||
import { Group } from '@typebot.io/schemas'
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
import { byId, isNotDefined, isWebhookBlock } from '@typebot.io/lib'
|
||||
import { isNotDefined, isWebhookBlock } from '@typebot.io/lib'
|
||||
import { methodNotAllowed } from '@typebot.io/lib/api'
|
||||
|
||||
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
@@ -24,15 +24,19 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
(block) =>
|
||||
isWebhookBlock(block) &&
|
||||
isNotDefined(
|
||||
typebot?.webhooks.find(byId((block as WebhookBlock).webhookId))?.url
|
||||
typebot?.webhooks.find((w) => {
|
||||
if ('id' in w && 'webhookId' in block)
|
||||
return w.id === block.webhookId
|
||||
return false
|
||||
})?.url
|
||||
)
|
||||
)
|
||||
return [
|
||||
...emptyWebhookBlocks,
|
||||
...blocks.map((s) => ({
|
||||
id: s.id,
|
||||
groupId: s.groupId,
|
||||
name: `${group.title} > ${s.id}`,
|
||||
...blocks.map((b) => ({
|
||||
id: b.id,
|
||||
groupId: group.id,
|
||||
name: `${group.title} > ${b.id}`,
|
||||
})),
|
||||
]
|
||||
}, [])
|
||||
|
||||
@@ -16,7 +16,7 @@ export const getServerSideProps: GetServerSideProps = async (
|
||||
const publishedTypebot = await getTypebotFromPublicId(
|
||||
context.query.publicId?.toString()
|
||||
)
|
||||
const headCode = publishedTypebot?.settings.metadata.customHeadCode
|
||||
const headCode = publishedTypebot?.settings.metadata?.customHeadCode
|
||||
return {
|
||||
props: {
|
||||
publishedTypebot,
|
||||
|
||||
Reference in New Issue
Block a user