From 5b58dd532ff495fa921053ee1bb48eef2544d678 Mon Sep 17 00:00:00 2001
From: OGBONNA SUNDAY <62995161+OgDev-01@users.noreply.github.com>
Date: Mon, 17 Jul 2023 15:51:02 +0100
Subject: [PATCH 1/3] feat: add top contributors panel to feeds page (#1347)
---
.../top-contributor-card.tsx | 79 +++++++++++++++++++
.../atoms/TopUserCard/top-user-card.tsx | 36 ---------
.../top-contributors-panel.tsx | 32 ++++++++
.../TopUsersPanel/top-user-panel.tsx | 18 -----
lib/hooks/useFetchTopContributors.ts | 20 +++++
lib/hooks/useFollowUser.ts | 7 +-
pages/feed/index.tsx | 5 +-
stories/atoms/top-user-card.stories.tsx | 18 ++---
.../top-contributors-panel.stories.tsx | 16 ++++
stories/molecules/top-users-panel.stories.tsx | 23 ------
10 files changed, 164 insertions(+), 90 deletions(-)
create mode 100644 components/atoms/TopContributorCard/top-contributor-card.tsx
delete mode 100644 components/atoms/TopUserCard/top-user-card.tsx
create mode 100644 components/molecules/TopContributorsPanel/top-contributors-panel.tsx
delete mode 100644 components/molecules/TopUsersPanel/top-user-panel.tsx
create mode 100644 lib/hooks/useFetchTopContributors.ts
create mode 100644 stories/molecules/top-contributors-panel.stories.tsx
delete mode 100644 stories/molecules/top-users-panel.stories.tsx
diff --git a/components/atoms/TopContributorCard/top-contributor-card.tsx b/components/atoms/TopContributorCard/top-contributor-card.tsx
new file mode 100644
index 0000000000..d6fded5a88
--- /dev/null
+++ b/components/atoms/TopContributorCard/top-contributor-card.tsx
@@ -0,0 +1,79 @@
+import React, { useEffect, useState } from "react";
+
+import Link from "next/link";
+import { useRouter } from "next/router";
+import { getAvatarByUsername } from "lib/utils/github";
+import useFollowUser from "lib/hooks/useFollowUser";
+import useSupabaseAuth from "lib/hooks/useSupabaseAuth";
+
+import Avatar from "../Avatar/avatar";
+import Button from "../Button/button";
+
+export interface TopContributorCardProps {
+ login: string;
+}
+
+const TopContributorCard = ({ login }: TopContributorCardProps) => {
+ const router = useRouter();
+ const currentPath = router.asPath;
+
+ const { isError: notFollowing, follow, unFollow } = useFollowUser(login);
+ const [host, setHost] = useState("");
+ const { sessionToken, signIn } = useSupabaseAuth();
+
+ const handleFollowContributor = async () => {
+ try {
+ if (notFollowing) {
+ await follow();
+ return;
+ }
+ await unFollow();
+ } catch (error) {
+ console.log(error);
+ }
+ };
+
+ useEffect(() => {
+ if (typeof window !== "undefined") {
+ setHost(window.location.origin as string);
+ }
+ }, []);
+
+ return (
+
+
+
+
+ {sessionToken && !notFollowing ? (
+
+ ) : (
+
+ )}
+
+ );
+};
+
+export default TopContributorCard;
diff --git a/components/atoms/TopUserCard/top-user-card.tsx b/components/atoms/TopUserCard/top-user-card.tsx
deleted file mode 100644
index 548a6a602f..0000000000
--- a/components/atoms/TopUserCard/top-user-card.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import React from "react";
-import { getAvatarByUsername } from "lib/utils/github";
-import Avatar from "../Avatar/avatar";
-import Button from "../Button/button";
-
-export interface TopUserCardProps {
- clasName?: string;
- following: boolean;
- username: string;
-}
-/**
- *
- * additional props to handle follow button click will be added in future versions
- */
-
-const TopUserCard = ({ username, following }: TopUserCardProps) => {
- return (
-
-
- {following ? (
-
- ) : (
-
- )}
-
- );
-};
-
-export default TopUserCard;
diff --git a/components/molecules/TopContributorsPanel/top-contributors-panel.tsx b/components/molecules/TopContributorsPanel/top-contributors-panel.tsx
new file mode 100644
index 0000000000..bc3e8df227
--- /dev/null
+++ b/components/molecules/TopContributorsPanel/top-contributors-panel.tsx
@@ -0,0 +1,32 @@
+import React from "react";
+import TopContributorCard from "components/atoms/TopContributorCard/top-contributor-card";
+import { useFetchTopContributors } from "lib/hooks/useFetchTopContributors";
+import SkeletonWrapper from "components/atoms/SkeletonLoader/skeleton-wrapper";
+
+interface TopContributorsPanelProps {
+ loggedInUserLogin: string;
+}
+const TopContributorsPanel = ({ loggedInUserLogin }: TopContributorsPanelProps) => {
+ const { data, isLoading } = useFetchTopContributors();
+
+ const topContributorsWithoutLoggedInUser = data ? data.filter((user) => user.login !== loggedInUserLogin) : [];
+ const top3Contributors = topContributorsWithoutLoggedInUser.slice(0, 3).map((user) => user.login);
+
+ return (
+
+
Top Contributors
+
+ {isLoading &&
+ Array.from({ length: 3 }).map((_, i) => (
+
+
+
+ ))}
+ {top3Contributors.map((login, i) => (
+
+ ))}
+
+ );
+};
+
+export default TopContributorsPanel;
diff --git a/components/molecules/TopUsersPanel/top-user-panel.tsx b/components/molecules/TopUsersPanel/top-user-panel.tsx
deleted file mode 100644
index 77d647b813..0000000000
--- a/components/molecules/TopUsersPanel/top-user-panel.tsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from "react";
-import TopUserCard, { TopUserCardProps } from "components/atoms/TopUserCard/top-user-card";
-
-interface TopUsersPanelProps {
- users: TopUserCardProps[];
-}
-const TopUsersPanel = ({ users }: TopUsersPanelProps) => {
- return (
-
-
Top Users
- {users.map((user, i) => (
-
- ))}
-
- );
-};
-
-export default TopUsersPanel;
diff --git a/lib/hooks/useFetchTopContributors.ts b/lib/hooks/useFetchTopContributors.ts
new file mode 100644
index 0000000000..454d4a2150
--- /dev/null
+++ b/lib/hooks/useFetchTopContributors.ts
@@ -0,0 +1,20 @@
+import useSWR, { Fetcher } from "swr";
+import publicApiFetcher from "lib/utils/public-api-fetcher";
+
+type TopContributorsResponse = { login: string }[];
+
+const useFetchTopContributors = () => {
+ const { data, error, mutate } = useSWR(
+ "users/top",
+ publicApiFetcher as Fetcher
+ );
+
+ return {
+ data: data ?? [],
+ isLoading: !error && !data,
+ isError: !!error,
+ mutate,
+ };
+};
+
+export { useFetchTopContributors };
diff --git a/lib/hooks/useFollowUser.ts b/lib/hooks/useFollowUser.ts
index d5395a951e..af2696dbec 100644
--- a/lib/hooks/useFollowUser.ts
+++ b/lib/hooks/useFollowUser.ts
@@ -1,4 +1,4 @@
-import useSWR, { Fetcher } from "swr";
+import useSWR, { Fetcher, useSWRConfig } from "swr";
import publicApiFetcher from "lib/utils/public-api-fetcher";
import useSupabaseAuth from "./useSupabaseAuth";
@@ -6,7 +6,8 @@ interface FollowUserResponse {
data: DbFollowUser;
}
const useFollowUser = (username: string) => {
- const { sessionToken } = useSupabaseAuth();
+ const { sessionToken, user } = useSupabaseAuth();
+ const { mutate: mutateGlobal } = useSWRConfig(); // adding this to mutate the global user data to update the users card status on follow/unfollow
const { data, error, mutate } = useSWR(
username ? `users/${username}/follow` : null,
@@ -23,6 +24,7 @@ const useFollowUser = (username: string) => {
if (req && req.ok) {
mutate();
+ mutateGlobal(`user/${user?.user_metadata?.username}`);
}
};
@@ -36,6 +38,7 @@ const useFollowUser = (username: string) => {
if (req && req.ok) {
mutate();
+ mutateGlobal(`user/${user?.user_metadata?.username}`);
}
};
diff --git a/pages/feed/index.tsx b/pages/feed/index.tsx
index 8b1e0dc2fe..85fe04d9ee 100644
--- a/pages/feed/index.tsx
+++ b/pages/feed/index.tsx
@@ -4,6 +4,7 @@ import Link from "next/link";
import formatDistanceToNowStrict from "date-fns/formatDistanceToNowStrict";
import clsx from "clsx";
+import TopContributorsPanel from "components/molecules/TopContributorsPanel/top-contributors-panel";
import useSupabaseAuth from "lib/hooks/useSupabaseAuth";
import { useFetchAllHighlights } from "lib/hooks/useFetchAllHighlights";
import { useFetchHighlightRepos } from "lib/hooks/useFetchHiglightRepos";
@@ -68,6 +69,7 @@ const Feeds: WithPageLayout = (props: HighlightSSRProps) => {
const { data, mutate, setPage, isLoading, meta } = useFetchAllHighlights(selectedRepo);
const { data: emojis } = useFetchAllEmojis();
+
const { data: loggedInUser, isLoading: loggedInUserLoading } = useFetchUser(user?.user_metadata.user_name as string);
const { followers_count, following_count, highlights_count } = loggedInUser || {};
@@ -121,7 +123,7 @@ const Feeds: WithPageLayout = (props: HighlightSSRProps) => {
twitterCard="summary_large_image"
/>
-
+
{user && (
= (props: HighlightSSRProps) => {
/>
)}
+
{singleHighlight && (