2
0

fix(engine): 🐛 Properly handle variable avatars

This commit is contained in:
Baptiste Arnaud
2022-02-25 18:19:01 +01:00
parent 74b3464474
commit d21b1722b5
9 changed files with 36 additions and 33 deletions

View File

@@ -34,6 +34,8 @@ export const AvatarForm = ({
onAvatarChange({ ...avatarProps, isEnabled: !isChecked }) onAvatarChange({ ...avatarProps, isEnabled: !isChecked })
const handleImageUrl = (url: string) => const handleImageUrl = (url: string) =>
onAvatarChange({ isEnabled: isChecked, url }) onAvatarChange({ isEnabled: isChecked, url })
const isDefaultAvatar = !avatarProps?.url || avatarProps.url.includes('{{')
return ( return (
<Stack borderWidth={1} rounded="md" p="4" spacing={4}> <Stack borderWidth={1} rounded="md" p="4" spacing={4}>
<Flex justifyContent="space-between"> <Flex justifyContent="space-between">
@@ -46,7 +48,14 @@ export const AvatarForm = ({
{isChecked && ( {isChecked && (
<Popover isLazy> <Popover isLazy>
<PopoverTrigger> <PopoverTrigger>
{avatarProps?.url ? ( {isDefaultAvatar ? (
<Box>
<DefaultAvatar
cursor="pointer"
_hover={{ filter: 'brightness(.9)' }}
/>
</Box>
) : (
<Image <Image
src={avatarProps.url} src={avatarProps.url}
alt="Website image" alt="Website image"
@@ -57,13 +66,6 @@ export const AvatarForm = ({
boxSize="40px" boxSize="40px"
objectFit="cover" objectFit="cover"
/> />
) : (
<Box>
<DefaultAvatar
cursor="pointer"
_hover={{ filter: 'brightness(.9)' }}
/>
</Box>
)} )}
</PopoverTrigger> </PopoverTrigger>
<Portal> <Portal>

View File

@@ -5,6 +5,7 @@ export const SendIcon = (props: React.SVGProps<SVGSVGElement>) => (
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512" viewBox="0 0 512 512"
width="19px" width="19px"
color="white"
{...props} {...props}
> >
<path d="M476.59 227.05l-.16-.07L49.35 49.84A23.56 23.56 0 0027.14 52 24.65 24.65 0 0016 72.59v113.29a24 24 0 0019.52 23.57l232.93 43.07a4 4 0 010 7.86L35.53 303.45A24 24 0 0016 327v113.31A23.57 23.57 0 0026.59 460a23.94 23.94 0 0013.22 4 24.55 24.55 0 009.52-1.93L476.4 285.94l.19-.09a32 32 0 000-58.8z" /> <path d="M476.59 227.05l-.16-.07L49.35 49.84A23.56 23.56 0 0027.14 52 24.65 24.65 0 0016 72.59v113.29a24 24 0 0019.52 23.57l232.93 43.07a4 4 0 010 7.86L35.53 303.45A24 24 0 0016 327v113.31A23.57 23.57 0 0026.59 460a23.94 23.94 0 0013.22 4 24.55 24.55 0 009.52-1.93L476.4 285.94l.19-.09a32 32 0 000-58.8z" />

View File

@@ -184,7 +184,7 @@ textarea {
} }
.typebot-button > .send-icon { .typebot-button > .send-icon {
fill: var(--typebot-button-active-color); fill: var(--typebot-button-color);
} }
.typebot-chat-view { .typebot-chat-view {

View File

@@ -7,7 +7,7 @@ import { useHostAvatars } from '../../contexts/HostAvatarsContext'
export const AvatarSideContainer = ({ export const AvatarSideContainer = ({
hostAvatarSrc, hostAvatarSrc,
}: { }: {
hostAvatarSrc: string hostAvatarSrc?: string
}) => { }) => {
const { lastBubblesTopOffset } = useHostAvatars() const { lastBubblesTopOffset } = useHostAvatars()
const { window, document } = useFrame() const { window, document } = useFrame()

View File

@@ -110,17 +110,18 @@ export const ChatBlock = ({
if (nextStep) setDisplayedSteps([...displayedSteps, nextStep]) if (nextStep) setDisplayedSteps([...displayedSteps, nextStep])
} }
const avatarSrc = typebot.theme.chat.hostAvatar?.url
return ( return (
<div className="flex"> <div className="flex w-full">
<HostAvatarsContext> <HostAvatarsContext>
{(typebot.theme.chat.hostAvatar?.isEnabled ?? true) && ( {(typebot.theme.chat.hostAvatar?.isEnabled ?? true) && (
<AvatarSideContainer <AvatarSideContainer
hostAvatarSrc={parseVariables(typebot.variables)( hostAvatarSrc={
typebot.theme.chat.hostAvatar?.url avatarSrc && parseVariables(typebot.variables)(avatarSrc)
)} }
/> />
)} )}
<div className="flex flex-col w-full"> <div className="flex flex-col w-full min-w-0">
<TransitionGroup> <TransitionGroup>
{displayedSteps {displayedSteps
.filter((step) => isInputStep(step) || isBubbleStep(step)) .filter((step) => isInputStep(step) || isBubbleStep(step))

View File

@@ -68,13 +68,12 @@ const InputChatStep = ({
} }
if (answer) { if (answer) {
const avatarUrl = typebot.theme.chat.guestAvatar?.url
return ( return (
<GuestBubble <GuestBubble
message={answer} message={answer}
showAvatar={typebot.theme.chat.guestAvatar?.isEnabled ?? false} showAvatar={typebot.theme.chat.guestAvatar?.isEnabled ?? false}
avatarSrc={parseVariables(typebot.variables)( avatarSrc={avatarUrl && parseVariables(typebot.variables)(avatarUrl)}
typebot.theme.chat.guestAvatar?.url
)}
/> />
) )
} }

View File

@@ -5,7 +5,7 @@ import { CSSTransition } from 'react-transition-group'
interface Props { interface Props {
message: string message: string
showAvatar: boolean showAvatar: boolean
avatarSrc: string avatarSrc?: string
} }
export const GuestBubble = ({ export const GuestBubble = ({
@@ -15,16 +15,14 @@ export const GuestBubble = ({
}: Props): JSX.Element => { }: Props): JSX.Element => {
return ( return (
<CSSTransition classNames="bubble" timeout={1000}> <CSSTransition classNames="bubble" timeout={1000}>
<div className="flex justify-end mb-2 items-center"> <div className="flex justify-end mb-2 items-end">
<div className="flex items-end w-11/12 lg:w-4/6 justify-end"> <span
<div className="px-4 py-2 rounded-lg mr-2 whitespace-pre-wrap max-w-full typebot-guest-bubble"
className="inline-flex px-4 py-2 rounded-lg mr-2 whitespace-pre-wrap max-w-full typebot-guest-bubble" data-testid="guest-bubble"
data-testid="guest-bubble" >
> {message}
{message} </span>
</div> {showAvatar && <Avatar avatarSrc={avatarSrc} />}
{showAvatar && <Avatar avatarSrc={avatarSrc} />}
</div>
</div> </div>
</CSSTransition> </CSSTransition>
) )

View File

@@ -61,7 +61,7 @@ export const TextBubble = ({ step, onTransitionEnd }: Props) => {
return ( return (
<div className="flex flex-col" ref={messageContainer}> <div className="flex flex-col" ref={messageContainer}>
<div className="flex mb-2 w-full lg:w-11/12 items-center"> <div className="flex mb-2 w-full items-center">
<div className={'flex relative z-10 items-start typebot-host-bubble'}> <div className={'flex relative z-10 items-start typebot-host-bubble'}>
<div <div
className="flex items-center absolute px-4 py-2 rounded-lg bubble-typing z-10 " className="flex items-center absolute px-4 py-2 rounded-lg bubble-typing z-10 "

View File

@@ -1,10 +1,12 @@
import React from 'react' import React from 'react'
import { isDefined } from 'utils'
import { DefaultAvatar } from './DefaultAvatar' import { DefaultAvatar } from './DefaultAvatar'
export const Avatar = ({ avatarSrc }: { avatarSrc: string }): JSX.Element => { export const Avatar = ({ avatarSrc }: { avatarSrc?: string }): JSX.Element => {
if (avatarSrc === '') return <></>
return ( return (
<div className="w-full h-full rounded-full text-2xl md:text-4xl text-center xs:w-10 xs:h-10"> <div className="w-full h-full rounded-full text-2xl md:text-4xl text-center xs:w-10 xs:h-10 flex-shrink-0">
{avatarSrc !== '' ? ( {isDefined(avatarSrc) ? (
<figure <figure
className={ className={
'flex justify-center items-center rounded-full text-white w-6 h-6 text-sm relative xs:w-full xs:h-full xs:text-xl' 'flex justify-center items-center rounded-full text-white w-6 h-6 text-sm relative xs:w-full xs:h-full xs:text-xl'