Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How would you manage existing files? #2

Open
fprl opened this issue Jan 29, 2025 · 8 comments
Open

How would you manage existing files? #2

fprl opened this issue Jan 29, 2025 · 8 comments

Comments

@fprl
Copy link

fprl commented Jan 29, 2025

Hi there, I'm testing the component and it works really well. I was wondering, how would you manage existing files? Let's say you have a grid of images that you display and you also have the dropzone to add more images.

@janglad
Copy link
Owner

janglad commented Jan 29, 2025

Good point, I should add a way to provide some default values. Will be on this, thanks for the feedback!

@jslno
Copy link

jslno commented Feb 10, 2025

Hey,
You could just add an init function to the reducer inside useDropzone

const [fileStatuses, dispatch] = useReducer(fileStatusReducer, [], () => {
    if (props.defaultFiles?.length && props.defaultFiles.length > 0) {
        return props.defaultFiles.map((defaultFile) => {
            const id = crypto.randomUUID()
            return {
                id,
                fileName: defaultFile.name,
                file: defaultFile,
                status: 'success',
                result: URL.createObjectURL(defaultFile) as TUploadRes,
                tries: 1
            } satisfies FileStatus<TUploadRes, TUploadError>
        })
    }
    return []
})

also add the type to UseDropzoneProps

defaultFiles?: File[]

@yazdanMhmmdi
Copy link

is there any way to set default files that fetched from API?

@jslno
Copy link

jslno commented Feb 16, 2025

is there any way to set default files that fetched from API?

I didn't test it but this should work:

const buf = Buffer.from('Hello World!') // buffer returned by the api
const blob = new Blob([buf])

const defaultFile = new File([blob], "filename")

@yazdanMhmmdi
Copy link

how pass it to useDropzone hook? defaultFiles is difined in useDropzone.
this is my code:

      let dropzone = useDropzone({
          defaultFiles:
            getMailInfoStore.mail == null
              ? []
              : getMailInfoStore?.mail?.attachments.map((e) => ({
                  id: e.attachmentNameWithoutExtention,
                  name: e.originalName,
                })),

    onRemoveFile: async (id) => {
      console.log(`to delete : ${id}`);
      await uploadStore.delete(token, id);
    },
    onDropFile: async (file, id, filename) => {
      // const duration = 2000; // Total duration in milliseconds
      // const interval = 100; // Update every 100 milliseconds
      // const totalSteps = duration / interval; // Total number of steps
      // const increment = Math.ceil(100 / totalSteps); // Amount to increment each step

      await uploadStore.upload(token, {
        attachment: file,
        id: id,
        originalName: filename,
      });

      return {
        status: "success",
        result: URL.createObjectURL(file),
      };
    },
    validation: {
      accept: {
        "image/*": [".png", ".jpg", ".jpeg"],
        "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
          [".docx"],
      },

      maxSize: 10 * 1024 * 1024,
      maxFiles: 10,
    },
  });

when mobx store change state and fetch data from API, defaultFiles is not detect changes.

@jslno
Copy link

jslno commented Feb 16, 2025

how pass it to useDropzone hook? defaultFiles is difined in useDropzone. this is my code:

      let dropzone = useDropzone({
          defaultFiles:
            getMailInfoStore.mail == null
              ? []
              : getMailInfoStore?.mail?.attachments.map((e) => ({
                  id: e.attachmentNameWithoutExtention,
                  name: e.originalName,
                })),

    onRemoveFile: async (id) => {
      console.log(`to delete : ${id}`);
      await uploadStore.delete(token, id);
    },
    onDropFile: async (file, id, filename) => {
      // const duration = 2000; // Total duration in milliseconds
      // const interval = 100; // Update every 100 milliseconds
      // const totalSteps = duration / interval; // Total number of steps
      // const increment = Math.ceil(100 / totalSteps); // Amount to increment each step

      await uploadStore.upload(token, {
        attachment: file,
        id: id,
        originalName: filename,
      });

      return {
        status: "success",
        result: URL.createObjectURL(file),
      };
    },
    validation: {
      accept: {
        "image/*": [".png", ".jpg", ".jpeg"],
        "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
          [".docx"],
      },

      maxSize: 10 * 1024 * 1024,
      maxFiles: 10,
    },
  });

