saas-js / saas-ui

The React component library for startups, built with Chakra UI.
https://saas-ui.dev
MIT License
1.23k stars 118 forks source link

FileUpload component: Clear button doesn't actually clear. #194

Closed dadsgone0 closed 5 months ago

dadsgone0 commented 5 months ago

Hello, i have found that in the FileUpload component, the clear button doesn't actually clear the file, even though it doesn't show the filename.

Here, you'll see that i have uploaded a file: image

But when I click clear, and click submit again, you'll see that it doesn't really clear, and still uploads the same file. image

Once you click clear, my API its fetching should be saying "No file provided", but its not because the clear function only clears the file from the component visually.

linear[bot] commented 5 months ago

SUI-386 FileUpload component: Clear button doesn't actually clear.

Pagebakers commented 5 months ago

Assuming you use the Forms example from the docs, I notice there's a mistake in the example.

onFilesChange={(files) => {
          if (files.acceptedFiles?.length) {
            onChange(files.acceptedFiles[0])
          }
}}

This only updates when there are files, but onChange should also be called with all files are removed.

Also misses a check on data.file and it throws an error when no file is selected.

Full working example:

import { Text, HStack } from '@chakra-ui/react'
import {
  FileUpload,
  FileUploadTrigger,
  FileUploadDropzone,
} from '@saas-ui/file-upload'
import { Form, FormLayout, createField } from '@saas-ui/forms'

const UploadField = createField(
  forwardRef((props, ref) => {
    const { onChange, ...rest } = props
    return (
      <FileUpload
        /* Remove `getRootNode` in your code, only required for this example */
        getRootNode={getRootNode}
        maxFileSize={1024 * 1024}
        accept="image/*"
        {...rest}
        onFilesChange={(files) => {
          onChange(files.acceptedFiles[0])
        }}
        maxFiles={1}
        inputRef={ref}
      >
        {({ files, deleteFile }) => (
          <FileUploadDropzone>
            <Text fontSize="sm">Drag your image here</Text>
            {!files?.length ? (
              <FileUploadTrigger as={Button}>Select files</FileUploadTrigger>
            ) : (
              <HStack>
                <Text fontSize="sm">{files[0].name}</Text>
                <Button
                  onClick={(e) => {
                    e.stopPropagation()
                    deleteFile(files[0])
                  }}
                >
                  Clear
                </Button>
              </HStack>
            )}
          </FileUploadDropzone>
        )}
      </FileUpload>
    )
  }),
  {
    isControlled: true,
  }
)

export default function FormField() {
  return (
    <Form
      onSubmit={async (data) => {
        const formData = new FormData()

        if (data.file) {
          formData.append('profilePicture', data.file)
          formData.append(
            'meta',
            JSON.stringify({
              filename: data.file.name,
              size: data.file.size,
              type: data.file.type,
            })
          )
          formData.append('name', data.name)
        }
        formData.append('name', data.name)

        return fetch('/api/user', {
          method: 'POST',
          body: formData,
        }).then((response) => {
          if (response.ok) {
            // Handle successful upload
          } else {
            // Handle error
          }
        })
      }}
    >
      {({ Field }) => (
        <FormLayout>
          <Field name="name" label="Your name" />
          <UploadField name="file" label="Profile picture" />
          <SubmitButton />
        </FormLayout>
      )}
    </Form>
  )
}