From de48f0d2e73181ac48a78e0c4df37e9a2c68ecc2 Mon Sep 17 00:00:00 2001 From: IgboPharaoh Date: Fri, 10 Nov 2023 06:53:52 +0100 Subject: [PATCH 01/17] update meta information --- src/app/layout.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 77aeee7..3c8c7bb 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -28,6 +28,13 @@ export const metadata: Metadata = { card: "summary", creator: "@chaincodelabs", images: ["https://ghstats.bitcoinsearch.xyz/images/bitcoin-dev-og.png"] + }, + metadataBase: new URL("https://ghstats.bitcoinsearch.xyz"), + alternates: { + canonical: "/", + languages: { + "en-US": "/en-US" + } } } From 215e6de1e288837e42c01d1277ce7b014c697392 Mon Sep 17 00:00:00 2001 From: IgboPharaoh Date: Fri, 10 Nov 2023 06:55:36 +0100 Subject: [PATCH 02/17] update type definitions --- src/types/comments.ts | 27 +++++++++++++++++++++++---- src/types/index.ts | 14 ++++++++++++++ src/types/pull_requests.ts | 28 ++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 4 deletions(-) diff --git a/src/types/comments.ts b/src/types/comments.ts index e5e881a..16677d3 100644 --- a/src/types/comments.ts +++ b/src/types/comments.ts @@ -1,3 +1,25 @@ +import { PageInfo, Repository } from '.' + +export type IssueCommentDataType = { + issueComments: IssueComments +} + +export type IssueComments = { + pageInfo: PageInfo + nodes: Array +} + +export type IssueCommentNodes = { + issue: Issue + body: string + repository: Repository + url: string + createdAt: string + author: { + login: string + } +} + export type Comment = { issue: Issue body: string @@ -7,7 +29,6 @@ export type Comment = { project: { login: string; avatarUrl: string } } - export type IssuesObject = { ownIssueComments: Comment[] longIssueComments: Comment[] @@ -19,7 +40,5 @@ export type Issue = { login: string avatarUrl: string } - comments: { - totalCount: number - } + comments: { totalCount: number } } diff --git a/src/types/index.ts b/src/types/index.ts index 6a317a0..c8dba76 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -3,6 +3,20 @@ export type Contributions = Record< Record> > +export type PageInfo = { + hasNextPage: boolean + startCursor: string + endCursor: string +} + +export type Repository = { + url: string + owner: { + login: string + avatarUrl: string + } +} + export type GridSet = { month: string boxes: Array<{ day: number; is_active: boolean }> diff --git a/src/types/pull_requests.ts b/src/types/pull_requests.ts index ceada8c..d1c00f4 100644 --- a/src/types/pull_requests.ts +++ b/src/types/pull_requests.ts @@ -1,3 +1,31 @@ +import { PageInfo, Repository } from "." + +export type PrDataType = { + contributionsCollection: { + contributionYears: Array + pullRequestContributions: { + pageInfo: PageInfo + nodes: Array + } + } +} + +export type PrNodes = { + pullRequest: { + author: { avatarUrl: string } + closed: boolean + closedAt: string + createdAt: string + merged: boolean + mergedAt: string + mergedBy: { login: string } + repository: Repository + title: string + totalCommentsCount: number + url: string + } +} + export type PR = { totalComments: number daysOpened: number From d08c3a5864123c0ccc87e3f5e5a0bf741cfc18d1 Mon Sep 17 00:00:00 2001 From: IgboPharaoh Date: Fri, 10 Nov 2023 06:56:21 +0100 Subject: [PATCH 03/17] update graphql queries --- src/graphql/queries.ts | 76 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/src/graphql/queries.ts b/src/graphql/queries.ts index 4250d61..58f4d1e 100644 --- a/src/graphql/queries.ts +++ b/src/graphql/queries.ts @@ -64,3 +64,79 @@ query ($username: String!){ } } ` + +export const FETCH_RANGED_PRS = `query contributions($username: String!, $startDate: DateTime!, $endDate: DateTime!, $endCursor: String) { + user(login: $username) { + contributionsCollection(from: $startDate, to: $endDate) { + contributionYears + pullRequestContributions(first: 100, after: $endCursor){ + pageInfo{ + hasNextPage + startCursor + endCursor + } + nodes { + pullRequest { + title + repository { + url + owner { + login + avatarUrl + } + } + author { + avatarUrl + } + totalCommentsCount + merged + mergedAt + closed + url + closedAt + createdAt + mergedBy { + login + } + } + } + } + } + } +}` + +export const FETCH_RANGED_COMMENTS = `query ($username: String!) { + user(login: $username) { + issueComments(last: 100) { + pageInfo { + hasNextPage + startCursor + endCursor + } + nodes { + issue { + author { + login + avatarUrl + } + comments(orderBy: {field: UPDATED_AT, direction: ASC}) { + totalCount + } + } + body + repository { + url + owner { + login + avatarUrl + } + } + url + createdAt + author { + login + } + } + } + } +}` From 9f8a131caebf2a192388114a18ed2bf194c09ff4 Mon Sep 17 00:00:00 2001 From: IgboPharaoh Date: Fri, 10 Nov 2023 06:57:17 +0100 Subject: [PATCH 04/17] add new utils for data fetching --- src/helpers/get-contribution-years.ts | 71 ++++++++++++ src/helpers/get-issues-data.ts | 91 ++++++++++++++++ src/helpers/get-prs-data.ts | 95 ++++++++++++++++ src/helpers/get-pull-requests.ts | 150 ++++++++++++++------------ src/helpers/utils.ts | 87 +++++---------- 5 files changed, 360 insertions(+), 134 deletions(-) create mode 100644 src/helpers/get-contribution-years.ts create mode 100644 src/helpers/get-issues-data.ts create mode 100644 src/helpers/get-prs-data.ts diff --git a/src/helpers/get-contribution-years.ts b/src/helpers/get-contribution-years.ts new file mode 100644 index 0000000..99d7468 --- /dev/null +++ b/src/helpers/get-contribution-years.ts @@ -0,0 +1,71 @@ +import { FETCH_RANGED_PRS } from "@/graphql/queries" +import { PrDataType } from "@/types/pull_requests" + +export async function getContributionYears({ + username, + token, + query, + startDate, + endDate +}: { + username: string + token?: string + query: "FETCH_RANGED_PRS" + startDate?: string + endDate?: string +}) { + const tokenFromEnv = process.env.GITHUB_TOKEN + + let graphqlQuery = "" + switch (query) { + case "FETCH_RANGED_PRS": + graphqlQuery = FETCH_RANGED_PRS + break + default: + throw new Error("Invalid query") + } + + try { + const res = await fetch("https://api.github.com/graphql", { + method: "POST", + headers: { + Authorization: `Bearer ${token ?? tokenFromEnv}`, + "Content-Type": "application/json" + }, + body: JSON.stringify({ + query: graphqlQuery, + variables: { + username, + startDate, + endDate + } + }) + }) + + if (!res.ok) { + console.log("res", res) + return { error: res.statusText, message: "Failed to fetch API" } + } + + const data = await res.json() + const jsonData: PrDataType = data.data.user + + const contributionYears = + jsonData?.contributionsCollection.contributionYears + + if (data.errors) { + return { error: data.errors, message: "Failed to fetch API" } + } + + return { + data: contributionYears, + error: null + } + } catch (error) { + console.log(error) + return { + error: error, + message: "Failed to fetch API" + } + } +} diff --git a/src/helpers/get-issues-data.ts b/src/helpers/get-issues-data.ts new file mode 100644 index 0000000..b11fc4c --- /dev/null +++ b/src/helpers/get-issues-data.ts @@ -0,0 +1,91 @@ +import { FETCH_RANGED_COMMENTS } from "@/graphql/queries" +import { IssueCommentDataType, IssueComments } from "@/types/comments" + +export async function getIssueCommentsData({ + username, + token, + query, + startDate +}: { + username: string + token?: string + query: "FETCH_RANGED_COMMENTS" + startDate?: string +}) { + const tokenFromEnv = process.env.GITHUB_TOKEN + + let graphqlQuery = "" + switch (query) { + case "FETCH_RANGED_COMMENTS": + graphqlQuery = FETCH_RANGED_COMMENTS + break + default: + throw new Error("Invalid query") + } + + try { + const res = await fetch("https://api.github.com/graphql", { + method: "POST", + headers: { + Authorization: `Bearer ${token ?? tokenFromEnv}`, + "Content-Type": "application/json" + }, + body: JSON.stringify({ + query: graphqlQuery, + variables: { + username + } + }) + }) + + if (!res.ok) { + return { error: res.statusText, message: "Failed to fetch API" } + } + + const data = await res.json() + const jsonData: IssueCommentDataType = data.data.user + + let result: Partial = {} + let nodesResult = "" + let yearlyResult: any = {} + + const hasNextPage = jsonData?.issueComments?.pageInfo?.hasNextPage + + if (hasNextPage === false) { + for (const [key, value] of Object.entries( + jsonData?.issueComments + )) { + if (key === "nodes" && Array.isArray(value)) { + yearlyResult[key] = value.filter( + (node) => + node.createdAt.slice(0, 4) === + // "2023" + startDate?.slice(0, 4) + ) + } else { + yearlyResult[key] = value + } + } + + return yearlyResult as IssueComments + } else { + for (const [key, value] of Object.entries(jsonData.issueComments)) { + } + } + + if (data.errors) { + return { error: data.errors, message: "Failed to fetch API" } + } + + return { + data: data.data.user, + error: null + } + } catch (error) { + console.log(error) + return { + error: error, + message: "Failed to fetch API" + } + } +} diff --git a/src/helpers/get-prs-data.ts b/src/helpers/get-prs-data.ts new file mode 100644 index 0000000..9e468db --- /dev/null +++ b/src/helpers/get-prs-data.ts @@ -0,0 +1,95 @@ +import { FETCH_RANGED_PRS } from "@/graphql/queries" +import { PrDataType, PrNodes } from "@/types/pull_requests" + +export async function getGithubPrsData({ + username, + token, + query, + startDate, + endDate +}: { + username: string + token?: string + query: "FETCH_RANGED_PRS" + startDate?: string + endDate?: string +}) { + const tokenFromEnv = process.env.GITHUB_TOKEN + + let graphqlQuery = "" + switch (query) { + case "FETCH_RANGED_PRS": + graphqlQuery = FETCH_RANGED_PRS + break + default: + throw new Error("Invalid query") + } + + let hasNextPage = true + let allPrs: Array = [] + let endCursor = null + + while (hasNextPage) { + try { + const res = await fetch("https://api.github.com/graphql", { + method: "POST", + headers: { + Authorization: `Bearer ${token ?? tokenFromEnv}`, + "Content-Type": "application/json" + }, + body: JSON.stringify({ + query: graphqlQuery, + variables: { + username, + startDate, + endDate, + endCursor + } + }) + }) + + if (!res.ok) { + return { error: res.statusText, message: "Failed to fetch API" } + } + + const data = await res.json() + const jsonData: PrDataType = data.data.user + + const isNextPage = + jsonData?.contributionsCollection?.pullRequestContributions + ?.pageInfo.hasNextPage + + const nodes_data = + jsonData?.contributionsCollection?.pullRequestContributions + .nodes + + const next_batch = + jsonData?.contributionsCollection?.pullRequestContributions + ?.pageInfo?.endCursor + + allPrs.push(...nodes_data) + hasNextPage = isNextPage + endCursor = next_batch + + if (data.errors) { + return { error: data.errors, message: "Failed to fetch API" } + } + } catch (error) { + console.log(error) + return { + error: error, + message: "Failed to fetch API" + } + } + } + + allPrs + .sort( + (a, b) => + new Date(a?.pullRequest.createdAt).getTime() - + new Date(b?.pullRequest.createdAt).getTime() + ) + .filter((x) => x?.pullRequest !== undefined) + + return { data: allPrs, error: null } +} diff --git a/src/helpers/get-pull-requests.ts b/src/helpers/get-pull-requests.ts index e7b591b..1828727 100644 --- a/src/helpers/get-pull-requests.ts +++ b/src/helpers/get-pull-requests.ts @@ -1,123 +1,131 @@ import { CURRENT_DAY, DAYS_TO_INACTIVE, ONE_DAY } from "@/config" -import { PullRequests, PR } from "../types/pull_requests" +import { PullRequests, PR, PrNodes } from "../types/pull_requests" export const getPullRequests = ({ data, username }: { - data: any + data: PrNodes[] username: string }): PullRequests => { - const openPRsData = data.pullRequests.edges.filter( - (pr: any) => pr.node.closed === false - ) - const openPRs: PR[] = openPRsData.map((pr: any) => ({ - totalComments: pr.node.totalCommentsCount, + data = data?.filter((x) => x?.pullRequest !== undefined) + + const openPRsData = data?.filter((pr) => pr?.pullRequest?.closed === false) + + const openPRs: PR[] = openPRsData?.map((pr) => ({ + totalComments: pr?.pullRequest?.totalCommentsCount, daysOpened: Math.floor( - (CURRENT_DAY - new Date(pr.node.createdAt).getTime()) / ONE_DAY + (CURRENT_DAY - new Date(pr?.pullRequest?.createdAt).getTime()) / + ONE_DAY ), - url: pr.node.url, - repoUrl: pr.node.repository.url, - title: pr.node.title, - createdAt: pr.node.createdAt, - avatarUrl: pr.node.author.avatarUrl, - project: pr.node.repository.owner + url: pr?.pullRequest?.url, + repoUrl: pr?.pullRequest?.repository.url, + title: pr?.pullRequest?.title, + createdAt: pr?.pullRequest?.createdAt, + avatarUrl: pr?.pullRequest?.author.avatarUrl, + project: pr?.pullRequest?.repository.owner })) - const openInactivePRsData = openPRsData.filter( - (pr: any) => + const openInactivePRsData = openPRsData?.filter( + (pr) => Math.floor( - (CURRENT_DAY - new Date(pr.node.createdAt).getTime()) / ONE_DAY + (CURRENT_DAY - new Date(pr?.pullRequest.createdAt).getTime()) / + ONE_DAY ) > DAYS_TO_INACTIVE ) - const openInactivePRs: PR[] = openInactivePRsData.map((pr: any) => ({ - totalComments: pr.node.totalCommentsCount, + + const openInactivePRs: PR[] = openInactivePRsData?.map((pr) => ({ + totalComments: pr?.pullRequest?.totalCommentsCount, daysOpened: Math.floor( - (CURRENT_DAY - new Date(pr.node.createdAt).getTime()) / ONE_DAY + (CURRENT_DAY - new Date(pr?.pullRequest?.createdAt).getTime()) / + ONE_DAY ), - url: pr.node.url, - repoUrl: pr.node.repository.url, - title: pr.node.title, - createdAt: pr.node.createdAt, - avatarUrl: pr.node.author.avatarUrl, - project: pr.node.repository.owner + url: pr?.pullRequest?.url, + repoUrl: pr?.pullRequest?.repository.url, + title: pr?.pullRequest?.title, + createdAt: pr?.pullRequest?.createdAt, + avatarUrl: pr?.pullRequest?.author.avatarUrl, + project: pr?.pullRequest?.repository.owner })) - const closedPRsData = data.pullRequests.edges.filter( - (pr: any) => pr.node.closed === true && pr.node.merged === false + const closedPRsData = data?.filter( + (pr) => + pr?.pullRequest?.closed === true && + pr?.pullRequest?.merged === false ) - const closedPRs: PR[] = closedPRsData.map((pr: any) => ({ - totalComments: pr.node.totalCommentsCount, + + const closedPRs: PR[] = closedPRsData?.map((pr) => ({ + totalComments: pr?.pullRequest?.totalCommentsCount, daysOpened: Math.floor( - (new Date(pr.node.closedAt).getTime() - - new Date(pr.node.createdAt).getTime()) / + (new Date(pr?.pullRequest?.closedAt).getTime() - + new Date(pr?.pullRequest?.createdAt).getTime()) / ONE_DAY ), - url: pr.node.url, - repoUrl: pr.node.repository.url, - title: pr.node.title, - createdAt: pr.node.createdAt, - avatarUrl: pr.node.author.avatarUrl, - project: pr.node.repository.owner + url: pr?.pullRequest?.url, + repoUrl: pr?.pullRequest?.repository.url, + title: pr?.pullRequest?.title, + createdAt: pr?.pullRequest?.createdAt, + avatarUrl: pr?.pullRequest?.author.avatarUrl, + project: pr?.pullRequest?.repository.owner })) - const closedPRsByOthersData = data.pullRequests.edges.filter( - (pr: any) => - pr.node.closed === true && - pr.node.merged === true && - pr.node.mergedBy.login !== username + const closedPRsByOthersData = data?.filter( + (pr) => + pr?.pullRequest?.closed === true && + pr?.pullRequest?.merged === true && + pr?.pullRequest?.mergedBy.login !== username ) - const closedPRsByOthers: PR[] = closedPRsByOthersData.map((pr: any) => ({ - totalComments: pr.node.totalCommentsCount, + + const closedPRsByOthers: PR[] = closedPRsByOthersData?.map((pr) => ({ + totalComments: pr?.pullRequest?.totalCommentsCount, daysOpened: Math.floor( - (new Date(pr.node.closedAt).getTime() - - new Date(pr.node.createdAt).getTime()) / + (new Date(pr?.pullRequest?.closedAt).getTime() - + new Date(pr?.pullRequest?.createdAt).getTime()) / ONE_DAY ), - url: pr.node.url, - repoUrl: pr.node.repository.url, - title: pr.node.title, - createdAt: pr.node.createdAt, - avatarUrl: pr.node.author.avatarUrl, - project: pr.node.repository.owner + url: pr?.pullRequest?.url, + repoUrl: pr?.pullRequest?.repository.url, + title: pr?.pullRequest?.title, + createdAt: pr?.pullRequest?.createdAt, + avatarUrl: pr?.pullRequest?.author.avatarUrl, + project: pr?.pullRequest?.repository.owner })) - const mergedPRData = data.pullRequests.edges.filter( - (pr: any) => pr.node.merged === true - ) - const mergedPRs: PR[] = mergedPRData.map((pr: any) => ({ - totalComments: pr.node.totalCommentsCount, + const mergedPRData = data?.filter((pr) => pr?.pullRequest?.merged === true) + + const mergedPRs: PR[] = mergedPRData?.map((pr) => ({ + totalComments: pr?.pullRequest?.totalCommentsCount, daysOpened: Math.floor( - (new Date(pr.node.mergedAt).getTime() - - new Date(pr.node.createdAt).getTime()) / + (new Date(pr?.pullRequest?.mergedAt).getTime() - + new Date(pr?.pullRequest?.createdAt).getTime()) / ONE_DAY ), - url: pr.node.url, - repoUrl: pr.node.repository.url, - title: pr.node.title, - createdAt: pr.node.createdAt, - avatarUrl: pr.node.author.avatarUrl, - project: pr.node.repository.owner + url: pr?.pullRequest?.url, + repoUrl: pr?.pullRequest?.repository.url, + title: pr?.pullRequest?.title, + createdAt: pr?.pullRequest?.createdAt, + avatarUrl: pr?.pullRequest?.author.avatarUrl, + project: pr?.pullRequest?.repository.owner })) - openPRs.sort( + openPRs?.sort( (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime() ) - openInactivePRs.sort( + openInactivePRs?.sort( (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime() ) - closedPRs.sort( + closedPRs?.sort( (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime() ) - closedPRsByOthers.sort( + closedPRsByOthers?.sort( (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime() ) - mergedPRs.sort( + mergedPRs?.sort( (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime() ) diff --git a/src/helpers/utils.ts b/src/helpers/utils.ts index f4cb415..92da27c 100644 --- a/src/helpers/utils.ts +++ b/src/helpers/utils.ts @@ -8,7 +8,7 @@ import { GRID_YELLOW } from "@/types" import { Comment, IssuesObject } from "@/types/comments" -import { Project, PRsObject } from "@/types/pull_requests" +import { PrNodes, Project, PRsObject } from "@/types/pull_requests" export const getIssueNumber = (arg: string) => { const splitUrl = arg.split("#") @@ -42,19 +42,19 @@ export const collapsibleHeader = (repoUrl: string, username: string) => { } export const getOrganisations = ( - prsData: any, + prsData: PrNodes[], issueData: any, username: string ) => { - const prOrgs: Array = prsData?.pullRequests?.edges - .filter( - (pr: any) => - pr.node.repository.owner.login.toLowerCase() !== - username.toLowerCase() + const prOrgs: Array = prsData + ?.filter( + (pr) => + pr?.pullRequest?.repository.owner.login.toLowerCase() !== + username.toLowerCase() && pr?.pullRequest !== undefined ) - .map((pr: any) => ({ - login: pr.node.repository.owner.login, - avatarUrl: pr.node.repository.owner.avatarUrl + .map((pr) => ({ + login: pr?.pullRequest?.repository.owner.login, + avatarUrl: pr?.pullRequest?.repository.owner.avatarUrl })) const issueOrgs: Array = issueData?.issueComments?.nodes @@ -96,7 +96,6 @@ export const extractYears = (prsData: PRsObject, issueData: IssuesObject) => { export function filterObject }>( toggleFilter: string | null, - yearlyFilter: string, toolTipKey: string | null, data: Type ): Type { @@ -111,10 +110,7 @@ export function filterObject }>( .slice(1, 3) .join(" ") - return ( - x.createdAt.toString().slice(0, 4) === yearlyFilter && - result_date === toolTipKey - ) + return result_date === toolTipKey }) if (toggleFilter) { @@ -127,8 +123,6 @@ export function filterObject }>( .join(" ") return ( - x.createdAt.toString().slice(0, 4) === - yearlyFilter && result_date === toolTipKey && x.project?.login?.toLowerCase() === toggleFilter?.toLowerCase() @@ -148,30 +142,6 @@ export function filterObject }>( x.project?.login?.toLowerCase() === toggleFilter?.toLowerCase() ) - - if (yearlyFilter) { - for (const [key, value] of Object.entries( - filteredObject as Type - )) { - filteredObject[key] = value.filter( - (x) => - x.createdAt.toString().slice(0, 4) === - yearlyFilter && - x.project?.login?.toLowerCase() === - toggleFilter?.toLowerCase() - ) - } - } - } - - return filteredObject - } - - if (yearlyFilter) { - for (const [key, value] of Object.entries(data)) { - filteredObject[key] = value.filter( - (x) => x.createdAt.toString().slice(0, 4) === yearlyFilter - ) } return filteredObject @@ -198,7 +168,6 @@ export const months = [ const days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] export const getYearlyContributions = ( - year: string, prsData: PRsObject, issueData: IssuesObject ) => { @@ -210,31 +179,23 @@ export const getYearlyContributions = ( const extractPrDates = Object.values(prsData) .map((set) => { - return set - .filter( - (item) => item.createdAt.toString().slice(0, 4) === year - ) - .map((x) => { - return { - date: new Date(x.createdAt).toDateString(), - type: "prs" - } - }) + return set.map((x) => { + return { + date: new Date(x.createdAt).toDateString(), + type: "prs" + } + }) }) .flat() const extractIssueDates = Object.values(issueData) .map((set) => { - return set - .filter( - (item) => item.createdAt.toString().slice(0, 4) === year - ) - .map((x) => { - return { - date: new Date(x.createdAt).toDateString(), - type: "issues" - } - }) + return set.map((x) => { + return { + date: new Date(x.createdAt).toDateString(), + type: "issues" + } + }) }) .flat() @@ -280,7 +241,7 @@ export const getYearlyContributions = ( }) } - return { year, contributions } + return { contributions } } export const createGridSet = (year: string) => { From 76aa93cb27b0ef1d8bc7262cf25def04f129d8d0 Mon Sep 17 00:00:00 2001 From: IgboPharaoh Date: Fri, 10 Nov 2023 06:58:15 +0100 Subject: [PATCH 05/17] update data fetching for prs by years --- src/app/components/search/action.ts | 42 ++++++++++++++++++++++-- src/hooks/useGithubIssues.ts | 50 +++++++++++++++++------------ 2 files changed, 70 insertions(+), 22 deletions(-) diff --git a/src/app/components/search/action.ts b/src/app/components/search/action.ts index da9095f..1355688 100644 --- a/src/app/components/search/action.ts +++ b/src/app/components/search/action.ts @@ -1,9 +1,20 @@ "use server" import { auth } from "@/auth" +import { getContributionYears } from "@/helpers/get-contribution-years" import { getGithubData } from "@/helpers/get-github-data" +import { getIssueCommentsData } from "@/helpers/get-issues-data" +import { getGithubPrsData } from "@/helpers/get-prs-data" -export const fetchIssues = async ({ username }: { username: string }) => { +export const fetchIssues = async ({ + username, + startDate, + endDate +}: { + username: string + startDate?: string + endDate?: string +}) => { const session = await auth() const token = session?.accessToken @@ -17,10 +28,37 @@ export const fetchIssues = async ({ username }: { username: string }) => { username, token, query: "PULL_REQUESTS" + }), + getContributionYears({ + username, + token, + query: "FETCH_RANGED_PRS", + startDate, + endDate + }) + ]) + + const ranged_response = await Promise.all([ + getGithubPrsData({ + username, + token, + query: "FETCH_RANGED_PRS", + startDate, + endDate + }), + getIssueCommentsData({ + username, + token, + query: "FETCH_RANGED_COMMENTS", + startDate }) ]) const issues = res[0] const prs = res[1] - return { issues, prs } + const years = res[2] + const ranged_prs = ranged_response[0] + const ranged_issues = ranged_response[1] + + return { issues, prs, years, ranged_prs, ranged_issues } } diff --git a/src/hooks/useGithubIssues.ts b/src/hooks/useGithubIssues.ts index aa29032..780cdb1 100644 --- a/src/hooks/useGithubIssues.ts +++ b/src/hooks/useGithubIssues.ts @@ -30,6 +30,7 @@ export const useGithubIssues = () => { const [error, setError] = useState(null) const [projects, setProjects] = useState>([]) const [toggleFilter, setToggleFilter] = useState("") + const [years, setYears] = useState>([]) const [yearlyFilter, setYearlyFilter] = useState(currentYear) const [toolTipKey, setToolTipKey] = useState("") const [issuesObject, setIssuesObject] = useState({ @@ -45,6 +46,9 @@ export const useGithubIssues = () => { mergedPrs: [] }) + const startDate = new Date(Number(yearlyFilter), 0, 1, 4).toISOString() + const endDate = new Date(Number(yearlyFilter), 12, 0, 4).toISOString() + useEffect(() => { const fetchGithubIssues = async () => { if (!username) { @@ -69,15 +73,20 @@ export const useGithubIssues = () => { mergedPrs: [] })) setProjects([]) - const { issues, prs } = await fetchIssues({ - username: username as string - }) + setYears([]) + const { issues, prs, ranged_prs, ranged_issues, years } = + await fetchIssues({ + username: username as string, + startDate, + endDate + }) setLoading(false) if (issues.error || prs.error) { console.error(issues.error, "error") setError(issues.error[0].message || prs.error[0].message) + setLoading(false) return } @@ -92,6 +101,7 @@ export const useGithubIssues = () => { data: issues.data, username: username as string }) + const { closedPRs, closedPRsByOthers, @@ -99,12 +109,17 @@ export const useGithubIssues = () => { openInactivePRs, openPRs } = getPullRequests({ - data: prs.data, + data: ranged_prs.data!, username: username as string }) - const { orgs } = getOrganisations(prs.data, issues.data, username) + const { orgs } = getOrganisations( + ranged_prs?.data!, + issues.data, + username + ) setProjects(orgs) + setYears(years.data!) setIssuesObject((prev) => ({ ...prev, @@ -124,26 +139,19 @@ export const useGithubIssues = () => { } fetchGithubIssues() - }, [username]) + }, [endDate, startDate, username]) const memoizedIssues = useMemo( - () => - filterObject(toggleFilter, yearlyFilter, toolTipKey, issuesObject), - [issuesObject, toggleFilter, toolTipKey, yearlyFilter] + () => filterObject(toggleFilter, toolTipKey, issuesObject), + [issuesObject, toggleFilter, toolTipKey] ) const memoizedPrs = useMemo( - () => filterObject(toggleFilter, yearlyFilter, toolTipKey, prsObject), - [prsObject, toggleFilter, toolTipKey, yearlyFilter] + () => filterObject(toggleFilter, toolTipKey, prsObject), + [prsObject, toggleFilter, toolTipKey] ) - const { years } = extractYears(prsObject, issuesObject) - - const { contributions } = getYearlyContributions( - yearlyFilter, - prsObject, - issuesObject - ) + const { contributions } = getYearlyContributions(prsObject, issuesObject) const { gridSet } = createGridSet(yearlyFilter!) const memoizedGraphValues = useMemo( @@ -156,7 +164,8 @@ export const useGithubIssues = () => { } const handleYearlyFilter = (key: string) => { - setYearlyFilter((prev) => (prev === key ? prev : key)) + if (key === yearlyFilter) return + setYearlyFilter(key) } const onClickToolTip = (content: Contribution) => { @@ -183,6 +192,7 @@ export const useGithubIssues = () => { handleYearlyFilter, years, memoizedGraphValues, - onClickToolTip, goBack + onClickToolTip, + goBack } } From e59cf60bd9629b50ff7ae17cce618e1717a1ebc0 Mon Sep 17 00:00:00 2001 From: IgboPharaoh Date: Fri, 10 Nov 2023 17:15:43 +0100 Subject: [PATCH 06/17] update data fetching for issue comments --- src/app/components/search/action.ts | 15 ++- src/graphql/queries.ts | 4 +- src/helpers/get-comments.ts | 30 +++--- src/helpers/get-issues-data.ts | 161 ++++++++++++++++++---------- src/helpers/get-pull-requests.ts | 10 +- src/hooks/useGithubIssues.ts | 19 +++- 6 files changed, 154 insertions(+), 85 deletions(-) diff --git a/src/app/components/search/action.ts b/src/app/components/search/action.ts index 1355688..5333ca3 100644 --- a/src/app/components/search/action.ts +++ b/src/app/components/search/action.ts @@ -9,11 +9,13 @@ import { getGithubPrsData } from "@/helpers/get-prs-data" export const fetchIssues = async ({ username, startDate, - endDate + endDate, + endCursor }: { username: string startDate?: string endDate?: string + endCursor: string }) => { const session = await auth() const token = session?.accessToken @@ -50,7 +52,8 @@ export const fetchIssues = async ({ username, token, query: "FETCH_RANGED_COMMENTS", - startDate + startDate, + endCursor }) ]) @@ -60,5 +63,11 @@ export const fetchIssues = async ({ const ranged_prs = ranged_response[0] const ranged_issues = ranged_response[1] - return { issues, prs, years, ranged_prs, ranged_issues } + return { + issues, + prs, + years, + ranged_prs, + ranged_issues + } } diff --git a/src/graphql/queries.ts b/src/graphql/queries.ts index 58f4d1e..6da6af5 100644 --- a/src/graphql/queries.ts +++ b/src/graphql/queries.ts @@ -105,9 +105,9 @@ export const FETCH_RANGED_PRS = `query contributions($username: String!, $startD } }` -export const FETCH_RANGED_COMMENTS = `query ($username: String!) { +export const FETCH_RANGED_COMMENTS = `query ($username: String!, $endCursor: String) { user(login: $username) { - issueComments(last: 100) { + issueComments(first: 100, orderBy: {field: UPDATED_AT, direction: DESC}, after: $endCursor) { pageInfo { hasNextPage startCursor diff --git a/src/helpers/get-comments.ts b/src/helpers/get-comments.ts index adb7ca0..58bee63 100644 --- a/src/helpers/get-comments.ts +++ b/src/helpers/get-comments.ts @@ -1,17 +1,17 @@ -import { Comment } from "@/types/comments" +import { Comment, IssueCommentNodes } from "@/types/comments" export const getOwnComments = ({ data, username }: { - data: any + data: IssueCommentNodes[] username: string }): Comment[] => { - const rawComments = data?.issueComments?.nodes.filter( - (comment: any) => comment.issue.author.login === username + const rawComments = data?.filter( + (comment) => comment.issue.author.login === username ) - const comments: Comment[] = rawComments.map((comment: any) => { + const comments: Comment[] = rawComments?.map((comment) => { return { body: comment.body, repository: comment.repository.url, @@ -34,14 +34,14 @@ export const getOthersComments = ({ data, username }: { - data: any + data: IssueCommentNodes[] username: string }): Comment[] => { - const rawComments = data?.issueComments?.nodes.filter( - (comment: any) => comment.issue.author.login !== username + const rawComments = data?.filter( + (comment) => comment.issue.author.login !== username ) - const comments: Comment[] = rawComments.map((comment: any) => { + const comments: Comment[] = rawComments?.map((comment) => { return { body: comment.body, repository: comment.repository.url, @@ -60,12 +60,14 @@ export const getOthersComments = ({ return comments } -export const getLongComments = ({ data }: { data: any }): Comment[] => { - const rawComments = data?.issueComments?.nodes.filter( - (comment: any) => comment.body.length > 500 - ) +export const getLongComments = ({ + data +}: { + data: IssueCommentNodes[] +}): Comment[] => { + const rawComments = data?.filter((comment) => comment.body.length > 500) - const comments: Comment[] = rawComments.map((comment: any) => { + const comments: Comment[] = rawComments?.map((comment) => { return { body: comment.body, repository: comment.repository.url, diff --git a/src/helpers/get-issues-data.ts b/src/helpers/get-issues-data.ts index b11fc4c..f478d99 100644 --- a/src/helpers/get-issues-data.ts +++ b/src/helpers/get-issues-data.ts @@ -1,16 +1,22 @@ import { FETCH_RANGED_COMMENTS } from "@/graphql/queries" -import { IssueCommentDataType, IssueComments } from "@/types/comments" +import { + IssueCommentDataType, + IssueCommentNodes, + IssueComments +} from "@/types/comments" export async function getIssueCommentsData({ username, token, query, - startDate + startDate, + endCursor }: { username: string token?: string query: "FETCH_RANGED_COMMENTS" startDate?: string + endCursor: string | null }) { const tokenFromEnv = process.env.GITHUB_TOKEN @@ -23,69 +29,110 @@ export async function getIssueCommentsData({ throw new Error("Invalid query") } - try { - const res = await fetch("https://api.github.com/graphql", { - method: "POST", - headers: { - Authorization: `Bearer ${token ?? tokenFromEnv}`, - "Content-Type": "application/json" - }, - body: JSON.stringify({ - query: graphqlQuery, - variables: { - username - } - }) - }) + let hasNextPage = true + + endCursor = startDate?.slice(0, 4) === "2022" ? endCursor : null + + let startCursorObj: any = {} + let endCursorObj: any = {} - if (!res.ok) { - return { error: res.statusText, message: "Failed to fetch API" } + let allIssueComments: Array = [] + + while (hasNextPage) { + if ( + startDate?.slice(0, 4) !== "2023" && + startDate?.slice(0, 4) !== "2022" + ) { + return { + data: [], + error: null + } } - const data = await res.json() - const jsonData: IssueCommentDataType = data.data.user - - let result: Partial = {} - let nodesResult = "" - let yearlyResult: any = {} - - const hasNextPage = jsonData?.issueComments?.pageInfo?.hasNextPage - - if (hasNextPage === false) { - for (const [key, value] of Object.entries( - jsonData?.issueComments - )) { - if (key === "nodes" && Array.isArray(value)) { - yearlyResult[key] = value.filter( - (node) => - node.createdAt.slice(0, 4) === - // "2023" - startDate?.slice(0, 4) - ) - } else { - yearlyResult[key] = value - } + try { + const res = await fetch("https://api.github.com/graphql", { + method: "POST", + headers: { + Authorization: `Bearer ${token ?? tokenFromEnv}`, + "Content-Type": "application/json" + }, + body: JSON.stringify({ + query: graphqlQuery, + variables: { + username, + endCursor + } + }) + }) + + if (!res.ok) { + return { error: res.statusText, message: "Failed to fetch API" } } - return yearlyResult as IssueComments - } else { - for (const [key, value] of Object.entries(jsonData.issueComments)) { + const data = await res.json() + const jsonData: IssueCommentDataType = data.data.user + + const nodes_data = jsonData?.issueComments?.nodes + const start_cursor = jsonData?.issueComments?.pageInfo?.startCursor + const isNextPage = jsonData?.issueComments?.pageInfo?.hasNextPage + const end_cursor = jsonData?.issueComments?.pageInfo?.endCursor + + const prevYear = Number(startDate?.slice(0, 4)) - 1 + + const findNextYear = nodes_data?.find( + (x) => x.createdAt.slice(0, 4) === prevYear.toString() + ) + + if ( + findNextYear || + (isNextPage === false && findNextYear === undefined) + ) { + const filter_node_data = nodes_data.filter((x) => { + return x.createdAt.slice(0, 4) === startDate?.slice(0, 4) + }) + + const res = filter_node_data + + allIssueComments.push(...res) + + hasNextPage = false + endCursor = end_cursor + + endCursorObj["end_cursor"] = endCursor + } else { + allIssueComments.push(...nodes_data) + hasNextPage = isNextPage + + endCursor = end_cursor + startCursorObj["start_cursor"] = start_cursor + endCursorObj["end_cursor"] = endCursor } - } - if (data.errors) { - return { error: data.errors, message: "Failed to fetch API" } + if (data.errors) { + return { error: data.errors, message: "Failed to fetch API" } + } + } catch (error) { + console.log(error) + return { + error: error, + message: "Failed to fetch API" + } } + } - return { - data: data.data.user, - error: null - } - } catch (error) { - console.log(error) - return { - error: error, - message: "Failed to fetch API" - } + allIssueComments + .sort( + (a, b) => + new Date(a?.createdAt).getTime() - + new Date(b?.createdAt).getTime() + ) + .filter((x) => x !== undefined) + + return { + data: allIssueComments, + error: null, + startCursorObj, + endCursorObj, + hasNextPage } } diff --git a/src/helpers/get-pull-requests.ts b/src/helpers/get-pull-requests.ts index 1828727..a7c6883 100644 --- a/src/helpers/get-pull-requests.ts +++ b/src/helpers/get-pull-requests.ts @@ -109,23 +109,23 @@ export const getPullRequests = ({ project: pr?.pullRequest?.repository.owner })) - openPRs?.sort( + openPRs.sort( (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime() ) - openInactivePRs?.sort( + openInactivePRs.sort( (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime() ) - closedPRs?.sort( + closedPRs.sort( (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime() ) - closedPRsByOthers?.sort( + closedPRsByOthers.sort( (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime() ) - mergedPRs?.sort( + mergedPRs.sort( (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime() ) diff --git a/src/hooks/useGithubIssues.ts b/src/hooks/useGithubIssues.ts index 780cdb1..ab171c5 100644 --- a/src/hooks/useGithubIssues.ts +++ b/src/hooks/useGithubIssues.ts @@ -74,12 +74,23 @@ export const useGithubIssues = () => { })) setProjects([]) setYears([]) + + const endCursor = localStorage.getItem("end_cursor") as string + const { issues, prs, ranged_prs, ranged_issues, years } = await fetchIssues({ username: username as string, startDate, - endDate + endDate, + endCursor }) + console.log(ranged_issues?.data, "RANGED ISSUES") + console.log(ranged_prs?.data, "RANGED PRS") + + localStorage.setItem( + "end_cursor", + ranged_issues?.endCursorObj?.end_cursor + ) setLoading(false) @@ -91,14 +102,14 @@ export const useGithubIssues = () => { } const issue = getOwnComments({ - data: issues.data, + data: ranged_issues?.data!, username: username as string }) const longIssue = getLongComments({ - data: issues.data + data: ranged_issues?.data! }) const othersIssue = getOthersComments({ - data: issues.data, + data: ranged_issues?.data!, username: username as string }) From f6a32df4e904b708c29e1a9e30e6e8b84b9d8c6e Mon Sep 17 00:00:00 2001 From: IgboPharaoh Date: Mon, 13 Nov 2023 07:34:13 +0100 Subject: [PATCH 07/17] add queries for fetching contribution years --- src/graphql/queries.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/graphql/queries.ts b/src/graphql/queries.ts index 6da6af5..615ff18 100644 --- a/src/graphql/queries.ts +++ b/src/graphql/queries.ts @@ -140,3 +140,11 @@ export const FETCH_RANGED_COMMENTS = `query ($username: String!, $endCursor: Str } } }` + +export const FETCH_CONTTRIBUTION_YEARS = `query contributions($username: String!, ) { + user(login: $username) { + contributionsCollection{ + contributionYears + } + } +}` From 228fbd74124a39979d1f09f8eb1ef5f7c4385af8 Mon Sep 17 00:00:00 2001 From: IgboPharaoh Date: Mon, 13 Nov 2023 07:36:17 +0100 Subject: [PATCH 08/17] abstract fetch years functionality --- src/app/components/search/action.ts | 28 ----------------- .../components/search/contribution-years.ts | 22 ++++++++++++++ src/helpers/get-contribution-years.ts | 27 ++++------------- src/hooks/useGetYears.ts | 30 +++++++++++++++++++ 4 files changed, 57 insertions(+), 50 deletions(-) create mode 100644 src/app/components/search/contribution-years.ts create mode 100644 src/hooks/useGetYears.ts diff --git a/src/app/components/search/action.ts b/src/app/components/search/action.ts index 5333ca3..dc693f5 100644 --- a/src/app/components/search/action.ts +++ b/src/app/components/search/action.ts @@ -1,8 +1,6 @@ "use server" import { auth } from "@/auth" -import { getContributionYears } from "@/helpers/get-contribution-years" -import { getGithubData } from "@/helpers/get-github-data" import { getIssueCommentsData } from "@/helpers/get-issues-data" import { getGithubPrsData } from "@/helpers/get-prs-data" @@ -20,26 +18,6 @@ export const fetchIssues = async ({ const session = await auth() const token = session?.accessToken - const res = await Promise.all([ - getGithubData({ - username, - token, - query: "ISSUES" - }), - getGithubData({ - username, - token, - query: "PULL_REQUESTS" - }), - getContributionYears({ - username, - token, - query: "FETCH_RANGED_PRS", - startDate, - endDate - }) - ]) - const ranged_response = await Promise.all([ getGithubPrsData({ username, @@ -57,16 +35,10 @@ export const fetchIssues = async ({ }) ]) - const issues = res[0] - const prs = res[1] - const years = res[2] const ranged_prs = ranged_response[0] const ranged_issues = ranged_response[1] return { - issues, - prs, - years, ranged_prs, ranged_issues } diff --git a/src/app/components/search/contribution-years.ts b/src/app/components/search/contribution-years.ts new file mode 100644 index 0000000..28221b0 --- /dev/null +++ b/src/app/components/search/contribution-years.ts @@ -0,0 +1,22 @@ +"use server" + +import { auth } from "@/auth" +import { getContributionYears } from "@/helpers/get-contribution-years" + +export const fetchYears = async ({ params }: { params: any }) => { + const session = await auth() + const token = session?.accessToken + + const res = await Promise.all([ + getContributionYears({ + token, + ...params + }) + ]) + + const years = res[0] + + return { + years + } +} diff --git a/src/helpers/get-contribution-years.ts b/src/helpers/get-contribution-years.ts index 99d7468..92839b3 100644 --- a/src/helpers/get-contribution-years.ts +++ b/src/helpers/get-contribution-years.ts @@ -1,30 +1,15 @@ -import { FETCH_RANGED_PRS } from "@/graphql/queries" +import { FETCH_CONTTRIBUTION_YEARS } from "@/graphql/queries" import { PrDataType } from "@/types/pull_requests" export async function getContributionYears({ - username, token, - query, - startDate, - endDate + username }: { - username: string token?: string - query: "FETCH_RANGED_PRS" - startDate?: string - endDate?: string + username: string }) { const tokenFromEnv = process.env.GITHUB_TOKEN - let graphqlQuery = "" - switch (query) { - case "FETCH_RANGED_PRS": - graphqlQuery = FETCH_RANGED_PRS - break - default: - throw new Error("Invalid query") - } - try { const res = await fetch("https://api.github.com/graphql", { method: "POST", @@ -33,11 +18,9 @@ export async function getContributionYears({ "Content-Type": "application/json" }, body: JSON.stringify({ - query: graphqlQuery, + query: FETCH_CONTTRIBUTION_YEARS, variables: { - username, - startDate, - endDate + username } }) }) diff --git a/src/hooks/useGetYears.ts b/src/hooks/useGetYears.ts new file mode 100644 index 0000000..02c6cc8 --- /dev/null +++ b/src/hooks/useGetYears.ts @@ -0,0 +1,30 @@ +import React from "react" +import { useSearchParams } from "next/navigation" +import { fetchYears } from "@/app/components/search/contribution-years" + +export const useGetYears = () => { + const searchParams = useSearchParams() + const username = searchParams.get("username") + const [years, setYears] = React.useState([]) + + React.useEffect(() => { + const getContributionByYear = async () => { + const params = { + username: username as string + } + const { years } = await fetchYears({ + params + }) + + const yearsData = + years?.data !== undefined + ? years.data.map((yr) => yr.toString()) + : [] + setYears(yearsData) + } + + getContributionByYear() + }, [username]) + + return { years } +} From 518059d50334a49c50a3608f35eadf2bbdd575ca Mon Sep 17 00:00:00 2001 From: IgboPharaoh Date: Mon, 13 Nov 2023 07:37:56 +0100 Subject: [PATCH 09/17] fix undefined issues of issue comments --- src/helpers/get-comments.ts | 6 ++++ src/helpers/get-pull-requests.ts | 2 +- src/hooks/useGithubIssues.ts | 50 +++++++++++++++++--------------- 3 files changed, 33 insertions(+), 25 deletions(-) diff --git a/src/helpers/get-comments.ts b/src/helpers/get-comments.ts index 58bee63..f4e0f9b 100644 --- a/src/helpers/get-comments.ts +++ b/src/helpers/get-comments.ts @@ -7,6 +7,8 @@ export const getOwnComments = ({ data: IssueCommentNodes[] username: string }): Comment[] => { + data = data !== undefined ? data : [] + const rawComments = data?.filter( (comment) => comment.issue.author.login === username ) @@ -37,6 +39,8 @@ export const getOthersComments = ({ data: IssueCommentNodes[] username: string }): Comment[] => { + data = data !== undefined ? data : [] + const rawComments = data?.filter( (comment) => comment.issue.author.login !== username ) @@ -65,6 +69,8 @@ export const getLongComments = ({ }: { data: IssueCommentNodes[] }): Comment[] => { + data = data !== undefined ? data : [] + const rawComments = data?.filter((comment) => comment.body.length > 500) const comments: Comment[] = rawComments?.map((comment) => { diff --git a/src/helpers/get-pull-requests.ts b/src/helpers/get-pull-requests.ts index a7c6883..bf4748d 100644 --- a/src/helpers/get-pull-requests.ts +++ b/src/helpers/get-pull-requests.ts @@ -9,7 +9,7 @@ export const getPullRequests = ({ data: PrNodes[] username: string }): PullRequests => { - data = data?.filter((x) => x?.pullRequest !== undefined) + data = data !== undefined ? data : [] const openPRsData = data?.filter((pr) => pr?.pullRequest?.closed === false) diff --git a/src/hooks/useGithubIssues.ts b/src/hooks/useGithubIssues.ts index ab171c5..15a24ac 100644 --- a/src/hooks/useGithubIssues.ts +++ b/src/hooks/useGithubIssues.ts @@ -10,7 +10,6 @@ import { Project, PRsObject } from "@/types/pull_requests" import { useRouter, useSearchParams } from "next/navigation" import { createGridSet, - extractYears, filterObject, generateGraphValues, getOrganisations, @@ -28,9 +27,10 @@ export const useGithubIssues = () => { const [loading, setLoading] = useState(false) const [error, setError] = useState(null) - const [projects, setProjects] = useState>([]) + const [projects, setProjects] = useState< + Array + >([]) const [toggleFilter, setToggleFilter] = useState("") - const [years, setYears] = useState>([]) const [yearlyFilter, setYearlyFilter] = useState(currentYear) const [toolTipKey, setToolTipKey] = useState("") const [issuesObject, setIssuesObject] = useState({ @@ -73,19 +73,20 @@ export const useGithubIssues = () => { mergedPrs: [] })) setProjects([]) - setYears([]) const endCursor = localStorage.getItem("end_cursor") as string - const { issues, prs, ranged_prs, ranged_issues, years } = - await fetchIssues({ - username: username as string, - startDate, - endDate, - endCursor - }) - console.log(ranged_issues?.data, "RANGED ISSUES") - console.log(ranged_prs?.data, "RANGED PRS") + const { ranged_prs, ranged_issues } = await fetchIssues({ + username: username as string, + startDate, + endDate, + endCursor + }) + + const rangedPrsData = + ranged_prs?.data !== undefined ? ranged_prs.data : [] + const rangedIssuesData = + ranged_issues?.data !== undefined ? ranged_issues.data : [] localStorage.setItem( "end_cursor", @@ -94,22 +95,25 @@ export const useGithubIssues = () => { setLoading(false) - if (issues.error || prs.error) { - console.error(issues.error, "error") - setError(issues.error[0].message || prs.error[0].message) + if (ranged_issues.error || ranged_prs.error) { + console.error(ranged_issues.error, "error") + setError( + ranged_issues.error[0].message || + ranged_prs.error[0].message + ) setLoading(false) return } const issue = getOwnComments({ - data: ranged_issues?.data!, + data: rangedIssuesData, username: username as string }) const longIssue = getLongComments({ - data: ranged_issues?.data! + data: rangedIssuesData }) const othersIssue = getOthersComments({ - data: ranged_issues?.data!, + data: rangedIssuesData, username: username as string }) @@ -120,17 +124,16 @@ export const useGithubIssues = () => { openInactivePRs, openPRs } = getPullRequests({ - data: ranged_prs.data!, + data: rangedPrsData, username: username as string }) const { orgs } = getOrganisations( - ranged_prs?.data!, - issues.data, + rangedPrsData, + rangedIssuesData, username ) setProjects(orgs) - setYears(years.data!) setIssuesObject((prev) => ({ ...prev, @@ -201,7 +204,6 @@ export const useGithubIssues = () => { toggleFilter, yearlyFilter, handleYearlyFilter, - years, memoizedGraphValues, onClickToolTip, goBack From 6eb89d5138083587371f48a66126a608ad370a79 Mon Sep 17 00:00:00 2001 From: IgboPharaoh Date: Mon, 13 Nov 2023 07:38:31 +0100 Subject: [PATCH 10/17] rearrange project according to order of contributions --- src/helpers/utils.ts | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/helpers/utils.ts b/src/helpers/utils.ts index 92da27c..619de2d 100644 --- a/src/helpers/utils.ts +++ b/src/helpers/utils.ts @@ -7,7 +7,7 @@ import { GRID_GREEN, GRID_YELLOW } from "@/types" -import { Comment, IssuesObject } from "@/types/comments" +import { Comment, IssueCommentNodes, IssuesObject } from "@/types/comments" import { PrNodes, Project, PRsObject } from "@/types/pull_requests" export const getIssueNumber = (arg: string) => { @@ -43,7 +43,7 @@ export const collapsibleHeader = (repoUrl: string, username: string) => { export const getOrganisations = ( prsData: PrNodes[], - issueData: any, + issueData: IssueCommentNodes[], username: string ) => { const prOrgs: Array = prsData @@ -57,9 +57,9 @@ export const getOrganisations = ( avatarUrl: pr?.pullRequest?.repository.owner.avatarUrl })) - const issueOrgs: Array = issueData?.issueComments?.nodes - .filter( - (issue: any) => + const issueOrgs: Array = issueData + ?.filter( + (issue) => issue.repository.owner.login.toLowerCase() !== username.toLowerCase() ) @@ -68,11 +68,28 @@ export const getOrganisations = ( avatarUrl: issue.repository.owner.avatarUrl })) - const orgs = [...prOrgs, ...issueOrgs].filter( - (value, index, arr) => - arr.map((x) => x.login).indexOf(value.login) === index + const allOrgs = [...prOrgs, ...issueOrgs].reduce( + (acc, curr) => { + const key = curr.login + + const group = acc[key] ?? [] + return { ...acc, [key]: [...group, curr] } + }, + {} as Record> ) + const addOrgPosition = [] + for (const [key, value] of Object.entries(allOrgs)) { + if (key) { + addOrgPosition.push({ + login: value[0].login, + avatarUrl: value[0].avatarUrl, + position: value.length + }) + } + } + const orgs = addOrgPosition.sort((a, c) => c.position - a.position) + return { orgs } } @@ -165,7 +182,7 @@ export const months = [ "Dec" ] -const days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] +export const days = ["Mon", "Wed", "Fri"] export const getYearlyContributions = ( prsData: PRsObject, From 3eaf126dab007e314c32f608860bf1ee10152bde Mon Sep 17 00:00:00 2001 From: IgboPharaoh Date: Mon, 13 Nov 2023 07:39:17 +0100 Subject: [PATCH 11/17] remove more button and show all projects --- src/app/components/cards/OrganisationCard.tsx | 67 +++---------------- 1 file changed, 10 insertions(+), 57 deletions(-) diff --git a/src/app/components/cards/OrganisationCard.tsx b/src/app/components/cards/OrganisationCard.tsx index b727eac..cc2b53a 100644 --- a/src/app/components/cards/OrganisationCard.tsx +++ b/src/app/components/cards/OrganisationCard.tsx @@ -6,7 +6,6 @@ type OrganisationCardProps = { login: string avatarUrl: string handleClick: (type: string) => void - more: boolean toggleFilter: string | null } @@ -14,20 +13,13 @@ export const OrganisationCard = ({ login, avatarUrl, handleClick, - more, toggleFilter }: OrganisationCardProps) => { return (
handleClick(login)} @@ -52,61 +44,22 @@ export const ProjectsBlock = ({ toggleFilter, handleFilterToggle }: { - projects: Array + projects: Array toggleFilter: string | null handleFilterToggle: (key: string) => void }) => { - const [showMore, setShowMore] = React.useState(false) - return (
{projects.length > 0 && - projects - .slice(0, 3) - .map((x, idx) => ( - - ))} - {projects.length > 3 ? ( -
- - {showMore ? ( -
setShowMore(!showMore)} - > -
-

- projects -

-
- {projects.slice(3).map((x, idx) => ( - - ))} -
-
-
- ) : null} -
- ) : null} + projects.map((x, idx) => ( + + ))}
) } From 51762e0d975321567479e43a3945062958405bf2 Mon Sep 17 00:00:00 2001 From: IgboPharaoh Date: Mon, 13 Nov 2023 07:40:34 +0100 Subject: [PATCH 12/17] add months and days to contribution graph --- .../components/contribution-graph/index.tsx | 65 +++++++++++++++++++ src/app/result/page.tsx | 42 ++++-------- 2 files changed, 76 insertions(+), 31 deletions(-) create mode 100644 src/app/components/contribution-graph/index.tsx diff --git a/src/app/components/contribution-graph/index.tsx b/src/app/components/contribution-graph/index.tsx new file mode 100644 index 0000000..2fd8db0 --- /dev/null +++ b/src/app/components/contribution-graph/index.tsx @@ -0,0 +1,65 @@ +import { days, months } from "@/helpers/utils" +import { Contribution } from "@/types" +import React from "react" +import ToolTip from "../tool-tip" + +const ContributionGraph = ({ + memoizedGraphValues, + loading, + onClickToolTip +}: { + memoizedGraphValues: Contribution[] + onClickToolTip: (content: Contribution) => void + loading: boolean +}) => { + return ( +
+
+
+ {days.map((d) => ( +

+ {d} +

+ ))} +
+
+
+ {months.map((m) => ( +

+ {m} +

+ ))} +
+
+
+ {memoizedGraphValues.map((day, idx) => ( + + ))} +
+
+
+
+
+
+

Commits

+
+
+
+

Comments

+
+
+
+

Commits & Comments

+
+
+
+
+ ) +} + +export default ContributionGraph diff --git a/src/app/result/page.tsx b/src/app/result/page.tsx index 29d0d19..98df9c1 100644 --- a/src/app/result/page.tsx +++ b/src/app/result/page.tsx @@ -1,15 +1,16 @@ "use client" -import { useSearchParams } from "next/navigation" import React from "react" +import { useSearchParams } from "next/navigation" import { ProjectsBlock } from "../components/cards/OrganisationCard" import YearSection from "../components/years-switch" import { useGithubIssues } from "@/hooks/useGithubIssues" import { IssuesAndPullRequests } from "../components/issues-and-prs" -import "../globals.css" -import ToolTip from "../components/tool-tip" import { ArrowLeftIcon } from "@radix-ui/react-icons" +import { useGetYears } from "@/hooks/useGetYears" +import ContributionGraph from "../components/contribution-graph" +import "../globals.css" const Page = () => { const searchParams = useSearchParams() @@ -23,11 +24,11 @@ const Page = () => { toggleFilter, yearlyFilter, handleYearlyFilter, - years, memoizedGraphValues, onClickToolTip, goBack } = useGithubIssues() + const { years } = useGetYears() return (
@@ -47,7 +48,7 @@ const Page = () => { className="arrowLeftIcon" /> -
+

{username} contributions

@@ -60,32 +61,11 @@ const Page = () => {
-
-
- {memoizedGraphValues.map((day, idx) => ( - - ))} -
-
-
-
-

Commits

-
-
-
-

Comments

-
-
-
-

Commits & Comments

-
-
-
+ Date: Mon, 13 Nov 2023 11:52:39 +0100 Subject: [PATCH 13/17] fix build error --- src/app/components/search/action.ts | 18 ++++++++++++++++++ src/app/components/search/index.tsx | 3 ++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/app/components/search/action.ts b/src/app/components/search/action.ts index dc693f5..4098467 100644 --- a/src/app/components/search/action.ts +++ b/src/app/components/search/action.ts @@ -1,6 +1,7 @@ "use server" import { auth } from "@/auth" +import { getGithubData } from "@/helpers/get-github-data" import { getIssueCommentsData } from "@/helpers/get-issues-data" import { getGithubPrsData } from "@/helpers/get-prs-data" @@ -18,6 +19,19 @@ export const fetchIssues = async ({ const session = await auth() const token = session?.accessToken + const res = await Promise.all([ + getGithubData({ + username, + token, + query: "ISSUES" + }), + getGithubData({ + username, + token, + query: "PULL_REQUESTS" + }) + ]) + const ranged_response = await Promise.all([ getGithubPrsData({ username, @@ -35,10 +49,14 @@ export const fetchIssues = async ({ }) ]) + const issues = res[0] + const prs = res[1] const ranged_prs = ranged_response[0] const ranged_issues = ranged_response[1] return { + issues, + prs, ranged_prs, ranged_issues } diff --git a/src/app/components/search/index.tsx b/src/app/components/search/index.tsx index 6e82da8..4c8c64d 100644 --- a/src/app/components/search/index.tsx +++ b/src/app/components/search/index.tsx @@ -30,7 +30,8 @@ export default function Search() { setError(null) const { issues, prs } = await fetchIssues({ - username: username as string + username: username as string, + endCursor: "" }) setLoading(false) From 269b32f983d358bdf28c3812050b6a3445b27a0c Mon Sep 17 00:00:00 2001 From: IgboPharaoh Date: Mon, 13 Nov 2023 14:19:37 +0100 Subject: [PATCH 14/17] fix endcursor being overwritten after viewing issues 3yrs past --- src/graphql/queries.ts | 2 +- src/helpers/get-comments.ts | 11 ++- src/helpers/get-contribution-years.ts | 6 +- src/helpers/get-issues-data.ts | 37 ++++---- src/helpers/get-pull-requests.ts | 119 +++++++++++++------------- src/hooks/useGithubIssues.ts | 27 ++++-- src/types/index.ts | 1 + 7 files changed, 112 insertions(+), 91 deletions(-) diff --git a/src/graphql/queries.ts b/src/graphql/queries.ts index 615ff18..1d75f36 100644 --- a/src/graphql/queries.ts +++ b/src/graphql/queries.ts @@ -141,7 +141,7 @@ export const FETCH_RANGED_COMMENTS = `query ($username: String!, $endCursor: Str } }` -export const FETCH_CONTTRIBUTION_YEARS = `query contributions($username: String!, ) { +export const FETCH_CONTRIBUTION_YEARS = `query contributionsYears($username: String!) { user(login: $username) { contributionsCollection{ contributionYears diff --git a/src/helpers/get-comments.ts b/src/helpers/get-comments.ts index f4e0f9b..aadcd5c 100644 --- a/src/helpers/get-comments.ts +++ b/src/helpers/get-comments.ts @@ -1,3 +1,4 @@ +import { MAX_COMMENT_LENGTH } from "@/types" import { Comment, IssueCommentNodes } from "@/types/comments" export const getOwnComments = ({ @@ -7,7 +8,7 @@ export const getOwnComments = ({ data: IssueCommentNodes[] username: string }): Comment[] => { - data = data !== undefined ? data : [] + data = data ?? [] const rawComments = data?.filter( (comment) => comment.issue.author.login === username @@ -39,7 +40,7 @@ export const getOthersComments = ({ data: IssueCommentNodes[] username: string }): Comment[] => { - data = data !== undefined ? data : [] + data = data ?? [] const rawComments = data?.filter( (comment) => comment.issue.author.login !== username @@ -69,9 +70,11 @@ export const getLongComments = ({ }: { data: IssueCommentNodes[] }): Comment[] => { - data = data !== undefined ? data : [] + data = data ?? [] - const rawComments = data?.filter((comment) => comment.body.length > 500) + const rawComments = data?.filter( + (comment) => comment.body.length > MAX_COMMENT_LENGTH + ) const comments: Comment[] = rawComments?.map((comment) => { return { diff --git a/src/helpers/get-contribution-years.ts b/src/helpers/get-contribution-years.ts index 92839b3..a589a6f 100644 --- a/src/helpers/get-contribution-years.ts +++ b/src/helpers/get-contribution-years.ts @@ -1,4 +1,4 @@ -import { FETCH_CONTTRIBUTION_YEARS } from "@/graphql/queries" +import { FETCH_CONTRIBUTION_YEARS } from "@/graphql/queries" import { PrDataType } from "@/types/pull_requests" export async function getContributionYears({ @@ -18,7 +18,7 @@ export async function getContributionYears({ "Content-Type": "application/json" }, body: JSON.stringify({ - query: FETCH_CONTTRIBUTION_YEARS, + query: FETCH_CONTRIBUTION_YEARS, variables: { username } @@ -26,7 +26,6 @@ export async function getContributionYears({ }) if (!res.ok) { - console.log("res", res) return { error: res.statusText, message: "Failed to fetch API" } } @@ -45,7 +44,6 @@ export async function getContributionYears({ error: null } } catch (error) { - console.log(error) return { error: error, message: "Failed to fetch API" diff --git a/src/helpers/get-issues-data.ts b/src/helpers/get-issues-data.ts index f478d99..4686b00 100644 --- a/src/helpers/get-issues-data.ts +++ b/src/helpers/get-issues-data.ts @@ -19,6 +19,23 @@ export async function getIssueCommentsData({ endCursor: string | null }) { const tokenFromEnv = process.env.GITHUB_TOKEN + let hasNextPage = true + const currentDate = new Date() + const currentYear = currentDate.getFullYear() + const prevYear = currentYear - 1 + const getYearFromDate = startDate?.slice(0, 4) + + endCursor = Number(getYearFromDate) <= prevYear ? endCursor : null + + if ( + getYearFromDate !== currentYear.toString() && + getYearFromDate !== prevYear.toString() + ) { + return { + data: [], + error: null + } + } let graphqlQuery = "" switch (query) { @@ -29,26 +46,12 @@ export async function getIssueCommentsData({ throw new Error("Invalid query") } - let hasNextPage = true - - endCursor = startDate?.slice(0, 4) === "2022" ? endCursor : null - let startCursorObj: any = {} let endCursorObj: any = {} let allIssueComments: Array = [] while (hasNextPage) { - if ( - startDate?.slice(0, 4) !== "2023" && - startDate?.slice(0, 4) !== "2022" - ) { - return { - data: [], - error: null - } - } - try { const res = await fetch("https://api.github.com/graphql", { method: "POST", @@ -76,10 +79,13 @@ export async function getIssueCommentsData({ const start_cursor = jsonData?.issueComments?.pageInfo?.startCursor const isNextPage = jsonData?.issueComments?.pageInfo?.hasNextPage const end_cursor = jsonData?.issueComments?.pageInfo?.endCursor + console.log(endCursor, "endCursor") - const prevYear = Number(startDate?.slice(0, 4)) - 1 + // get previous year from start date of query + const prevYear = Number(getYearFromDate) - 1 const findNextYear = nodes_data?.find( + // return first year that is a previous year, we are slicing the createdAt date to get current year of eaxh result (x) => x.createdAt.slice(0, 4) === prevYear.toString() ) @@ -87,6 +93,7 @@ export async function getIssueCommentsData({ findNextYear || (isNextPage === false && findNextYear === undefined) ) { + // filter previous year from response data, when previous year is found in current query date range const filter_node_data = nodes_data.filter((x) => { return x.createdAt.slice(0, 4) === startDate?.slice(0, 4) }) diff --git a/src/helpers/get-pull-requests.ts b/src/helpers/get-pull-requests.ts index bf4748d..1954353 100644 --- a/src/helpers/get-pull-requests.ts +++ b/src/helpers/get-pull-requests.ts @@ -9,104 +9,103 @@ export const getPullRequests = ({ data: PrNodes[] username: string }): PullRequests => { - data = data !== undefined ? data : [] + data = data ?? [] - const openPRsData = data?.filter((pr) => pr?.pullRequest?.closed === false) + const openPRsData = data.filter((pr) => pr.pullRequest.closed === false) - const openPRs: PR[] = openPRsData?.map((pr) => ({ - totalComments: pr?.pullRequest?.totalCommentsCount, + const openPRs: PR[] = openPRsData.map((pr) => ({ + totalComments: pr.pullRequest.totalCommentsCount, daysOpened: Math.floor( - (CURRENT_DAY - new Date(pr?.pullRequest?.createdAt).getTime()) / + (CURRENT_DAY - new Date(pr.pullRequest.createdAt).getTime()) / ONE_DAY ), - url: pr?.pullRequest?.url, - repoUrl: pr?.pullRequest?.repository.url, - title: pr?.pullRequest?.title, - createdAt: pr?.pullRequest?.createdAt, - avatarUrl: pr?.pullRequest?.author.avatarUrl, - project: pr?.pullRequest?.repository.owner + url: pr.pullRequest.url, + repoUrl: pr.pullRequest.repository.url, + title: pr.pullRequest.title, + createdAt: pr.pullRequest.createdAt, + avatarUrl: pr.pullRequest.author.avatarUrl, + project: pr.pullRequest.repository.owner })) - const openInactivePRsData = openPRsData?.filter( + const openInactivePRsData = openPRsData.filter( (pr) => Math.floor( - (CURRENT_DAY - new Date(pr?.pullRequest.createdAt).getTime()) / + (CURRENT_DAY - new Date(pr.pullRequest.createdAt).getTime()) / ONE_DAY ) > DAYS_TO_INACTIVE ) - const openInactivePRs: PR[] = openInactivePRsData?.map((pr) => ({ - totalComments: pr?.pullRequest?.totalCommentsCount, + const openInactivePRs: PR[] = openInactivePRsData.map((pr) => ({ + totalComments: pr.pullRequest.totalCommentsCount, daysOpened: Math.floor( - (CURRENT_DAY - new Date(pr?.pullRequest?.createdAt).getTime()) / + (CURRENT_DAY - new Date(pr.pullRequest.createdAt).getTime()) / ONE_DAY ), - url: pr?.pullRequest?.url, - repoUrl: pr?.pullRequest?.repository.url, - title: pr?.pullRequest?.title, - createdAt: pr?.pullRequest?.createdAt, - avatarUrl: pr?.pullRequest?.author.avatarUrl, - project: pr?.pullRequest?.repository.owner + url: pr.pullRequest.url, + repoUrl: pr.pullRequest.repository.url, + title: pr.pullRequest.title, + createdAt: pr.pullRequest.createdAt, + avatarUrl: pr.pullRequest.author.avatarUrl, + project: pr.pullRequest.repository.owner })) - const closedPRsData = data?.filter( + const closedPRsData = data.filter( (pr) => - pr?.pullRequest?.closed === true && - pr?.pullRequest?.merged === false + pr.pullRequest.closed === true && pr.pullRequest.merged === false ) - const closedPRs: PR[] = closedPRsData?.map((pr) => ({ - totalComments: pr?.pullRequest?.totalCommentsCount, + const closedPRs: PR[] = closedPRsData.map((pr) => ({ + totalComments: pr.pullRequest.totalCommentsCount, daysOpened: Math.floor( - (new Date(pr?.pullRequest?.closedAt).getTime() - - new Date(pr?.pullRequest?.createdAt).getTime()) / + (new Date(pr.pullRequest.closedAt).getTime() - + new Date(pr.pullRequest.createdAt).getTime()) / ONE_DAY ), - url: pr?.pullRequest?.url, - repoUrl: pr?.pullRequest?.repository.url, - title: pr?.pullRequest?.title, - createdAt: pr?.pullRequest?.createdAt, - avatarUrl: pr?.pullRequest?.author.avatarUrl, - project: pr?.pullRequest?.repository.owner + url: pr.pullRequest.url, + repoUrl: pr.pullRequest.repository.url, + title: pr.pullRequest.title, + createdAt: pr.pullRequest.createdAt, + avatarUrl: pr.pullRequest.author.avatarUrl, + project: pr.pullRequest.repository.owner })) - const closedPRsByOthersData = data?.filter( + const closedPRsByOthersData = data.filter( (pr) => - pr?.pullRequest?.closed === true && - pr?.pullRequest?.merged === true && - pr?.pullRequest?.mergedBy.login !== username + pr.pullRequest.closed === true && + pr.pullRequest.merged === true && + pr.pullRequest.mergedBy.login !== username ) - const closedPRsByOthers: PR[] = closedPRsByOthersData?.map((pr) => ({ - totalComments: pr?.pullRequest?.totalCommentsCount, + const closedPRsByOthers: PR[] = closedPRsByOthersData.map((pr) => ({ + totalComments: pr.pullRequest.totalCommentsCount, daysOpened: Math.floor( - (new Date(pr?.pullRequest?.closedAt).getTime() - - new Date(pr?.pullRequest?.createdAt).getTime()) / + (new Date(pr.pullRequest.closedAt).getTime() - + new Date(pr.pullRequest.createdAt).getTime()) / ONE_DAY ), - url: pr?.pullRequest?.url, - repoUrl: pr?.pullRequest?.repository.url, - title: pr?.pullRequest?.title, - createdAt: pr?.pullRequest?.createdAt, - avatarUrl: pr?.pullRequest?.author.avatarUrl, - project: pr?.pullRequest?.repository.owner + url: pr.pullRequest.url, + repoUrl: pr.pullRequest.repository.url, + title: pr.pullRequest.title, + createdAt: pr.pullRequest.createdAt, + avatarUrl: pr.pullRequest.author.avatarUrl, + project: pr.pullRequest.repository.owner })) - const mergedPRData = data?.filter((pr) => pr?.pullRequest?.merged === true) + const mergedPRData = data.filter((pr) => pr.pullRequest.merged === true) - const mergedPRs: PR[] = mergedPRData?.map((pr) => ({ - totalComments: pr?.pullRequest?.totalCommentsCount, + const mergedPRs: PR[] = mergedPRData.map((pr) => ({ + totalComments: pr.pullRequest.totalCommentsCount, daysOpened: Math.floor( - (new Date(pr?.pullRequest?.mergedAt).getTime() - - new Date(pr?.pullRequest?.createdAt).getTime()) / + (new Date(pr.pullRequest.mergedAt).getTime() - + new Date(pr.pullRequest.createdAt).getTime()) / ONE_DAY ), - url: pr?.pullRequest?.url, - repoUrl: pr?.pullRequest?.repository.url, - title: pr?.pullRequest?.title, - createdAt: pr?.pullRequest?.createdAt, - avatarUrl: pr?.pullRequest?.author.avatarUrl, - project: pr?.pullRequest?.repository.owner + url: pr.pullRequest.url, + repoUrl: pr.pullRequest.repository.url, + title: pr.pullRequest.title, + createdAt: pr.pullRequest.createdAt, + avatarUrl: pr.pullRequest.author.avatarUrl, + project: pr.pullRequest.repository.owner })) openPRs.sort( diff --git a/src/hooks/useGithubIssues.ts b/src/hooks/useGithubIssues.ts index 15a24ac..cddc4aa 100644 --- a/src/hooks/useGithubIssues.ts +++ b/src/hooks/useGithubIssues.ts @@ -46,6 +46,17 @@ export const useGithubIssues = () => { mergedPrs: [] }) + /** + * We are using the Date object to create the startDate and endDate of the query range + * new Date(): creates a date using the Date constructor + * Number(args): Converts the string variable of args to a number + * + * 0, 1, 4 or 12, 0, 4: are parameters passed to the Date contructor to modify the Date object; + * the first Argument: This specifies the month parameter + * the second Argument: This specifies the day parameter + * the first Argument: This specifies the time parameter, using the 24:00hr clock format + */ + const startDate = new Date(Number(yearlyFilter), 0, 1, 4).toISOString() const endDate = new Date(Number(yearlyFilter), 12, 0, 4).toISOString() @@ -75,6 +86,7 @@ export const useGithubIssues = () => { setProjects([]) const endCursor = localStorage.getItem("end_cursor") as string + console.log(endCursor, "Saved End cursor") const { ranged_prs, ranged_issues } = await fetchIssues({ username: username as string, @@ -88,18 +100,19 @@ export const useGithubIssues = () => { const rangedIssuesData = ranged_issues?.data !== undefined ? ranged_issues.data : [] - localStorage.setItem( - "end_cursor", - ranged_issues?.endCursorObj?.end_cursor - ) + const storedCursor = + Number(yearlyFilter) <= Number(currentYear) - 1 + ? endCursor + : ranged_issues?.endCursorObj?.end_cursor + + localStorage.setItem("end_cursor", storedCursor) setLoading(false) if (ranged_issues.error || ranged_prs.error) { - console.error(ranged_issues.error, "error") setError( - ranged_issues.error[0].message || - ranged_prs.error[0].message + ranged_issues?.error[0]?.message || + ranged_prs?.error[0]?.message ) setLoading(false) return diff --git a/src/types/index.ts b/src/types/index.ts index c8dba76..0db39b7 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -35,3 +35,4 @@ export const GRID_YELLOW = "#E7C23E" export const GRID_BLUE = "#0783F5" export const GRID_GRAY = "#EEEEEE" export const GRID_GREEN = "#39D353" +export const MAX_COMMENT_LENGTH = 500 From 163523b764587dfdedc5f990417ab5760d36e29a Mon Sep 17 00:00:00 2001 From: IgboPharaoh Date: Mon, 13 Nov 2023 14:41:07 +0100 Subject: [PATCH 15/17] fix overflowing side panel --- src/app/components/years-switch/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/components/years-switch/index.tsx b/src/app/components/years-switch/index.tsx index 04df2ee..ccbe5dd 100644 --- a/src/app/components/years-switch/index.tsx +++ b/src/app/components/years-switch/index.tsx @@ -12,7 +12,7 @@ const YearSection = ({ years, currentYear, handleClick }: YearSectionProps) => { const [showYears, setShowYears] = React.useState(false) return ( -
+
{years.map((year) => (
Date: Mon, 13 Nov 2023 14:41:41 +0100 Subject: [PATCH 16/17] fix overflowing side panel in mobile --- src/app/components/years-switch/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/components/years-switch/index.tsx b/src/app/components/years-switch/index.tsx index ccbe5dd..e315046 100644 --- a/src/app/components/years-switch/index.tsx +++ b/src/app/components/years-switch/index.tsx @@ -12,7 +12,7 @@ const YearSection = ({ years, currentYear, handleClick }: YearSectionProps) => { const [showYears, setShowYears] = React.useState(false) return ( -
+
{years.map((year) => (
{ {showYears ? ( -
+
{years.slice(1).map((year) => (
Date: Mon, 13 Nov 2023 16:11:59 +0100 Subject: [PATCH 17/17] fix: remove console.logs add ternaries --- src/app/components/search/index.tsx | 1 - src/helpers/get-github-data.ts | 2 - src/helpers/get-issues-data.ts | 2 - src/helpers/get-prs-data.ts | 1 - src/helpers/get-pull-requests.ts | 116 ++++++++++++++-------------- src/hooks/useGithubIssues.ts | 3 +- 6 files changed, 59 insertions(+), 66 deletions(-) diff --git a/src/app/components/search/index.tsx b/src/app/components/search/index.tsx index 4c8c64d..59a8415 100644 --- a/src/app/components/search/index.tsx +++ b/src/app/components/search/index.tsx @@ -36,7 +36,6 @@ export default function Search() { setLoading(false) if (issues.error || prs.error) { - console.error(issues.error, "error") setError(issues.error[0].message || prs.error[0].message) return } diff --git a/src/helpers/get-github-data.ts b/src/helpers/get-github-data.ts index 39cc1c6..253cd0d 100644 --- a/src/helpers/get-github-data.ts +++ b/src/helpers/get-github-data.ts @@ -38,7 +38,6 @@ export async function getGithubData({ }) }) if (!res.ok) { - console.log("res", res) return { error: res.statusText, message: "Failed to fetch API" } } @@ -52,7 +51,6 @@ export async function getGithubData({ error: null } } catch (error) { - console.log(error) return { error: error, message: "Failed to fetch API" diff --git a/src/helpers/get-issues-data.ts b/src/helpers/get-issues-data.ts index 4686b00..579902c 100644 --- a/src/helpers/get-issues-data.ts +++ b/src/helpers/get-issues-data.ts @@ -79,7 +79,6 @@ export async function getIssueCommentsData({ const start_cursor = jsonData?.issueComments?.pageInfo?.startCursor const isNextPage = jsonData?.issueComments?.pageInfo?.hasNextPage const end_cursor = jsonData?.issueComments?.pageInfo?.endCursor - console.log(endCursor, "endCursor") // get previous year from start date of query const prevYear = Number(getYearFromDate) - 1 @@ -119,7 +118,6 @@ export async function getIssueCommentsData({ return { error: data.errors, message: "Failed to fetch API" } } } catch (error) { - console.log(error) return { error: error, message: "Failed to fetch API" diff --git a/src/helpers/get-prs-data.ts b/src/helpers/get-prs-data.ts index 9e468db..4fd7d3f 100644 --- a/src/helpers/get-prs-data.ts +++ b/src/helpers/get-prs-data.ts @@ -75,7 +75,6 @@ export async function getGithubPrsData({ return { error: data.errors, message: "Failed to fetch API" } } } catch (error) { - console.log(error) return { error: error, message: "Failed to fetch API" diff --git a/src/helpers/get-pull-requests.ts b/src/helpers/get-pull-requests.ts index 1954353..251dd6f 100644 --- a/src/helpers/get-pull-requests.ts +++ b/src/helpers/get-pull-requests.ts @@ -11,101 +11,101 @@ export const getPullRequests = ({ }): PullRequests => { data = data ?? [] - const openPRsData = data.filter((pr) => pr.pullRequest.closed === false) + const openPRsData = data?.filter((pr) => pr?.pullRequest.closed === false) - const openPRs: PR[] = openPRsData.map((pr) => ({ - totalComments: pr.pullRequest.totalCommentsCount, + const openPRs: PR[] = openPRsData?.map((pr) => ({ + totalComments: pr?.pullRequest.totalCommentsCount, daysOpened: Math.floor( - (CURRENT_DAY - new Date(pr.pullRequest.createdAt).getTime()) / + (CURRENT_DAY - new Date(pr?.pullRequest.createdAt).getTime()) / ONE_DAY ), - url: pr.pullRequest.url, - repoUrl: pr.pullRequest.repository.url, - title: pr.pullRequest.title, - createdAt: pr.pullRequest.createdAt, - avatarUrl: pr.pullRequest.author.avatarUrl, - project: pr.pullRequest.repository.owner + url: pr?.pullRequest.url, + repoUrl: pr?.pullRequest.repository.url, + title: pr?.pullRequest.title, + createdAt: pr?.pullRequest.createdAt, + avatarUrl: pr?.pullRequest.author.avatarUrl, + project: pr?.pullRequest.repository.owner })) - const openInactivePRsData = openPRsData.filter( + const openInactivePRsData = openPRsData?.filter( (pr) => Math.floor( - (CURRENT_DAY - new Date(pr.pullRequest.createdAt).getTime()) / + (CURRENT_DAY - new Date(pr?.pullRequest.createdAt).getTime()) / ONE_DAY ) > DAYS_TO_INACTIVE ) - const openInactivePRs: PR[] = openInactivePRsData.map((pr) => ({ - totalComments: pr.pullRequest.totalCommentsCount, + const openInactivePRs: PR[] = openInactivePRsData?.map((pr) => ({ + totalComments: pr?.pullRequest.totalCommentsCount, daysOpened: Math.floor( - (CURRENT_DAY - new Date(pr.pullRequest.createdAt).getTime()) / + (CURRENT_DAY - new Date(pr?.pullRequest.createdAt).getTime()) / ONE_DAY ), - url: pr.pullRequest.url, - repoUrl: pr.pullRequest.repository.url, - title: pr.pullRequest.title, - createdAt: pr.pullRequest.createdAt, - avatarUrl: pr.pullRequest.author.avatarUrl, - project: pr.pullRequest.repository.owner + url: pr?.pullRequest.url, + repoUrl: pr?.pullRequest.repository.url, + title: pr?.pullRequest.title, + createdAt: pr?.pullRequest.createdAt, + avatarUrl: pr?.pullRequest.author.avatarUrl, + project: pr?.pullRequest.repository.owner })) - const closedPRsData = data.filter( + const closedPRsData = data?.filter( (pr) => - pr.pullRequest.closed === true && pr.pullRequest.merged === false + pr?.pullRequest.closed === true && pr?.pullRequest.merged === false ) - const closedPRs: PR[] = closedPRsData.map((pr) => ({ - totalComments: pr.pullRequest.totalCommentsCount, + const closedPRs: PR[] = closedPRsData?.map((pr) => ({ + totalComments: pr?.pullRequest.totalCommentsCount, daysOpened: Math.floor( - (new Date(pr.pullRequest.closedAt).getTime() - - new Date(pr.pullRequest.createdAt).getTime()) / + (new Date(pr?.pullRequest.closedAt).getTime() - + new Date(pr?.pullRequest.createdAt).getTime()) / ONE_DAY ), - url: pr.pullRequest.url, - repoUrl: pr.pullRequest.repository.url, - title: pr.pullRequest.title, - createdAt: pr.pullRequest.createdAt, - avatarUrl: pr.pullRequest.author.avatarUrl, - project: pr.pullRequest.repository.owner + url: pr?.pullRequest.url, + repoUrl: pr?.pullRequest.repository.url, + title: pr?.pullRequest.title, + createdAt: pr?.pullRequest.createdAt, + avatarUrl: pr?.pullRequest.author.avatarUrl, + project: pr?.pullRequest.repository.owner })) - const closedPRsByOthersData = data.filter( + const closedPRsByOthersData = data?.filter( (pr) => - pr.pullRequest.closed === true && - pr.pullRequest.merged === true && - pr.pullRequest.mergedBy.login !== username + pr?.pullRequest.closed === true && + pr?.pullRequest.merged === true && + pr?.pullRequest.mergedBy.login !== username ) - const closedPRsByOthers: PR[] = closedPRsByOthersData.map((pr) => ({ - totalComments: pr.pullRequest.totalCommentsCount, + const closedPRsByOthers: PR[] = closedPRsByOthersData?.map((pr) => ({ + totalComments: pr?.pullRequest.totalCommentsCount, daysOpened: Math.floor( - (new Date(pr.pullRequest.closedAt).getTime() - - new Date(pr.pullRequest.createdAt).getTime()) / + (new Date(pr?.pullRequest.closedAt).getTime() - + new Date(pr?.pullRequest.createdAt).getTime()) / ONE_DAY ), - url: pr.pullRequest.url, - repoUrl: pr.pullRequest.repository.url, - title: pr.pullRequest.title, - createdAt: pr.pullRequest.createdAt, - avatarUrl: pr.pullRequest.author.avatarUrl, - project: pr.pullRequest.repository.owner + url: pr?.pullRequest.url, + repoUrl: pr?.pullRequest.repository.url, + title: pr?.pullRequest.title, + createdAt: pr?.pullRequest.createdAt, + avatarUrl: pr?.pullRequest.author.avatarUrl, + project: pr?.pullRequest.repository.owner })) - const mergedPRData = data.filter((pr) => pr.pullRequest.merged === true) + const mergedPRData = data?.filter((pr) => pr?.pullRequest.merged === true) - const mergedPRs: PR[] = mergedPRData.map((pr) => ({ - totalComments: pr.pullRequest.totalCommentsCount, + const mergedPRs: PR[] = mergedPRData?.map((pr) => ({ + totalComments: pr?.pullRequest.totalCommentsCount, daysOpened: Math.floor( - (new Date(pr.pullRequest.mergedAt).getTime() - - new Date(pr.pullRequest.createdAt).getTime()) / + (new Date(pr?.pullRequest.mergedAt).getTime() - + new Date(pr?.pullRequest.createdAt).getTime()) / ONE_DAY ), - url: pr.pullRequest.url, - repoUrl: pr.pullRequest.repository.url, - title: pr.pullRequest.title, - createdAt: pr.pullRequest.createdAt, - avatarUrl: pr.pullRequest.author.avatarUrl, - project: pr.pullRequest.repository.owner + url: pr?.pullRequest.url, + repoUrl: pr?.pullRequest.repository.url, + title: pr?.pullRequest.title, + createdAt: pr?.pullRequest.createdAt, + avatarUrl: pr?.pullRequest.author.avatarUrl, + project: pr?.pullRequest.repository.owner })) openPRs.sort( diff --git a/src/hooks/useGithubIssues.ts b/src/hooks/useGithubIssues.ts index cddc4aa..6c89fb3 100644 --- a/src/hooks/useGithubIssues.ts +++ b/src/hooks/useGithubIssues.ts @@ -86,7 +86,6 @@ export const useGithubIssues = () => { setProjects([]) const endCursor = localStorage.getItem("end_cursor") as string - console.log(endCursor, "Saved End cursor") const { ranged_prs, ranged_issues } = await fetchIssues({ username: username as string, @@ -166,7 +165,7 @@ export const useGithubIssues = () => { } fetchGithubIssues() - }, [endDate, startDate, username]) + }, [currentYear, endDate, startDate, username, yearlyFilter]) const memoizedIssues = useMemo( () => filterObject(toggleFilter, toolTipKey, issuesObject),