⚡ Improve old engine bubbles display robustness
This commit is contained in:
@ -63,6 +63,7 @@ export const BlockNode = ({
|
|||||||
setOpenedBlockId,
|
setOpenedBlockId,
|
||||||
setFocusedGroupId,
|
setFocusedGroupId,
|
||||||
previewingEdge,
|
previewingEdge,
|
||||||
|
isReadOnly,
|
||||||
} = useGraph()
|
} = useGraph()
|
||||||
const { mouseOverBlock, setMouseOverBlock } = useBlockDnd()
|
const { mouseOverBlock, setMouseOverBlock } = useBlockDnd()
|
||||||
const { typebot, updateBlock } = useTypebot()
|
const { typebot, updateBlock } = useTypebot()
|
||||||
@ -111,6 +112,7 @@ export const BlockNode = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleMouseEnter = () => {
|
const handleMouseEnter = () => {
|
||||||
|
if (isReadOnly) return
|
||||||
if (mouseOverBlock?.id !== block.id)
|
if (mouseOverBlock?.id !== block.id)
|
||||||
setMouseOverBlock({ id: block.id, ref: blockRef })
|
setMouseOverBlock({ id: block.id, ref: blockRef })
|
||||||
if (connectingIds)
|
if (connectingIds)
|
||||||
|
@ -4,7 +4,6 @@ import { ImageBubble } from '@/features/blocks/bubbles/image'
|
|||||||
import { TextBubble } from '@/features/blocks/bubbles/textBubble'
|
import { TextBubble } from '@/features/blocks/bubbles/textBubble'
|
||||||
import { VideoBubble } from '@/features/blocks/bubbles/video'
|
import { VideoBubble } from '@/features/blocks/bubbles/video'
|
||||||
import { BubbleBlock, BubbleBlockType } from 'models'
|
import { BubbleBlock, BubbleBlockType } from 'models'
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
block: BubbleBlock
|
block: BubbleBlock
|
||||||
|
@ -307,7 +307,7 @@ const ChatChunks = ({
|
|||||||
unmountOnExit
|
unmountOnExit
|
||||||
in={isDefined(input)}
|
in={isDefined(input)}
|
||||||
>
|
>
|
||||||
{input && (
|
{input ? (
|
||||||
<InputChatBlock
|
<InputChatBlock
|
||||||
block={input}
|
block={input}
|
||||||
onTransitionEnd={onDisplayNextBlock}
|
onTransitionEnd={onDisplayNextBlock}
|
||||||
@ -315,6 +315,8 @@ const ChatChunks = ({
|
|||||||
hasAvatar={hostAvatar.isEnabled}
|
hasAvatar={hostAvatar.isEnabled}
|
||||||
hasGuestAvatar={hasGuestAvatar}
|
hasGuestAvatar={hasGuestAvatar}
|
||||||
/>
|
/>
|
||||||
|
) : (
|
||||||
|
<div />
|
||||||
)}
|
)}
|
||||||
</CSSTransition>
|
</CSSTransition>
|
||||||
)}
|
)}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useMemo, useRef, useState } from 'react'
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||||
import { EmbedBubbleBlock } from 'models'
|
import { EmbedBubbleBlock } from 'models'
|
||||||
import { TypingBubble } from '../../../../../components/TypingBubble'
|
import { TypingBubble } from '../../../../../components/TypingBubble'
|
||||||
import { parseVariables } from '@/features/variables'
|
import { parseVariables } from '@/features/variables'
|
||||||
@ -21,25 +21,24 @@ export const EmbedBubble = ({ block, onTransitionEnd }: Props) => {
|
|||||||
[block.content?.url, typebot.variables]
|
[block.content?.url, typebot.variables]
|
||||||
)
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
const onTypingEnd = useCallback(() => {
|
||||||
if (!isTyping || isLoading) return
|
|
||||||
showContentAfterMediaLoad()
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [isLoading])
|
|
||||||
|
|
||||||
const showContentAfterMediaLoad = () => {
|
|
||||||
setTimeout(() => {
|
|
||||||
setIsTyping(false)
|
|
||||||
onTypingEnd()
|
|
||||||
}, 1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
const onTypingEnd = () => {
|
|
||||||
setIsTyping(false)
|
setIsTyping(false)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
onTransitionEnd()
|
onTransitionEnd()
|
||||||
}, showAnimationDuration)
|
}, showAnimationDuration)
|
||||||
|
}, [onTransitionEnd])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isTyping || isLoading) return
|
||||||
|
const timeout = setTimeout(() => {
|
||||||
|
setIsTyping(false)
|
||||||
|
onTypingEnd()
|
||||||
|
}, 1000)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
clearTimeout(timeout)
|
||||||
}
|
}
|
||||||
|
}, [isLoading, isTyping, onTypingEnd])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col w-full" ref={messageContainer}>
|
<div className="flex flex-col w-full" ref={messageContainer}>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useMemo, useRef, useState } from 'react'
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||||
import { useTypebot } from '@/providers/TypebotProvider'
|
import { useTypebot } from '@/providers/TypebotProvider'
|
||||||
import { ImageBubbleBlock } from 'models'
|
import { ImageBubbleBlock } from 'models'
|
||||||
import { TypingBubble } from '@/components/TypingBubble'
|
import { TypingBubble } from '@/components/TypingBubble'
|
||||||
@ -24,31 +24,37 @@ export const ImageBubble = ({ block, onTransitionEnd }: Props) => {
|
|||||||
[block.content?.url, typebot.variables]
|
[block.content?.url, typebot.variables]
|
||||||
)
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
const onTypingEnd = useCallback(() => {
|
||||||
if (!isTyping || isLoading) return
|
|
||||||
showContentAfterMediaLoad()
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [isLoading])
|
|
||||||
|
|
||||||
const showContentAfterMediaLoad = () => {
|
|
||||||
if (!image.current) return
|
|
||||||
const timeout = setTimeout(() => {
|
|
||||||
setIsTyping(false)
|
|
||||||
onTypingEnd()
|
|
||||||
}, mediaLoadingFallbackTimeout)
|
|
||||||
image.current.onload = () => {
|
|
||||||
clearTimeout(timeout)
|
|
||||||
setIsTyping(false)
|
|
||||||
onTypingEnd()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const onTypingEnd = () => {
|
|
||||||
setIsTyping(false)
|
setIsTyping(false)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
onTransitionEnd()
|
onTransitionEnd()
|
||||||
}, showAnimationDuration)
|
}, showAnimationDuration)
|
||||||
|
}, [onTransitionEnd])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isTyping || isLoading) return
|
||||||
|
|
||||||
|
const timeout = setTimeout(() => {
|
||||||
|
setIsTyping(false)
|
||||||
|
onTypingEnd()
|
||||||
|
}, mediaLoadingFallbackTimeout)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
clearTimeout(timeout)
|
||||||
}
|
}
|
||||||
|
}, [isLoading, isTyping, onTypingEnd])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const currentImage = image.current
|
||||||
|
if (!currentImage || isLoading || !isTyping) return
|
||||||
|
currentImage.onload = () => {
|
||||||
|
setIsTyping(false)
|
||||||
|
onTypingEnd()
|
||||||
|
}
|
||||||
|
return () => {
|
||||||
|
currentImage.onload = null
|
||||||
|
}
|
||||||
|
}, [isLoading, isTyping, onTypingEnd])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col" ref={messageContainer}>
|
<div className="flex flex-col" ref={messageContainer}>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useRef, useState } from 'react'
|
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||||
import { useTypebot } from '@/providers/TypebotProvider'
|
import { useTypebot } from '@/providers/TypebotProvider'
|
||||||
import { BubbleBlockType, TextBubbleBlock } from 'models'
|
import { BubbleBlockType, TextBubbleBlock } from 'models'
|
||||||
import { computeTypingDuration } from '../utils/computeTypingDuration'
|
import { computeTypingDuration } from '../utils/computeTypingDuration'
|
||||||
@ -27,24 +27,34 @@ export const TextBubble = ({ block, onTransitionEnd }: Props) => {
|
|||||||
parseVariables(typebot.variables)(block.content.html)
|
parseVariables(typebot.variables)(block.content.html)
|
||||||
)
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
const onTypingEnd = useCallback(() => {
|
||||||
if (!isTyping || isLoading) return
|
|
||||||
const typingTimeout = computeTypingDuration(
|
|
||||||
block.content.plainText,
|
|
||||||
typebot.settings?.typingEmulation ?? defaultTypingEmulation
|
|
||||||
)
|
|
||||||
setTimeout(() => {
|
|
||||||
onTypingEnd()
|
|
||||||
}, typingTimeout)
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [isLoading])
|
|
||||||
|
|
||||||
const onTypingEnd = () => {
|
|
||||||
setIsTyping(false)
|
setIsTyping(false)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
onTransitionEnd()
|
onTransitionEnd()
|
||||||
}, showAnimationDuration)
|
}, showAnimationDuration)
|
||||||
|
}, [onTransitionEnd])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isTyping || isLoading) return
|
||||||
|
|
||||||
|
const typingTimeout = computeTypingDuration(
|
||||||
|
block.content.plainText,
|
||||||
|
typebot.settings?.typingEmulation ?? defaultTypingEmulation
|
||||||
|
)
|
||||||
|
const timeout = setTimeout(() => {
|
||||||
|
onTypingEnd()
|
||||||
|
}, typingTimeout)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
clearTimeout(timeout)
|
||||||
}
|
}
|
||||||
|
}, [
|
||||||
|
block.content.plainText,
|
||||||
|
isLoading,
|
||||||
|
isTyping,
|
||||||
|
onTypingEnd,
|
||||||
|
typebot.settings?.typingEmulation,
|
||||||
|
])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col" ref={messageContainer}>
|
<div className="flex flex-col" ref={messageContainer}>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useMemo, useRef, useState } from 'react'
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||||
import { useTypebot } from '@/providers/TypebotProvider'
|
import { useTypebot } from '@/providers/TypebotProvider'
|
||||||
import {
|
import {
|
||||||
Variable,
|
Variable,
|
||||||
@ -23,25 +23,24 @@ export const VideoBubble = ({ block, onTransitionEnd }: Props) => {
|
|||||||
const messageContainer = useRef<HTMLDivElement | null>(null)
|
const messageContainer = useRef<HTMLDivElement | null>(null)
|
||||||
const [isTyping, setIsTyping] = useState(true)
|
const [isTyping, setIsTyping] = useState(true)
|
||||||
|
|
||||||
useEffect(() => {
|
const onTypingEnd = useCallback(() => {
|
||||||
if (!isTyping || isLoading) return
|
|
||||||
showContentAfterMediaLoad()
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [isLoading])
|
|
||||||
|
|
||||||
const showContentAfterMediaLoad = () => {
|
|
||||||
setTimeout(() => {
|
|
||||||
setIsTyping(false)
|
|
||||||
onTypingEnd()
|
|
||||||
}, 1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
const onTypingEnd = () => {
|
|
||||||
setIsTyping(false)
|
setIsTyping(false)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
onTransitionEnd()
|
onTransitionEnd()
|
||||||
}, showAnimationDuration)
|
}, showAnimationDuration)
|
||||||
|
}, [onTransitionEnd])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isTyping || isLoading) return
|
||||||
|
const timeout = setTimeout(() => {
|
||||||
|
setIsTyping(false)
|
||||||
|
onTypingEnd()
|
||||||
|
}, 1000)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
clearTimeout(timeout)
|
||||||
}
|
}
|
||||||
|
}, [isLoading, isTyping, onTypingEnd])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col" ref={messageContainer}>
|
<div className="flex flex-col" ref={messageContainer}>
|
||||||
|
Reference in New Issue
Block a user