feat(editor): ✨ Add Zapier step
This commit is contained in:
15
apps/builder/assets/logos/ZapierLogo.tsx
Normal file
15
apps/builder/assets/logos/ZapierLogo.tsx
Normal file
@ -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>
|
||||
)
|
@ -14,3 +14,4 @@ export * from './WordpressLogo'
|
||||
export * from './WixLogo'
|
||||
export * from './GoogleLogo'
|
||||
export * from './FacebookLogo'
|
||||
export * from './ZapierLogo'
|
||||
|
@ -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 <GoogleAnalyticsLogo {...props} />
|
||||
case IntegrationStepType.WEBHOOK:
|
||||
return <WebhookIcon {...props} />
|
||||
case IntegrationStepType.ZAPIER:
|
||||
return <ZapierLogo {...props} />
|
||||
case IntegrationStepType.EMAIL:
|
||||
return <SendEmailIcon {...props} />
|
||||
case 'start':
|
||||
|
@ -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:
|
||||
|
@ -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>
|
||||
@ -199,6 +200,9 @@ export const StepSettings = ({
|
||||
/>
|
||||
)
|
||||
}
|
||||
case IntegrationStepType.ZAPIER: {
|
||||
return <ZapierSettings step={step} />
|
||||
}
|
||||
case IntegrationStepType.WEBHOOK: {
|
||||
return (
|
||||
<WebhookSettings
|
||||
|
@ -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>
|
||||
)
|
||||
}
|
@ -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 <WebhookContent step={step} />
|
||||
}
|
||||
case IntegrationStepType.ZAPIER: {
|
||||
return <ZapierContent step={step} />
|
||||
}
|
||||
case IntegrationStepType.EMAIL: {
|
||||
return <SendEmailContent step={step} />
|
||||
}
|
||||
|
@ -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>
|
||||
)
|
||||
}
|
@ -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:
|
||||
|
@ -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: {
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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<WebhookStep, 'type'> & {
|
||||
type: IntegrationStepType.ZAPIER
|
||||
}
|
||||
|
||||
export type SendEmailStep = StepBase & {
|
||||
type: IntegrationStepType.EMAIL
|
||||
options: SendEmailOptions
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user