@ -52,7 +52,7 @@ export const MyAccountForm = () => {
|
||||
<Stack>
|
||||
<UploadButton
|
||||
size="sm"
|
||||
filePath={`public/users/${user?.id}/avatar`}
|
||||
filePath={`users/${user?.id}/avatar`}
|
||||
leftIcon={<UploadIcon />}
|
||||
onFileUploaded={handleFileUploaded}
|
||||
>
|
||||
|
@ -37,11 +37,14 @@ export const WorkspaceSettingsForm = ({ onClose }: { onClose: () => void }) => {
|
||||
<FormControl>
|
||||
<FormLabel>Icon</FormLabel>
|
||||
<Flex>
|
||||
{workspace && (
|
||||
<EditableEmojiOrImageIcon
|
||||
icon={workspace?.icon}
|
||||
uploadFilePath={`workspaces/${workspace.id}/icon`}
|
||||
icon={workspace.icon}
|
||||
onChangeIcon={handleChangeIcon}
|
||||
boxSize="40px"
|
||||
/>
|
||||
)}
|
||||
</Flex>
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
|
@ -16,12 +16,14 @@ import { CodeEditor } from 'components/shared/CodeEditor'
|
||||
import { MoreInfoTooltip } from 'components/shared/MoreInfoTooltip'
|
||||
|
||||
type Props = {
|
||||
typebotId: string
|
||||
typebotName: string
|
||||
metadata: Metadata
|
||||
onMetadataChange: (metadata: Metadata) => void
|
||||
}
|
||||
|
||||
export const MetadataForm = ({
|
||||
typebotId,
|
||||
typebotName,
|
||||
metadata,
|
||||
onMetadataChange,
|
||||
@ -57,7 +59,8 @@ export const MetadataForm = ({
|
||||
</PopoverTrigger>
|
||||
<PopoverContent p="4">
|
||||
<ImageUploadContent
|
||||
url={metadata.favIconUrl ?? ''}
|
||||
filePath={`typebots/${typebotId}/favIcon`}
|
||||
defaultUrl={metadata.favIconUrl ?? ''}
|
||||
onSubmit={handleFavIconSubmit}
|
||||
isGiphyEnabled={false}
|
||||
/>
|
||||
@ -81,7 +84,8 @@ export const MetadataForm = ({
|
||||
</PopoverTrigger>
|
||||
<PopoverContent p="4">
|
||||
<ImageUploadContent
|
||||
url={metadata.imageUrl}
|
||||
filePath={`typebots/${typebotId}/ogImage`}
|
||||
defaultUrl={metadata.imageUrl}
|
||||
onSubmit={handleImageSubmit}
|
||||
isGiphyEnabled={false}
|
||||
/>
|
||||
|
@ -90,6 +90,7 @@ export const SettingsSideMenu = () => {
|
||||
<AccordionPanel pb={4} px="6">
|
||||
{typebot && (
|
||||
<MetadataForm
|
||||
typebotId={typebot.id}
|
||||
typebotName={typebot.name}
|
||||
metadata={typebot.settings.metadata}
|
||||
onMetadataChange={handleMetadataChange}
|
||||
|
@ -11,12 +11,14 @@ import { EmojiOrImageIcon } from './EmojiOrImageIcon'
|
||||
import { ImageUploadContent } from './ImageUploadContent'
|
||||
|
||||
type Props = {
|
||||
uploadFilePath: string
|
||||
icon?: string | null
|
||||
onChangeIcon: (icon: string) => void
|
||||
boxSize?: string
|
||||
}
|
||||
|
||||
export const EditableEmojiOrImageIcon = ({
|
||||
uploadFilePath,
|
||||
icon,
|
||||
onChangeIcon,
|
||||
boxSize,
|
||||
@ -47,7 +49,8 @@ export const EditableEmojiOrImageIcon = ({
|
||||
</Tooltip>
|
||||
<PopoverContent p="2">
|
||||
<ImageUploadContent
|
||||
url={icon ?? ''}
|
||||
filePath={uploadFilePath}
|
||||
defaultUrl={icon ?? ''}
|
||||
onSubmit={onChangeIcon}
|
||||
isGiphyEnabled={false}
|
||||
isEmojiEnabled={true}
|
||||
|
@ -55,7 +55,7 @@ export const BlockNode = ({
|
||||
setFocusedGroupId,
|
||||
previewingEdge,
|
||||
} = useGraph()
|
||||
const { updateBlock } = useTypebot()
|
||||
const { typebot, updateBlock } = useTypebot()
|
||||
const [isConnecting, setIsConnecting] = useState(false)
|
||||
const [isPopoverOpened, setIsPopoverOpened] = useState(
|
||||
openedBlockId === block.id
|
||||
@ -227,8 +227,9 @@ export const BlockNode = ({
|
||||
</SettingsModal>
|
||||
</>
|
||||
)}
|
||||
{isMediaBubbleBlock(block) && (
|
||||
{typebot && isMediaBubbleBlock(block) && (
|
||||
<MediaBubblePopoverContent
|
||||
typebotId={typebot.id}
|
||||
block={block}
|
||||
onContentChange={handleContentChange}
|
||||
/>
|
||||
|
@ -16,6 +16,7 @@ import { EmbedUploadContent } from './EmbedUploadContent'
|
||||
import { VideoUploadContent } from './VideoUploadContent'
|
||||
|
||||
type Props = {
|
||||
typebotId: string
|
||||
block: Exclude<BubbleBlock, TextBubbleBlock>
|
||||
onContentChange: (content: BubbleBlockContent) => void
|
||||
}
|
||||
@ -39,14 +40,19 @@ export const MediaBubblePopoverContent = (props: Props) => {
|
||||
)
|
||||
}
|
||||
|
||||
export const MediaBubbleContent = ({ block, onContentChange }: Props) => {
|
||||
export const MediaBubbleContent = ({
|
||||
typebotId,
|
||||
block,
|
||||
onContentChange,
|
||||
}: Props) => {
|
||||
const handleImageUrlChange = (url: string) => onContentChange({ url })
|
||||
|
||||
switch (block.type) {
|
||||
case BubbleBlockType.IMAGE: {
|
||||
return (
|
||||
<ImageUploadContent
|
||||
url={block.content?.url}
|
||||
filePath={`typebots/${typebotId}/blocks/${block.id}`}
|
||||
defaultUrl={block.content?.url}
|
||||
onSubmit={handleImageUrlChange}
|
||||
/>
|
||||
)
|
||||
|
@ -2,12 +2,13 @@ import { useState } from 'react'
|
||||
import { Button, Flex, HStack, Stack } from '@chakra-ui/react'
|
||||
import { UploadButton } from '../buttons/UploadButton'
|
||||
import { GiphySearchForm } from './GiphySearchForm'
|
||||
import { useTypebot } from 'contexts/TypebotContext'
|
||||
import { Input } from '../Textbox/Input'
|
||||
import { EmojiSearchableList } from './emoji/EmojiSearchableList'
|
||||
|
||||
type Props = {
|
||||
url?: string
|
||||
filePath: string
|
||||
includeFileName?: boolean
|
||||
defaultUrl?: string
|
||||
isEmojiEnabled?: boolean
|
||||
isGiphyEnabled?: boolean
|
||||
onSubmit: (url: string) => void
|
||||
@ -15,7 +16,9 @@ type Props = {
|
||||
}
|
||||
|
||||
export const ImageUploadContent = ({
|
||||
url,
|
||||
filePath,
|
||||
includeFileName,
|
||||
defaultUrl,
|
||||
onSubmit,
|
||||
isEmojiEnabled = false,
|
||||
isGiphyEnabled = true,
|
||||
@ -67,25 +70,41 @@ export const ImageUploadContent = ({
|
||||
)}
|
||||
</HStack>
|
||||
|
||||
<BodyContent tab={currentTab} onSubmit={handleSubmit} url={url} />
|
||||
<BodyContent
|
||||
filePath={filePath}
|
||||
includeFileName={includeFileName}
|
||||
tab={currentTab}
|
||||
onSubmit={handleSubmit}
|
||||
defaultUrl={defaultUrl}
|
||||
/>
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
|
||||
const BodyContent = ({
|
||||
includeFileName,
|
||||
filePath,
|
||||
tab,
|
||||
url,
|
||||
defaultUrl,
|
||||
onSubmit,
|
||||
}: {
|
||||
includeFileName?: boolean
|
||||
filePath: string
|
||||
tab: 'upload' | 'link' | 'giphy' | 'emoji'
|
||||
url?: string
|
||||
defaultUrl?: string
|
||||
onSubmit: (url: string) => void
|
||||
}) => {
|
||||
switch (tab) {
|
||||
case 'upload':
|
||||
return <UploadFileContent onNewUrl={onSubmit} />
|
||||
return (
|
||||
<UploadFileContent
|
||||
filePath={filePath}
|
||||
includeFileName={includeFileName}
|
||||
onNewUrl={onSubmit}
|
||||
/>
|
||||
)
|
||||
case 'link':
|
||||
return <EmbedLinkContent initialUrl={url} onNewUrl={onSubmit} />
|
||||
return <EmbedLinkContent defaultUrl={defaultUrl} onNewUrl={onSubmit} />
|
||||
case 'giphy':
|
||||
return <GiphyContent onNewUrl={onSubmit} />
|
||||
case 'emoji':
|
||||
@ -93,30 +112,34 @@ const BodyContent = ({
|
||||
}
|
||||
}
|
||||
|
||||
type ContentProps = { initialUrl?: string; onNewUrl: (url: string) => void }
|
||||
type ContentProps = { onNewUrl: (url: string) => void }
|
||||
|
||||
const UploadFileContent = ({ onNewUrl }: ContentProps) => {
|
||||
const { typebot } = useTypebot()
|
||||
return (
|
||||
const UploadFileContent = ({
|
||||
filePath,
|
||||
includeFileName,
|
||||
onNewUrl,
|
||||
}: ContentProps & { filePath: string; includeFileName?: boolean }) => (
|
||||
<Flex justify="center" py="2">
|
||||
<UploadButton
|
||||
filePath={`public/typebots/${typebot?.id}`}
|
||||
filePath={filePath}
|
||||
onFileUploaded={onNewUrl}
|
||||
includeFileName
|
||||
includeFileName={includeFileName}
|
||||
colorScheme="blue"
|
||||
>
|
||||
Choose an image
|
||||
</UploadButton>
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
const EmbedLinkContent = ({ initialUrl, onNewUrl }: ContentProps) => (
|
||||
const EmbedLinkContent = ({
|
||||
defaultUrl,
|
||||
onNewUrl,
|
||||
}: ContentProps & { defaultUrl?: string }) => (
|
||||
<Stack py="2">
|
||||
<Input
|
||||
placeholder={'Paste the image link...'}
|
||||
onChange={onNewUrl}
|
||||
defaultValue={initialUrl ?? ''}
|
||||
defaultValue={defaultUrl ?? ''}
|
||||
/>
|
||||
</Stack>
|
||||
)
|
||||
|
@ -140,10 +140,13 @@ export const TypebotHeader = () => {
|
||||
size="sm"
|
||||
/>
|
||||
<HStack spacing={1}>
|
||||
{typebot && (
|
||||
<EditableEmojiOrImageIcon
|
||||
uploadFilePath={`typebots/${typebot.id}/icon`}
|
||||
icon={typebot?.icon}
|
||||
onChangeIcon={handleChangeIcon}
|
||||
/>
|
||||
)}
|
||||
{typebot?.name && (
|
||||
<EditableTypebotName
|
||||
name={typebot?.name}
|
||||
|
@ -25,7 +25,7 @@ export const UploadButton = ({
|
||||
files: [
|
||||
{
|
||||
file: await compressFile(file),
|
||||
path: filePath + (includeFileName ? `/${file.name}` : ''),
|
||||
path: `public/${filePath}${includeFileName ? `/${file.name}` : ''}`,
|
||||
},
|
||||
],
|
||||
})
|
||||
|
@ -17,6 +17,7 @@ import { ImageUploadContent } from 'components/shared/ImageUploadContent'
|
||||
import { DefaultAvatar } from 'assets/DefaultAvatar'
|
||||
|
||||
type Props = {
|
||||
uploadFilePath: string
|
||||
title: string
|
||||
avatarProps?: AvatarProps
|
||||
isDefaultCheck?: boolean
|
||||
@ -24,6 +25,7 @@ type Props = {
|
||||
}
|
||||
|
||||
export const AvatarForm = ({
|
||||
uploadFilePath,
|
||||
title,
|
||||
avatarProps,
|
||||
isDefaultCheck = false,
|
||||
@ -71,7 +73,8 @@ export const AvatarForm = ({
|
||||
<Portal>
|
||||
<PopoverContent p="4">
|
||||
<ImageUploadContent
|
||||
url={avatarProps?.url}
|
||||
filePath={uploadFilePath}
|
||||
defaultUrl={avatarProps?.url}
|
||||
onSubmit={handleImageUrl}
|
||||
/>
|
||||
</PopoverContent>
|
||||
|
@ -8,11 +8,16 @@ import { HostBubbles } from './HostBubbles'
|
||||
import { InputsTheme } from './InputsTheme'
|
||||
|
||||
type Props = {
|
||||
typebotId: string
|
||||
chatTheme: ChatTheme
|
||||
onChatThemeChange: (chatTheme: ChatTheme) => void
|
||||
}
|
||||
|
||||
export const ChatThemeSettings = ({ chatTheme, onChatThemeChange }: Props) => {
|
||||
export const ChatThemeSettings = ({
|
||||
typebotId,
|
||||
chatTheme,
|
||||
onChatThemeChange,
|
||||
}: Props) => {
|
||||
const handleHostBubblesChange = (hostBubbles: ContainerColors) =>
|
||||
onChatThemeChange({ ...chatTheme, hostBubbles })
|
||||
const handleGuestBubblesChange = (guestBubbles: ContainerColors) =>
|
||||
@ -30,12 +35,14 @@ export const ChatThemeSettings = ({ chatTheme, onChatThemeChange }: Props) => {
|
||||
return (
|
||||
<Stack spacing={6}>
|
||||
<AvatarForm
|
||||
uploadFilePath={`typebots/${typebotId}/hostAvatar`}
|
||||
title="Bot avatar"
|
||||
avatarProps={chatTheme.hostAvatar}
|
||||
isDefaultCheck
|
||||
onAvatarChange={handleHostAvatarChange}
|
||||
/>
|
||||
<AvatarForm
|
||||
uploadFilePath={`typebots/${typebotId}/guestAvatar`}
|
||||
title="User avatar"
|
||||
avatarProps={chatTheme.guestAvatar}
|
||||
onAvatarChange={handleGuestAvatarChange}
|
||||
|
@ -72,6 +72,7 @@ export const ThemeSideMenu = () => {
|
||||
<AccordionPanel pb={4}>
|
||||
{typebot && (
|
||||
<ChatThemeSettings
|
||||
typebotId={typebot.id}
|
||||
chatTheme={typebot.theme.chat}
|
||||
onChatThemeChange={handleChatThemeChange}
|
||||
/>
|
||||
|
@ -21,7 +21,9 @@ test('should display user info properly', async ({ page }) => {
|
||||
await expect(page.locator('img >> nth=1')).toHaveAttribute(
|
||||
'src',
|
||||
new RegExp(
|
||||
`${process.env.S3_ENDPOINT}/${process.env.S3_BUCKET}/public/users/${userId}/avatar`,
|
||||
`${process.env.S3_ENDPOINT}${
|
||||
process.env.S3_PORT ? `:${process.env.S3_PORT}` : ''
|
||||
}/${process.env.S3_BUCKET}/public/users/${userId}/avatar`,
|
||||
'gm'
|
||||
)
|
||||
)
|
||||
|
@ -32,10 +32,11 @@ test.describe.parallel('Image bubble block', () => {
|
||||
)
|
||||
await expect(page.locator('img')).toHaveAttribute(
|
||||
'src',
|
||||
new RegExp(
|
||||
`${process.env.S3_ENDPOINT}/${process.env.S3_BUCKET}/public/typebots/${typebotId}/avatar.jpg`,
|
||||
'gm'
|
||||
)
|
||||
`${process.env.S3_SSL === 'false' ? 'http://' : 'https://'}${
|
||||
process.env.S3_ENDPOINT
|
||||
}${process.env.S3_PORT ? `:${process.env.S3_PORT}` : ''}/${
|
||||
process.env.S3_BUCKET
|
||||
}/public/typebots/${typebotId}/blocks/block1`
|
||||
)
|
||||
})
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
"apps/*"
|
||||
],
|
||||
"scripts": {
|
||||
"docker:up": "docker compose -f docker-compose.dev.yml up -d",
|
||||
"docker:up": "docker compose -f docker-compose.dev.yml up -d && sleep 5",
|
||||
"docker:nuke": "docker compose -f docker-compose.dev.yml down --volumes --remove-orphans",
|
||||
"dev": "pnpm docker:up && NEXT_PUBLIC_E2E_TEST=false turbo run dev --filter=builder... --filter=viewer... --parallel --no-cache",
|
||||
"dev:mocking": "pnpm docker:up && NEXT_PUBLIC_E2E_TEST=true turbo run dev --filter=builder... --filter=viewer... --parallel --no-cache",
|
||||
|
Reference in New Issue
Block a user