Skip to content

Commit

Permalink
feat(editor): ✨ Add Zapier step
Browse files Browse the repository at this point in the history
  • Loading branch information
baptisteArno committed Feb 22, 2022
1 parent d0994e6 commit 642a427
Show file tree
Hide file tree
Showing 15 changed files with 117 additions and 13 deletions.
15 changes: 15 additions & 0 deletions apps/builder/assets/logos/ZapierLogo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Icon, IconProps } from '@chakra-ui/react'

export const ZapierLogo = (props: IconProps) => (
<Icon
viewBox="0 0 256 256"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M159.999 128.056a76.55 76.55 0 0 1-4.915 27.024 76.745 76.745 0 0 1-27.032 4.923h-.108c-9.508-.012-18.618-1.75-27.024-4.919A76.557 76.557 0 0 1 96 128.056v-.112a76.598 76.598 0 0 1 4.91-27.02A76.492 76.492 0 0 1 127.945 96h.108a76.475 76.475 0 0 1 27.032 4.923 76.51 76.51 0 0 1 4.915 27.02v.112zm94.223-21.389h-74.716l52.829-52.833a128.518 128.518 0 0 0-13.828-16.349v-.004a129 129 0 0 0-16.345-13.816l-52.833 52.833V1.782A128.606 128.606 0 0 0 128.064 0h-.132c-7.248.004-14.347.62-21.265 1.782v74.716L53.834 23.665A127.82 127.82 0 0 0 37.497 37.49l-.028.02A128.803 128.803 0 0 0 23.66 53.834l52.837 52.833H1.782S0 120.7 0 127.956v.088c0 7.256.615 14.367 1.782 21.289h74.716l-52.837 52.833a128.91 128.91 0 0 0 30.173 30.173l52.833-52.837v74.72a129.3 129.3 0 0 0 21.24 1.778h.181a129.15 129.15 0 0 0 21.24-1.778v-74.72l52.838 52.837a128.994 128.994 0 0 0 16.341-13.82l.012-.012a129.245 129.245 0 0 0 13.816-16.341l-52.837-52.833h74.724c1.163-6.91 1.77-14 1.778-21.24v-.186c-.008-7.24-.615-14.33-1.778-21.24z"
fill="#FF4A00"
/>
</Icon>
)
1 change: 1 addition & 0 deletions apps/builder/assets/logos/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ export * from './WordpressLogo'
export * from './WixLogo'
export * from './GoogleLogo'
export * from './FacebookLogo'
export * from './ZapierLogo'
4 changes: 3 additions & 1 deletion apps/builder/components/editor/StepsSideBar/StepIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -63,6 +63,8 @@ export const StepIcon = ({ type, ...props }: StepIconProps) => {
return <GoogleAnalyticsLogo {...props} />
case IntegrationStepType.WEBHOOK:
return <WebhookIcon {...props} />
case IntegrationStepType.ZAPIER:
return <ZapierLogo {...props} />
case IntegrationStepType.EMAIL:
return <SendEmailIcon {...props} />
case 'start':
Expand Down
2 changes: 2 additions & 0 deletions apps/builder/components/editor/StepsSideBar/StepTypeLabel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ export const StepTypeLabel = ({ type }: Props) => {
)
case IntegrationStepType.WEBHOOK:
return <Text>Webhook</Text>
case IntegrationStepType.ZAPIER:
return <Text>Zapier</Text>
case IntegrationStepType.EMAIL:
return <Text>Email</Text>
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<Step, TextBubbleStep>
Expand Down Expand Up @@ -199,6 +200,9 @@ export const StepSettings = ({
/>
)
}
case IntegrationStepType.ZAPIER: {
return <ZapierSettings step={step} />
}
case IntegrationStepType.WEBHOOK: {
return (
<WebhookSettings
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import {
Alert,
AlertIcon,
Button,
Input,
Link,
Stack,
Text,
} from '@chakra-ui/react'
import { ExternalLinkIcon } from 'assets/icons'
import { ZapierStep } from 'models'
import React from 'react'

type Props = {
step: ZapierStep
}

export const ZapierSettings = ({ step }: Props) => {
return (
<Stack spacing={4}>
<Alert
status={step.webhook.url ? 'success' : 'info'}
bgColor={step.webhook.url ? undefined : 'blue.50'}
rounded="md"
>
<AlertIcon />
{step.webhook.url ? (
<>Your zap is correctly configured 🚀</>
) : (
<Stack>
<Text>Head up to Zapier to configure this step:</Text>
<Button
as={Link}
href="https://zapier.com/apps/typebot/integrations"
isExternal
colorScheme="blue"
>
<Text mr="2">Zapier</Text> <ExternalLinkIcon />
</Button>
</Stack>
)}
</Alert>
{step.webhook.url && <Input value={step.webhook.url} isDisabled />}
</Stack>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -102,6 +103,9 @@ export const StepNodeContent = ({ step, indices }: Props) => {
case IntegrationStepType.WEBHOOK: {
return <WebhookContent step={step} />
}
case IntegrationStepType.ZAPIER: {
return <ZapierContent step={step} />
}
case IntegrationStepType.EMAIL: {
return <SendEmailContent step={step} />
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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 <Text color="gray.500">Configure...</Text>
return (
<Text isTruncated pr="6">
{step.webhook.url ? 'Enabled' : 'Disabled'}
</Text>
)
}
1 change: 1 addition & 0 deletions apps/builder/services/typebots.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
@@ -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') {
Expand Down Expand Up @@ -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: {
Expand Down
Original file line number Diff line number Diff line change
@@ -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') {
Expand Down Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions apps/viewer/pages/api/typebots/[typebotId]/webhookSteps.ts
Original file line number Diff line number Diff line change
@@ -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') {
Expand All @@ -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,
Expand Down
4 changes: 3 additions & 1 deletion packages/bot-engine/src/services/integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
WebhookStep,
SendEmailStep,
PublicBlock,
ZapierStep,
} from 'models'
import { stringify } from 'qs'
import { parseAnswers, sendRequest } from 'utils'
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -156,7 +158,7 @@ const parseCellValues = (
}, {})

const executeWebhook = async (
step: WebhookStep,
step: WebhookStep | ZapierStep,
{
blockId,
stepId,
Expand Down
6 changes: 6 additions & 0 deletions packages/models/src/typebot/steps/integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export type IntegrationStep =
| GoogleAnalyticsStep
| WebhookStep
| SendEmailStep
| ZapierStep

export type IntegrationStepOptions =
| GoogleSheetsOptions
Expand All @@ -17,6 +18,7 @@ export enum IntegrationStepType {
GOOGLE_ANALYTICS = 'Google Analytics',
WEBHOOK = 'Webhook',
EMAIL = 'Email',
ZAPIER = 'Zapier',
}

export type GoogleSheetsStep = StepBase & {
Expand All @@ -35,6 +37,10 @@ export type WebhookStep = StepBase & {
webhook: Webhook
}

export type ZapierStep = Omit<WebhookStep, 'type'> & {
type: IntegrationStepType.ZAPIER
}

export type SendEmailStep = StepBase & {
type: IntegrationStepType.EMAIL
options: SendEmailOptions
Expand Down
8 changes: 6 additions & 2 deletions packages/utils/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand Down

2 comments on commit 642a427

@vercel
Copy link

@vercel vercel bot commented on 642a427 Feb 22, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on 642a427 Feb 22, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

builder-v2 – ./apps/builder

builder-v2-git-main-typebot-io.vercel.app
builder-v2-typebot-io.vercel.app
app.typebot.io

Please sign in to comment.