ABSYZABSYZ
  • Home
  • About Us
  • Our Services
    • Consulting Services
    • Managed Services
    • Implementation Services
    • Staffing Services
  • Our Approach
  • Products

  • Home

    Home

  • About us

    Who We Are

  • Our Expertise

    What we Do

  • Our Approach

    How We Do It

  • Products

    What We Made

  • Industries

    Who We Do It For

  • Clients

    Whom We Did It For.

  • Article & Blogs

    What Experts Think

  • Careers

    Join The Team

  • Get In Touch

    Let’s Get Started

  • White papers

    Trends We Explored

ABSYZ

How To Upload A File To Google Drive Using LWC

Home / Article & Blogs / Salesforce / Integration / How To Upload A File To Google Drive Using LWC
By Rakesh Neelam inIntegration, Salesforce

In the realm of digital innovation, Salesforce Lightning Web Components (LWC) offer a plethora of opportunities for creating versatile, customized solutions. Among these, a standout is the ability to construct an advanced Google Drive File Uploader completely using LWC without Apex . 

In this blog, we’ll explore the nuts and bolts of this uploader, which is not only highly functional but also customizable to meet your specific requirements.

Understanding the File Uploader Component

The file uploader component is positioned within a `lightning-card`, a container component that groups related pieces of content. The card is equipped with a file input component and a submit button.

File Input

Users select their desired upload file via an input of type “file”. This input only accepts ‘zip’ and ‘pdf’ files as defined by the `SUPPORTED_FILES` constant. 

File Validation

Upon file selection, the component triggers the `validateDocument` method to verify the file’s compliance with the required conditions. Specifically, the file size must not exceed 10 MB, and the file type should be either ‘zip’ or ‘pdf’. These conditions can be effortlessly customized to suit your particular needs. If a file fails to meet these conditions, the component displays an error message, and the submit button is disabled.

File Submission

Once a file is successfully selected, the ‘Submit’ button becomes available. Clicking this button initiates the `processSelectedFile` method, which prepares the file for upload to Google Drive.

Uploading Files to Google Drive

To upload the selected files to Google Drive, they must first be converted into a suitable format. This involves reading the file data as a Data URL and extracting the base64 encoded string of the file’s content. 

After all selected files are converted and ready, they are transferred to Google Drive via the `sendFileToGoogleDrive` method.

 Retrieving the Google Access Token

Before the files can be sent to Google Drive, a Google Access Token must be obtained. This token authorizes the application to access Google Drive. The `getGoogleAccessToken` method manages this process, sending a POST request to a pre-configured endpoint to fetch the access token.

Dispatching Files to Google Drive

Upon securing the access token, the `sendFileToGoogleDrive` method dispatches a multipart POST request to the Google Drive API. This request is authorized using the previously obtained access token and attaches the file data along with its metadata. 

Prerequisites

It’s critical to mention that for this uploader to function correctly, the domain `https://www.googleapis.com` needs to be added to Salesforce’s Content Security Policy (CSP) Trusted Sites list. Adding this domain to the list is vital because it allows Salesforce to make secure HTTP requests to Google’s APIs.

Additionally, remember to store the required values in custom labels within your Salesforce org. These labels can include Google Drive API credentials such as ClientId, ClientSecret, and GoogleDriveRefreshToken, as well as other necessary parameters such as prejoining_folder_id, GoogleDriveApiResponse, and GoogleAccessTokenPrejoining. You may rename these labels as per your preference, but be sure to adjust their references in the code accordingly.

Lightning Web Component:

Html:
    <template>
    <lightning-card title="File Upload" icon-name="utility:upload">
      <div class="slds-m-around_medium">
        <!-- File Upload Component -->
        <div class="slds-m-top_large">
          <label class="custom-file-upload">
            <input class="input input-file document" required type="file" onchange={fileHandler} accept={acceptedFormats} />
          </label>
        </div>
        <!-- Display uploaded file name -->
        <div class="slds-text-align_left slds-m-top_small">
          <p style="font-size: 0.8rem; font-weight:normal; font-style:italic;color: navy;">{fileName}</p>
        </div>
        <!-- Error message display section -->
        <template if:true={errorMessage}>
          <div class="slds-text-align_left slds-m-top_small">
            <p style="font-size: 0.8rem; font-weight:normal; font-style:italic;color: red;">{errorMessage}</p>
          </div>
        </template>
        <!-- File upload requirements section -->
        <div class="slds-m-top_small">
          <small>Upload only zip file or pdf (less than 5MB) containing all the above documents</small>
        </div>
        <!-- Submit Button -->
        <div class="slds-m-top_medium">
          <lightning-button label="Submit" variant="brand" onclick={processSelectedFile} disabled={isSubmitDisabled}></lightning-button>
        </div>
      </div>
    </lightning-card>
  </template>