when mobx store change state and fetch data from API, defaultFiles is not detect changes.

Maybe try to wrap getMailInfoStore?.mail?.attachments.map((e) => ({ id: e.attachmentNameWithoutExtention, name: e.originalName, })) in useMemo with the object stringified as JSON as dependency.

But i've never used mobx so i can't really help you with that.

@yazdanMhmmdi
Copy link

any asynchronous opration to set defaultFiles in useDropzone would be fine.

@yazdanMhmmdi
Copy link

i fixed it, now i can get data from mobx API calls, i edited reducer like @jslno mentioned:

  const [fileStatuses, dispatch] = useReducer(fileStatusReducer, [], () => {
    if (defaultFiles?.length && defaultFiles.length > 0) {
      return defaultFiles.map((defaultFile) => {
        const id = crypto.randomUUID();
        return {
          id: defaultFile.id,
          fileName: defaultFile.name,
          // file: defaultFile,
          status: "success",
          // result: URL.createObjectURL(defaultFile),
          tries: 1,
        };
      });
    }
    return [];
  });

and this is my code:

  function MyDropzone({ defaultFiles }) {
    let dropzone = useDropzone({
      defaultFiles: defaultFiles, // Pass the state as defaultFiles
      onRemoveFile: async (id) => {
        console.log(`to delete : ${id}`);
        await uploadStore.delete(token, id);
      },
      onDropFile: async (file, id, filename) => {
        await uploadStore.upload(token, {
          attachment: file,
          id: id,
          originalName: filename,
        });

        return {
          status: "success",
          result: URL.createObjectURL(file),
        };
      },
      validation: {
        accept: {
          "image/*": [".png", ".jpg", ".jpeg"],
          "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
            [".docx"],
        },

        maxSize: 10 * 1024 * 1024,
        maxFiles: 10,
      },
    });

    return (
      <Dropzone {...dropzone}>
        <DropZoneArea>
          <DropzoneTrigger className="flex flex-col items-center justify-center p-8 border-2 border-dashed rounded-md bg-secondary text-muted-foreground">
            <CloudUploadIcon className="size-12 mb-2" />
            <p className="text-lg font-semibold">
              فایل ها را بکشید یا اینجا ضربه بزنید
            </p>
            <p className="text-sm">Accepts images and documents</p>
          </DropzoneTrigger>
        </DropZoneArea>

        {dropzone?.fileStatuses?.length > 0 && (
          <DropzoneFileList className="mt-4 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 gap-4">
            {dropzone?.fileStatuses?.map((file) => (
              <DropzoneFileListItem
                key={file.id}
                file={file}
                className="rounded-md shadow-sm border border-gray-200"
              >
                <div className="p-2 flex items-center justify-between">
                  <span className="text-sm">{file.fileName}</span>
                  <DropzoneRemoveFile variant="ghost">
                    <Trash2Icon className="size-4" />
                  </DropzoneRemoveFile>
                </div>

                {/* Loading Bar */}
                {file.status === "pending" && (
                  <div className="relative w-full h-2 bg-gray-200 rounded">
                    <div
                      className={`absolute h-full bg-blue-500 rounded transition-all duration-300`}
                      style={{ width: `${uploadStore.progress}%` }} // Assuming 'progress' is a percentage value
                    />
                  </div>
                )}

                {/* Success Message */}
                {/* {file.status === "success" && (
              <div className="text-green-600 text-xs p-2">Upload successful!</div>
            )} */}
              </DropzoneFileListItem>
            ))}
          </DropzoneFileList>
        )}
      </Dropzone>
    );
  }

and this:

<MyDropzone defaultFiles={uploadStore?.attachments} />

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants