2
0

🚸 (fileUpload) Add success labels cutomization

Closes #515
This commit is contained in:
Baptiste Arnaud
2024-02-05 14:11:04 +01:00
parent 27b95c1f0b
commit 9fc05cb150
8 changed files with 125 additions and 33 deletions

View File

@ -1,4 +1,12 @@
import { FormLabel, Stack } from '@chakra-ui/react'
import {
Accordion,
AccordionButton,
AccordionIcon,
AccordionItem,
AccordionPanel,
FormLabel,
Stack,
} from '@chakra-ui/react'
import { CodeEditor } from '@/components/inputs/CodeEditor'
import { FileInputBlock, Variable } from '@typebot.io/schemas'
import React from 'react'
@ -45,6 +53,24 @@ export const FileInputSettings = ({ options, onOptionsChange }: Props) => {
visibility: (typeof fileVisibilityOptions)[number]
) => onOptionsChange({ ...options, visibility })
const updateSingleFileSuccessLabel = (single: string) =>
onOptionsChange({
...options,
labels: {
...options?.labels,
success: { ...options?.labels?.success, single },
},
})
const updateMultipleFilesSuccessLabel = (multiple: string) =>
onOptionsChange({
...options,
labels: {
...options?.labels,
success: { ...options?.labels?.success, multiple },
},
})
return (
<Stack spacing={4}>
<SwitchWithLabel
@ -75,30 +101,66 @@ export const FileInputSettings = ({ options, onOptionsChange }: Props) => {
withVariableButton={false}
/>
</Stack>
<TextInput
label={t('blocks.inputs.settings.button.label')}
defaultValue={
options?.labels?.button ?? defaultFileInputOptions.labels.button
}
onChange={handleButtonLabelChange}
withVariableButton={false}
/>
<TextInput
label={t('blocks.inputs.file.settings.clear.label')}
defaultValue={
options?.labels?.clear ?? defaultFileInputOptions.labels.clear
}
onChange={updateClearButtonLabel}
withVariableButton={false}
/>
<TextInput
label={t('blocks.inputs.file.settings.skip.label')}
defaultValue={
options?.labels?.skip ?? defaultFileInputOptions.labels.skip
}
onChange={updateSkipButtonLabel}
withVariableButton={false}
/>
<Accordion allowToggle>
<AccordionItem>
<AccordionButton justifyContent="space-between">
Labels
<AccordionIcon />
</AccordionButton>
<AccordionPanel as={Stack} spacing={4}>
<TextInput
label={t('blocks.inputs.settings.button.label')}
defaultValue={
options?.labels?.button ?? defaultFileInputOptions.labels.button
}
onChange={handleButtonLabelChange}
withVariableButton={false}
/>
{options?.isMultipleAllowed && (
<TextInput
label={t('blocks.inputs.file.settings.clear.label')}
defaultValue={
options?.labels?.clear ?? defaultFileInputOptions.labels.clear
}
onChange={updateClearButtonLabel}
withVariableButton={false}
/>
)}
{!(options?.isRequired ?? defaultFileInputOptions.isRequired) && (
<TextInput
label={t('blocks.inputs.file.settings.skip.label')}
defaultValue={
options?.labels?.skip ?? defaultFileInputOptions.labels.skip
}
onChange={updateSkipButtonLabel}
withVariableButton={false}
/>
)}
<TextInput
label="Single file success"
defaultValue={
options?.labels?.success?.single ??
defaultFileInputOptions.labels.success.single
}
onChange={updateSingleFileSuccessLabel}
withVariableButton={false}
/>
{options?.isMultipleAllowed && (
<TextInput
label="Multi files success"
moreInfoTooltip="Include {total} to show the total number of files uploaded"
defaultValue={
options?.labels?.success?.multiple ??
defaultFileInputOptions.labels.success.multiple
}
onChange={updateMultipleFilesSuccessLabel}
withVariableButton={false}
/>
)}
</AccordionPanel>
</AccordionItem>
</Accordion>
<DropdownList
label="Visibility:"
moreInfoTooltip='This setting determines who can see the uploaded files. "Public" means that anyone who has the link can see the files. "Private" means that only a members of this workspace can see the files.'

View File

@ -2,4 +2,6 @@ const urlRegex =
/^(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]:[0-9]*\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]:[0-9]*\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})$/
export const validateUrl = (url: string) =>
url.startsWith('http://localhost') || urlRegex.test(url)
url.startsWith('http://localhost') ||
url.startsWith('http://fake-upload-url.com') ||
urlRegex.test(url)

