2022-01-20 17:45:25 +01:00
|
|
|
import React, { useEffect, useMemo, useRef, useState } from 'react'
|
|
|
|
import { useTypebot } from 'contexts/TypebotContext'
|
|
|
|
import {
|
|
|
|
Variable,
|
|
|
|
VideoBubbleContent,
|
|
|
|
VideoBubbleContentType,
|
2022-06-11 07:27:38 +02:00
|
|
|
VideoBubbleBlock,
|
2022-01-20 17:45:25 +01:00
|
|
|
} from 'models'
|
|
|
|
import { TypingContent } from './TypingContent'
|
|
|
|
import { parseVariables } from 'services/variable'
|
|
|
|
|
|
|
|
type Props = {
|
2022-06-11 07:27:38 +02:00
|
|
|
block: VideoBubbleBlock
|
2022-01-20 17:45:25 +01:00
|
|
|
onTransitionEnd: () => void
|
|
|
|
}
|
|
|
|
|
|
|
|
export const showAnimationDuration = 400
|
|
|
|
|
|
|
|
export const mediaLoadingFallbackTimeout = 5000
|
|
|
|
|
2022-06-11 07:27:38 +02:00
|
|
|
export const VideoBubble = ({ block, onTransitionEnd }: Props) => {
|
2022-01-20 17:45:25 +01:00
|
|
|
const { typebot } = useTypebot()
|
|
|
|
const messageContainer = useRef<HTMLDivElement | null>(null)
|
|
|
|
const [isTyping, setIsTyping] = useState(true)
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
showContentAfterMediaLoad()
|
2022-01-25 18:19:37 +01:00
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
2022-01-20 17:45:25 +01:00
|
|
|
}, [])
|
|
|
|
|
|
|
|
const showContentAfterMediaLoad = () => {
|
|
|
|
setTimeout(() => {
|
|
|
|
setIsTyping(false)
|
|
|
|
onTypingEnd()
|
|
|
|
}, 1000)
|
|
|
|
}
|
|
|
|
|
|
|
|
const onTypingEnd = () => {
|
|
|
|
setIsTyping(false)
|
|
|
|
setTimeout(() => {
|
|
|
|
onTransitionEnd()
|
|
|
|
}, showAnimationDuration)
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div className="flex flex-col" ref={messageContainer}>
|
|
|
|
<div className="flex mb-2 w-full lg:w-11/12 items-center">
|
|
|
|
<div className={'flex relative z-10 items-start typebot-host-bubble'}>
|
|
|
|
<div
|
|
|
|
className="flex items-center absolute px-4 py-2 rounded-lg bubble-typing z-10 "
|
|
|
|
style={{
|
|
|
|
width: isTyping ? '4rem' : '100%',
|
|
|
|
height: isTyping ? '2rem' : '100%',
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
{isTyping ? <TypingContent /> : <></>}
|
|
|
|
</div>
|
|
|
|
<VideoContent
|
2022-06-11 07:27:38 +02:00
|
|
|
content={block.content}
|
2022-01-20 17:45:25 +01:00
|
|
|
isTyping={isTyping}
|
|
|
|
variables={typebot.variables}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
const VideoContent = ({
|
|
|
|
content,
|
|
|
|
isTyping,
|
|
|
|
variables,
|
|
|
|
}: {
|
|
|
|
content?: VideoBubbleContent
|
|
|
|
isTyping: boolean
|
2022-02-04 19:00:08 +01:00
|
|
|
variables: Variable[]
|
2022-01-20 17:45:25 +01:00
|
|
|
}) => {
|
|
|
|
const url = useMemo(
|
2022-02-07 18:06:37 +01:00
|
|
|
() => parseVariables(variables)(content?.url),
|
2022-01-25 18:19:37 +01:00
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
2022-01-20 17:45:25 +01:00
|
|
|
[variables]
|
|
|
|
)
|
|
|
|
if (!content?.type) return <></>
|
|
|
|
switch (content.type) {
|
|
|
|
case VideoBubbleContentType.URL:
|
|
|
|
const isSafariBrowser = window.navigator.vendor.match(/apple/i)
|
|
|
|
return (
|
|
|
|
<video
|
|
|
|
controls
|
|
|
|
className={
|
|
|
|
'p-4 focus:outline-none w-full z-10 content-opacity rounded-md ' +
|
|
|
|
(isTyping ? 'opacity-0' : 'opacity-100')
|
|
|
|
}
|
|
|
|
style={{
|
|
|
|
height: isTyping ? '2rem' : 'auto',
|
|
|
|
maxHeight: isSafariBrowser ? '40vh' : '',
|
|
|
|
}}
|
|
|
|
autoPlay
|
|
|
|
>
|
|
|
|
<source src={url} type="video/mp4" />
|
|
|
|
Sorry, your browser doesn't support embedded videos.
|
|
|
|
</video>
|
|
|
|
)
|
|
|
|
case VideoBubbleContentType.VIMEO:
|
|
|
|
case VideoBubbleContentType.YOUTUBE: {
|
|
|
|
const baseUrl =
|
|
|
|
content.type === VideoBubbleContentType.VIMEO
|
|
|
|
? 'https://player.vimeo.com/video'
|
|
|
|
: 'https://www.youtube.com/embed'
|
|
|
|
return (
|
|
|
|
<iframe
|
|
|
|
src={`${baseUrl}/${content.id}`}
|
|
|
|
className={
|
|
|
|
'w-full p-4 content-opacity z-10 rounded-md ' +
|
|
|
|
(isTyping ? 'opacity-0' : 'opacity-100')
|
|
|
|
}
|
|
|
|
height={isTyping ? '2rem' : '200px'}
|
|
|
|
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
|
|
|
allowFullScreen
|
|
|
|
/>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|