diff --git a/apps/builder/assets/logos/ZapierLogo.tsx b/apps/builder/assets/logos/ZapierLogo.tsx
new file mode 100644
index 000000000..c7b32512f
--- /dev/null
+++ b/apps/builder/assets/logos/ZapierLogo.tsx
@@ -0,0 +1,15 @@
+import { Icon, IconProps } from '@chakra-ui/react'
+
+export const ZapierLogo = (props: IconProps) => (
+
+
+
+)
diff --git a/apps/builder/assets/logos/index.tsx b/apps/builder/assets/logos/index.tsx
index 2ec27f1ed..c72f19a62 100644
--- a/apps/builder/assets/logos/index.tsx
+++ b/apps/builder/assets/logos/index.tsx
@@ -14,3 +14,4 @@ export * from './WordpressLogo'
export * from './WixLogo'
export * from './GoogleLogo'
export * from './FacebookLogo'
+export * from './ZapierLogo'
diff --git a/apps/builder/components/editor/StepsSideBar/StepIcon.tsx b/apps/builder/components/editor/StepsSideBar/StepIcon.tsx
index a2f6a5b11..1da130f81 100644
--- a/apps/builder/components/editor/StepsSideBar/StepIcon.tsx
+++ b/apps/builder/components/editor/StepsSideBar/StepIcon.tsx
@@ -17,7 +17,7 @@ import {
TextIcon,
WebhookIcon,
} from 'assets/icons'
-import { GoogleAnalyticsLogo, GoogleSheetsLogo } from 'assets/logos'
+import { GoogleAnalyticsLogo, GoogleSheetsLogo, ZapierLogo } from 'assets/logos'
import {
BubbleStepType,
InputStepType,
@@ -63,6 +63,8 @@ export const StepIcon = ({ type, ...props }: StepIconProps) => {
return
case IntegrationStepType.WEBHOOK:
return
+ case IntegrationStepType.ZAPIER:
+ return
case IntegrationStepType.EMAIL:
return
case 'start':
diff --git a/apps/builder/components/editor/StepsSideBar/StepTypeLabel.tsx b/apps/builder/components/editor/StepsSideBar/StepTypeLabel.tsx
index 1236a6de7..2f6c66934 100644
--- a/apps/builder/components/editor/StepsSideBar/StepTypeLabel.tsx
+++ b/apps/builder/components/editor/StepsSideBar/StepTypeLabel.tsx
@@ -51,6 +51,8 @@ export const StepTypeLabel = ({ type }: Props) => {
)
case IntegrationStepType.WEBHOOK:
return Webhook
+ case IntegrationStepType.ZAPIER:
+ return Zapier
case IntegrationStepType.EMAIL:
return Email
default:
diff --git a/apps/builder/components/shared/Graph/Nodes/StepNode/SettingsPopoverContent/SettingsPopoverContent.tsx b/apps/builder/components/shared/Graph/Nodes/StepNode/SettingsPopoverContent/SettingsPopoverContent.tsx
index 7e9ad3549..ede5e0553 100644
--- a/apps/builder/components/shared/Graph/Nodes/StepNode/SettingsPopoverContent/SettingsPopoverContent.tsx
+++ b/apps/builder/components/shared/Graph/Nodes/StepNode/SettingsPopoverContent/SettingsPopoverContent.tsx
@@ -36,6 +36,7 @@ import { RedirectSettings } from './bodies/RedirectSettings'
import { SendEmailSettings } from './bodies/SendEmailSettings/SendEmailSettings'
import { SetVariableSettings } from './bodies/SetVariableSettings'
import { WebhookSettings } from './bodies/WebhookSettings'
+import { ZapierSettings } from './bodies/ZapierSettings'
type Props = {
step: Exclude
@@ -199,6 +200,9 @@ export const StepSettings = ({
/>
)
}
+ case IntegrationStepType.ZAPIER: {
+ return
+ }
case IntegrationStepType.WEBHOOK: {
return (
{
+ return (
+
+
+
+ {step.webhook.url ? (
+ <>Your zap is correctly configured 🚀>
+ ) : (
+
+ Head up to Zapier to configure this step:
+
+
+ )}
+
+ {step.webhook.url && }
+
+ )
+}
diff --git a/apps/builder/components/shared/Graph/Nodes/StepNode/StepNodeContent/StepNodeContent.tsx b/apps/builder/components/shared/Graph/Nodes/StepNode/StepNodeContent/StepNodeContent.tsx
index 14b760dc5..d676b95b8 100644
--- a/apps/builder/components/shared/Graph/Nodes/StepNode/StepNodeContent/StepNodeContent.tsx
+++ b/apps/builder/components/shared/Graph/Nodes/StepNode/StepNodeContent/StepNodeContent.tsx
@@ -21,6 +21,7 @@ import { ConfigureContent } from './contents/ConfigureContent'
import { ImageBubbleContent } from './contents/ImageBubbleContent'
import { PlaceholderContent } from './contents/PlaceholderContent'
import { SendEmailContent } from './contents/SendEmailContent'
+import { ZapierContent } from './contents/ZapierContent'
type Props = {
step: Step | StartStep
@@ -102,6 +103,9 @@ export const StepNodeContent = ({ step, indices }: Props) => {
case IntegrationStepType.WEBHOOK: {
return
}
+ case IntegrationStepType.ZAPIER: {
+ return
+ }
case IntegrationStepType.EMAIL: {
return
}
diff --git a/apps/builder/components/shared/Graph/Nodes/StepNode/StepNodeContent/contents/ZapierContent.tsx b/apps/builder/components/shared/Graph/Nodes/StepNode/StepNodeContent/contents/ZapierContent.tsx
new file mode 100644
index 000000000..aaed7b2a1
--- /dev/null
+++ b/apps/builder/components/shared/Graph/Nodes/StepNode/StepNodeContent/contents/ZapierContent.tsx
@@ -0,0 +1,17 @@
+import { Text } from '@chakra-ui/react'
+import { ZapierStep } from 'models'
+import { isNotDefined } from 'utils'
+
+type Props = {
+ step: ZapierStep
+}
+
+export const ZapierContent = ({ step }: Props) => {
+ if (isNotDefined(step.webhook.body))
+ return Configure...
+ return (
+
+ {step.webhook.url ? 'Enabled' : 'Disabled'}
+
+ )
+}
diff --git a/apps/builder/services/typebots.ts b/apps/builder/services/typebots.ts
index 565dd1fa5..a06aed0f0 100644
--- a/apps/builder/services/typebots.ts
+++ b/apps/builder/services/typebots.ts
@@ -218,6 +218,7 @@ const parseDefaultStepOptions = (type: StepWithOptionsType): StepOptions => {
return defaultGoogleSheetsOptions
case IntegrationStepType.GOOGLE_ANALYTICS:
return defaultGoogleAnalyticsOptions
+ case IntegrationStepType.ZAPIER:
case IntegrationStepType.WEBHOOK:
return defaultWebhookOptions
case IntegrationStepType.EMAIL:
diff --git a/apps/viewer/pages/api/typebots/[typebotId]/blocks/[blockId]/steps/[stepId]/subscribeWebhook.ts b/apps/viewer/pages/api/typebots/[typebotId]/blocks/[blockId]/steps/[stepId]/subscribeWebhook.ts
index d271d949b..21a8eda81 100644
--- a/apps/viewer/pages/api/typebots/[typebotId]/blocks/[blockId]/steps/[stepId]/subscribeWebhook.ts
+++ b/apps/viewer/pages/api/typebots/[typebotId]/blocks/[blockId]/steps/[stepId]/subscribeWebhook.ts
@@ -1,10 +1,10 @@
import { withSentry } from '@sentry/nextjs'
import { Prisma } from 'db'
import prisma from 'libs/prisma'
-import { HttpMethod, IntegrationStepType, Typebot } from 'models'
+import { HttpMethod, Typebot } from 'models'
import { NextApiRequest, NextApiResponse } from 'next'
import { authenticateUser } from 'services/api/utils'
-import { methodNotAllowed } from 'utils'
+import { isWebhookStep, methodNotAllowed } from 'utils'
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
if (req.method === 'PATCH') {
@@ -46,7 +46,7 @@ const addUrlToWebhookStep = (
...b,
steps: b.steps.map((s) => {
if (s.id === stepId) {
- if (s.type !== IntegrationStepType.WEBHOOK) throw new Error()
+ if (!isWebhookStep(s)) throw new Error()
return {
...s,
webhook: {
diff --git a/apps/viewer/pages/api/typebots/[typebotId]/blocks/[blockId]/steps/[stepId]/unsubscribeWebhook.ts b/apps/viewer/pages/api/typebots/[typebotId]/blocks/[blockId]/steps/[stepId]/unsubscribeWebhook.ts
index a1265a02e..f35310dcb 100644
--- a/apps/viewer/pages/api/typebots/[typebotId]/blocks/[blockId]/steps/[stepId]/unsubscribeWebhook.ts
+++ b/apps/viewer/pages/api/typebots/[typebotId]/blocks/[blockId]/steps/[stepId]/unsubscribeWebhook.ts
@@ -1,11 +1,11 @@
import { withSentry } from '@sentry/nextjs'
import { Prisma } from 'db'
import prisma from 'libs/prisma'
-import { IntegrationStepType, Typebot } from 'models'
+import { Typebot } from 'models'
import { NextApiRequest, NextApiResponse } from 'next'
import { authenticateUser } from 'services/api/utils'
import { omit } from 'services/utils'
-import { methodNotAllowed } from 'utils'
+import { isWebhookStep, methodNotAllowed } from 'utils'
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
if (req.method === 'DELETE') {
@@ -44,7 +44,7 @@ const removeUrlFromWebhookStep = (
...b,
steps: b.steps.map((s) => {
if (s.id === stepId) {
- if (s.type !== IntegrationStepType.WEBHOOK) throw new Error()
+ if (!isWebhookStep(s)) throw new Error()
return { ...s, webhook: omit(s.webhook, 'url') }
}
return s
diff --git a/apps/viewer/pages/api/typebots/[typebotId]/webhookSteps.ts b/apps/viewer/pages/api/typebots/[typebotId]/webhookSteps.ts
index 0bc94926e..a88672bb7 100644
--- a/apps/viewer/pages/api/typebots/[typebotId]/webhookSteps.ts
+++ b/apps/viewer/pages/api/typebots/[typebotId]/webhookSteps.ts
@@ -1,9 +1,9 @@
import { withSentry } from '@sentry/nextjs'
import prisma from 'libs/prisma'
-import { Block, IntegrationStepType } from 'models'
+import { Block } from 'models'
import { NextApiRequest, NextApiResponse } from 'next'
import { authenticateUser } from 'services/api/utils'
-import { methodNotAllowed } from 'utils'
+import { isWebhookStep, methodNotAllowed } from 'utils'
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
if (req.method === 'GET') {
@@ -18,7 +18,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
{ blockId: string; id: string; name: string }[]
>((emptyWebhookSteps, block) => {
const steps = block.steps.filter(
- (step) => step.type === IntegrationStepType.WEBHOOK && !step.webhook.url
+ (step) => isWebhookStep(step) && !step.webhook.url
)
return [
...emptyWebhookSteps,
diff --git a/packages/bot-engine/src/services/integration.ts b/packages/bot-engine/src/services/integration.ts
index bee087e60..579598976 100644
--- a/packages/bot-engine/src/services/integration.ts
+++ b/packages/bot-engine/src/services/integration.ts
@@ -13,6 +13,7 @@ import {
WebhookStep,
SendEmailStep,
PublicBlock,
+ ZapierStep,
} from 'models'
import { stringify } from 'qs'
import { parseAnswers, sendRequest } from 'utils'
@@ -46,6 +47,7 @@ export const executeIntegration = ({
return executeGoogleSheetIntegration(step, context)
case IntegrationStepType.GOOGLE_ANALYTICS:
return executeGoogleAnalyticsIntegration(step, context)
+ case IntegrationStepType.ZAPIER:
case IntegrationStepType.WEBHOOK:
return executeWebhook(step, context)
case IntegrationStepType.EMAIL:
@@ -156,7 +158,7 @@ const parseCellValues = (
}, {})
const executeWebhook = async (
- step: WebhookStep,
+ step: WebhookStep | ZapierStep,
{
blockId,
stepId,
diff --git a/packages/models/src/typebot/steps/integration.ts b/packages/models/src/typebot/steps/integration.ts
index 82221c41f..1d02278e4 100644
--- a/packages/models/src/typebot/steps/integration.ts
+++ b/packages/models/src/typebot/steps/integration.ts
@@ -5,6 +5,7 @@ export type IntegrationStep =
| GoogleAnalyticsStep
| WebhookStep
| SendEmailStep
+ | ZapierStep
export type IntegrationStepOptions =
| GoogleSheetsOptions
@@ -17,6 +18,7 @@ export enum IntegrationStepType {
GOOGLE_ANALYTICS = 'Google Analytics',
WEBHOOK = 'Webhook',
EMAIL = 'Email',
+ ZAPIER = 'Zapier',
}
export type GoogleSheetsStep = StepBase & {
@@ -35,6 +37,10 @@ export type WebhookStep = StepBase & {
webhook: Webhook
}
+export type ZapierStep = Omit & {
+ type: IntegrationStepType.ZAPIER
+}
+
export type SendEmailStep = StepBase & {
type: IntegrationStepType.EMAIL
options: SendEmailOptions
diff --git a/packages/utils/src/utils.ts b/packages/utils/src/utils.ts
index e3e188f22..dc5f348a6 100644
--- a/packages/utils/src/utils.ts
+++ b/packages/utils/src/utils.ts
@@ -99,7 +99,7 @@ export const isIntegrationStep = (
(Object.values(IntegrationStepType) as string[]).includes(step.type)
export const isWebhookStep = (step: Step | PublicStep): step is WebhookStep =>
- step.type === IntegrationStepType.WEBHOOK
+ 'webhook' in step
export const isBubbleStepType = (type: StepType): type is BubbleStepType =>
(Object.values(BubbleStepType) as string[]).includes(type)
@@ -114,7 +114,11 @@ export const stepTypeHasOption = (
export const stepTypeHasWebhook = (
type: StepType
-): type is IntegrationStepType.WEBHOOK => type === IntegrationStepType.WEBHOOK
+): type is IntegrationStepType.WEBHOOK =>
+ Object.values([
+ IntegrationStepType.WEBHOOK,
+ IntegrationStepType.ZAPIER,
+ ] as string[]).includes(type)
export const stepTypeHasItems = (
type: StepType