View File

@ -1,6 +1,6 @@
{
"name": "@typebot.io/js",
"version": "0.2.39",
"version": "0.2.40",
"description": "Javascript library to display typebots on your website",
"type": "module",
"main": "dist/index.js",

View File

@ -51,7 +51,9 @@ export const FileUploadForm = (props: Props) => {
const startSingleFileUpload = async (file: File) => {
if (props.context.isPreview || !props.context.resultId)
return props.onSubmit({
label: `File uploaded`,
label:
props.block.options?.labels?.success?.single ??
defaultFileInputOptions.labels.success.single,
value: 'http://fake-upload-url.com',
})
setIsUploading(true)
@ -70,7 +72,9 @@ export const FileUploadForm = (props: Props) => {
setIsUploading(false)
if (urls.length)
return props.onSubmit({
label: `File uploaded`,
label:
props.block.options?.labels?.success?.single ??
defaultFileInputOptions.labels.success.single,
value: urls[0] ? encodeUrl(urls[0]) : '',
})
setErrorMessage('An error occured while uploading the file')
@ -79,7 +83,14 @@ export const FileUploadForm = (props: Props) => {
const resultId = props.context.resultId
if (props.context.isPreview || !resultId)
return props.onSubmit({
label: `${files.length} file${files.length > 1 ? 's' : ''} uploaded`,
label:
files.length > 1
? (
props.block.options?.labels?.success?.multiple ??
defaultFileInputOptions.labels.success.multiple
).replaceAll('{total}', files.length.toString())
: props.block.options?.labels?.success?.single ??
defaultFileInputOptions.labels.success.single,
value: files
.map((_, idx) => `http://fake-upload-url.com/${idx}`)
.join(', '),
@ -101,7 +112,14 @@ export const FileUploadForm = (props: Props) => {
if (urls.length !== files.length)
return setErrorMessage('An error occured while uploading the files')
props.onSubmit({
label: `${urls.length} file${urls.length > 1 ? 's' : ''} uploaded`,
label:
urls.length > 1
? (
props.block.options?.labels?.success?.multiple ??
defaultFileInputOptions.labels.success.multiple
).replaceAll('{total}', urls.length.toString())
: props.block.options?.labels?.success?.single ??
defaultFileInputOptions.labels.success.single,
value: urls.filter(isDefined).map(encodeUrl).join(', '),
})
}

View File

@ -1,6 +1,6 @@
{
"name": "@typebot.io/nextjs",
"version": "0.2.39",
"version": "0.2.40",
"description": "Convenient library to display typebots on your Next.js website",
"main": "dist/index.js",
"types": "dist/index.d.ts",

View File

@ -1,6 +1,6 @@
{
"name": "@typebot.io/react",
"version": "0.2.39",
"version": "0.2.40",
"description": "Convenient library to display typebots on your React app",
"main": "dist/index.js",
"types": "dist/index.d.ts",

View File

@ -12,6 +12,10 @@ export const defaultFileInputOptions = {
button: 'Upload',
clear: 'Clear',
skip: 'Skip',
success: {
single: 'File uploaded',
multiple: '{total} files uploaded',
},
},
} as const satisfies FileInputBlock['options']

View File

@ -13,6 +13,12 @@ const fileInputOptionsV5Schema = optionBaseSchema.merge(
button: z.string().optional(),
clear: z.string().optional(),
skip: z.string().optional(),
success: z
.object({
single: z.string().optional(),
multiple: z.string().optional(),
})
.optional(),
})
.optional(),
sizeLimit: z.number().optional(),