Skip to content

Commit

Permalink
fix: handle undefined on user profile
Browse files Browse the repository at this point in the history
  • Loading branch information
kerolloz committed Jul 27, 2024
1 parent 596a6c6 commit 759c4ce
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 40 deletions.
78 changes: 40 additions & 38 deletions follows-you.js
Original file line number Diff line number Diff line change
@@ -1,95 +1,97 @@
const $ = document.querySelector.bind(document);
const HOVER_CARD_SELECTOR = ".Popover.js-hovercard-content.position-absolute";
const HOVER_CARD_FOLLOWS_YOU_ID = "hovercard-follows-you";
const PROFILE_FOLLOWS_YOU_ID = "profile-follows-you";

/**
* returns whether user X is following user Y
* @param {string} x
* @param {string} y
*/
async function isFollowing(x, y) {
const cachekey = new Date().toISOString().split(":")[0];
const cacheKey = new Date().toISOString().split(":")[0];
// toISOString() '2022-01-02T13:36:43.370Z' => split(":")[0] '2022-01-02T13' Caching by Date & Hour
// cache is considered valid for an hour
// https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting
// X-RateLimit-Limit: 60 => The maximum number of requests you're permitted to make per hour.
const url = `https://api.github.com/users/${x}/following/${y}?${cachekey}`;
const url = `https://api.github.com/users/${x}/following/${y}?${cacheKey}`;
const response = await fetch(url, { cache: "force-cache" });
return response.status === 204; // according to github docs 204 means follows
return response.status === 204; // according to github docs, 204 means follows
}

/**
* Follows You
*/
class FY {
const FY = {
/**
* creates and returns a `follows you` element
* @param {...string} classes
* @returns {HTMLSpanElement} follows you element
*/
static createElement(...classes) {
createElement(...classes) {
const el = document.createElement("span");
el.innerText = "follows you";
el.style.fontSize = "10px";
el.classList.add(...classes, "label", "text-uppercase", "v-align-middle");
return el;
}
},

/**
* shows `follows-you` label on the profile page
*/
static showOnProfilePage() {
const stickyBarUsername = $(
"span.d-table-cell.v-align-middle.lh-condensed.pr-2 > div"
);
stickyBarUsername?.after(FY.createElement());
$("h1.vcard-names").appendChild(FY.createElement());
}
showOnProfilePage() {
const element = FY.createElement();
element.id = PROFILE_FOLLOWS_YOU_ID;

$("h1.vcard-names")?.appendChild(element);
},

/**
* shows `follows-you` label on the user hover card
*/
static showOnHoverCard() {
const hovercardLabel = FY.createElement(
"mt-2",
"d-flex",
"flex-justify-center"
);
hovercardLabel.id = "hovercard-follows-you";
showOnHoverCard() {
const element = FY.createElement("mt-2", "d-flex", "flex-justify-center");
element.id = HOVER_CARD_FOLLOWS_YOU_ID;

if ($(`#${hovercardLabel.id}`)) return; // already added
$(`${HOVER_CARD_SELECTOR} .px-3`)?.append(hovercardLabel);
}
}
$(`${HOVER_CARD_SELECTOR} .px-3`)?.append(element);
},
};

(async () => {
const followsMe = (x) => isFollowing(x, loggedInUsername);
async function init() {
const loggedInUsername = $("meta[name='user-login']")?.content;
const followsMe = (x) => isFollowing(x, loggedInUsername);

// PART 1 --------------------------------------------------
// if I'm logged in and viewing some user's profile page who follows me
const isProfilePage = !!$(".vcard-fullname");
const openedProfileUsername = $("command-palette-token")?.dataset.text;
// extract from current url: github.com/username
const openedProfileUsername = location.pathname.split("/").pop();
const shouldShowOnProfile =
isProfilePage &&
loggedInUsername !== openedProfileUsername && // not my profile
!$(`#${PROFILE_FOLLOWS_YOU_ID}`) && // not already shown
(await followsMe(openedProfileUsername));

if (shouldShowOnProfile) {
const PROFILE_TAB_SWITCH = "pjax:end";
document.addEventListener(PROFILE_TAB_SWITCH, FY.showOnProfilePage);
document.dispatchEvent(new Event(PROFILE_TAB_SWITCH));
FY.showOnProfilePage();
}

// PART 2 --------------------------------------------------
// show on hover card
const callback = async () => {
const userimage = $(`${HOVER_CARD_SELECTOR} .avatar-user`);
if (!userimage) return;
const username = userimage.getAttribute("alt").substring(1); // @username => username
if (await followsMe(username)) {
const hoverCardCallback = async () => {
// already has the label, return
if ($(`#${HOVER_CARD_FOLLOWS_YOU_ID}`)) return;
const userImage = $(`${HOVER_CARD_SELECTOR} .avatar-user`);
const username = userImage?.getAttribute("alt")?.substring(1); // @username => username
if (username && (await followsMe(username))) {
FY.showOnHoverCard();
}
};
const hovercard = $(HOVER_CARD_SELECTOR);
new MutationObserver(callback).observe(hovercard, { attributes: true });
})();

const selectedHoverCard = $(HOVER_CARD_SELECTOR);
new MutationObserver(hoverCardCallback).observe(selectedHoverCard, {
attributes: true,
});
}

document.documentElement.addEventListener("turbo:load", init);
4 changes: 2 additions & 2 deletions manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"manifest_version": 2,
"manifest_version": 3,
"name": "Follows You GitHub",
"version": "0.4.4",
"version": "1.0.0",
"description": "Adds a \"follows you\" label on a GitHub follower profile or hovercard",
"icons": {
"16": "icons/16.png",
Expand Down

0 comments on commit 759c4ce

Please sign in to comment.