JS:

// Importing necessary modules
import { LightningElement, api, track } from 'lwc';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import CLIENT_ID from '@salesforce/label/c.ClientId';
import CLIENT_SECRET from '@salesforce/label/c.Client_Srecret';
import GOOGLE_DRIVE_REFRESH_TOKEN from '@salesforce/label/c.GoogleDriveRefreshToken';
import DRIVE_FOLDER_ID from '@salesforce/label/c.drive_folder_id';
import GoogleDriveApiResponse from '@salesforce/label/c.GoogleDriveApiResponse';
import GoogleAccessToken from '@salesforce/label/c.GoogleAccessToken';

const SUPPORTED_FILES = ['zip', 'pdf']; // Supported file formats

export default class GoogleDriveFileUploader extends LightningElement {
  @track fileName = "No File Selected";
  @track errorMessage = "";
  @api recordId;
  @track isSubmitDisabled = true;
  @track selectedFiles = []; 

  // Method that returns accepted formats
  get acceptedFormats() {
    return SUPPORTED_FILES.map(format => `.${format.toLowerCase()}`);
  }

  // File handler method
  fileHandler(event) {
    console.log("File handler method triggered");
    const files = event.target.files;
    if (files.length > 0) {
      this.selectedFiles = [...files]; 
      this.validateDocument(files[0]) && this.buildFile();
    }
  }

  // Method for document validation
  validateDocument(file) {
    console.log("Validating document");
    let documentField = this.template.querySelector(".document");
    let fileSize = file.size; // size in bytes
    let maxSize = 10 * 1024 * 1024; // 10 MB in bytes
    let fileExtension = file.name.split(".").pop();

    // Check file size
    if (fileSize > maxSize) {
      documentField.setCustomValidity("File size exceeds 10 MB");
      this.isSubmitDisabled = true;
    } 
    // Check file type
    else if (!SUPPORTED_FILES.includes(fileExtension.toLowerCase())) {
      documentField.setCustomValidity("File format not supported");
      this.isSubmitDisabled = true;
    } 
    // Valid file
    else {
      documentField.setCustomValidity("");
      this.fileName = file.name;
      this.isSubmitDisabled = false;
      return true;
    }

    documentField.reportValidity();
    this.fileName = '';
    return false;
  }

  // Method for building the file
  buildFile() {
    console.log("Building file");
    let processedFiles = []; 
    let filesProcessed = 0;

    for (let i = 0; i < this.selectedFiles.length; i++) {
      let fileReader = new FileReader();
      fileReader.readAsDataURL(this.selectedFiles[i]);

      fileReader.onload = () => {
        let base64 = 'base64,';
        let content = fileReader.result.indexOf(base64) + base64.length;
        let fileContents = fileReader.result.substring(content);

        processedFiles.push({
          Title: this.selectedFiles[i].name,
          VersionData: fileContents
        });

        if (++filesProcessed === this.selectedFiles.length) {
          this.selectedFiles = processedFiles;
          console.log("File successfully built");
          
        }
      };
    }
  }

