2
0

docs(share): 📝 Add code blocks in embed instructions

This commit is contained in:
Baptiste Arnaud
2022-02-10 08:08:58 +01:00
parent c66827b606
commit 276f1c1e90
23 changed files with 1166 additions and 304 deletions

View File

@ -0,0 +1,38 @@
import { FlexProps } from '@chakra-ui/layout'
import prettier from 'prettier/standalone'
import parserHtml from 'prettier/parser-html'
import { BubbleParams } from 'typebot-js'
import { parseInitBubbleCode, typebotJsHtml } from '../params'
import { useTypebot } from 'contexts/TypebotContext'
import { CodeEditor } from 'components/shared/CodeEditor'
type ChatEmbedCodeProps = {
withStarterVariables?: boolean
onCopied?: () => void
} & Pick<BubbleParams, 'button' | 'proactiveMessage'>
export const ChatEmbedCode = ({
proactiveMessage,
button,
}: ChatEmbedCodeProps & FlexProps) => {
const { typebot } = useTypebot()
const snippet = prettier.format(
createSnippet({
publishId: typebot?.publicId ?? '',
button,
proactiveMessage,
}),
{
parser: 'html',
plugins: [parserHtml],
}
)
return <CodeEditor value={snippet} lang="html" isReadOnly />
}
const createSnippet = (params: BubbleParams): string => {
const jsCode = parseInitBubbleCode(params)
return `${typebotJsHtml}
<script>${jsCode}</script>`
}

View File

