Skip to content

Commit

Permalink
feat: add PR velocity to profile page (#111)
Browse files Browse the repository at this point in the history
* add date-fns library for proper date calculations

* add getRelativeDays as a new date util

* fetch PR data and calculate user PR Velocity

* add PR velocity in profile page

* remove getContributorPullRequestVelocity from fetchOpenSaucedApiData.ts

* add IUserPR type for PR API responses

* add getUserPRVelocity utility function

* use getUserPRVelocity function in the profile page

* export IUserPR from types
  • Loading branch information
Nanak360 committed May 25, 2023
1 parent 3bac76b commit ba7fad6
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 6 deletions.
20 changes: 17 additions & 3 deletions npm-shrinkwrap.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"dependencies": {
"@types/chrome": "^0.0.231",
"@types/node-emoji": "^1.8.2",
"date-fns": "^2.30.0",
"gpt-tokenizer": "^1.0.5",
"node-emoji": "^1.11.0",
"react": "^18.0.0",
Expand Down
10 changes: 8 additions & 2 deletions src/pages/profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import OpenSaucedLogo from "../assets/opensauced-logo.svg";
import { getUserData, getUserPRData, getUserHighlightsData } from "../utils/fetchOpenSaucedApiData";
import { emojify } from "node-emoji";
import { goBack } from "react-chrome-extension-router";
import { getRelativeDays } from "../utils/dateUtils";
import { getUserPRVelocity } from "../utils/getUserPRVelocity";

const interestIcon = {
python: <SiPython />,
Expand All @@ -28,10 +30,11 @@ const interestIcon = {

type InterestIconKeys = keyof typeof interestIcon;

export const Profile = ({ username }: {username: string}) => {
export const Profile = ({ username }: { username: string }) => {
const [user, setUser] = useState<null | { id: string, user_name: string, bio: string, created_at: string, linkedin_url: string, twitter_username: string, blog: string, interests: string, open_issues: number }>(null);
const [userPR, setUserPR] = useState<null | { meta: { itemCount: number } }>(null);
const [userHighlights, setUserHighlights] = useState<null | { meta: { itemCount: number } }>(null);
const [userPRVelocity, setUserPRVelocity] = useState<number>(0);

useEffect(() => {
const fetchUserData = async () => {
Expand All @@ -40,6 +43,7 @@ export const Profile = ({ username }: {username: string}) => {
setUser(userData);
setUserPR(userPRData);
setUserHighlights(userHighlightsData);
setUserPRVelocity(getUserPRVelocity(userPRData?.data || []));
};

void fetchUserData();
Expand Down Expand Up @@ -163,7 +167,9 @@ export const Profile = ({ username }: {username: string}) => {
<div className="flex flex-col items-center justify-center p-2 text-xs">
<p>Avg PRs Velocity</p>

<p className="font-medium text-5xl">-</p>
<p className="font-medium text-5xl">
{getRelativeDays(userPRVelocity)}
</p>
</div>

<div className="flex flex-col items-center justify-center p-2 text-xs">
Expand Down
19 changes: 19 additions & 0 deletions src/ts/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export interface IUserPR {
readonly title: string;
readonly author_login: string;
readonly state: string;
readonly created_at: string;
readonly closed_at: string;
readonly merged_at: string;
readonly updated_at: string;
readonly filesCount: number;
linesCount: number;
readonly merged: boolean;
readonly draft: boolean;
readonly full_name: string;
readonly number: number;
readonly additions: number;
readonly deletions: number;
readonly changed_files: number;
readonly repo_id: number;
}
15 changes: 15 additions & 0 deletions src/utils/dateUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export const getRelativeDays = (days: number) => {
if (days === 0) {
return "-";
}

if (days >= 365) {
return `${Math.floor(days / 365)}y`;
}

if (days > 30 && days < 365) {
return `${Math.floor(days / 30)}mo`;
}

return `${days}d`;
};
8 changes: 7 additions & 1 deletion src/utils/fetchOpenSaucedApiData.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import differenceInDays from "date-fns/differenceInDays";
import { cachedFetch } from "./cache";
import { OPEN_SAUCED_USERS_ENDPOINT, OPEN_SAUCED_SESSION_ENDPOINT, OPEN_SAUCED_REPOS_ENDPOINT, OPEN_SAUCED_USER_INSIGHTS_ENDPOINT } from "../constants";
import {
OPEN_SAUCED_USERS_ENDPOINT,
OPEN_SAUCED_SESSION_ENDPOINT,
OPEN_SAUCED_REPOS_ENDPOINT,
OPEN_SAUCED_USER_INSIGHTS_ENDPOINT,
} from "../constants";
import { IInsight } from "../ts/InsightDto";

export const isOpenSaucedUser = async (username: string) => {
Expand Down
16 changes: 16 additions & 0 deletions src/utils/getUserPRVelocity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { differenceInDays } from "date-fns";
import { IUserPR } from "../ts/types";

export const getUserPRVelocity = ((prDetails: IUserPR[]) => {
const mergedPRs = prDetails.filter((prState: IUserPR) => prState.state.toLowerCase() === "merged");

const totalDays = mergedPRs.reduce((total: number, pr: IUserPR) => {
const daysBetween = differenceInDays(new Date(pr.closed_at), new Date(pr.created_at));

return (total += daysBetween);
}, 0);

const averageVelocity: number = mergedPRs.length > 0 ? Math.round(totalDays / mergedPRs.length) : 0;

return averageVelocity;
});

0 comments on commit ba7fad6

Please sign in to comment.