refactor: ♻️ Rename step to block
This commit is contained in:
@ -0,0 +1,156 @@
|
||||
import { Text } from '@chakra-ui/react'
|
||||
import {
|
||||
Block,
|
||||
StartBlock,
|
||||
BubbleBlockType,
|
||||
InputBlockType,
|
||||
LogicBlockType,
|
||||
IntegrationBlockType,
|
||||
BlockIndices,
|
||||
} from 'models'
|
||||
import { isChoiceInput, isInputBlock } from 'utils'
|
||||
import { ItemNodesList } from '../../ItemNode'
|
||||
import {
|
||||
EmbedBubbleContent,
|
||||
SetVariableContent,
|
||||
TextBubbleContent,
|
||||
VideoBubbleContent,
|
||||
WebhookContent,
|
||||
WithVariableContent,
|
||||
} from './contents'
|
||||
import { ConfigureContent } from './contents/ConfigureContent'
|
||||
import { ImageBubbleContent } from './contents/ImageBubbleContent'
|
||||
import { PaymentInputContent } from './contents/PaymentInputContent'
|
||||
import { PlaceholderContent } from './contents/PlaceholderContent'
|
||||
import { RatingInputContent } from './contents/RatingInputContent'
|
||||
import { SendEmailContent } from './contents/SendEmailContent'
|
||||
import { TypebotLinkContent } from './contents/TypebotLinkContent'
|
||||
import { ProviderWebhookContent } from './contents/ZapierContent'
|
||||
|
||||
type Props = {
|
||||
block: Block | StartBlock
|
||||
indices: BlockIndices
|
||||
}
|
||||
export const BlockNodeContent = ({ block, indices }: Props): JSX.Element => {
|
||||
if (
|
||||
isInputBlock(block) &&
|
||||
!isChoiceInput(block) &&
|
||||
block.options.variableId
|
||||
) {
|
||||
return <WithVariableContent block={block} />
|
||||
}
|
||||
switch (block.type) {
|
||||
case BubbleBlockType.TEXT: {
|
||||
return <TextBubbleContent block={block} />
|
||||
}
|
||||
case BubbleBlockType.IMAGE: {
|
||||
return <ImageBubbleContent block={block} />
|
||||
}
|
||||
case BubbleBlockType.VIDEO: {
|
||||
return <VideoBubbleContent block={block} />
|
||||
}
|
||||
case BubbleBlockType.EMBED: {
|
||||
return <EmbedBubbleContent block={block} />
|
||||
}
|
||||
case InputBlockType.TEXT: {
|
||||
return (
|
||||
<PlaceholderContent
|
||||
placeholder={block.options.labels.placeholder}
|
||||
isLong={block.options.isLong}
|
||||
/>
|
||||
)
|
||||
}
|
||||
case InputBlockType.NUMBER:
|
||||
case InputBlockType.EMAIL:
|
||||
case InputBlockType.URL:
|
||||
case InputBlockType.PHONE: {
|
||||
return (
|
||||
<PlaceholderContent placeholder={block.options.labels.placeholder} />
|
||||
)
|
||||
}
|
||||
case InputBlockType.DATE: {
|
||||
return <Text color={'gray.500'}>Pick a date...</Text>
|
||||
}
|
||||
case InputBlockType.CHOICE: {
|
||||
return <ItemNodesList block={block} indices={indices} />
|
||||
}
|
||||
case InputBlockType.PAYMENT: {
|
||||
return <PaymentInputContent block={block} />
|
||||
}
|
||||
case InputBlockType.RATING: {
|
||||
return <RatingInputContent block={block} />
|
||||
}
|
||||
case LogicBlockType.SET_VARIABLE: {
|
||||
return <SetVariableContent block={block} />
|
||||
}
|
||||
case LogicBlockType.CONDITION: {
|
||||
return <ItemNodesList block={block} indices={indices} isReadOnly />
|
||||
}
|
||||
case LogicBlockType.REDIRECT: {
|
||||
return (
|
||||
<ConfigureContent
|
||||
label={
|
||||
block.options?.url ? `Redirect to ${block.options?.url}` : undefined
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
case LogicBlockType.CODE: {
|
||||
return (
|
||||
<ConfigureContent
|
||||
label={
|
||||
block.options?.content ? `Run ${block.options?.name}` : undefined
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
case LogicBlockType.TYPEBOT_LINK:
|
||||
return <TypebotLinkContent block={block} />
|
||||
|
||||
case IntegrationBlockType.GOOGLE_SHEETS: {
|
||||
return (
|
||||
<ConfigureContent
|
||||
label={
|
||||
block.options && 'action' in block.options
|
||||
? block.options.action
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
case IntegrationBlockType.GOOGLE_ANALYTICS: {
|
||||
return (
|
||||
<ConfigureContent
|
||||
label={
|
||||
block.options?.action
|
||||
? `Track "${block.options?.action}" `
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
case IntegrationBlockType.WEBHOOK: {
|
||||
return <WebhookContent block={block} />
|
||||
}
|
||||
case IntegrationBlockType.ZAPIER: {
|
||||
return (
|
||||
<ProviderWebhookContent block={block} configuredLabel="Trigger zap" />
|
||||
)
|
||||
}
|
||||
case IntegrationBlockType.PABBLY_CONNECT:
|
||||
case IntegrationBlockType.MAKE_COM: {
|
||||
return (
|
||||
<ProviderWebhookContent
|
||||
block={block}
|
||||
configuredLabel="Trigger scenario"
|
||||
/>
|
||||
)
|
||||
}
|
||||
case IntegrationBlockType.EMAIL: {
|
||||
return <SendEmailContent block={block} />
|
||||
}
|
||||
case 'start': {
|
||||
return <Text>Start</Text>
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
import React from 'react'
|
||||
import { Text } from '@chakra-ui/react'
|
||||
|
||||
type Props = { label?: string }
|
||||
|
||||
export const ConfigureContent = ({ label }: Props) => (
|
||||
<Text color={label ? 'currentcolor' : 'gray.500'} noOfLines={0}>
|
||||
{label ?? 'Configure...'}
|
||||
</Text>
|
||||
)
|
@ -0,0 +1,20 @@
|
||||
import { Box, Text } from '@chakra-ui/react'
|
||||
import { EmbedBubbleBlock } from 'models'
|
||||
|
||||
export const EmbedBubbleContent = ({ block }: { block: EmbedBubbleBlock }) => {
|
||||
if (!block.content?.url) return <Text color="gray.500">Click to edit...</Text>
|
||||
return (
|
||||
<Box w="full" h="120px" pos="relative">
|
||||
<iframe
|
||||
id="embed-bubble-content"
|
||||
src={block.content.url}
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
pointerEvents: 'none',
|
||||
borderRadius: '5px',
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
import { Box, Text, Image } from '@chakra-ui/react'
|
||||
import { ImageBubbleBlock } from 'models'
|
||||
|
||||
export const ImageBubbleContent = ({ block }: { block: ImageBubbleBlock }) => {
|
||||
const containsVariables =
|
||||
block.content?.url?.includes('{{') && block.content.url.includes('}}')
|
||||
return !block.content?.url ? (
|
||||
<Text color={'gray.500'}>Click to edit...</Text>
|
||||
) : (
|
||||
<Box w="full">
|
||||
<Image
|
||||
src={
|
||||
containsVariables ? '/images/dynamic-image.png' : block.content?.url
|
||||
}
|
||||
alt="Group image"
|
||||
rounded="md"
|
||||
objectFit="cover"
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
import { Text } from '@chakra-ui/react'
|
||||
import { PaymentInputBlock } from 'models'
|
||||
|
||||
type Props = {
|
||||
block: PaymentInputBlock
|
||||
}
|
||||
|
||||
export const PaymentInputContent = ({ block }: Props) => {
|
||||
if (
|
||||
!block.options.amount ||
|
||||
!block.options.credentialsId ||
|
||||
!block.options.currency
|
||||
)
|
||||
return <Text color="gray.500">Configure...</Text>
|
||||
return (
|
||||
<Text noOfLines={0} pr="6">
|
||||
Collect {block.options.amount} {block.options.currency}
|
||||
</Text>
|
||||
)
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
import React from 'react'
|
||||
import { Text } from '@chakra-ui/react'
|
||||
|
||||
type Props = { placeholder: string; isLong?: boolean }
|
||||
|
||||
export const PlaceholderContent = ({ placeholder, isLong }: Props) => (
|
||||
<Text color={'gray.500'} h={isLong ? '100px' : 'auto'}>
|
||||
{placeholder}
|
||||
</Text>
|
||||
)
|
@ -0,0 +1,12 @@
|
||||
import { Text } from '@chakra-ui/react'
|
||||
import { RatingInputBlock } from 'models'
|
||||
|
||||
type Props = {
|
||||
block: RatingInputBlock
|
||||
}
|
||||
|
||||
export const RatingInputContent = ({ block }: Props) => (
|
||||
<Text noOfLines={0} pr="6">
|
||||
Rate from 1 to {block.options.length}
|
||||
</Text>
|
||||
)
|
@ -0,0 +1,23 @@
|
||||
import { Tag, Text, Wrap, WrapItem } from '@chakra-ui/react'
|
||||
import { SendEmailBlock } from 'models'
|
||||
|
||||
type Props = {
|
||||
block: SendEmailBlock
|
||||
}
|
||||
|
||||
export const SendEmailContent = ({ block }: Props) => {
|
||||
if (block.options.recipients.length === 0)
|
||||
return <Text color="gray.500">Configure...</Text>
|
||||
return (
|
||||
<Wrap noOfLines={2} pr="6">
|
||||
<WrapItem>
|
||||
<Text>Send email to</Text>
|
||||
</WrapItem>
|
||||
{block.options.recipients.map((to) => (
|
||||
<WrapItem key={to}>
|
||||
<Tag>{to}</Tag>
|
||||
</WrapItem>
|
||||
))}
|
||||
</Wrap>
|
||||
)
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
import { Text } from '@chakra-ui/react'
|
||||
import { useTypebot } from 'contexts/TypebotContext'
|
||||
import { SetVariableBlock } from 'models'
|
||||
import { byId } from 'utils'
|
||||
|
||||
export const SetVariableContent = ({ block }: { block: SetVariableBlock }) => {
|
||||
const { typebot } = useTypebot()
|
||||
const variableName =
|
||||
typebot?.variables.find(byId(block.options.variableId))?.name ?? ''
|
||||
const expression = block.options.expressionToEvaluate ?? ''
|
||||
return (
|
||||
<Text color={'gray.500'} noOfLines={2}>
|
||||
{variableName === '' && expression === ''
|
||||
? 'Click to edit...'
|
||||
: `${variableName} ${expression ? `= ${expression}` : ``}`}
|
||||
</Text>
|
||||
)
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
import { Flex } from '@chakra-ui/react'
|
||||
import { useTypebot } from 'contexts/TypebotContext'
|
||||
import { TextBubbleBlock } from 'models'
|
||||
import React from 'react'
|
||||
import { parseVariableHighlight } from 'services/utils'
|
||||
|
||||
type Props = {
|
||||
block: TextBubbleBlock
|
||||
}
|
||||
|
||||
export const TextBubbleContent = ({ block }: Props) => {
|
||||
const { typebot } = useTypebot()
|
||||
if (!typebot) return <></>
|
||||
return (
|
||||
<Flex
|
||||
w="90%"
|
||||
flexDir={'column'}
|
||||
opacity={block.content.html === '' ? '0.5' : '1'}
|
||||
className="slate-html-container"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html:
|
||||
block.content.html === ''
|
||||
? `<p>Click to edit...</p>`
|
||||
: parseVariableHighlight(block.content.html, typebot),
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
import { TypebotLinkBlock } from 'models'
|
||||
import React from 'react'
|
||||
import { Tag, Text } from '@chakra-ui/react'
|
||||
import { useTypebot } from 'contexts/TypebotContext'
|
||||
import { byId } from 'utils'
|
||||
|
||||
type Props = {
|
||||
block: TypebotLinkBlock
|
||||
}
|
||||
|
||||
export const TypebotLinkContent = ({ block }: Props) => {
|
||||
const { linkedTypebots, typebot } = useTypebot()
|
||||
const isCurrentTypebot =
|
||||
typebot &&
|
||||
(block.options.typebotId === typebot.id ||
|
||||
block.options.typebotId === 'current')
|
||||
const linkedTypebot = isCurrentTypebot
|
||||
? typebot
|
||||
: linkedTypebots?.find(byId(block.options.typebotId))
|
||||
const blockTitle = linkedTypebot?.groups.find(
|
||||
byId(block.options.groupId)
|
||||
)?.title
|
||||
if (!block.options.typebotId)
|
||||
return <Text color="gray.500">Configure...</Text>
|
||||
return (
|
||||
<Text>
|
||||
Jump{' '}
|
||||
{blockTitle ? (
|
||||
<>
|
||||
to <Tag>{blockTitle}</Tag>
|
||||
</>
|
||||
) : (
|
||||
<></>
|
||||
)}{' '}
|
||||
{!isCurrentTypebot ? (
|
||||
<>
|
||||
in <Tag colorScheme="blue">{linkedTypebot?.name}</Tag>
|
||||
</>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Text>
|
||||
)
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
import { Box, Text } from '@chakra-ui/react'
|
||||
import { VideoBubbleBlock, VideoBubbleContentType } from 'models'
|
||||
|
||||
export const VideoBubbleContent = ({ block }: { block: VideoBubbleBlock }) => {
|
||||
if (!block.content?.url || !block.content.type)
|
||||
return <Text color="gray.500">Click to edit...</Text>
|
||||
switch (block.content.type) {
|
||||
case VideoBubbleContentType.URL:
|
||||
return (
|
||||
<Box w="full" h="120px" pos="relative">
|
||||
<video
|
||||
key={block.content.url}
|
||||
controls
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
position: 'absolute',
|
||||
left: '0',
|
||||
top: '0',
|
||||
borderRadius: '10px',
|
||||
}}
|
||||
>
|
||||
<source src={block.content.url} />
|
||||
</video>
|
||||
</Box>
|
||||
)
|
||||
case VideoBubbleContentType.VIMEO:
|
||||
case VideoBubbleContentType.YOUTUBE: {
|
||||
const baseUrl =
|
||||
block.content.type === VideoBubbleContentType.VIMEO
|
||||
? 'https://player.vimeo.com/video'
|
||||
: 'https://www.youtube.com/embed'
|
||||
return (
|
||||
<Box w="full" h="120px" pos="relative">
|
||||
<iframe
|
||||
src={`${baseUrl}/${block.content.id}`}
|
||||
allowFullScreen
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
position: 'absolute',
|
||||
left: '0',
|
||||
top: '0',
|
||||
borderRadius: '10px',
|
||||
pointerEvents: 'none',
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
import { Text } from '@chakra-ui/react'
|
||||
import { useTypebot } from 'contexts/TypebotContext'
|
||||
import { WebhookBlock } from 'models'
|
||||
import { byId } from 'utils'
|
||||
|
||||
type Props = {
|
||||
block: WebhookBlock
|
||||
}
|
||||
|
||||
export const WebhookContent = ({ block: { webhookId } }: Props) => {
|
||||
const { webhooks } = useTypebot()
|
||||
const webhook = webhooks.find(byId(webhookId))
|
||||
|
||||
if (!webhook?.url) return <Text color="gray.500">Configure...</Text>
|
||||
return (
|
||||
<Text noOfLines={2} pr="6">
|
||||
{webhook.method} {webhook.url}
|
||||
</Text>
|
||||
)
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
import { InputBlock } from 'models'
|
||||
import { chakra, Text } from '@chakra-ui/react'
|
||||
import React from 'react'
|
||||
import { useTypebot } from 'contexts/TypebotContext'
|
||||
import { byId } from 'utils'
|
||||
|
||||
type Props = {
|
||||
block: InputBlock
|
||||
}
|
||||
|
||||
export const WithVariableContent = ({ block }: Props) => {
|
||||
const { typebot } = useTypebot()
|
||||
const variableName = typebot?.variables.find(
|
||||
byId(block.options.variableId)
|
||||
)?.name
|
||||
|
||||
return (
|
||||
<Text>
|
||||
Collect{' '}
|
||||
<chakra.span
|
||||
bgColor="orange.400"
|
||||
color="white"
|
||||
rounded="md"
|
||||
py="0.5"
|
||||
px="1"
|
||||
>
|
||||
{variableName}
|
||||
</chakra.span>
|
||||
</Text>
|
||||
)
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
import { Text } from '@chakra-ui/react'
|
||||
import { useTypebot } from 'contexts/TypebotContext'
|
||||
import {
|
||||
defaultWebhookAttributes,
|
||||
MakeComBlock,
|
||||
PabblyConnectBlock,
|
||||
Webhook,
|
||||
ZapierBlock,
|
||||
} from 'models'
|
||||
import { useEffect } from 'react'
|
||||
import { byId, isNotDefined } from 'utils'
|
||||
|
||||
type Props = {
|
||||
block: ZapierBlock | MakeComBlock | PabblyConnectBlock
|
||||
configuredLabel: string
|
||||
}
|
||||
|
||||
export const ProviderWebhookContent = ({ block, configuredLabel }: Props) => {
|
||||
const { webhooks, typebot, updateWebhook } = useTypebot()
|
||||
const webhook = webhooks.find(byId(block.webhookId))
|
||||
|
||||
useEffect(() => {
|
||||
if (!typebot) return
|
||||
if (!webhook) {
|
||||
const { webhookId } = block
|
||||
const newWebhook = {
|
||||
id: webhookId,
|
||||
...defaultWebhookAttributes,
|
||||
typebotId: typebot.id,
|
||||
} as Webhook
|
||||
updateWebhook(webhookId, newWebhook)
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [])
|
||||
|
||||
if (isNotDefined(webhook?.body))
|
||||
return <Text color="gray.500">Configure...</Text>
|
||||
return (
|
||||
<Text noOfLines={0} pr="6">
|
||||
{webhook?.url ? configuredLabel : 'Disabled'}
|
||||
</Text>
|
||||
)
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
export * from './SetVariableContent'
|
||||
export * from './WithVariableContent'
|
||||
export * from './VideoBubbleContent'
|
||||
export * from './WebhookContent'
|
||||
export * from './TextBubbleContent'
|
||||
export * from './EmbedBubbleContent'
|
@ -0,0 +1 @@
|
||||
export { BlockNodeContent } from './BlockNodeContent'
|
Reference in New Issue
Block a user