From Upwork Idea to a Fully Functional Chrome Extension Tool

in Digital Lifestyle3 months ago (edited)

In the past, I have found out that taking up coding challenges by building projects related to the challenge/quiz helps strengthen my skills. But for some reason, my portfolio projects or showcases look empty.

Recently, I took my Upwork account seriously by updating my profile details and project section. After I was done, I started browsing for jobs till I came across an offer that caught my attention. It's an offer to build or modify an existing Chrome extension.

Immediately, I looked at my portfolio and found no extension-related project. Then, I remembered I once worked on one, which I also blogged about here But I didn't include it in my portfolio.

The last time I developed an extension was 2 years ago, but I wanted to refresh my skills in that area. So, I decided to create a simple tool that meets 90% of the job descriptions I found on Upwork.

After gathering all the info I needed, I came up with the idea to build Quicksave; a Chrome extension tool that lets users seamlessly save their current tab to their Google Drive in one click.

qucikdriveLogin.png

Quickdrive.png


I understand that this idea might not be unique, but It surely refreshed my memory on building an extension, which should be enough experience needed to apply for the Upwork gig.

The Process

One of the most important aspects of an extension is the Manifest file. This file holds the overall details which include, description, permissions, scopes (access to Google Drive and user profile data), Auth details, and so on.


{
 "manifest_version": 3,
 "name": "QuickSave - Google Drive Bookmark Manager",
 "version": "1.0",
 "description": "Save and organize URLs in Google Drive.",
 "permissions": ["identity", "storage", "tabs", "activeTab"],
 "background": {
   "service_worker": "background.js"
 },
 "oauth2": {
   "client_id": "CLIENT_ID",
   "scopes": [
     "https://www.googleapis.com/auth/drive.file",
     "https://www.googleapis.com/auth/userinfo.profile",
     "https://www.googleapis.com/auth/userinfo.email"
   ]
 },
 "host_permissions": [
   "https://accounts.google.com/*",
   "https://www.googleapis.com/*"
 ]
}

For consistency and better user experience, I decided that once the user hits the Login button, the code fetches and saves the access token locally for that particular session. This was done in the background script.

chrome.identity.getAuthToken({ interactive: true }, function(token) {
  if (chrome.runtime.lastError) {
    console.error(chrome.runtime.lastError);
  } else {
    chrome.storage.sync.set({ token }, () => {
      console.log(`Token stored: ${token}`);
    });
  }
});

I was initially running this part of the code in the popup.js file but I faced an issue where it wasn't authenticating properly.

Moving forward, after a user is authenticated and the user clicks on the save tab button, the current tab’s URL and title are saved to Google Drive as a text file. This required making a POST request to the Google Drive API.

async function saveBookmarkToDrive(token, title, url) {
  const metadata = {
    name: `${title}.txt`,
    mimeType: "text/plain"
  };

  const fileContent = `Title: ${title}\nURL: ${url}`;
  const file = new Blob([fileContent], { type: "text/plain" });

  const form = new FormData();
  form.append("metadata", new Blob([JSON.stringify(metadata)], { type: "application/json" }));
  form.append("file", file);

  try {
    const response = await fetch("https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart", {
      method: "POST",
      headers: new Headers({
        Authorization: `Bearer ${token}`
      }),
      body: form
    });

    const data = await response.json();
    console.log("Bookmark saved:", data);
    alert("Bookmark saved to Google Drive!");
  } catch (error) {
    console.error("Error saving bookmark:", error);
  }
}


Challenges

One of the toughest challenges I faced was solving the 401 errors after I was unknowingly sending requests to the Google API without including userinfo.profile and userinfo.email scopes in the manifest file.

Also, I needed a smooth authentication process where it saves the token when the user logs in and clears or revokes the token when the logout button is clicked. It happened that I was successfully clearing the token from local storage but I wasn't revoking it. I spent several minutes debugging it before I finally resolved it.

You might be wondering what was the feedback I got after sending the proposal to the client. The answer is nothing, I still haven't heard from them yet. I believe we all know how tough it is to get offers on a freelancing platform. However, Building QuickSave for me, was a valuable experience that helped me create a useful tool for myself and would be for the public when I eventually upload it to the Chrome store. Also, I have just added it to my portfolio.

If anyone is willing to see how it works, I have a video demonstration on YouTube

I'd also love to implement a feature where the tabs are saved in folders based on days. This feature will prevent the files from littering on the drive. Even though I don't have the extension published to the Chrome store for public usage, What do you think about Quicksave?

Sort:  

I think this is a good idea for those people who wants to have a one place to store everything on the internet. Lol.

Thanks. It’s a tool meant for those who wish to have the current url they are browsing saved on Google Drive for easy access.

So what do I do if I’m experiencing the same authentication problems like you did?
Or you said it and I missed it?

  • By revoking the token, and clearing it from local storage solved the issue.

  • For the other 401 error, always make sure to have your required permissions in your scope which is located in the manifest Json file.

Alright, thank you