@@ -10,16 +10,17 @@ import {
|
||||
import React from 'react'
|
||||
import { EmojiOrImageIcon } from './EmojiOrImageIcon'
|
||||
import { ImageUploadContent } from './ImageUploadContent'
|
||||
import { FilePathUploadProps } from '@/features/upload/api/generateUploadUrl'
|
||||
|
||||
type Props = {
|
||||
uploadFilePath: string
|
||||
uploadFileProps: FilePathUploadProps
|
||||
icon?: string | null
|
||||
onChangeIcon: (icon: string) => void
|
||||
boxSize?: string
|
||||
}
|
||||
|
||||
export const EditableEmojiOrImageIcon = ({
|
||||
uploadFilePath,
|
||||
uploadFileProps,
|
||||
icon,
|
||||
onChangeIcon,
|
||||
boxSize,
|
||||
@@ -54,7 +55,7 @@ export const EditableEmojiOrImageIcon = ({
|
||||
</Tooltip>
|
||||
<PopoverContent p="2">
|
||||
<ImageUploadContent
|
||||
filePath={uploadFilePath}
|
||||
uploadFileProps={uploadFileProps}
|
||||
defaultUrl={icon ?? ''}
|
||||
onSubmit={onChangeIcon}
|
||||
excludedTabs={['giphy', 'unsplash']}
|
||||
|
||||
@@ -6,12 +6,12 @@ import { TextInput } from '../inputs/TextInput'
|
||||
import { EmojiSearchableList } from './emoji/EmojiSearchableList'
|
||||
import { UnsplashPicker } from './UnsplashPicker'
|
||||
import { IconPicker } from './IconPicker'
|
||||
import { FilePathUploadProps } from '@/features/upload/api/generateUploadUrl'
|
||||
|
||||
type Tabs = 'link' | 'upload' | 'giphy' | 'emoji' | 'unsplash' | 'icon'
|
||||
|
||||
type Props = {
|
||||
filePath: string | undefined
|
||||
includeFileName?: boolean
|
||||
uploadFileProps: FilePathUploadProps | undefined
|
||||
defaultUrl?: string
|
||||
imageSize?: 'small' | 'regular' | 'thumb'
|
||||
initialTab?: Tabs
|
||||
@@ -36,8 +36,7 @@ const defaultDisplayedTabs: Tabs[] = [
|
||||
]
|
||||
|
||||
export const ImageUploadContent = ({
|
||||
filePath,
|
||||
includeFileName,
|
||||
uploadFileProps,
|
||||
defaultUrl,
|
||||
onSubmit,
|
||||
imageSize = 'regular',
|
||||
@@ -123,8 +122,7 @@ export const ImageUploadContent = ({
|
||||
</HStack>
|
||||
|
||||
<BodyContent
|
||||
filePath={filePath}
|
||||
includeFileName={includeFileName}
|
||||
uploadFileProps={uploadFileProps}
|
||||
tab={currentTab}
|
||||
imageSize={imageSize}
|
||||
onSubmit={handleSubmit}
|
||||
@@ -135,15 +133,13 @@ export const ImageUploadContent = ({
|
||||
}
|
||||
|
||||
const BodyContent = ({
|
||||
includeFileName,
|
||||
filePath,
|
||||
uploadFileProps,
|
||||
tab,
|
||||
defaultUrl,
|
||||
imageSize,
|
||||
onSubmit,
|
||||
}: {
|
||||
includeFileName?: boolean
|
||||
filePath: string | undefined
|
||||
uploadFileProps?: FilePathUploadProps
|
||||
tab: Tabs
|
||||
defaultUrl?: string
|
||||
imageSize: 'small' | 'regular' | 'thumb'
|
||||
@@ -151,11 +147,10 @@ const BodyContent = ({
|
||||
}) => {
|
||||
switch (tab) {
|
||||
case 'upload': {
|
||||
if (!filePath) return null
|
||||
if (!uploadFileProps) return null
|
||||
return (
|
||||
<UploadFileContent
|
||||
filePath={filePath}
|
||||
includeFileName={includeFileName}
|
||||
uploadFileProps={uploadFileProps}
|
||||
onNewUrl={onSubmit}
|
||||
/>
|
||||
)
|
||||
@@ -176,16 +171,14 @@ const BodyContent = ({
|
||||
type ContentProps = { onNewUrl: (url: string) => void }
|
||||
|
||||
const UploadFileContent = ({
|
||||
filePath,
|
||||
includeFileName,
|
||||
uploadFileProps,
|
||||
onNewUrl,
|
||||
}: ContentProps & { filePath: string; includeFileName?: boolean }) => (
|
||||
}: ContentProps & { uploadFileProps: FilePathUploadProps }) => (
|
||||
<Flex justify="center" py="2">
|
||||
<UploadButton
|
||||
fileType="image"
|
||||
filePath={filePath}
|
||||
filePathProps={uploadFileProps}
|
||||
onFileUploaded={onNewUrl}
|
||||
includeFileName={includeFileName}
|
||||
colorScheme="blue"
|
||||
>
|
||||
Choose an image
|
||||
|
||||
@@ -1,25 +1,44 @@
|
||||
import { useToast } from '@/hooks/useToast'
|
||||
import { Button, ButtonProps, chakra } from '@chakra-ui/react'
|
||||
import { ChangeEvent, useState } from 'react'
|
||||
import { uploadFiles } from '@typebot.io/lib/s3/uploadFiles'
|
||||
import { FilePathUploadProps } from '@/features/upload/api/generateUploadUrl'
|
||||
import { trpc } from '@/lib/trpc'
|
||||
import { compressFile } from '@/helpers/compressFile'
|
||||
|
||||
type UploadButtonProps = {
|
||||
fileType: 'image' | 'audio'
|
||||
filePath: string
|
||||
includeFileName?: boolean
|
||||
filePathProps: FilePathUploadProps
|
||||
onFileUploaded: (url: string) => void
|
||||
} & ButtonProps
|
||||
|
||||
export const UploadButton = ({
|
||||
fileType,
|
||||
filePath,
|
||||
includeFileName,
|
||||
filePathProps,
|
||||
onFileUploaded,
|
||||
...props
|
||||
}: UploadButtonProps) => {
|
||||
const [isUploading, setIsUploading] = useState(false)
|
||||
const { showToast } = useToast()
|
||||
const [file, setFile] = useState<File>()
|
||||
|
||||
const { mutate } = trpc.generateUploadUrl.useMutation({
|
||||
onSettled: () => {
|
||||
setIsUploading(false)
|
||||
},
|
||||
onSuccess: async (data) => {
|
||||
const upload = await fetch(data.presignedUrl, {
|
||||
method: 'PUT',
|
||||
body: file,
|
||||
})
|
||||
|
||||
if (!upload.ok) {
|
||||
showToast({ description: 'Error while trying to upload the file.' })
|
||||
return
|
||||
}
|
||||
|
||||
onFileUploaded(data.fileUrl + '?v=' + Date.now())
|
||||
},
|
||||
})
|
||||
|
||||
const handleInputChange = async (e: ChangeEvent<HTMLInputElement>) => {
|
||||
if (!e.target?.files) return
|
||||
@@ -27,16 +46,11 @@ export const UploadButton = ({
|
||||
const file = e.target.files[0] as File | undefined
|
||||
if (!file)
|
||||
return showToast({ description: 'Could not read file.', status: 'error' })
|
||||
const urls = await uploadFiles({
|
||||
files: [
|
||||
{
|
||||
file: await compressFile(file),
|
||||
path: `public/${filePath}${includeFileName ? `/${file.name}` : ''}`,
|
||||
},
|
||||
],
|
||||
setFile(await compressFile(file))
|
||||
mutate({
|
||||
filePathProps,
|
||||
fileType: file.type,
|
||||
})
|
||||
if (urls.length && urls[0]) onFileUploaded(urls[0] + '?v=' + Date.now())
|
||||
setIsUploading(false)
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user