  processSelectedFile() {
    console.log("File method triggered");
    this.selectedFiles.forEach((fileObject) => {
      // Convert files from base64 to byte array and set file properties
      const byteArray = this.base64ToUint8Array(fileObject.VersionData);
      const fileExtension = fileObject.Title.split('.').pop().toLowerCase();
      const mimeType = fileExtension === 'pdf' ? 'application/pdf' : 'application/zip';
      this.file = new File([byteArray], fileObject.Title, { type: mimeType });
      console.log("Sending file to Google Drive");
      this.sendFileToGoogleDrive(); // Upload file     });
  }

  // Converts a base64 string into a Uint8Array
  base64ToUint8Array(base64) {
    const binaryString = atob(base64);
    const len = binaryString.length;
    const bytes = new Uint8Array(len);
    for (let i = 0; i < len; i++) {
      bytes[i] = binaryString.charCodeAt(i);
    }
    return bytes;
  }

  // Sends a file to Google Drive
  async sendFileToGoogleDrive() {
    console.log("File reader is loading file");
    const fileReader = new FileReader();
    fileReader.onload = async () => {
      const base64FileData = fileReader.result.split(',')[1];
      const fileTitle = this.file.name;
      const fileContentType = this.file.type;

      // Upload file to Google Drive
      console.log("Uploading file to Google Drive");
      const fileId = await this.uploadFileToGoogleDrive(fileTitle, base64FileData, fileContentType);
      
      // Dispatch a success event
      console.log("Dispatching success event");
      this.dispatchEvent(
        new ShowToastEvent({
          title: 'Success',
          message: 'File uploaded Successfully',
          variant: 'success'
        })
      );
    };
    fileReader.readAsDataURL(this.file);
  }

  // Upload file to Google Drive
  async uploadFileToGoogleDrive(fileTitle, base64FileData, fileContentType) {
    console.log("Retrieving Google Access Token");
    const accessToken = await this.getGoogleAccessToken();
    const folderId = DRIVE_FOLDER_ID;
    const boundary = '----------9889464542212';
    const delimiter = `\r\n--${boundary}\r\n`;
    const close_delim = `\r\n--${boundary}--`;

    // Set metadata for the file
    const metadata = {
      title: fileTitle,
      mimeType: fileContentType,
      parents: [{ id: folderId }],
    };

    // Prepare the multipart request body
    const multipartRequestBody =
        delimiter +
        'Content-Type: application/json\r\n\r\n' +
        JSON.stringify(metadata) +
        delimiter +
        'Content-Type: ' +
        fileContentType +
        '\r\n' +
        'Content-Transfer-Encoding: base64\r\n' +
        '\r\n' +
        base64FileData +
        close_delim;

    // Set request options
    const requestOptions = {
      method: 'POST',
      headers: {
        'Content-Type': `multipart/mixed; boundary="${boundary}"`,
        Authorization: `Bearer ${accessToken}`,
      },
      body: multipartRequestBody,
    };

    // Send the request and process the response
    console.log("Sending request to Google Drive API");
    const response = await fetch(GoogleDriveApiResponse, requestOptions);
    if (!response.ok) {
      throw new Error('Error uploading file to Google Drive');
    }
    const responseData = await response.json();
    console.log("Response data received from Google Drive API", responseData);
    return responseData.id;
  }

  // Retrieves a Google Access Token
  async getGoogleAccessToken() {
    console.log("Retrieving Google Access Token");
    const clientId = CLIENT_ID;
    const clientSecret = CLIENT_SECRET;
    const refreshToken = GOOGLE_DRIVE_REFRESH_TOKEN;

    // Prepare the body of the request
    const bodyRequest = new URLSearchParams();
    bodyRequest.append('client_id', clientId);
    bodyRequest.append('client_secret', clientSecret);
    bodyRequest.append('refresh_token', refreshToken);
    bodyRequest.append('grant_type', 'refresh_token');

    // Set request options
    const requestOptions = {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
      },
      body: bodyRequest,
    };

    // Send the request and process the response
    console.log("Sending request to retrieve access token");
    const response = await fetch(GoogleAccessToken, requestOptions);
    if (!response.ok) {
      throw new Error('Error retrieving Google Access Token');
    }
    const responseData = await response.json();
    console.log("Access token retrieved", responseData.access_token);
    return responseData.access_token;
  }
}

CSS:

/* fileUploadToGoogleDrive.css */

.THIS .custom-file-upload {
    padding: 10px;
    background-color: #e0e0e0;
    border-radius: 5px;
    display: inline-block;
    width: 100%;
    text-align: center;
    cursor: pointer;
    color: #5a5a5a;
}

.THIS .custom-file-upload:hover {
    background-color: #c2c2c2;
}

.THIS .input-file {
    display: none;
}

.THIS .input {
    width: 100%;
    padding: 10px;
    border: 1px solid #c2c2c2;
    border-radius: 5px;
}

.THIS p {
    margin: 0;
}

XML:

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>57.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>

Conclusion

The LWC Google Drive File Uploader component effectively enables users to select a file, validates the chosen file, and uploads it directly to Google Drive from Salesforce. This streamlined process saves time and enhances productivity by integrating two separate platforms, facilitating a seamless data exchange.

The code is scalable and maintainable, meaning supported file types, file size restrictions, or the upload logic can be easily added or modified to meet specific business needs. By adjusting the API calls and authentication methods, the uploader could be modified to work with other cloud storage services like Dropbox or OneDrive. Remember to adhere to security best practices and add the necessary domain to your trusted sites list for secure and successful file uploads.

get in touch
file upload to google driveupload file to google drive without apex
138
Like this post
3 Posts
Rakesh Neelam

Search Posts

Archives

Categories

Recent posts

Einstein For Developers: Get Started Now

Einstein For Developers: Get Started Now

<strong>K-Means Clustering: Exploring and Clarifying Its Enigmatic Nature</strong>

K-Means Clustering: Exploring and Clarifying Its Enigmatic Nature

Dreamforce 2023: What To Expect

Dreamforce 2023: What To Expect

Salesforce Einstein GPT: Generative AI Transforming Customer Experiences

Salesforce Einstein GPT: Generative AI Transforming Customer Experiences

Redux In React Native: A Complete Guide

Redux In React Native: A Complete Guide

