What's your biggest current challenge? Have your say in Community Polls along the right column.
Our Partner & Developer boards on the community are moving to a brand new home: the .dev community forums! While you can still access past discussions here, for all your future app and storefront building questions, head over to the new forums.

Uploading Media Files to Shopify from Remix app.

Uploading Media Files to Shopify from Remix app.

Wakil_eFoli
Shopify Partner
47 2 6

I'm using DropZone for uploading file in my app and then after uploading I'm converting the acceptedFiles to base64 string cause my File obj gets missing when submitting the form. 

Then 
on form submit, in the action method I'm doing the following but this is not working. Can anyone help me fix it? 

// Fetching the mediaFiles data.
    const mediaFiles = formData.mediaFiles;

    // Handling Media Files START =========
    if(mediaFiles) {

      // Finding the files with and without uploaded files
      const filesWithUploads = mediaFiles.filter(upload => Object.keys(upload.fileData).length > 0);
      const filesWithOutUpload = mediaFiles.filter(upload => Object.keys(upload.fileData).length === 0);

      // Array to store the final media urls for the product. 
      let productImgResouceUrls = [];

      // Handing media files without uploads.
      if(filesWithOutUpload) {
        // Pushing their url's to the productImgResouceUrls array.
        filesWithOutUpload.forEach(file => {
          productImgResouceUrls.push(file.url);
        });
      }

      // Handle uploaded media files START.
      if(filesWithUploads) {

        // Array to store the stagedUploadInput for the stagedUploadsCreate mutation
        let stagedUploadInput = [];

        // Creating the stagedUploadInput for each upload
        filesWithUploads.forEach(file => {
          stagedUploadInput.push({
            filename: file.fileData.fileName,
            fileSize: file.fileData.fileSize.toString(),
            mimeType: file.fileData.mimeType,
            resource: file.fileData.resource,
            // resource: "FILE",
            httpMethod: "POST",
          }) 
        });

        // Calling the stagedUploadsCreate mutation
        const stagedUploadsCreateReq = await admin.graphql(
          `#graphql
          mutation stagedUploadsCreate($input: [StagedUploadInput!]!) {
            stagedUploadsCreate(input: $input) {
              stagedTargets {
                url
                resourceUrl
                parameters {
                  name
                  value
                }
              }
              userErrors {
                field
                message
              }
            }
          }`,
          {
            variables: {
              input: stagedUploadInput, 
            },
          },
        );

        const stagedUploadsCreateRes = await stagedUploadsCreateReq.json();  // Fetching the mutation response.

        // If no errors then proceed with the stagedUploadsCreateRes data.
        if(stagedUploadsCreateRes.data.stagedUploadsCreate.userErrors.length === 0) {
          
          // Fetching the main data node
          const stagedTargets = stagedUploadsCreateRes.data.stagedUploadsCreate.stagedTargets;

          // Handling the file uploads.
          const uploadPromises = stagedTargets.map(async (target, index) => {
            // Save the target info.
            const params = target.parameters;  
            const url = target.url;   
            const resourceUrl = target.resourceUrl; 

            // Generate a form, add the necessary params and append the file.
            const form = new FormData();

            params.forEach(({name, value}) => {
              form.append(name, value);
            });

            // Add the file to the form
            const base64EncodedFile = filesWithUploads[index].fileData.base64StringFile;
            const fileName = filesWithUploads[index].fileData.fileName;
            const mimeType = filesWithUploads[index].fileData.mimeType;

            // Convert the base64 string to File
            const decodedFile = base64ToFile(base64EncodedFile, fileName, mimeType);

            form.append("file", decodedFile);

            const fetchOptions = {
              method: 'POST',
              headers: {
                "Content-Length": filesWithUploads[index].fileData.fileSize + 5000,
                'Content-Type': 'multipart/form-data',
              },
              body: form,
            }

            // Uploading the file using fetch
            const response = await fetch(url, fetchOptions);

            // Handle the response
            if (!response.ok) {
              console.error(`Fetch request for file ${index} failed with status: ${response.status}`);
              throw new Error(`Fetch request for file ${index} failed with status: ${response.status}`);
            }

            // Returning the response.
            return response.json();

          })

          // Create an array to store information about each upload, including the target index
          const uploadResults = await Promise.all(uploadPromises.map((promise, index) => ({
            promise,
            index,
          })));


          // Iterate over each upload result
          uploadResults.forEach(({ promise, index }) => {
            promise.then(result => {
              result.push(result);
              if (result.ok) {

                // When success Push this stagedTargets resourceUrl to the productImgResouceUrls array.
                productImgResouceUrls.push(stagedTargets[index].resourceUrl)

                console.log(`Upload of file ${index + 1} to staged target ${index} was successful.`);

              } else {
                // The upload failed
                console.error(`Upload of file ${index + 1} to staged target ${index} failed with status: ${result.status}`);
              }
            });
          });

        
        } else {
          // Handling the mutation errors.
          console.error(`Error when creating stagedUploadsCreate. Error: ${stagedUploadsCreateRes.data.stagedUploadsCreate.userErrors}`)
        }

      }   // Handle uploaded media files END.


      // return json(productImgResouceUrls);

      // Loop over the productImgResouceUrls and create the input for productCreateMedia mutation.
      const createMediaInput = productImgResouceUrls.map(url => ({
        alt: "Bundle Image",
        mediaContentType: "IMAGE",
        originalSource: url,
      }));

      // return json(createMediaInput)

      // FIX: Static data
      const productId = "gid://shopify/Product/8204421038230";

      if(createMediaInput) {
        // Uploading the media to the product
        const productCreateMediaReq = await admin.graphql(
          `#graphql
          mutation productCreateMedia($media: [CreateMediaInput!]!, $productId: ID!) {
            productCreateMedia(media: $media, productId: $productId) {
              media {
                id
                alt
                mediaContentType
                status
              }
              mediaUserErrors {
                field
                message
              }
              product {
                id
                title
              }
            }
          }`, 
          {
            variables: {
              media: createMediaInput, 
              productId: productId,
            }
          }
        )

        // Fetching the productCreateMedia Response
        const productCreateMediaRes = await productCreateMediaReq.json();


        if(productCreateMediaRes.data.productCreateMedia.mediaUserErrors) {
          console.log(`Error running productCreateMedia Mutation. Error: ${productCreateMediaRes.data.productCreateMedia.mediaUserErrors}`)
        }
      }




      // Returning the productImgResouceUrls
      return json(productImgResouceUrls);


    }  // // Handling Media Files END =========

 

Thanks!

 

 

Replies 0 (0)