From 3ce3f5612802e73de1aca35e2f18fe382da21f9d Mon Sep 17 00:00:00 2001 From: Sunday Ogbonna Date: Wed, 14 Jun 2023 06:39:17 +0100 Subject: [PATCH 1/3] refactor: fix scatter plot tooltip issue --- components/atoms/Avatar/avatar-hover-card.tsx | 47 ++++---- .../molecules/CardProfile/card-profile.tsx | 15 ++- .../contributor-hover-card.tsx | 1 + .../HoverCardWrapper/hover-card-wrapper.tsx | 4 +- .../NivoScatterChart/nivo-scatter-chart.tsx | 102 +++++++++--------- components/organisms/Dashboard/dashboard.tsx | 8 +- 6 files changed, 91 insertions(+), 86 deletions(-) diff --git a/components/atoms/Avatar/avatar-hover-card.tsx b/components/atoms/Avatar/avatar-hover-card.tsx index e028d9bd07..f8376b6856 100644 --- a/components/atoms/Avatar/avatar-hover-card.tsx +++ b/components/atoms/Avatar/avatar-hover-card.tsx @@ -5,37 +5,32 @@ import Link from "next/link"; import HoverCardWrapper from "components/molecules/HoverCardWrapper/hover-card-wrapper"; import { getAvatarByUsername } from "lib/utils/github"; -import roundedImage from "lib/utils/roundedImages"; +import Image from "next/image"; declare interface AvatarProps { contributor: string; repositories: number[]; } -const AvatarHoverCard = ({ contributor, repositories }: AvatarProps): JSX.Element => { - const avatar = roundedImage(getAvatarByUsername(contributor), process.env.NEXT_PUBLIC_CLOUD_NAME); - - return ( - - - - {contributor} - - - - - - - - - - ); -}; +const AvatarHoverCard = ({ contributor, repositories }: AvatarProps): JSX.Element => ( + + + + {contributor} + + + + + + + + +); export default AvatarHoverCard; diff --git a/components/molecules/CardProfile/card-profile.tsx b/components/molecules/CardProfile/card-profile.tsx index ae5ff93fcc..fbdb3f1497 100644 --- a/components/molecules/CardProfile/card-profile.tsx +++ b/components/molecules/CardProfile/card-profile.tsx @@ -14,19 +14,26 @@ interface CardProfileProps { githubName: string; totalPRs: number; dateOfFirstPR: string; + isRoundedAvatar?: boolean; } -const CardProfile = ({ githubAvatar, githubName, totalPRs, dateOfFirstPR }: CardProfileProps): JSX.Element => { +const CardProfile = ({ + githubAvatar, + githubName, + totalPRs, + dateOfFirstPR, + isRoundedAvatar, +}: CardProfileProps): JSX.Element => { return (
- +
{githubName}
-
-
+
+
{totalPRs !== undefined && ( <> diff --git a/components/molecules/ContributorHoverCard/contributor-hover-card.tsx b/components/molecules/ContributorHoverCard/contributor-hover-card.tsx index a8c247d570..10705447f6 100644 --- a/components/molecules/ContributorHoverCard/contributor-hover-card.tsx +++ b/components/molecules/ContributorHoverCard/contributor-hover-card.tsx @@ -40,6 +40,7 @@ const ContributorHoverCard = ({ githubAvatar={githubAvatar} githubName={githubName} totalPRs={totalPR} + isRoundedAvatar={true} />
diff --git a/components/molecules/HoverCardWrapper/hover-card-wrapper.tsx b/components/molecules/HoverCardWrapper/hover-card-wrapper.tsx index 3e513867eb..4fcf9019e4 100644 --- a/components/molecules/HoverCardWrapper/hover-card-wrapper.tsx +++ b/components/molecules/HoverCardWrapper/hover-card-wrapper.tsx @@ -2,9 +2,9 @@ import { useRouter } from "next/router"; import ContributorHoverCard, { ContributorsProfileType } from "../ContributorHoverCard/contributor-hover-card"; -import roundedImage from "lib/utils/roundedImages"; import { useFetchUser } from "lib/hooks/useFetchUser"; import { useContributorPullRequestsChart } from "lib/hooks/useContributorPullRequestsChart"; +import { getAvatarByUsername } from "lib/utils/github"; interface HoverCardWrapperProps { username: string; @@ -18,7 +18,7 @@ const HoverCardWrapper = ({ username, repositories }: HoverCardWrapperProps) => const { repoList } = useContributorPullRequestsChart(username, "*", repositories); const profile: ContributorsProfileType = { - githubAvatar: roundedImage(`https://www.github.com/${username}.png?size=60`, process.env.NEXT_PUBLIC_CLOUD_NAME), + githubAvatar: getAvatarByUsername(username, 40), githubName: username, totalPR: repoList.length, }; diff --git a/components/molecules/NivoScatterChart/nivo-scatter-chart.tsx b/components/molecules/NivoScatterChart/nivo-scatter-chart.tsx index de83f06a57..7ee8d6c084 100644 --- a/components/molecules/NivoScatterChart/nivo-scatter-chart.tsx +++ b/components/molecules/NivoScatterChart/nivo-scatter-chart.tsx @@ -1,16 +1,16 @@ import { useRouter } from "next/router"; import { MouseEvent, useCallback, useState } from "react"; -import { ResponsiveScatterPlot } from "@nivo/scatterplot"; +import { ResponsiveScatterPlot, ScatterPlotNodeProps } from "@nivo/scatterplot"; import { animated } from "@react-spring/web"; import humanizeNumber from "lib/utils/humanizeNumber"; import ToggleOption from "components/atoms/ToggleOption/toggle-option"; import Title from "components/atoms/Typography/title"; -import HoverCardWrapper from "../HoverCardWrapper/hover-card-wrapper"; import ToggleGroup from "components/atoms/ToggleGroup/toggle-group"; import { PrStatusFilter } from "components/organisms/Dashboard/dashboard"; +import AvatarHoverCard from "components/atoms/Avatar/avatar-hover-card"; export interface ScatterChartDataItems { x: string | number; @@ -49,13 +49,52 @@ const NivoScatterPlot = ({ isMobile, repositories, metadata, - handleSetPrFilter + handleSetPrFilter, }: ScatterPlotProps) => { const [showMembers, setShowMembers] = useState(false); const [isLogarithmic, setIsLogarithmic] = useState(false); let functionTimeout: any; + // Brought this in here to have access to repositories + const CustomNode = (props: ScatterPlotNodeProps) => { + const router = useRouter(); + const handleMouseEnter = useCallback( + (event: React.MouseEvent) => props.onMouseEnter?.(props.node, event), + [props.node.data.contributor, props.onMouseEnter] + ); + const handleMouseMove = useCallback( + (event: MouseEvent) => props.onMouseMove?.(props.node, event), + [props.node.data.contributor, props.onMouseMove] + ); + const handleMouseLeave = useCallback( + (event: React.MouseEvent) => props.onMouseLeave?.(props.node, event), + [props.node, props.onMouseLeave] + ); + const handleClick = useCallback( + (event: React.MouseEvent) => router.push(`/user/${props.node.data.contributor}`), + [props.node, props.onClick] + ); + + return ( + size / 2) as unknown as number} + y={props.style.y.to((yVal: number) => yVal - 35 / 1) as unknown as number} + x={props.style.x.to((xVal: number) => xVal - 35 / 2) as unknown as number} + // href={props.node.data.image} + onMouseEnter={props.isInteractive ? handleMouseEnter : undefined} + onMouseMove={props.isInteractive ? handleMouseMove : undefined} + onMouseLeave={props.isInteractive ? handleMouseLeave : undefined} + onClick={props.isInteractive ? handleClick : undefined} + > + + + ); + }; + const handleTogglePrFilter = (val: string) => { switch (val) { case "0": @@ -102,7 +141,7 @@ const NivoScatterPlot = ({ return ( <> -
+
{title} @@ -127,7 +166,7 @@ const NivoScatterPlot = ({ {/* replaced display flex to hidden on show/bots container */} -
+
@@ -142,9 +181,8 @@ const NivoScatterPlot = ({
( - <>{isMobile ? "" : } - )} + // leaving this here for now so we don't see the default tooltip from nivo + tooltip={() => <>} nodeSize={isMobile ? 25 : 35} data={isMobile ? filteredData : data} margin={{ top: 30, right: isMobile ? 30 : 60, bottom: 70, left: isMobile ? 75 : 90 }} @@ -152,7 +190,7 @@ const NivoScatterPlot = ({ yScale={{ type: isLogarithmic ? "symlog" : "linear", min: 0, - max: Math.max(Math.round(maxFilesModified * 3), 10) + max: Math.max(Math.round(maxFilesModified * 3), 10), }} blendMode="normal" useMesh={false} @@ -163,7 +201,7 @@ const NivoScatterPlot = ({ tickPadding: 5, tickRotation: 0, tickValues: isMobile ? 4 : 7, - format: (value) => (value === 0 ? "Today" : value > 32 ? "30+ days ago" : `${value} days ago`) + format: (value) => (value === 0 ? "Today" : value > 32 ? "30+ days ago" : `${value} days ago`), }} theme={{ axis: {}, @@ -171,9 +209,9 @@ const NivoScatterPlot = ({ line: { strokeDasharray: "4 4", strokeWidth: 1, - strokeOpacity: 0.7 - } - } + strokeOpacity: 0.7, + }, + }, }} isInteractive={true} axisLeft={{ @@ -186,7 +224,7 @@ const NivoScatterPlot = ({ legendOffset: -60, format: (value: number) => { return parseInt(`${value}`) >= 1000 ? humanizeNumber(value, "abbreviation") : `${value}`; - } + }, }} />
@@ -194,40 +232,4 @@ const NivoScatterPlot = ({ ); }; -const CustomNode = (props: any) => { - const router = useRouter(); - const handleMouseEnter = useCallback( - (event: React.MouseEvent) => props.onMouseEnter?.(props.node, event), - [props.node.data.contributor, props.onMouseEnter] - ); - const handleMouseMove = useCallback( - (event: MouseEvent) => props.onMouseMove?.(props.node, event), - [props.node.data.contributor, props.onMouseMove] - ); - const handleMouseLeave = useCallback( - (event: React.MouseEvent) => props.onMouseLeave?.(props.node, event), - [props.node, props.onMouseLeave] - ); - const handleClick = useCallback( - (event: React.MouseEvent) => router.push(`/user/${props.node.data.contributor}`), - [props.node, props.onClick] - ); - - return ( - size / 2)} - y={props.style.y.to((yVal: number) => yVal - 35 / 1)} - x={props.style.x.to((xVal: number) => xVal - 35 / 2)} - href={props.node.data.image} - onMouseEnter={props.isInteractive ? handleMouseEnter : undefined} - onMouseMove={props.isInteractive ? handleMouseMove : undefined} - onMouseLeave={props.isInteractive ? handleMouseLeave : undefined} - onClick={props.isInteractive ? handleClick : undefined} - /> - ); -}; - export default NivoScatterPlot; diff --git a/components/organisms/Dashboard/dashboard.tsx b/components/organisms/Dashboard/dashboard.tsx index eb608c6608..1ca3d82637 100644 --- a/components/organisms/Dashboard/dashboard.tsx +++ b/components/organisms/Dashboard/dashboard.tsx @@ -10,9 +10,9 @@ import humanizeNumber from "lib/utils/humanizeNumber"; import { useMediaQuery } from "lib/hooks/useMediaQuery"; import { getInsights, useInsights } from "lib/hooks/api/useInsights"; import { calcDaysFromToday } from "lib/utils/date-utils"; -import roundedImage from "lib/utils/roundedImages"; import usePullRequests from "lib/hooks/api/usePullRequests"; import useContributors from "lib/hooks/api/useContributors"; +import { getAvatarByUsername } from "lib/utils/github"; type ContributorPrMap = { [contributor: string]: DbRepoPR }; export type PrStatusFilter = "open" | "closed" | "all"; @@ -73,7 +73,7 @@ const Dashboard = ({ repositories }: DashboardProps): JSX.Element => { x: calcDaysFromToday(new Date(updated_at)), y: linesCount, contributor: author_login, - image: roundedImage(`https://www.github.com/${author_image}.png?size=60`, process.env.NEXT_PUBLIC_CLOUD_NAME), + image: getAvatarByUsername(author_image, 40), }; return data; }); @@ -92,7 +92,7 @@ const Dashboard = ({ repositories }: DashboardProps): JSX.Element => { return (
-
+
{ isLoading={isLoading} />
-
+
Date: Wed, 14 Jun 2023 07:54:14 +0100 Subject: [PATCH 2/3] refactor: remove redundant code --- .../NivoScatterChart/nivo-scatter-chart.tsx | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/components/molecules/NivoScatterChart/nivo-scatter-chart.tsx b/components/molecules/NivoScatterChart/nivo-scatter-chart.tsx index 7ee8d6c084..19cde4fc0f 100644 --- a/components/molecules/NivoScatterChart/nivo-scatter-chart.tsx +++ b/components/molecules/NivoScatterChart/nivo-scatter-chart.tsx @@ -58,24 +58,6 @@ const NivoScatterPlot = ({ // Brought this in here to have access to repositories const CustomNode = (props: ScatterPlotNodeProps) => { - const router = useRouter(); - const handleMouseEnter = useCallback( - (event: React.MouseEvent) => props.onMouseEnter?.(props.node, event), - [props.node.data.contributor, props.onMouseEnter] - ); - const handleMouseMove = useCallback( - (event: MouseEvent) => props.onMouseMove?.(props.node, event), - [props.node.data.contributor, props.onMouseMove] - ); - const handleMouseLeave = useCallback( - (event: React.MouseEvent) => props.onMouseLeave?.(props.node, event), - [props.node, props.onMouseLeave] - ); - const handleClick = useCallback( - (event: React.MouseEvent) => router.push(`/user/${props.node.data.contributor}`), - [props.node, props.onClick] - ); - return ( size / 2) as unknown as number} y={props.style.y.to((yVal: number) => yVal - 35 / 1) as unknown as number} x={props.style.x.to((xVal: number) => xVal - 35 / 2) as unknown as number} - // href={props.node.data.image} - onMouseEnter={props.isInteractive ? handleMouseEnter : undefined} - onMouseMove={props.isInteractive ? handleMouseMove : undefined} - onMouseLeave={props.isInteractive ? handleMouseLeave : undefined} - onClick={props.isInteractive ? handleClick : undefined} > @@ -182,7 +159,6 @@ const NivoScatterPlot = ({
<>} nodeSize={isMobile ? 25 : 35} data={isMobile ? filteredData : data} margin={{ top: 30, right: isMobile ? 30 : 60, bottom: 70, left: isMobile ? 75 : 90 }} From 2406f9315774f6be2111c75eb491c3e63108ee18 Mon Sep 17 00:00:00 2001 From: Sunday Ogbonna Date: Tue, 20 Jun 2023 13:10:02 +0100 Subject: [PATCH 3/3] remove rounded image lib helper --- lib/utils/roundedImages.ts | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 lib/utils/roundedImages.ts diff --git a/lib/utils/roundedImages.ts b/lib/utils/roundedImages.ts deleted file mode 100644 index 7d75070b1b..0000000000 --- a/lib/utils/roundedImages.ts +++ /dev/null @@ -1,10 +0,0 @@ -// Inspired by https://cloudinary.com/documentation/fetch_remote_images#remote_image_fetch_url -// This is temporary and requires a Cloudinary account's cloud name. -// https://github.com/open-sauced/insights/issues/680 -const roundedImage = (imageUrl: string, cloudName: string | undefined) => { - return cloudName - ? `https://res.cloudinary.com/${cloudName}/image/fetch/c_fill,g_face,h_300,w_300,bo_20px_solid_white,r_max/f_auto,e_shadow/${imageUrl}` - : imageUrl; -}; - -export default roundedImage;