@ -0,0 +1,159 @@
import {
StackProps,
Stack,
Heading,
HStack,
Input,
Flex,
FormControl,
FormLabel,
NumberInput,
NumberInputField,
NumberInputStepper,
NumberIncrementStepper,
NumberDecrementStepper,
Switch,
Text,
Tag,
} from '@chakra-ui/react'
import { ColorPicker } from 'components/theme/GeneralSettings/ColorPicker'
import { useTypebot } from 'contexts/TypebotContext'
import { useState, useEffect } from 'react'
import { BubbleParams } from 'typebot-js'
type ChatEmbedSettingsProps = {
onUpdateSettings: (
windowSettings: Pick<BubbleParams, 'button' | 'proactiveMessage'>
) => void
}
export const ChatEmbedSettings = ({
onUpdateSettings,
...props
}: ChatEmbedSettingsProps & StackProps) => {
const { typebot } = useTypebot()
const [proactiveMessageChecked, setProactiveMessageChecked] = useState(false)
const [rememberProMessageChecked] = useState(true)
const [customIconInputValue, setCustomIconInputValue] = useState('')
const [inputValues, setInputValues] = useState({
messageDelay: '0',
messageContent: 'I have a question for you!',
})
const [bubbleColor, setBubbleColor] = useState(
typebot?.theme.chat.buttons.backgroundColor ?? '#0042DA'
)
useEffect(() => {
if (proactiveMessageChecked) {
onUpdateSettings({
button: {
color: bubbleColor,
iconUrl: customIconInputValue,
},
proactiveMessage: {
delay: parseInt(inputValues.messageDelay) * 1000,
textContent: inputValues.messageContent,
rememberClose: rememberProMessageChecked,
},
})
} else {
onUpdateSettings({
button: {
color: bubbleColor,
iconUrl: customIconInputValue,
},
proactiveMessage: undefined,
})
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
inputValues,
bubbleColor,
rememberProMessageChecked,
customIconInputValue,
proactiveMessageChecked,
])
return (
<Stack {...props}>
<Heading fontSize="md" fontWeight="semibold">
Chat bubble settings
</Heading>
<Flex justify="space-between" align="center" mb="4">
<Text>Button color</Text>
<ColorPicker
initialColor={bubbleColor}
onColorChange={setBubbleColor}
/>
</Flex>
<HStack>
<Text flexShrink={0}>
Custom button icon <Tag>Optional</Tag>
</Text>
<Input
placeholder={'Paste image link (.png, .svg)'}
value={customIconInputValue}
onChange={(e) => setCustomIconInputValue(e.target.value)}
/>
</HStack>
<Flex alignItems="center">
<FormControl
display="flex"
alignItems="center"
w="full"
justifyContent="space-between"
pr={1}
>
<FormLabel htmlFor="fullscreen-option" mb="1">
Enable popup message?
</FormLabel>
<Switch
id="fullscreen-option"
onChange={() =>
setProactiveMessageChecked(!proactiveMessageChecked)
}
isChecked={proactiveMessageChecked}
/>
</FormControl>
</Flex>
{proactiveMessageChecked && (
<>
<Flex justify="space-between" align="center" pl="4" mb="2">
<Text>Appearance delay</Text>
<NumberInput
onChange={(messageDelay) =>
setInputValues({
...inputValues,
messageDelay,
})
}
value={inputValues.messageDelay}
min={0}
>
<NumberInputField />
<NumberInputStepper>
<NumberIncrementStepper />
<NumberDecrementStepper />
</NumberInputStepper>
</NumberInput>
</Flex>
<Flex justify="space-between" align="center" pl="4" mb="2">
<Text>Message content</Text>
<Input
type="text"
onChange={(e) =>
setInputValues({
...inputValues,
messageContent: e.target.value,
})
}
value={inputValues.messageContent}
/>
</Flex>
</>
)}
</Stack>
)
}

View File

@ -0,0 +1,56 @@
import { FlexProps } from '@chakra-ui/react'
import parserHtml from 'prettier/parser-html'
import prettier from 'prettier/standalone'
import { parseInitContainerCode, typebotJsHtml } from '../params'
import { IframeParams } from 'typebot-js'
import { useTypebot } from 'contexts/TypebotContext'
import { CodeEditor } from 'components/shared/CodeEditor'
type ContainerEmbedCodeProps = {
widthLabel: string
heightLabel: string
withStarterVariables?: boolean
onCopied?: () => void
}
export const ContainerEmbedCode = ({
widthLabel,
heightLabel,
}: ContainerEmbedCodeProps & FlexProps) => {
const { typebot } = useTypebot()
const snippet = prettier.format(
parseSnippet({
publishId: typebot?.publicId ?? '',
heightLabel,
widthLabel,
}),
{
parser: 'html',
plugins: [parserHtml],
}
)
return <CodeEditor value={snippet} lang="html" isReadOnly />
}
type SnippetProps = IframeParams &
Pick<ContainerEmbedCodeProps, 'widthLabel' | 'heightLabel'>
const parseSnippet = ({
publishId,
customDomain,
backgroundColor,
hiddenVariables,
...embedProps
}: SnippetProps): string => {
const jsCode = parseInitContainerCode({
customDomain,
hiddenVariables,
backgroundColor,
publishId,
})
return `${typebotJsHtml}
<div id="typebot-container" style="width: ${embedProps.widthLabel}; height: ${embedProps.heightLabel};"></div>
<script>${jsCode}</script>`
}

View File

@ -0,0 +1,120 @@
import {
StackProps,
Stack,
Flex,
Heading,
FormControl,
FormLabel,
Switch,
Input,
HStack,
Text,
} from '@chakra-ui/react'
import { DropdownList } from 'components/shared/DropdownList'
import { useState, useEffect } from 'react'
type StandardEmbedWindowSettingsProps = {
onUpdateWindowSettings: (windowSettings: {
heightLabel: string
widthLabel: string
}) => void
}
export const StandardEmbedWindowSettings = ({
onUpdateWindowSettings,
...props
}: StandardEmbedWindowSettingsProps & StackProps) => {
const [fullscreen, setFullscreen] = useState(false)
const [inputValues, setInputValues] = useState({
widthValue: '100',
widthType: '%',
heightValue: '600',
heightType: 'px',
})
useEffect(() => {
onUpdateWindowSettings({
widthLabel: fullscreen
? '100%'
: inputValues.widthValue + inputValues.widthType,
heightLabel: fullscreen
? '100vh'
: inputValues.heightValue + inputValues.heightType,
})
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [inputValues, fullscreen])
const handleWidthTypeSelect = (widthType: string) =>
setInputValues({ ...inputValues, widthType })
const handleHeightTypeSelect = (heightType: string) =>
setInputValues({ ...inputValues, heightType })
return (
<Stack {...props}>
<Flex alignItems="center" justifyContent="space-between">
<Heading fontSize="md" fontWeight="semibold" style={{ flexShrink: 0 }}>
Window settings
</Heading>
<FormControl
display="flex"
alignItems="center"
w="full"
justifyContent="flex-end"
>
<FormLabel htmlFor="fullscreen-option" mb="1">
Set to fullscreen?
</FormLabel>
<Switch
id="fullscreen-option"
onChange={() => setFullscreen(!fullscreen)}
isChecked={fullscreen}
/>
</FormControl>
</Flex>
{!fullscreen && (
<>
<Flex justify="space-between" align="center" mb="2">
<Text>Width</Text>
<HStack>
<Input
onChange={(e) =>
setInputValues({
...inputValues,
widthValue: e.target.value,
})
}
w="70px"
value={inputValues.widthValue}
/>
<DropdownList<string>
items={['px', '%']}
onItemSelect={handleWidthTypeSelect}
currentItem={inputValues.widthType}
/>
</HStack>
</Flex>
<Flex justify="space-between" align="center" mb="2">
<Text>Height</Text>
<HStack>
<Input
onChange={(e) =>
setInputValues({
...inputValues,
heightValue: e.target.value,
})
}
w="70px"
value={inputValues.heightValue}
/>
<DropdownList<string>
items={['px', '%']}
onItemSelect={handleHeightTypeSelect}
currentItem={inputValues.heightType}
/>
</HStack>
</Flex>
</>
)}
</Stack>
)
}

View File

@ -0,0 +1,19 @@
import { FlexProps } from '@chakra-ui/react'
import { CodeEditor } from 'components/shared/CodeEditor'
import { useTypebot } from 'contexts/TypebotContext'
type Props = {
widthLabel: string
heightLabel: string
onCopied?: () => void
}
export const IframeEmbedCode = ({
widthLabel,
heightLabel,
}: Props & FlexProps) => {
const { typebot } = useTypebot()
const src = `https://${typebot?.publicId}.typebot.io`
const code = `<iframe src="${src}" width="${widthLabel}" height="${heightLabel}" />`
return <CodeEditor value={code} lang="html" isReadOnly />
}

View File

@ -0,0 +1,34 @@
import { FlexProps } from '@chakra-ui/layout'
import { CodeEditor } from 'components/shared/CodeEditor'
import { useTypebot } from 'contexts/TypebotContext'
import parserHtml from 'prettier/parser-html'
import prettier from 'prettier/standalone'
import { PopupParams } from 'typebot-js'
import { parseInitPopupCode, typebotJsHtml } from '../params'
type PopupEmbedCodeProps = {
delay: number
withStarterVariables?: boolean
onCopied?: () => void
}
export const PopupEmbedCode = ({ delay }: PopupEmbedCodeProps & FlexProps) => {
const { typebot } = useTypebot()
const snippet = prettier.format(
createSnippet({
publishId: typebot?.publicId ?? '',
delay,
}),
{
parser: 'html',
plugins: [parserHtml],
}
)
return <CodeEditor value={snippet} lang="html" isReadOnly />
}
const createSnippet = (params: PopupParams): string => {
const jsCode = parseInitPopupCode(params)
return `${typebotJsHtml}
<script>${jsCode}</script>`
}

View File

@ -0,0 +1,55 @@
import {
StackProps,
Stack,
Flex,
Heading,
NumberInput,
NumberInputField,
NumberInputStepper,
NumberIncrementStepper,
NumberDecrementStepper,
} from '@chakra-ui/react'
import { useState, useEffect } from 'react'
import { PopupParams } from 'typebot-js'
type PopupEmbedSettingsProps = {
onUpdateSettings: (windowSettings: Pick<PopupParams, 'delay'>) => void
}
export const PopupEmbedSettings = ({
onUpdateSettings,
...props
}: PopupEmbedSettingsProps & StackProps) => {
const [inputValue, setInputValue] = useState(0)
useEffect(() => {
onUpdateSettings({
delay: inputValue * 1000,
})
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [inputValue])
return (
<Stack {...props}>
<Flex alignItems="center" justifyContent="space-between">
<Heading fontSize="md" fontWeight="semibold">
Popup settings
</Heading>
</Flex>
<Flex justify="space-between" align="center" mb="2">
<p>Appearance delay</p>
<NumberInput
onChange={(_, val) => setInputValue(val)}
value={inputValue}
min={0}
>
<NumberInputField />
<NumberInputStepper>
<NumberIncrementStepper />
<NumberDecrementStepper />
</NumberInputStepper>
</NumberInput>
</Flex>
</Stack>
)
}

View File

@ -0,0 +1,154 @@
import { FlexProps } from '@chakra-ui/react'
import React from 'react'
import { BubbleParams, IframeParams, PopupParams } from 'typebot-js'
import {
parseInitBubbleCode,
parseInitContainerCode,
parseInitPopupCode,
} from './params'
import parserBabel from 'prettier/parser-babel'
import prettier from 'prettier/standalone'
import { CodeEditor } from 'components/shared/CodeEditor'
import { useTypebot } from 'contexts/TypebotContext'
type StandardReactDivProps = { widthLabel: string; heightLabel: string }
export const StandardReactDiv = ({
widthLabel,
heightLabel,
}: StandardReactDivProps) => {
const { typebot } = useTypebot()
const snippet = prettier.format(
parseContainerSnippet({
publishId: typebot?.publicId ?? '',
heightLabel,
widthLabel,
}),
{
parser: 'babel',
plugins: [parserBabel],
}
)
return <CodeEditor value={snippet} lang="js" isReadOnly />
}
type SnippetProps = IframeParams &
Pick<StandardReactDivProps, 'widthLabel' | 'heightLabel'>
const parseContainerSnippet = ({
publishId,
customDomain,
backgroundColor,
hiddenVariables,
...embedProps
}: SnippetProps): string => {
const jsCode = parseInitContainerCode({
publishId,
customDomain,
backgroundColor,
hiddenVariables,
})
return `import {initContainer} from "typebot-js";
const Component = () => {
useEffect(()=> {
${jsCode}
}, [])
return <div id="typebot-container" style={{width: "${embedProps.widthLabel}", height: "${embedProps.heightLabel}"}} />
}`
}
type PopupEmbedCodeProps = {
delay: number
withStarterVariables?: boolean
}
export const PopupReactCode = ({ delay }: PopupEmbedCodeProps & FlexProps) => {
const { typebot } = useTypebot()
const snippet = prettier.format(
parsePopupSnippet({
publishId: typebot?.publicId ?? '',
delay,
}),
{
parser: 'babel',
plugins: [parserBabel],
}
)
return <CodeEditor value={snippet} lang="js" isReadOnly />
}
const parsePopupSnippet = ({
publishId,
customDomain,
backgroundColor,
hiddenVariables,
delay,
}: PopupParams): string => {
const jsCode = parseInitPopupCode({
publishId,
customDomain,
backgroundColor,
hiddenVariables,
delay,
})
return `import {initPopup} from "typebot-js";
const Component = () => {
useEffect(()=> {
${jsCode}
}, [])
return <></>;
}`
}
type ChatEmbedCodeProps = {
withStarterVariables?: boolean
} & Pick<BubbleParams, 'button' | 'proactiveMessage'>
export const ChatReactCode = ({
proactiveMessage,
button,
}: ChatEmbedCodeProps & FlexProps) => {
const { typebot } = useTypebot()
const snippet = prettier.format(
parseBubbleSnippet({
publishId: typebot?.publicId ?? '',
button,
proactiveMessage,
}),
{
parser: 'babel',
plugins: [parserBabel],
}
)
return <CodeEditor value={snippet} lang="js" isReadOnly />
}
const parseBubbleSnippet = ({
publishId,
customDomain,
backgroundColor,
hiddenVariables,
proactiveMessage,
button,
}: BubbleParams): string => {
const jsCode = parseInitBubbleCode({
publishId,
customDomain,
backgroundColor,
hiddenVariables,
proactiveMessage,
button,
})
return `import {initBubble} from "typebot-js";
const Component = () => {
useEffect(()=> {
${jsCode}
}, [])
return <></>
}`
}

View File

@ -0,0 +1,142 @@
import {
BubbleParams,
ButtonParams,
IframeParams,
PopupParams,
ProactiveMessageParams,
} from 'typebot-js'
import parserBabel from 'prettier/parser-babel'
import prettier from 'prettier/standalone'
const parseStringParam = (fieldName: string, fieldValue?: string) =>
fieldValue ? `${fieldName}: "${fieldValue}",` : ``
const parseNonStringParam = (
fieldName: string,
fieldValue?: number | boolean
) => (fieldValue ? `${fieldName}: ${fieldValue},` : ``)
const parseCustomDomain = (domain?: string): string =>
parseStringParam('customDomain', domain)
const parseHiddenVariables = (
variables: { [key: string]: string | undefined } | undefined
): string => (variables ? `hiddenVariables: ${JSON.stringify(variables)},` : ``)
const parseBackgroundColor = (bgColor?: string): string =>
parseStringParam('backgroundColor', bgColor)
const parseDelay = (delay?: number) => parseNonStringParam('delay', delay)
const parseButton = (button?: ButtonParams): string => {
if (!button) return ''
const iconUrlString = parseStringParam('iconUrl', button.iconUrl)
const buttonColorstring = parseStringParam('color', button.color)
return `button: {${iconUrlString}${buttonColorstring}},`
}
const parseProactiveMessage = (
proactiveMessage?: ProactiveMessageParams
): string => {
if (!proactiveMessage) return ``
const { avatarUrl, textContent, delay, rememberClose } = proactiveMessage
const avatarUrlString = parseStringParam('avatarUrl', avatarUrl)
const textContentString = parseStringParam('textContent', textContent)
const rememberCloseString = parseNonStringParam(
'rememberClose',
rememberClose
)
const delayString = parseNonStringParam('delay', delay)
return `proactiveMessage: {${avatarUrlString}${textContentString}${rememberCloseString}${delayString}},`
}
const parseIframeParams = ({
customDomain,
hiddenVariables,
backgroundColor,
}: Pick<
IframeParams,
'customDomain' | 'hiddenVariables' | 'backgroundColor'
>) => ({
customDomainString: parseCustomDomain(customDomain),
hiddenVariablesString: parseHiddenVariables(hiddenVariables),
bgColorString: parseBackgroundColor(backgroundColor),
})
const parsePopupParams = ({ delay }: Pick<PopupParams, 'delay'>) => ({
delayString: parseDelay(delay),
})
const parseBubbleParams = ({
button,
proactiveMessage,
}: Pick<BubbleParams, 'button' | 'proactiveMessage'>) => ({
proactiveMessageString: parseProactiveMessage(proactiveMessage),
buttonString: parseButton(button),
})
export const parseInitContainerCode = ({
publishId,
customDomain,
backgroundColor,
hiddenVariables,
}: IframeParams) => {
const { customDomainString, hiddenVariablesString, bgColorString } =
parseIframeParams({
customDomain,
hiddenVariables,
backgroundColor,
})
return prettier.format(
`Typebot.initContainer("typebot-container", {
publishId: "${publishId}",${bgColorString}${customDomainString}${hiddenVariablesString}
});`,
{ parser: 'babel', plugins: [parserBabel] }
)
}
export const parseInitPopupCode = ({
publishId,
customDomain,
hiddenVariables,
backgroundColor,
delay,
}: PopupParams) => {
const { customDomainString, hiddenVariablesString, bgColorString } =
parseIframeParams({
customDomain,
hiddenVariables,
backgroundColor,
})
const { delayString } = parsePopupParams({ delay })
return prettier.format(
`var typebotCommands = Typebot.initPopup({publishId: "${publishId}",${delayString}${bgColorString}${customDomainString}${hiddenVariablesString}});`,
{ parser: 'babel', plugins: [parserBabel] }
)
}
export const parseInitBubbleCode = ({
publishId,
customDomain,
hiddenVariables,
backgroundColor,
button,
proactiveMessage,
}: BubbleParams) => {
const { customDomainString, hiddenVariablesString, bgColorString } =
parseIframeParams({
customDomain,
hiddenVariables,
backgroundColor,
})
const { buttonString, proactiveMessageString } = parseBubbleParams({
button,
proactiveMessage,
})
return prettier.format(
`var typebotCommands = Typebot.initBubble({publishId: "${publishId}",${bgColorString}${customDomainString}${hiddenVariablesString}${proactiveMessageString}${buttonString}});`,
{ parser: 'babel', plugins: [parserBabel] }
)
}
export const typebotJsHtml = `<script src="https://unpkg.com/typebot-js@2.0.20"></script>`

View File

@ -21,6 +21,7 @@ import {
ReactModal,
NotionModal,
IframeModal,
WixModal,
} from './modals'
export type ModalProps = {
@ -82,7 +83,7 @@ export const integrationsList = [
<EmbedButton
logo={<WixLogo height={100} width="90px" />}
label="Wix"
Modal={WebflowModal}
Modal={WixModal}
{...props}
/>
),
@ -128,7 +129,7 @@ export const integrationsList = [
),
(props: Pick<ModalProps, 'publicId' | 'isPublished'>) => (
<EmbedButton
logo={<IframeLogo height={100} width={80} />}
logo={<IframeLogo height={100} width="70px" />}
label="Iframe"
Modal={IframeModal}
{...props}
@ -136,7 +137,7 @@ export const integrationsList = [
),
(props: Pick<ModalProps, 'publicId' | 'isPublished'>) => (
<EmbedButton
logo={<OtherLogo height={100} width={80} />}
logo={<OtherLogo height={100} width="70px" />}
label="Other"
Modal={JavascriptModal}
{...props}

View File

@ -1,14 +1,27 @@
import { OrderedList, ListItem, Tag } from '@chakra-ui/react'
import { ChatEmbedCode } from 'components/share/codeSnippets/Chat/EmbedCode'
import { ChatEmbedSettings } from 'components/share/codeSnippets/Chat/EmbedSettings'
import { StandardEmbedWindowSettings } from 'components/share/codeSnippets/Container/EmbedSettings'
import {
parseInitContainerCode,
typebotJsHtml,
} from 'components/share/codeSnippets/params'
import { PopupEmbedCode } from 'components/share/codeSnippets/Popup/EmbedCode'
import { PopupEmbedSettings } from 'components/share/codeSnippets/Popup/EmbedSettings'
import { CodeEditor } from 'components/shared/CodeEditor'
import { useState } from 'react'
import { BubbleParams } from 'typebot-js'
import { ModalProps } from '../../EmbedButton'
type GtmInstructionsProps = {
type: 'standard' | 'popup' | 'bubble'
publicId: string
}
export const GtmInstructions = ({ type }: GtmInstructionsProps) => {
export const GtmInstructions = ({ type, publicId }: GtmInstructionsProps) => {
switch (type) {
case 'standard': {
return <StandardInstructions />
return <StandardInstructions publicId={publicId} />
}
case 'popup': {
return <PopupInstructions />
@ -19,23 +32,21 @@ export const GtmInstructions = ({ type }: GtmInstructionsProps) => {
}
}
const StandardInstructions = () => {
// const [windowSizes, setWindowSizes] = useState({
// height: '100%',
// width: '100%',
// })
const StandardInstructions = ({ publicId }: Pick<ModalProps, 'publicId'>) => {
const [windowSizes, setWindowSizes] = useState({
height: '100%',
width: '100%',
})
// const jsCode = parseInitContainerCode({
// publishId: chatbot?.publishId ?? '',
// backgroundColor: chatbot?.themeColors.chatbotBackground.value,
// customDomain: chatbot?.customDomains[0],
// })
// const headCode = `${typebotJsHtml}
// <script>
// ${jsCode}
// </script>`
const jsCode = parseInitContainerCode({
publishId: publicId,
})
const headCode = `${typebotJsHtml}
<script>
${jsCode}
</script>`
// const elementCode = `<div id="typebot-container" style="background-color: ${backgroundColor}; height: ${windowSizes.height}; width: ${windowSizes.width}"></div>`
const elementCode = `<div id="typebot-container" style="height: ${windowSizes.height}; width: ${windowSizes.width}"></div>`
return (
<OrderedList spacing={2} mb={4}>
<ListItem>
@ -46,16 +57,12 @@ const StandardInstructions = () => {
</ListItem>
<ListItem>
Paste the code below:
{/* <CodeEditor
code={headCode}
mt={2}
onCopied={() => sendGtmCopyEvent('standard')}
/> */}
<CodeEditor value={headCode} mt={2} isReadOnly lang="html" />
</ListItem>
<ListItem>
On your webpage, you need to have an element on which the typebot will
go. It needs to have the id <Tag>typebot-container</Tag>:
{/* <StandardEmbedWindowSettings
<StandardEmbedWindowSettings
my={4}
onUpdateWindowSettings={(sizes) =>
setWindowSizes({
@ -64,14 +71,14 @@ const StandardInstructions = () => {
})
}
/>
<CodeBlock code={elementCode} mt={2} /> */}
<CodeEditor value={elementCode} mt={2} isReadOnly lang="html" />
</ListItem>
</OrderedList>
)
}
const PopupInstructions = () => {
// const [inputValue, setInputValue] = useState(0)
const [inputValue, setInputValue] = useState(0)
return (
<OrderedList spacing={2} mb={4}>
@ -83,29 +90,26 @@ const PopupInstructions = () => {
</ListItem>
<ListItem>
Paste the code below:
{/* <PopupEmbedSettings
mb={4}
<PopupEmbedSettings
my={4}
onUpdateSettings={(settings) => setInputValue(settings.delay ?? 0)}
/>
<PopupEmbedCode
delay={inputValue}
onCopied={() => sendGtmCopyEvent('popup')}
/> */}
<PopupEmbedCode delay={inputValue} />
</ListItem>
</OrderedList>
)
}
const BubbleInstructions = () => {
// const [inputValues, setInputValues] = useState<
// Pick<BubbleParams, 'proactiveMessage' | 'button'>
// >({
// proactiveMessage: undefined,
// button: {
// color: '',
// iconUrl: '',
// },
// })
const [inputValues, setInputValues] = useState<
Pick<BubbleParams, 'proactiveMessage' | 'button'>
>({
proactiveMessage: undefined,
button: {
color: '',
iconUrl: '',
},
})
return (
<OrderedList spacing={2} mb={4}>
@ -117,14 +121,10 @@ const BubbleInstructions = () => {
</ListItem>
<ListItem>
Paste the code below:
{/* <ChatEmbedSettings
<ChatEmbedSettings
onUpdateSettings={(settings) => setInputValues({ ...settings })}
/>
<ChatEmbedCode
mt={4}
{...inputValues}
onCopied={() => sendGtmCopyEvent('bubble')}
/> */}
<ChatEmbedCode my={4} {...inputValues} />
</ListItem>
</OrderedList>
)

View File

@ -18,7 +18,12 @@ import { capitalize } from 'utils'
import { PublishFirstInfo } from 'components/shared/Info'
import { GtmInstructions } from './GtmInstructions'
export const GtmModal = ({ isOpen, onClose, isPublished }: ModalProps) => {
export const GtmModal = ({
isOpen,
onClose,
isPublished,
publicId,
}: ModalProps) => {
const [chosenEmbedType, setChosenEmbedType] = useState<
'standard' | 'popup' | 'bubble' | undefined
>()
@ -53,7 +58,7 @@ export const GtmModal = ({ isOpen, onClose, isPublished }: ModalProps) => {
{!chosenEmbedType ? (
<ChooseEmbedTypeList onSelectEmbedType={setChosenEmbedType} />
) : (
<GtmInstructions type={chosenEmbedType} />
<GtmInstructions type={chosenEmbedType} publicId={publicId} />
)}
</ModalBody>
<ModalFooter />

View File

@ -9,16 +9,13 @@ import {
ModalFooter,
Text,
} from '@chakra-ui/react'
import { StandardEmbedWindowSettings } from 'components/share/codeSnippets/Container/EmbedSettings'
import { IframeEmbedCode } from 'components/share/codeSnippets/Iframe/EmbedCode'
import { PublishFirstInfo } from 'components/shared/Info'
import { useState } from 'react'
import { ModalProps } from '../EmbedButton'
export const IframeModal = ({
isPublished,
publicId,
isOpen,
onClose,
}: ModalProps) => {
export const IframeModal = ({ isPublished, isOpen, onClose }: ModalProps) => {
const [inputValues, setInputValues] = useState({
heightLabel: '100%',
widthLabel: '100%',
@ -33,6 +30,12 @@ export const IframeModal = ({
<ModalBody as={Stack} spacing={4}>
{!isPublished && <PublishFirstInfo />}
<Text>Paste this anywhere in your HTML code:</Text>
<StandardEmbedWindowSettings
onUpdateWindowSettings={(settings) =>
setInputValues({ ...settings })
}
/>
<IframeEmbedCode {...inputValues} />
</ModalBody>
<ModalFooter />
</ModalContent>

View File

@ -1,4 +1,12 @@
import { Stack, Tag, Text } from '@chakra-ui/react'
import { ChatEmbedCode } from 'components/share/codeSnippets/Chat/EmbedCode'
import { ChatEmbedSettings } from 'components/share/codeSnippets/Chat/EmbedSettings'
import { ContainerEmbedCode } from 'components/share/codeSnippets/Container/EmbedCode'
import { StandardEmbedWindowSettings } from 'components/share/codeSnippets/Container/EmbedSettings'
import { PopupEmbedCode } from 'components/share/codeSnippets/Popup/EmbedCode'
import { PopupEmbedSettings } from 'components/share/codeSnippets/Popup/EmbedSettings'
import { useState } from 'react'
import { BubbleParams } from 'typebot-js'
type JavascriptInstructionsProps = {
type: 'standard' | 'popup' | 'bubble'
@ -21,75 +29,61 @@ export const JavascriptInstructions = ({
}
const StandardInstructions = () => {
// const [inputValues, setInputValues] = useState({
// heightLabel: '100%',
// widthLabel: '100%',
// })
const [inputValues, setInputValues] = useState({
heightLabel: '100%',
widthLabel: '100%',
})
return (
<Stack>
<Stack spacing={4}>
<Text>
Paste this anywhere in the <Tag>body</Tag>
</Text>
{/* <StandardEmbedWindowSettings
<StandardEmbedWindowSettings
onUpdateWindowSettings={(settings) => setInputValues({ ...settings })}
/>
<ContainerEmbedCode
withStarterVariables={true}
{...inputValues}
mt={4}
onCopied={() => sendJsCopyEvent('standard')}
/> */}
<ContainerEmbedCode withStarterVariables={true} {...inputValues} mt={4} />
</Stack>
)
}
const PopupInstructions = () => {
// const [inputValue, setInputValue] = useState(0)
const [inputValue, setInputValue] = useState(0)
return (
<Stack>
<Stack spacing={4}>
<Text>
Paste this anywhere in the <Tag>body</Tag>
</Text>
{/* <StandardEmbedWindowSettings
onUpdateWindowSettings={(settings) => setInputValues({ ...settings })}
<PopupEmbedSettings
mb={4}
onUpdateSettings={(settings) => setInputValue(settings.delay ?? 0)}
/>
<ContainerEmbedCode
withStarterVariables={true}
{...inputValues}
mt={4}
onCopied={() => sendJsCopyEvent('standard')}
/> */}
<PopupEmbedCode delay={inputValue} />
</Stack>
)
}
const BubbleInstructions = () => {
// const [inputValues, setInputValues] = useState<
// Pick<BubbleParams, 'proactiveMessage' | 'button'>
// >({
// proactiveMessage: undefined,
// button: {
// color: '',
// iconUrl: '',
// },
// })
const [inputValues, setInputValues] = useState<
Pick<BubbleParams, 'proactiveMessage' | 'button'>
>({
proactiveMessage: undefined,
button: {
color: '',
iconUrl: '',
},
})
return (
<Stack>
<Stack spacing={4}>
<Text>
Paste this anywhere in the <Tag>body</Tag>
</Text>
{/* <StandardEmbedWindowSettings
onUpdateWindowSettings={(settings) => setInputValues({ ...settings })}
<ChatEmbedSettings
onUpdateSettings={(settings) => setInputValues({ ...settings })}
/>
<ContainerEmbedCode
withStarterVariables={true}
{...inputValues}
mt={4}
onCopied={() => sendJsCopyEvent('standard')}
/> */}
<ChatEmbedCode {...inputValues} />
</Stack>
)
}

View File

@ -1,5 +1,15 @@
import { Stack, Text } from '@chakra-ui/react'
import { ChatEmbedSettings } from 'components/share/codeSnippets/Chat/EmbedSettings'
import { StandardEmbedWindowSettings } from 'components/share/codeSnippets/Container/EmbedSettings'
import { PopupEmbedSettings } from 'components/share/codeSnippets/Popup/EmbedSettings'
import {
ChatReactCode,
PopupReactCode,
StandardReactDiv,
} from 'components/share/codeSnippets/ReactCode'
import { CodeEditor } from 'components/shared/CodeEditor'
import { useState } from 'react'
import { BubbleParams } from 'typebot-js'
type Props = {
type: 'standard' | 'popup' | 'bubble'
@ -20,58 +30,57 @@ export const ReactInstructions = ({ type }: Props) => {
}
const StandardInstructions = () => {
// const [inputValues, setInputValues] = useState({
// heightLabel: '100%',
// widthLabel: '100%',
// })
const [inputValues, setInputValues] = useState({
heightLabel: '100%',
widthLabel: '100%',
})
return (
<Stack spacing={4}>
{/* <InstallPackageInstruction /> */}
{/* <StandardEmbedWindowSettings
<InstallPackageInstruction />
<StandardEmbedWindowSettings
onUpdateWindowSettings={(settings) => setInputValues({ ...settings })}
/> */}
{/* <Text>{t('insert-the-typebot-container')}</Text>
<StandardReactDiv {...inputValues} /> */}
/>
<Text>Insert the typebot container</Text>
<StandardReactDiv {...inputValues} />
</Stack>
)
}
const PopupInstructions = () => {
// const [inputValue, setInputValue] = useState(0)
const [inputValue, setInputValue] = useState(0)
return (
<Stack spacing={4}>
{/* <InstallPackageInstruction />
<InstallPackageInstruction />
<PopupEmbedSettings
onUpdateSettings={(settings) => setInputValue(settings.delay ?? 0)}
/>
<Text>{t('initialize-the-typebot')}</Text>
<PopupReactCode withStarterVariables={true} delay={inputValue} /> */}
<Text>Initialize the typebot</Text>
<PopupReactCode withStarterVariables={true} delay={inputValue} />
</Stack>
)
}
const BubbleInstructions = () => {
// const { t } = useTranslation()
// const [inputValues, setInputValues] = useState<
// Pick<BubbleParams, 'proactiveMessage' | 'button'>
// >({
// proactiveMessage: undefined,
// button: {
// color: '',
// iconUrl: '',
// },
// })
const [inputValues, setInputValues] = useState<
Pick<BubbleParams, 'proactiveMessage' | 'button'>
>({
proactiveMessage: undefined,
button: {
color: '',
iconUrl: '',
},
})
return (
<Stack spacing={4}>
{/* <InstallPackageInstruction />
<InstallPackageInstruction />
<ChatEmbedSettings
onUpdateSettings={(settings) => setInputValues({ ...settings })}
/>
<Text>{t('initialize-the-typebot')}</Text>
<ChatReactCode withStarterVariables={true} {...inputValues} mt={4} /> */}
<Text>Initialize the typebot</Text>
<ChatReactCode withStarterVariables={true} {...inputValues} mt={4} />
</Stack>
)
}

View File

@ -1,13 +1,32 @@
import { OrderedList, ListItem, Tag } from '@chakra-ui/react'
import { ChatEmbedCode } from 'components/share/codeSnippets/Chat/EmbedCode'
import { ChatEmbedSettings } from 'components/share/codeSnippets/Chat/EmbedSettings'
import { StandardEmbedWindowSettings } from 'components/share/codeSnippets/Container/EmbedSettings'
import {
parseInitContainerCode,
typebotJsHtml,
} from 'components/share/codeSnippets/params'
import { PopupEmbedCode } from 'components/share/codeSnippets/Popup/EmbedCode'
import { PopupEmbedSettings } from 'components/share/codeSnippets/Popup/EmbedSettings'
import { CodeEditor } from 'components/shared/CodeEditor'
import { useState } from 'react'
import { BubbleParams } from 'typebot-js'
import { ModalProps } from '../../EmbedButton'
import parserHtml from 'prettier/parser-html'
import prettier from 'prettier/standalone'
type ShopifyInstructionsProps = {
type: 'standard' | 'popup' | 'bubble'
publicId: string
}
export const ShopifyInstructions = ({ type }: ShopifyInstructionsProps) => {
export const ShopifyInstructions = ({
type,
publicId,
}: ShopifyInstructionsProps) => {
switch (type) {
case 'standard': {
return <StandardInstructions />
return <StandardInstructions publicId={publicId} />
}
case 'popup': {
return <PopupInstructions />
@ -18,24 +37,30 @@ export const ShopifyInstructions = ({ type }: ShopifyInstructionsProps) => {
}
}
const StandardInstructions = () => {
// const backgroundColor = chatbot?.themeColors.siteBackground.value
// const [windowSizes, setWindowSizes] = useState({
// height: '100%',
// width: '100%',
// })
const StandardInstructions = ({ publicId }: Pick<ModalProps, 'publicId'>) => {
const [windowSizes, setWindowSizes] = useState({
height: '100%',
width: '100%',
})
// const jsCode = parseInitContainerCode({
// publishId: chatbot?.publishId ?? '',
// customDomain: chatbot?.customDomains[0],
// backgroundColor: chatbot?.themeColors.chatbotBackground.value,
// })
// const headCode = `${typebotJsHtml}
// <script>
// ${jsCode}
// </script>`
const jsCode = parseInitContainerCode({
publishId: publicId,
})
const headCode = prettier.format(
`${typebotJsHtml}<script>${jsCode}</script>`,
{
parser: 'html',
plugins: [parserHtml],
}
)
// const elementCode = `<div id="typebot-container" style="background-color: ${backgroundColor}; height: ${windowSizes.height}; width: ${windowSizes.width}"></div>`
const elementCode = prettier.format(
`<div id="typebot-container" style="height: ${windowSizes.height}; width: ${windowSizes.width}"></div>`,
{
parser: 'html',
plugins: [parserHtml],
}
)
return (
<OrderedList spacing={2} mb={4}>
@ -46,17 +71,13 @@ const StandardInstructions = () => {
<ListItem>
In <Tag>Layout {'>'} theme.liquid</Tag> file, paste this code just
before the closing <Tag>head</Tag> tag:
{/* <CodeBlock
code={headCode}
mt={2}
onCopied={() => sendShopifyCopyEvent('standard')}
/> */}
<CodeEditor value={headCode} mt={2} lang="html" isReadOnly />
</ListItem>
<ListItem>
Then, you can place an element on which the typebot will go in any file
in the <Tag>body</Tag> tags. It needs to have the id{' '}
<Tag>typebot-container</Tag>:
{/* <StandardEmbedWindowSettings
<StandardEmbedWindowSettings
my={4}
onUpdateWindowSettings={(sizes) =>
setWindowSizes({
@ -65,14 +86,14 @@ const StandardInstructions = () => {
})
}
/>
<CodeBlock code={elementCode} mt={2} /> */}
<CodeEditor value={elementCode} mt={2} lang="html" isReadOnly />
</ListItem>
</OrderedList>
)
}
const PopupInstructions = () => {
// const [inputValue, setInputValue] = useState(0)
const [inputValue, setInputValue] = useState(0)
return (
<OrderedList spacing={2} mb={4}>
@ -83,29 +104,26 @@ const PopupInstructions = () => {
<ListItem>
In <Tag>Layout {'>'} theme.liquid</Tag> file, paste this code just
before the closing <Tag>head</Tag> tag:
{/* <PopupEmbedSettings
mb={4}
onUpdateSettings={(settings) => setInputValue(settings.delay ?? 0)}
/>
<PopupEmbedCode
delay={inputValue}
onCopied={() => sendShopifyCopyEvent('popup')}
/> */}
<PopupEmbedSettings
my="4"
onUpdateSettings={(settings) => setInputValue(settings.delay ?? 0)}
/>
<PopupEmbedCode delay={inputValue} />
</ListItem>
</OrderedList>
)
}
const BubbleInstructions = () => {
// const [inputValues, setInputValues] = useState<
// Pick<BubbleParams, 'proactiveMessage' | 'button'>
// >({
// proactiveMessage: undefined,
// button: {
// color: '',
// iconUrl: '',
// },
// })
const [inputValues, setInputValues] = useState<
Pick<BubbleParams, 'proactiveMessage' | 'button'>
>({
proactiveMessage: undefined,
button: {
color: '',
iconUrl: '',
},
})
return (
<OrderedList spacing={2} mb={4}>
@ -116,14 +134,11 @@ const BubbleInstructions = () => {
<ListItem>
In <Tag>Layout {'>'} theme.liquid</Tag> file, paste this code just
before the closing <Tag>head</Tag> tag:
{/* <ChatEmbedSettings
onUpdateSettings={(settings) => setInputValues({ ...settings })}
/>
<ChatEmbedCode
mt={4}
{...inputValues}
onCopied={() => sendShopifyCopyEvent('bubble')}
/> */}
<ChatEmbedSettings
my="4"
onUpdateSettings={(settings) => setInputValues({ ...settings })}
/>
<ChatEmbedCode mt={4} {...inputValues} />
</ListItem>
</OrderedList>
)

View File

@ -18,7 +18,12 @@ import { capitalize } from 'utils'
import { PublishFirstInfo } from 'components/shared/Info'
import { ShopifyInstructions } from './ShopifyInstructions'
export const ShopifyModal = ({ isOpen, onClose, isPublished }: ModalProps) => {
export const ShopifyModal = ({
isOpen,
onClose,
isPublished,
publicId,
}: ModalProps) => {
const [chosenEmbedType, setChosenEmbedType] = useState<
'standard' | 'popup' | 'bubble' | undefined
>()
@ -53,7 +58,7 @@ export const ShopifyModal = ({ isOpen, onClose, isPublished }: ModalProps) => {
{!chosenEmbedType ? (
<ChooseEmbedTypeList onSelectEmbedType={setChosenEmbedType} />
) : (
<ShopifyInstructions type={chosenEmbedType} />
<ShopifyInstructions type={chosenEmbedType} publicId={publicId} />
)}
</ModalBody>
<ModalFooter />

View File

@ -1,4 +1,11 @@
import { OrderedList, ListItem, Tag, Text, Stack } from '@chakra-ui/react'
import { ChatEmbedCode } from 'components/share/codeSnippets/Chat/EmbedCode'
import { ChatEmbedSettings } from 'components/share/codeSnippets/Chat/EmbedSettings'
import { ContainerEmbedCode } from 'components/share/codeSnippets/Container/EmbedCode'
import { PopupEmbedCode } from 'components/share/codeSnippets/Popup/EmbedCode'
import { PopupEmbedSettings } from 'components/share/codeSnippets/Popup/EmbedSettings'
import { useState } from 'react'
import { BubbleParams } from 'typebot-js'
type WebflowInstructionsProps = {
type: 'standard' | 'popup' | 'bubble'
@ -21,8 +28,22 @@ export const WebflowInstructions = ({ type }: WebflowInstructionsProps) => {
}
const StandardInstructions = () => (
<Stack>
<Text>In the Webflow editor:</Text>
<OrderedList spacing={2} mb={4}>
<ListItem>
Press <Tag>A</Tag> to open the <Tag>Add elements</Tag> panel
</ListItem>
<ListItem>
Add an <Tag>embed</Tag> element from the <Tag>components</Tag>
section and paste this code:
<ContainerEmbedCode widthLabel="100%" heightLabel="100%" my={4} />
</ListItem>
</OrderedList>
)
const PopupInstructions = () => {
const [inputValue, setInputValue] = useState(0)
return (
<OrderedList spacing={2} mb={4}>
<ListItem>
Press <Tag>A</Tag> to open the <Tag>Add elements</Tag> panel
@ -30,78 +51,41 @@ const StandardInstructions = () => (
<ListItem>
Add an <Tag>embed</Tag> element from the <Tag>components</Tag>
section and paste this code:
{/* <ContainerEmbedCode
widthLabel="100%"
heightLabel="100%"
mt={4}
onCopied={() => sendWebflowCopyEvent('standard')}
/> */}
<PopupEmbedSettings
onUpdateSettings={(settings) => setInputValue(settings.delay ?? 0)}
my={4}
/>
<PopupEmbedCode delay={inputValue} mt={4} />
</ListItem>
</OrderedList>
</Stack>
)
const PopupInstructions = () => {
// const [inputValue, setInputValue] = useState(0)
return (
<Stack>
<Text>In the Webflow editor</Text>
<OrderedList spacing={2} mb={4}>
<ListItem>
Press <Tag>A</Tag> to open the <Tag>Add elements</Tag> panel
</ListItem>
<ListItem>
Add an <Tag>embed</Tag> element from the <Tag>components</Tag>
section and paste this code:
{/* <PopupEmbedSettings
onUpdateSettings={(settings) => setInputValue(settings.delay ?? 0)}
mt={4}
/>
<PopupEmbedCode
delay={inputValue}
mt={4}
onCopied={() => sendWebflowCopyEvent('popup')}
/> */}
</ListItem>
</OrderedList>
</Stack>
)
}
const BubbleInstructions = () => {
// const [inputValues, setInputValues] = useState<
// Pick<BubbleParams, 'proactiveMessage' | 'button'>
// >({
// proactiveMessage: undefined,
// button: {
// color: '',
// iconUrl: '',
// },
// })
const [inputValues, setInputValues] = useState<
Pick<BubbleParams, 'proactiveMessage' | 'button'>
>({
proactiveMessage: undefined,
button: {
color: '',
iconUrl: '',
},
})
return (
<Stack>
<Text>In the Webflow editor</Text>
<OrderedList spacing={2} mb={4}>
<ListItem>
Press <Tag>A</Tag> to open the <Tag>Add elements</Tag> panel
</ListItem>
<ListItem>
Add an <Tag>embed</Tag> element from the <Tag>components</Tag>
section and paste this code:
{/* <ChatEmbedSettings
onUpdateSettings={(settings) => setInputValues({ ...settings })}
mt={4}
/>
<ChatEmbedCode
withStarterVariables={true}
{...inputValues}
mt={4}
onCopied={() => sendWebflowCopyEvent('bubble')}
/> */}
</ListItem>
</OrderedList>
</Stack>
<OrderedList spacing={2} mb={4}>
<ListItem>
Press <Tag>A</Tag> to open the <Tag>Add elements</Tag> panel
</ListItem>
<ListItem>
Add an <Tag>embed</Tag> element from the <Tag>components</Tag>
section and paste this code:
<ChatEmbedSettings
onUpdateSettings={(settings) => setInputValues({ ...settings })}
my={4}
/>
<ChatEmbedCode withStarterVariables={true} {...inputValues} my={4} />
</ListItem>
</OrderedList>
)
}

View File

@ -1,5 +1,11 @@
import { ListItem, OrderedList, Tag } from '@chakra-ui/react'
import { ChatEmbedCode } from 'components/share/codeSnippets/Chat/EmbedCode'
import { ChatEmbedSettings } from 'components/share/codeSnippets/Chat/EmbedSettings'
import { ContainerEmbedCode } from 'components/share/codeSnippets/Container/EmbedCode'
import { PopupEmbedCode } from 'components/share/codeSnippets/Popup/EmbedCode'
import { PopupEmbedSettings } from 'components/share/codeSnippets/Popup/EmbedSettings'
import { useState } from 'react'
import { BubbleParams } from 'typebot-js'
type WixInstructionsProps = {
type: 'standard' | 'popup' | 'bubble'
@ -21,24 +27,23 @@ export const WixInstructions = ({ type }: WixInstructionsProps) => {
const StandardInstructions = () => {
return (
<>
<OrderedList spacing={2} mb={4}>
<ListItem>
In the Wix Website Editor:
<Tag>
Add {'>'} Embed {'>'} Embed a Widget
</Tag>
</ListItem>
<ListItem>
Click on <Tag>Enter code</Tag> and paste this code:
</ListItem>
</OrderedList>
</>
<OrderedList spacing={2} mb={4}>
<ListItem>
In the Wix Website Editor:
<Tag>
Add {'>'} Embed {'>'} Embed a Widget
</Tag>
</ListItem>
<ListItem>
Click on <Tag>Enter code</Tag> and paste this code:
</ListItem>
<ContainerEmbedCode widthLabel="100%" heightLabel="100%" />
</OrderedList>
)
}
const PopupInstructions = () => {
// const [inputValue, setInputValue] = useState(0)
const [inputValue, setInputValue] = useState(0)
return (
<>
@ -52,45 +57,49 @@ const PopupInstructions = () => {
<ListItem>
Click <Tag>+ Add Custom Code</Tag> at the top right.
</ListItem>
<ListItem>Paste this snippet in the code box:</ListItem>
<ListItem>
Paste this snippet in the code box:
<PopupEmbedSettings
onUpdateSettings={(settings) => setInputValue(settings.delay ?? 0)}
my={4}
/>
<PopupEmbedCode delay={inputValue} />
</ListItem>
</OrderedList>
</>
)
}
const BubbleInstructions = () => {
// const [inputValues, setInputValues] = useState<
// Pick<BubbleParams, 'proactiveMessage' | 'button'>
// >({
// proactiveMessage: undefined,
// button: {
// color: '',
// iconUrl: '',
// },
// })
const [inputValues, setInputValues] = useState<
Pick<BubbleParams, 'proactiveMessage' | 'button'>
>({
proactiveMessage: undefined,
button: {
color: '',
iconUrl: '',
},
})
return (
<>
<OrderedList spacing={2} mb={4}>
<ListItem>
Go to <Tag>Settings</Tag> in your dashboard on Wix
</ListItem>
<ListItem>
Click on <Tag>Custom Code</Tag> under <Tag>Advanced</Tag>
</ListItem>
<ListItem>
Click <Tag>+ Add Custom Code</Tag> at the top right.
</ListItem>
<ListItem>Paste this snippet in the code box:</ListItem>
</OrderedList>
{/* <ChatEmbedSettings
onUpdateSettings={(settings) => setInputValues({ ...settings })}
/>
<ChatEmbedCode
mt={4}
{...inputValues}
onCopied={() => sendWixCopyEvent('bubble')}
/> */}
</>
<OrderedList spacing={2} mb={4}>
<ListItem>
Go to <Tag>Settings</Tag> in your dashboard on Wix
</ListItem>
<ListItem>
Click on <Tag>Custom Code</Tag> under <Tag>Advanced</Tag>
</ListItem>
<ListItem>
Click <Tag>+ Add Custom Code</Tag> at the top right.
</ListItem>
<ListItem>
Paste this snippet in the code box:{' '}
<ChatEmbedSettings
my="4"
onUpdateSettings={(settings) => setInputValues({ ...settings })}
/>
<ChatEmbedCode {...inputValues} />
</ListItem>
</OrderedList>
)
}

View File

@ -2,11 +2,13 @@ import { Box, BoxProps } from '@chakra-ui/react'
import { EditorState, EditorView, basicSetup } from '@codemirror/basic-setup'
import { json } from '@codemirror/lang-json'
import { css } from '@codemirror/lang-css'
import { javascript } from '@codemirror/lang-javascript'
import { html } from '@codemirror/lang-html'
import { useEffect, useRef, useState } from 'react'
type Props = {
value: string
lang?: 'css' | 'json'
lang?: 'css' | 'json' | 'js' | 'html'
onChange?: (value: string) => void
isReadOnly?: boolean
}
@ -24,7 +26,11 @@ export const CodeEditor = ({
useEffect(() => {
if (!editorView.current || !isReadOnly) return
editorView.current.dispatch({
changes: { from: 0, insert: value },
changes: {
from: 0,
to: editorView.current.state.doc.length,
insert: value,
},
})
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [value])
@ -36,6 +42,14 @@ export const CodeEditor = ({
}, [plainTextValue])
useEffect(() => {
const editor = initEditor(value)
return () => {
editor?.destroy()
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
const initEditor = (value: string) => {
if (!editorContainer.current) return
const updateListenerExtension = EditorView.updateListener.of((update) => {
if (update.docChanged && onChange)
@ -48,6 +62,8 @@ export const CodeEditor = ({
]
if (lang === 'json') extensions.push(json())
if (lang === 'css') extensions.push(css())
if (lang === 'js') extensions.push(javascript())
if (lang === 'html') extensions.push(html())
const editor = new EditorView({
state: EditorState.create({
extensions,
@ -58,13 +74,8 @@ export const CodeEditor = ({
changes: { from: 0, insert: value },
})
editorView.current = editor
return () => {
editor.destroy()
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
return editor
}
return (
<Box ref={editorContainer} h="200px" data-testid="code-editor" {...props} />
)
return <Box ref={editorContainer} data-testid="code-editor" {...props} />
}

View File

@ -15,6 +15,8 @@
"@chakra-ui/react": "^1.8.1",
"@codemirror/basic-setup": "^0.19.1",
"@codemirror/lang-css": "^0.19.3",
"@codemirror/lang-html": "^0.19.4",
"@codemirror/lang-javascript": "^0.19.7",
"@codemirror/lang-json": "^0.19.1",
"@codemirror/text": "^0.19.6",
"@emotion/react": "^11.7.1",
@ -69,7 +71,8 @@
"swr": "^1.2.0",
"use-debounce": "^7.0.1",
"use-immer": "^0.6.0",
"utils": "*"
"utils": "*",
"typebot-js": "2.0.21"
},
"devDependencies": {
"@playwright/test": "^1.18.1",
@ -79,6 +82,7 @@
"@types/node": "^16.11.9",
"@types/nprogress": "^0.2.0",
"@types/papaparse": "^5.3.1",
"@types/prettier": "^2.4.4",
"@types/qs": "^6.9.7",
"@types/react": "^17.0.38",
"@types/react-table": "^7.7.9",

View File

@ -1,5 +1,4 @@
import { ItemBase, ItemType } from '.'
import { Item } from './item'
import { StepBase } from './steps'
export type InputStep =

View File

@ -1110,7 +1110,7 @@
"@codemirror/state" "^0.19.0"
"@codemirror/view" "^0.19.23"
"@codemirror/highlight@^0.19.0", "@codemirror/highlight@^0.19.6":
"@codemirror/highlight@^0.19.0", "@codemirror/highlight@^0.19.6", "@codemirror/highlight@^0.19.7":
version "0.19.7"
resolved "https://registry.yarnpkg.com/@codemirror/highlight/-/highlight-0.19.7.tgz#91a0c9994c759f5f153861e3aae74ff9e7c7c35b"
integrity sha512-3W32hBCY0pbbv/xidismw+RDMKuIag+fo4kZIbD7WoRj+Ttcaxjf+vP6RttRHXLaaqbWh031lTeON8kMlDhMYw==
@ -1130,7 +1130,7 @@
"@codemirror/state" "^0.19.2"
"@codemirror/view" "^0.19.0"
"@codemirror/lang-css@^0.19.3":
"@codemirror/lang-css@^0.19.0", "@codemirror/lang-css@^0.19.3":
version "0.19.3"
resolved "https://registry.yarnpkg.com/@codemirror/lang-css/-/lang-css-0.19.3.tgz#7a17adf78c6fcdab4ad5ee4e360631c41e949e4a"
integrity sha512-tyCUJR42/UlfOPLb94/p7dN+IPsYSIzHbAHP2KQHANj0I+Orqp+IyIOS++M8TuCX4zkWh9dvi8s92yy/Tn8Ifg==
@ -1141,6 +1141,33 @@
"@codemirror/state" "^0.19.0"
"@lezer/css" "^0.15.2"
"@codemirror/lang-html@^0.19.4":
version "0.19.4"
resolved "https://registry.yarnpkg.com/@codemirror/lang-html/-/lang-html-0.19.4.tgz#e6eec28462f18842a0e108732a214a7416b5e333"
integrity sha512-GpiEikNuCBeFnS+/TJSeanwqaOfNm8Kkp9WpVNEPZCLyW1mAMCuFJu/3xlWYeWc778Hc3vJqGn3bn+cLNubgCA==
dependencies:
"@codemirror/autocomplete" "^0.19.0"
"@codemirror/highlight" "^0.19.6"
"@codemirror/lang-css" "^0.19.0"
"@codemirror/lang-javascript" "^0.19.0"
"@codemirror/language" "^0.19.0"
"@codemirror/state" "^0.19.0"
"@lezer/common" "^0.15.0"
"@lezer/html" "^0.15.0"
"@codemirror/lang-javascript@^0.19.0", "@codemirror/lang-javascript@^0.19.7":
version "0.19.7"
resolved "https://registry.yarnpkg.com/@codemirror/lang-javascript/-/lang-javascript-0.19.7.tgz#84581ef6abf2a16d78f017ffc96c2d6227de5eb5"
integrity sha512-DL9f3JLqOEHH9cIwEqqjnP5bkjdVXeECksLtV+/MbPm+l4H+AG+PkwZaJQ2oR1GfPZKh8MVSIE94aGWNkJP8WQ==
dependencies:
"@codemirror/autocomplete" "^0.19.0"
"@codemirror/highlight" "^0.19.7"
"@codemirror/language" "^0.19.0"
"@codemirror/lint" "^0.19.0"
"@codemirror/state" "^0.19.0"
"@codemirror/view" "^0.19.0"
"@lezer/javascript" "^0.15.1"
"@codemirror/lang-json@^0.19.1":
version "0.19.1"
resolved "https://registry.yarnpkg.com/@codemirror/lang-json/-/lang-json-0.19.1.tgz#616588d1422529965243c10af6c44ad0b9134fb0"
@ -1633,6 +1660,20 @@
dependencies:
"@lezer/lr" "^0.15.0"
"@lezer/html@^0.15.0":
version "0.15.0"
resolved "https://registry.yarnpkg.com/@lezer/html/-/html-0.15.0.tgz#572c9444bc39c1afc0529a70e089abf7254edf5d"
integrity sha512-ErmgP/Vv0AhYJvs/Ekb9oue4IzBHemKLi7K8tJ0jgS+20Y8FGC9foK6knCXtEHqdPaxVGQH9PVp7gecLnzLd9Q==
dependencies:
"@lezer/lr" "^0.15.0"
"@lezer/javascript@^0.15.1":
version "0.15.3"
resolved "https://registry.yarnpkg.com/@lezer/javascript/-/javascript-0.15.3.tgz#833a4c5650bae07805b9af88de6706368844dc55"
integrity sha512-8jA2NpOfpWwSPZxRhd9BxK2ZPvGd7nLE3LFTJ5AbMhXAzMHeMjneV6GEVd7dAIee85dtap0jdb6bgOSO0+lfwA==
dependencies:
"@lezer/lr" "^0.15.0"
"@lezer/json@^0.15.0":
version "0.15.0"
resolved "https://registry.yarnpkg.com/@lezer/json/-/json-0.15.0.tgz#b96c1161eb8514e05f4eaaec95c68376e76e539f"
@ -2208,6 +2249,11 @@
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
"@types/prettier@^2.4.4":
version "2.4.4"
resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.4.4.tgz#5d9b63132df54d8909fce1c3f8ca260fdd693e17"
integrity sha512-ReVR2rLTV1kvtlWFyuot+d1pkpG2Fw/XKE3PDAdj57rbM97ttSp9JZ2UsP+2EHTylra9cUf6JA7tGwW1INzUrA==
"@types/prop-types@*":
version "15.7.4"
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11"
@ -8061,7 +8107,7 @@ type-fest@^0.21.3:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37"
integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==
typebot-js@^2.0.21:
typebot-js@2.0.21, typebot-js@^2.0.21:
version "2.0.21"
resolved "https://registry.yarnpkg.com/typebot-js/-/typebot-js-2.0.21.tgz#1211ef4ffbf8f69facf538721073ec17660283b9"
integrity sha512-7a0vODc1MLYe2u9TtaO7u0Sz9V9+3Tk+YeY2cXjDgWEhFWNcUPyBZOJZMB5EDir5/togTMTIYr/TCm6fyGRi2Q==