put multiple files to one zip folder before downloading on client side reactJS

Viewed 7300

I have two functions here that takes an array of file keys, and passes it to a download function that will download each file individually from aws s3.

I would like to have all the files together in one zip folder and just download that one zip folder, so that all the files are together.

Questions:

1st How would I first set the directory to save the files to?

2nd How would I put all the files that are being downloaded in to one zip folder, then download the zip folder?

any help or insight is greatly appreciated.

current code

async function handleDownloadClick(event) {
         event.preventDefault();

      const imagesAsArray = [...imagesUploaded];

        for (let i = 0; i < imagesAsArray.length; i++) {                      

            await DownloadFile(imagesAsArray[i]);

        }
    }


    async function DownloadFile(fileToDownload) {

    const filename = `${fileToDownload.key}`;

   const result = await Storage.get(fileToDownload.key, {download: true})

        console.log(result)
        let mimeType = result.ContentType

        let fileName = fileToDownload.key.split(`${job.jobId},/`)

        console.log(fileToDownload.key)

        try {
          let blob = new Blob([result.Body], {type: mimeType})

          //downloading the file depends on the browser
          //IE handles it differently than chrome/webkit
          if (window.navigator && window.navigator.msSaveOrOpenBlob) {
            window.navigator.msSaveOrOpenBlob(blob, fileName)
          } else {
            let objectUrl = URL.createObjectURL(blob);
            let link = document.createElement('a')
            link.href = objectUrl
            link.setAttribute('download', fileName)
            document.body.appendChild(link)
            link.click()
            document.body.removeChild(link)
          }
        } catch (exc) {
          console.log("Save Blob method failed with the following exception.");
          console.log(exc);
        }

   }

Updated Code doing what I needed it to do

figured I would share my solution, as i've seen alot of questions about this, but not many helpful answers.

using JSZip: https://stuk.github.io/jszip/

using saveAs from fileSaver.js: https://github.com/eligrey/FileSaver.js

First: it loops through downloading each file individually from s3, creates a blob, and puts each blob/file into a "folder".

Second: after each file has been downloaded from s3, it will then use the saveAs method to download/save the zipped folder.


function NewEditInfo(props) {
const [job, setJob] = useState([]);
const [imagesUploaded, setImagesUploaded] = useState(null); 

//initialize jsZip
var JSZip = require("jszip");
let zip = new JSZip();
let photoZip = zip.folder(`${job.streetAddress}`);

useEffect(() => { 
     //// API call to load job info from dynamo db
  function loadJob() {
    return API.get("api name", "/tablename/tableinfo", {
  'queryStringParameters': {jobId: props.match.params.id}    
   }); 
  } 
   /// onload function to load job info and get a count of files
    async function onLoad() {   

      try {
        const job = await loadJob();
        setJob(job[0])

        const ImagesUploaded = await Storage.list(`${job[0].jobId}`);
        setImagesUploaded(ImagesUploaded);

        } catch (e) {
          alert(e);
      }

    }

    onLoad();
  }, [props.match.params.id,]);


  /// On download button click, loop through / download images using the key given from storage.list in onload function
  async function handleDownloadClick(event) {
         event.preventDefault();    
      const imagesAsArray = [...imagesUploaded];

    for (let i = 0; i < imagesAsArray.length; i++) {                                                                                          
      await DownloadFileFromS3(imagesAsArray[i]); 
        }
       /// waits for "await DownloadFileFromS3, then executes the save as which saves the zipped folder created in "DownloadFileFromS3"
        zip.generateAsync({type:"blob"})
             .then(function(content) {
        saveAs(content, `${job.streetAddress}`);
        });
   }


    /// download each file from s3 and put it in the zip folder
    async function DownloadFileFromS3(fileToDownload) {

        const result = await Storage.get(fileToDownload.key, {download: true})

        let mimeType = result.ContentType
        let fileName = fileToDownload.key
        let blob = new Blob([result.Body], {type: mimeType})

        photoZip.file(fileName[1], blob)

   }

 return(

      <IonPage>
      <IonHeader>
        <IonToolbar>
      <IonButtons slot="start">
          <IonBackButton/>
      </IonButtons>
          <IonTitle>Download Images</IonTitle>
        </IonToolbar>
      </IonHeader>  
      <IonContent className="ion-padding">   
      <IonButton onclick={handleDownloadClick}> download </IonButton>
      </IonContent>
      </IonPage>
    );


  }


export default withRouter(NewEditInfo);

1 Answers

figured I would share my solution, as i've seen alot of questions about this, but not many helpful answers.

using JSZip: https://stuk.github.io/jszip/

using saveAs from fileSaver.js: https://github.com/eligrey/FileSaver.js

First: it loops through downloading each file individually from s3, creates a blob, and puts each blob/file into a "folder".

Second: after each file has been downloaded from s3, it will then use the saveAs method to download/save the zipped folder.

function NewEditInfo(props) {
const [job, setJob] = useState([]);
const [imagesUploaded, setImagesUploaded] = useState(null); 

//initialize jsZip
var JSZip = require("jszip");
let zip = new JSZip();
let photoZip = zip.folder(`${job.streetAddress}`);

useEffect(() => { 
     //// API call to load job info from dynamo db
  function loadJob() {
    return API.get("api name", "/tablename/tableinfo", {
  'queryStringParameters': {jobId: props.match.params.id}    
   }); 
  } 
   /// onload function to load job info and get a count of files
    async function onLoad() {   

      try {
        const job = await loadJob();
        setJob(job[0])

        const ImagesUploaded = await Storage.list(`${job[0].jobId}`);
        setImagesUploaded(ImagesUploaded);

        } catch (e) {
          alert(e);
      }

    }

    onLoad();
  }, [props.match.params.id,]);


  /// On download button click, loop through / download images using the key given from storage.list in onload function
  async function handleDownloadClick(event) {
         event.preventDefault();    
      const imagesAsArray = [...imagesUploaded];

    for (let i = 0; i < imagesAsArray.length; i++) {                                                                                          
      await DownloadFileFromS3(imagesAsArray[i]); 
        }
       /// waits for "await DownloadFileFromS3, then executes the save as which saves the zipped folder created in "DownloadFileFromS3"
        zip.generateAsync({type:"blob"})
             .then(function(content) {
        saveAs(content, `${job.streetAddress}`);
        });
   }


    /// download each file from s3 and put it in the zip folder
    async function DownloadFileFromS3(fileToDownload) {

        const result = await Storage.get(fileToDownload.key, {download: true})

        let mimeType = result.ContentType
        let fileName = fileToDownload.key
        let blob = new Blob([result.Body], {type: mimeType})

        photoZip.file(fileName[1], blob)

   }

 return(

      <IonPage>
      <IonHeader>
        <IonToolbar>
      <IonButtons slot="start">
          <IonBackButton/>
      </IonButtons>
          <IonTitle>Download Images</IonTitle>
        </IonToolbar>
      </IonHeader>  
      <IonContent className="ion-padding">   
      <IonButton onclick={handleDownloadClick}> download </IonButton>
      </IonContent>
      </IonPage>
    );


  }


export default withRouter(NewEditInfo);
Related