  • How To  Generate A PDF Using JSPDF In LWC
    Previous PostHow To  Generate A PDF Using JSPDF In LWC
  • Next PostEmbedding CRM Analytics Dashboard On Home Page Using Lightning Component
    How To  Generate A PDF Using JSPDF In LWC

Related Posts

Dreamforce 2023: What To Expect
Salesforce

Dreamforce 2023: What To Expect

Embedding CRM Analytics Dashboard On Home Page Using Lightning Component
CRM Analytics Salesforce

Embedding CRM Analytics Dashboard On Home Page Using Lightning Component

How To  Generate A PDF Using JSPDF In LWC
Lightning Web Components Salesforce

How To  Generate A PDF Using JSPDF In LWC

Create a No-Code Facebook Messenger Channel in the Service Cloud
Salesforce Service Cloud

Create a No-Code Facebook Messenger Channel in the Service Cloud

Leave a Reply (Cancel reply)

Your email address will not be published. Required fields are marked *

*
*

ABSYZ Logo

INDIA | USA | UAE | CANADA

  • About us
  • Article & Blogs
  • Careers
  • Get In Touch
  • Our Expertise
  • Our Approach
  • Products
  • Industries
  • Clients
  • White papers

Copyright ©2022 Absyz Inc. All Rights Reserved.

youngsoft
Copy
We use cookies on our website to give you the most relevant experience by remembering your preferences and repeat visits. By clicking “ACCEPT ALL”, you consent to the use of ALL the cookies. However, you may visit "Cookie Settings" to provide a controlled consent. Privacy Policy
Cookie SettingsREJECT ALLACCEPT ALL
Manage consent

Privacy Overview

This website uses cookies to improve your experience while you navigate through the website. Out of these, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may affect your browsing experience.
Necessary
Always Enabled

Necessary cookies are absolutely essential for the website to function properly. These cookies ensure basic functionalities and security features of the website, anonymously.

CookieDurationDescription
cookielawinfo-checkbox-analytics11 monthsThis cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Analytics".
cookielawinfo-checkbox-functional11 monthsThe cookie is set by GDPR cookie consent to record the user consent for the cookies in the category "Functional".
cookielawinfo-checkbox-necessary11 monthsThis cookie is set by GDPR Cookie Consent plugin. The cookies is used to store the user consent for the cookies in the category "Necessary".
cookielawinfo-checkbox-others11 monthsThis cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Other.
cookielawinfo-checkbox-performance11 monthsThis cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Performance".
viewed_cookie_policy11 monthsThe cookie is set by the GDPR Cookie Consent plugin and is used to store whether or not user has consented to the use of cookies. It does not store any personal data.

Functional

Functional cookies help to perform certain functionalities like sharing the content of the website on social media platforms, collect feedbacks, and other third-party features.

Performance

Performance cookies are used to understand and analyze the key performance indexes of the website which helps in delivering a better user experience for the visitors.

Analytics

Analytical cookies are used to understand how visitors interact with the website. These cookies help provide information on metrics the number of visitors, bounce rate, traffic source, etc.

Advertisement

Advertisement cookies are used to provide visitors with relevant ads and marketing campaigns. These cookies track visitors across websites and collect information to provide customized ads.

Others

Other uncategorized cookies are those that are being analyzed and have not been classified into a category as yet.

SAVE & ACCEPT