diff --git a/apps/builder/assets/icons.tsx b/apps/builder/assets/icons.tsx index 6cdf97e03..df5a15ce7 100644 --- a/apps/builder/assets/icons.tsx +++ b/apps/builder/assets/icons.tsx @@ -267,3 +267,16 @@ export const ExternalLinkIcon = (props: IconProps) => ( ) + +export const FilmIcon = (props: IconProps) => ( + + + + + + + + + + +) diff --git a/apps/builder/components/board/StepTypesList/StepIcon.tsx b/apps/builder/components/board/StepTypesList/StepIcon.tsx index b24a8c195..e72d59b4f 100644 --- a/apps/builder/components/board/StepTypesList/StepIcon.tsx +++ b/apps/builder/components/board/StepTypesList/StepIcon.tsx @@ -6,6 +6,7 @@ import { EditIcon, EmailIcon, ExternalLinkIcon, + FilmIcon, FilterIcon, FlagIcon, GlobeIcon, @@ -32,6 +33,8 @@ export const StepIcon = ({ type, ...props }: StepIconProps) => { return case BubbleStepType.IMAGE: return + case BubbleStepType.VIDEO: + return case InputStepType.TEXT: return case InputStepType.NUMBER: diff --git a/apps/builder/components/board/StepTypesList/StepTypeLabel.tsx b/apps/builder/components/board/StepTypesList/StepTypeLabel.tsx index b66953235..279e8467c 100644 --- a/apps/builder/components/board/StepTypesList/StepTypeLabel.tsx +++ b/apps/builder/components/board/StepTypesList/StepTypeLabel.tsx @@ -13,54 +13,43 @@ type Props = { type: StepType } export const StepTypeLabel = ({ type }: Props) => { switch (type) { case BubbleStepType.TEXT: - case InputStepType.TEXT: { + case InputStepType.TEXT: return Text - } case BubbleStepType.IMAGE: return Image - case InputStepType.NUMBER: { + case BubbleStepType.VIDEO: + return Video + case InputStepType.NUMBER: return Number - } - case InputStepType.EMAIL: { + case InputStepType.EMAIL: return Email - } - case InputStepType.URL: { + case InputStepType.URL: return Website - } - case InputStepType.DATE: { + case InputStepType.DATE: return Date - } - case InputStepType.PHONE: { + case InputStepType.PHONE: return Phone - } - case InputStepType.CHOICE: { + case InputStepType.CHOICE: return Button - } - case LogicStepType.SET_VARIABLE: { + case LogicStepType.SET_VARIABLE: return Set variable - } - case LogicStepType.CONDITION: { + case LogicStepType.CONDITION: return Condition - } - case LogicStepType.REDIRECT: { + case LogicStepType.REDIRECT: return Redirect - } - case IntegrationStepType.GOOGLE_SHEETS: { + case IntegrationStepType.GOOGLE_SHEETS: return ( Sheets ) - } - case IntegrationStepType.GOOGLE_ANALYTICS: { + case IntegrationStepType.GOOGLE_ANALYTICS: return ( Analytics ) - } - default: { + default: return <> - } } } diff --git a/apps/builder/components/board/graph/BlockNode/StepNode/ContentPopover/ContentPopover.tsx b/apps/builder/components/board/graph/BlockNode/StepNode/ContentPopover/ContentPopover.tsx index 59cb42cc2..daf1d068c 100644 --- a/apps/builder/components/board/graph/BlockNode/StepNode/ContentPopover/ContentPopover.tsx +++ b/apps/builder/components/board/graph/BlockNode/StepNode/ContentPopover/ContentPopover.tsx @@ -4,16 +4,17 @@ import { PopoverArrow, PopoverBody, } from '@chakra-ui/react' -import { ImagePopoverContent } from 'components/shared/ImageUploadContent' +import { ImageUploadContent } from 'components/shared/ImageUploadContent' import { useTypebot } from 'contexts/TypebotContext' import { BubbleStep, + BubbleStepContent, BubbleStepType, - ImageBubbleContent, ImageBubbleStep, TextBubbleStep, } from 'models' import { useRef } from 'react' +import { VideoUploadContent } from './VideoUploadContent' type Props = { step: Exclude @@ -25,7 +26,7 @@ export const ContentPopover = ({ step }: Props) => { return ( - + @@ -37,16 +38,24 @@ export const ContentPopover = ({ step }: Props) => { export const StepContent = ({ step }: Props) => { const { updateStep } = useTypebot() - const handleContentChange = (content: ImageBubbleContent) => + + const handleContentChange = (content: BubbleStepContent) => updateStep(step.id, { content } as Partial) - const handleNewImageSubmit = (url: string) => handleContentChange({ url }) switch (step.type) { case BubbleStepType.IMAGE: { return ( - + ) + } + case BubbleStepType.VIDEO: { + return ( + ) } diff --git a/apps/builder/components/board/graph/BlockNode/StepNode/ContentPopover/VideoUploadContent.tsx b/apps/builder/components/board/graph/BlockNode/StepNode/ContentPopover/VideoUploadContent.tsx new file mode 100644 index 000000000..814eef702 --- /dev/null +++ b/apps/builder/components/board/graph/BlockNode/StepNode/ContentPopover/VideoUploadContent.tsx @@ -0,0 +1,38 @@ +import { Stack, Text } from '@chakra-ui/react' +import { InputWithVariableButton } from 'components/shared/InputWithVariableButton' +import { VideoBubbleContent, VideoBubbleContentType } from 'models' +import urlParser from 'js-video-url-parser/lib/base' +import 'js-video-url-parser/lib/provider/vimeo' +import 'js-video-url-parser/lib/provider/youtube' +import { isDefined } from 'utils' + +type Props = { + content?: VideoBubbleContent + onSubmit: (content: VideoBubbleContent) => void +} + +export const VideoUploadContent = ({ content, onSubmit }: Props) => { + const handleUrlChange = (url: string) => { + const info = urlParser.parse(url) + return isDefined(info) && info.provider && info.id + ? onSubmit({ + type: info.provider as VideoBubbleContentType, + url, + id: info.id, + }) + : onSubmit({ type: VideoBubbleContentType.URL, url }) + } + return ( + + + + Works with Youtube, Vimeo and others + + + ) +} diff --git a/apps/builder/components/board/graph/BlockNode/StepNode/StepNodeContent.tsx b/apps/builder/components/board/graph/BlockNode/StepNode/StepNodeContent.tsx index fe49e3277..0739718f0 100644 --- a/apps/builder/components/board/graph/BlockNode/StepNode/StepNodeContent.tsx +++ b/apps/builder/components/board/graph/BlockNode/StepNode/StepNodeContent.tsx @@ -9,6 +9,8 @@ import { SetVariableStep, ConditionStep, IntegrationStepType, + VideoBubbleStep, + VideoBubbleContentType, } from 'models' import { ChoiceItemsList } from './ChoiceInputStepNode/ChoiceItemsList' import { SourceEndpoint } from './SourceEndpoint' @@ -48,6 +50,9 @@ export const StepNodeContent = ({ step }: Props) => { ) } + case BubbleStepType.VIDEO: { + return + } case InputStepType.TEXT: { return ( @@ -182,3 +187,52 @@ const ConditionNodeContent = ({ step }: { step: ConditionStep }) => { ) } + +const VideoStepNodeContent = ({ step }: { step: VideoBubbleStep }) => { + if (!step.content?.url || !step.content.type) + return Click to edit... + switch (step.content.type) { + case VideoBubbleContentType.URL: + return ( + + + + ) + case VideoBubbleContentType.VIMEO: + case VideoBubbleContentType.YOUTUBE: { + const baseUrl = + step.content.type === VideoBubbleContentType.VIMEO + ? 'https://player.vimeo.com/video' + : 'https://www.youtube.com/embed' + return ( + +