+
+
Avg PRs Velocity
-
-
+
+
-
-
+
+
Contributed Repos
-
-
+
+
-
- {
-
-
Current Interest
-
+
+
+
Current Interest
+
+
- }
+
- )
-}
\ No newline at end of file
+ );
+};
diff --git a/src/pages/start.tsx b/src/pages/start.tsx
index af3d4bdc..97b08b19 100644
--- a/src/pages/start.tsx
+++ b/src/pages/start.tsx
@@ -1,25 +1,32 @@
import OpenSaucedLogo from "../assets/opensauced-logo.svg";
import { SUPABASE_LOGIN_URL } from "../constants";
-function Start() {
-
- return (
+const Start = () => (
);
-}
export default Start;
diff --git a/src/utils/cache.ts b/src/utils/cache.ts
index fb2589c7..36677269 100644
--- a/src/utils/cache.ts
+++ b/src/utils/cache.ts
@@ -2,10 +2,11 @@ export const cachedFetch = async (
url: string,
options:
| number
- | (RequestInit & { expireInSeconds: number; forceRefresh?: boolean })
- | undefined
+ | (RequestInit & { expireInSeconds?: number; forceRefresh?: boolean })
+ | undefined,
) => {
- let expiry = 5 * 60; // 5 min default
+ let expiry = 5 * 60;
+
if (typeof options === "number") {
expiry = options;
options = undefined;
@@ -13,34 +14,34 @@ export const cachedFetch = async (
expiry = options.expireInSeconds ?? expiry;
}
- let cacheKey = url;
- let cached = (await chrome.storage.local.get(cacheKey))[cacheKey];
- let whenCached = (await chrome.storage.local.get(cacheKey + ":ts"))[cacheKey + ":ts"];
-
+ const cacheKey = url;
+ const cached = (await chrome.storage.local.get(cacheKey))[cacheKey];
+ const whenCached = (await chrome.storage.local.get(`${cacheKey}:ts`))[`${cacheKey}:ts`];
+
if (cached && whenCached !== null && !options?.forceRefresh) {
- let age = (Date.now() - parseInt(whenCached)) / 1000;
+ const age = (Date.now() - parseInt(whenCached)) / 1000;
+
if (age < expiry) {
- let response = new Response(new Blob([cached]));
+ const response = new Response(new Blob([cached]));
+
return Promise.resolve(response);
- } else {
- chrome.storage.local.remove(cacheKey);
- chrome.storage.local.remove(cacheKey + ":ts");
}
+ void chrome.storage.local.remove(cacheKey);
+ void chrome.storage.local.remove(`${cacheKey}:ts`);
}
- return fetch(url, options).then((response) => {
+ return fetch(url, options).then(async response => {
if (response.status === 200) {
- let ct = response.headers.get("Content-Type");
- if (ct && ct.match(/(application\/json|text\/.*)/i)) {
- response
- .clone()
- .text()
- .then((content) => {
- chrome.storage.local.set({ [cacheKey]: content });
- chrome.storage.local.set({ [cacheKey + ":ts"]: Date.now() });
- });
+ const ct = response.headers.get("Content-Type");
+
+ if (ct?.match(/(application\/json|text\/.*)/i)) {
+ const content = await response.clone().text();
+
+ void chrome.storage.local.set({ [cacheKey]: content });
+ void chrome.storage.local.set({ [`${cacheKey}:ts`]: Date.now() });
}
}
return response;
- });
-};
\ No newline at end of file
+ })
+.catch(console.error);
+};
diff --git a/src/utils/colorPreference.ts b/src/utils/colorPreference.ts
index 1bf453ec..de6e360e 100644
--- a/src/utils/colorPreference.ts
+++ b/src/utils/colorPreference.ts
@@ -5,6 +5,7 @@ export const prefersDarkMode = (cookieString: string): boolean => {
const match = regex.exec(cookieString);
const cookie = match && JSON.parse(decodeURIComponent(match[0]));
const colorScheme: ColorScheme = cookie.color_mode ?? "auto";
+
if (colorScheme === "auto") {
return window.matchMedia("(prefers-color-scheme: dark)").matches;
}
diff --git a/src/utils/createHtmlElement.ts b/src/utils/createHtmlElement.ts
index 3e775423..e1bfaab5 100644
--- a/src/utils/createHtmlElement.ts
+++ b/src/utils/createHtmlElement.ts
@@ -1,21 +1,23 @@
import { CSSProperties } from "react";
-type ElementProps = {
+interface ElementProps {
style?: CSSProperties;
[key: string]: any;
-};
+}
type CssDeclaration = keyof Omit
;
-export function createHtmlElement(
+export function createHtmlElement (
nodeName: T,
- props: ElementProps
+ props: ElementProps,
) {
const { style, ...nonStyleProps } = props;
- const element = Object.assign(document.createElement(nodeName), props);
- if (style != undefined)
- Object.entries(style).forEach(([key, value]) => {
+ const element = Object.assign(document.createElement(nodeName), nonStyleProps);
+
+ if (style !== undefined) {
+ Object.entries(style).forEach(([key, value]) => {
element.style[key as CssDeclaration] = value;
});
+}
return element;
}
diff --git a/src/utils/dom-utils/inviteToOpenSauced.ts b/src/utils/dom-utils/inviteToOpenSauced.ts
index 1aca5662..f63bc36a 100644
--- a/src/utils/dom-utils/inviteToOpenSauced.ts
+++ b/src/utils/dom-utils/inviteToOpenSauced.ts
@@ -4,16 +4,34 @@ import { InviteToOpenSaucedModal } from "../../content-scripts/components/Invite
import { getTwitterUsername, getLinkedInUsername } from "../urlMatchers";
const injectOpenSaucedInviteButton = (username: string) => {
- const emailAddress: string | undefined = (
- document.querySelector(`a[href^="mailto:"]`) as HTMLAnchorElement
- )?.href.substr(7);
- const twitterUrl: string | undefined = (
- document.querySelector(`a[href*="twitter.com"]`) as HTMLAnchorElement
- )?.href;
- const linkedInUrl: string | undefined = (
- document.querySelector(`a[href*="linkedin.com"]`) as HTMLAnchorElement
- )?.href;
- if (!(emailAddress || twitterUrl || linkedInUrl)) return;
+ const emailAddress: string | undefined = (() => {
+ const element = document.querySelector(`a[href^="mailto:"]`);
+
+ if (element instanceof HTMLAnchorElement) {
+ return element.href;
+ }
+ return undefined;
+ })();
+ const twitterUrl: string | undefined = (() => {
+ const element = document.querySelector(`a[href*="twitter.com"]`);
+
+ if (element instanceof HTMLAnchorElement) {
+ return element.href;
+ }
+ return undefined;
+ })();
+ const linkedInUrl: string | undefined = (() => {
+ const element = document.querySelector(`a[href*="linkedin.com"]`);
+
+ if (element instanceof HTMLAnchorElement) {
+ return element.href;
+ }
+ return undefined;
+ })();
+
+ if (!(emailAddress || twitterUrl || linkedInUrl)) {
+ return;
+}
const twitterUsername = twitterUrl && getTwitterUsername(twitterUrl);
const linkedInUsername = linkedInUrl && getLinkedInUsername(linkedInUrl);
@@ -25,12 +43,17 @@ const injectOpenSaucedInviteButton = (username: string) => {
twitterUsername,
linkedInUsername,
},
- inviteToOpenSaucedButton
+ inviteToOpenSaucedButton,
);
const userBio = document.querySelector(GITHUB_PROFILE_MENU_SELECTOR);
- if (!userBio || !userBio.parentNode) return;
- if (userBio.lastChild?.isEqualNode(inviteToOpenSaucedButton)) return;
+
+ if (!userBio?.parentNode) {
+ return;
+}
+ if (userBio.lastChild?.isEqualNode(inviteToOpenSaucedButton)) {
+ return;
+}
userBio.append(inviteToOpenSaucedButton);
document.body.appendChild(inviteToOpenSaucedModal);
};
diff --git a/src/utils/dom-utils/viewOnOpenSauced.ts b/src/utils/dom-utils/viewOnOpenSauced.ts
index 5c97137e..c545ebb5 100644
--- a/src/utils/dom-utils/viewOnOpenSauced.ts
+++ b/src/utils/dom-utils/viewOnOpenSauced.ts
@@ -8,10 +8,15 @@ const injectViewOnOpenSaucedButton = (username: string) => {
const viewOnOpenSaucedButton = ViewOnOpenSaucedButton(username);
const userBio = document.querySelector(
- `${GITHUB_PROFILE_MENU_SELECTOR}, ${GITHUB_PROFILE_EDIT_MENU_SELECTOR}`
+ `${GITHUB_PROFILE_MENU_SELECTOR}, ${GITHUB_PROFILE_EDIT_MENU_SELECTOR}`,
);
- if (!userBio || !userBio.parentNode) return;
- if (userBio.lastChild?.isEqualNode(viewOnOpenSaucedButton)) return;
+
+ if (!userBio?.parentNode) {
+ return;
+}
+ if (userBio.lastChild?.isEqualNode(viewOnOpenSaucedButton)) {
+ return;
+}
userBio.append(viewOnOpenSaucedButton);
};
diff --git a/src/utils/fetchOpenSaucedApiData.ts b/src/utils/fetchOpenSaucedApiData.ts
index c8bffdfd..6509d388 100644
--- a/src/utils/fetchOpenSaucedApiData.ts
+++ b/src/utils/fetchOpenSaucedApiData.ts
@@ -4,10 +4,12 @@ import { OPEN_SAUCED_USERS_ENDPOINT, OPEN_SAUCED_SESSION_ENDPOINT } from "../con
export const isOpenSaucedUser = async (username: string) => {
try {
const response = await fetch(
- `${OPEN_SAUCED_USERS_ENDPOINT}/${username}`
+ `${OPEN_SAUCED_USERS_ENDPOINT}/${username}`,
);
+
if (response.status === 200) {
const data = await response.json();
+
return data.is_open_sauced_member;
}
return false;
@@ -19,45 +21,32 @@ export const isOpenSaucedUser = async (username: string) => {
export const checkTokenValidity = async (token: string) => {
const response = await fetch(OPEN_SAUCED_SESSION_ENDPOINT, {
method: "GET",
- headers: {
- Authorization: `Bearer ${token}`,
- },
+ headers: { Authorization: `Bearer ${token}` },
});
+
return response.status === 200;
};
-export const getUserData = async (userName: string, forceRefresh: boolean = false) => {
- return cachedFetch(`${OPEN_SAUCED_USERS_ENDPOINT}/${userName}`, {
- expireInSeconds: 2 * 60 * 60, // 2 hours
- forceRefresh,
- headers: {
- Accept: 'application/json',
- },
- }).then((resp) => {
- if (!resp.ok) {
- console.log('error getting user info')
- }
- return resp.json()
- })
- .then((json) => {
- return json
- })
-}
+export const getUserData = async (userName: string, forceRefresh: boolean = false) => cachedFetch(`${OPEN_SAUCED_USERS_ENDPOINT}/${userName}`, {
+ expireInSeconds: 2 * 60 * 60,
+ forceRefresh,
+ headers: { Accept: "application/json" },
+}).then(async resp => {
+ if (!resp?.ok) {
+ console.log("error getting user info");
+ }
+ return resp?.json();
+})
+ .then(json => json);
-export const getUserPRData = async (userName: string, forceRefresh: boolean = false) => {
- return cachedFetch(`${OPEN_SAUCED_USERS_ENDPOINT}/${userName}/prs`, {
- expireInSeconds: 2 * 60 * 60, // 2 hours
- forceRefresh,
- headers: {
- Accept: 'application/json',
- },
- }).then((resp) => {
- if (!resp.ok) {
- console.log('error getting user PR info')
- }
- return resp.json()
- })
- .then((json) => {
- return json
- })
-}
+export const getUserPRData = async (userName: string, forceRefresh: boolean = false) => cachedFetch(`${OPEN_SAUCED_USERS_ENDPOINT}/${userName}/prs`, {
+ expireInSeconds: 2 * 60 * 60,
+ forceRefresh,
+ headers: { Accept: "application/json" },
+}).then(async resp => {
+ if (!resp?.ok) {
+ console.log("error getting user PR info");
+ }
+ return resp?.json();
+})
+ .then(json => json);
diff --git a/src/utils/getAccessToken.ts b/src/utils/getAccessToken.ts
index 0d427fb0..951433eb 100644
--- a/src/utils/getAccessToken.ts
+++ b/src/utils/getAccessToken.ts
@@ -2,9 +2,12 @@ import { SUPABASE_LOCAL_STORAGE_KEY } from "../constants";
const getAccessToken = (): string | null => {
const localStore = window.localStorage.getItem(SUPABASE_LOCAL_STORAGE_KEY);
- if (localStore === null) return null;
+
+ if (localStore === null) {
+ return null;
+}
return JSON.parse(localStore)?.currentSession?.access_token;
};
-
+
export default getAccessToken;
-
\ No newline at end of file
+
diff --git a/src/utils/setAccessToken.ts b/src/utils/setAccessToken.ts
index 7f3ac5cb..e6ba370a 100644
--- a/src/utils/setAccessToken.ts
+++ b/src/utils/setAccessToken.ts
@@ -1,7 +1,6 @@
import { OPEN_SAUCED_AUTH_TOKEN_KEY } from "../constants";
-const setAccessTokenInChromeStorage = (accessToken: string): Promise => {
- return new Promise((resolve, reject) => {
+const setAccessTokenInChromeStorage = async (accessToken: string): Promise => new Promise((resolve, reject) => {
chrome.storage.sync.set({ [OPEN_SAUCED_AUTH_TOKEN_KEY]: accessToken }, () => {
if (chrome.runtime.lastError) {
reject(chrome.runtime.lastError);
@@ -10,7 +9,6 @@ const setAccessTokenInChromeStorage = (accessToken: string): Promise => {
}
});
});
- };
-
+
export default setAccessTokenInChromeStorage;
-
\ No newline at end of file
+
diff --git a/src/utils/urlMatchers.ts b/src/utils/urlMatchers.ts
index af1eb703..c46930c1 100644
--- a/src/utils/urlMatchers.ts
+++ b/src/utils/urlMatchers.ts
@@ -1,18 +1,21 @@
export const getGithubUsername = (url: string) => {
const match = url.match(/github\.com\/([\w.-]+)/);
- return match && match[1];
+
+ return match ? match[1] : undefined;
};
export const getLinkedInUsername = (url: string) => {
const match = url.match(
- /(?:https?:\/\/)?(?:www\.)?linkedin\.com\/in\/(?:#!\/)?@?([^\/\?\s]*)/
+ /(?:https?:\/\/)?(?:www\.)?linkedin\.com\/in\/(?:#!\/)?@?([^/?\s]*)/,
);
+
return match ? match[1] : undefined;
};
export const getTwitterUsername = (url: string) => {
const match = url.match(
- /(?:https?:\/\/)?(?:www\.)?twitter\.com\/(?:#!\/)?@?([^\/\?\s]*)/
+ /(?:https?:\/\/)?(?:www\.)?twitter\.com\/(?:#!\/)?@?([^/?\s]*)/,
);
+
return match ? match[1] : undefined;
};
diff --git a/src/worker/background.ts b/src/worker/background.ts
index b3779bc4..2977019d 100644
--- a/src/worker/background.ts
+++ b/src/worker/background.ts
@@ -3,26 +3,33 @@ import { checkTokenValidity } from "../utils/fetchOpenSaucedApiData";
import setAccessTokenInChromeStorage from "../utils/setAccessToken";
chrome.webRequest.onCompleted.addListener(
- (details) => {
- chrome.storage.sync.remove(OPEN_SAUCED_AUTH_TOKEN_KEY);
+ () => {
+ void chrome.storage.sync.remove(OPEN_SAUCED_AUTH_TOKEN_KEY);
},
- { urls: [SUPABASE_LOGOUT_URL] }
+ { urls: [SUPABASE_LOGOUT_URL] },
);
-chrome.tabs.onUpdated.addListener(function (tabId, changeInfo) {
+chrome.tabs.onUpdated.addListener((tabId, changeInfo) => {
if (changeInfo.url?.includes("github.com")) {
- chrome.tabs.sendMessage(tabId, { message: "GITHUB_URL_CHANGED" });
+ void chrome.tabs.sendMessage(tabId, { message: "GITHUB_URL_CHANGED" });
}
});
-chrome.cookies.onChanged.addListener(async (changeInfo) => {
+chrome.cookies.onChanged.addListener(async changeInfo => {
try {
- if (changeInfo.cookie.name != SUPABASE_COOKIE_NAME || changeInfo.cookie.domain != SUPABASE_AUTH_DOMAIN) return;
- if (changeInfo.removed) return chrome.storage.sync.remove(OPEN_SAUCED_AUTH_TOKEN_KEY);
- const isValidToken = await checkTokenValidity(changeInfo.cookie.value)
- if (!isValidToken) return chrome.storage.sync.remove(OPEN_SAUCED_AUTH_TOKEN_KEY);
- setAccessTokenInChromeStorage(changeInfo.cookie.value);
- } catch(error) {
+ if (changeInfo.cookie.name !== SUPABASE_COOKIE_NAME || changeInfo.cookie.domain !== SUPABASE_AUTH_DOMAIN) {
+ return;
+ }
+ if (changeInfo.removed) {
+ return chrome.storage.sync.remove(OPEN_SAUCED_AUTH_TOKEN_KEY);
+ }
+ const isValidToken = await checkTokenValidity(changeInfo.cookie.value);
+
+ if (!isValidToken) {
+ return chrome.storage.sync.remove(OPEN_SAUCED_AUTH_TOKEN_KEY);
+ }
+ void setAccessTokenInChromeStorage(changeInfo.cookie.value);
+ } catch (error) {
console.error("Error processing cookie update:", error);
}
-})
\ No newline at end of file
+});