diff --git a/app/projects/[id]/page.module.css b/app/projects/[id]/page.module.css
index 5698f41d..918d995c 100644
--- a/app/projects/[id]/page.module.css
+++ b/app/projects/[id]/page.module.css
@@ -38,6 +38,7 @@
.project__container__details__additionalDetails,
.project__container__info__contributors,
.project__container__info__teams,
+.project__container__details__stats,
.project__container__info__contacts {
padding: 16px;
background-color: #ffffff;
@@ -76,6 +77,7 @@
.project__container__details__additionalDetails,
.project__container__info__contributors,
.project__container__info__teams,
+ .project__container__details__stats,
.project__container__info__contacts {
padding: 16px;
box-shadow: 0px 4px 4px 0px rgba(15, 23, 42, 0.04), 0px 0px 1px 0px rgba(15, 23, 42, 0.12);
diff --git a/app/projects/[id]/page.tsx b/app/projects/[id]/page.tsx
index 0deb0912..72fc03ed 100644
--- a/app/projects/[id]/page.tsx
+++ b/app/projects/[id]/page.tsx
@@ -8,7 +8,7 @@ import Header from '@/components/page/project-details/header';
import Hyperlinks from '@/components/page/project-details/hyper-links';
import KPIs from '@/components/page/project-details/kpis';
import TeamsInvolved from '@/components/page/project-details/teams-involved';
-import { getProject } from '@/services/projects.service';
+import { getProject, getProjectOsoDetails } from '@/services/projects.service';
import { getAllTeams } from '@/services/teams.service';
import { hasProjectDeleteAccess, hasProjectEditAccess } from '@/utils/common.utils';
import { getCookiesFromHeaders } from '@/utils/next-helpers';
@@ -18,10 +18,12 @@ import { IFocusArea } from '@/types/shared.types';
import SelectedFocusAreas from '@/components/core/selected-focus-area';
import { PAGE_ROUTES, SOCIAL_IMAGE_URL } from '@/utils/constants';
import { Metadata, ResolvingMetadata } from 'next';
+import ProjectStats from '@/components/page/project-details/stats';
export default async function ProjectDetails({ params }: any) {
const projectId = params?.id;
- const { isError, userInfo, hasEditAccess, hasDeleteAccess, project, focusAreas, authToken } = await getPageData(projectId);
+ const { isError, userInfo, hasEditAccess, hasDeleteAccess, project, focusAreas, authToken, osoInfo } = await getPageData(projectId);
+ const showProjectStats = osoInfo?.forkCount > 0 || osoInfo?.starCount > 0 || osoInfo?.repositoryCount > 0 || osoInfo?.contributorCount > 0;
if (isError) {
return ;
@@ -36,7 +38,7 @@ export default async function ProjectDetails({ params }: any) {
-
+
{project?.projectLinks?.length > 0 && (
@@ -58,6 +60,12 @@ export default async function ProjectDetails({ params }: any) {
)}
+ {showProjectStats && (
+
+ )}
+
@@ -86,6 +94,7 @@ const getPageData = async (projectId: string) => {
let isError = false;
const { authToken, isLoggedIn, userInfo } = getCookiesFromHeaders();
let project = null;
+ let osoInfo = null;
let hasEditAccess = false;
let hasDeleteAccess = false;
let loggedInMemberTeams = [];
@@ -93,7 +102,6 @@ const getPageData = async (projectId: string) => {
try {
const [projectResponse, focusAreaResponse] = await Promise.all([getProject(projectId, {}), getFocusAreas('Project', {})]);
-
if (projectResponse?.error || focusAreaResponse?.error) {
return {
isError: true,
@@ -124,6 +132,12 @@ const getPageData = async (projectId: string) => {
project = projectResponse?.data?.formattedData;
focusAreas = focusAreaResponse?.data?.filter((data: IFocusArea) => !data.parentUid);
+ if (project.osoProjectName) {
+ const osoResponse = await getProjectOsoDetails(project.osoProjectName);
+ if (!osoResponse?.error) {
+ osoInfo = osoResponse?.data ?? {};
+ }
+ }
hasEditAccess = hasProjectEditAccess(userInfo, project, isLoggedIn, loggedInMemberTeams);
hasDeleteAccess = hasProjectDeleteAccess(userInfo, project, isLoggedIn);
@@ -137,6 +151,7 @@ const getPageData = async (projectId: string) => {
project,
focusAreas,
authToken,
+ osoInfo,
};
} catch (error) {
return {
@@ -148,11 +163,11 @@ const getPageData = async (projectId: string) => {
project,
focusAreas,
authToken,
+ osoInfo,
};
}
};
-
type IGenerateMetadata = {
params: { id: string };
searchParams: { [key: string]: string | string[] | undefined };
diff --git a/components/page/project-details/stats-card.tsx b/components/page/project-details/stats-card.tsx
new file mode 100644
index 00000000..964a5a5c
--- /dev/null
+++ b/components/page/project-details/stats-card.tsx
@@ -0,0 +1,89 @@
+'use client';
+
+import Image from 'next/image';
+
+interface IStatsCard {
+ statsName: string;
+ count: number;
+ icon: string;
+ newContributors?: number;
+}
+
+const StatsCard = (props: IStatsCard) => {
+ const statsName = props?.statsName;
+ const count = props?.count;
+ const icon = props?.icon;
+ const newContributors = props?.newContributors ?? 0;
+
+ return (
+ <>
+
+
+ {count} {statsName === 'Contributors' && newContributors > 0 && {`(${newContributors} New)`}}
+
+
+
+ {statsName}
+
+ {(statsName === 'Contributors' && newContributors > 0) &&
Last 6 months}
+
+
+ >
+ );
+};
+
+export default StatsCard;
diff --git a/components/page/project-details/stats.tsx b/components/page/project-details/stats.tsx
new file mode 100644
index 00000000..1bd13b2c
--- /dev/null
+++ b/components/page/project-details/stats.tsx
@@ -0,0 +1,69 @@
+'use client';
+
+import StatsCard from './stats-card';
+
+interface IProjectStats {
+ stats: any;
+}
+
+const ProjectStats = (props: IProjectStats) => {
+ const stats = props?.stats;
+
+ return (
+ <>
+
+
Project Stats
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+
+export default ProjectStats;
diff --git a/public/icons/contributors.svg b/public/icons/contributors.svg
new file mode 100644
index 00000000..33efd6fb
--- /dev/null
+++ b/public/icons/contributors.svg
@@ -0,0 +1,4 @@
+
diff --git a/public/icons/fork.svg b/public/icons/fork.svg
new file mode 100644
index 00000000..a961c0d1
--- /dev/null
+++ b/public/icons/fork.svg
@@ -0,0 +1,3 @@
+
diff --git a/public/icons/repos.svg b/public/icons/repos.svg
new file mode 100644
index 00000000..6b6699de
--- /dev/null
+++ b/public/icons/repos.svg
@@ -0,0 +1,6 @@
+
diff --git a/services/projects.service.ts b/services/projects.service.ts
index 303efb86..17eea237 100644
--- a/services/projects.service.ts
+++ b/services/projects.service.ts
@@ -73,6 +73,7 @@ const getFormattedProject = (project: any) => {
formattedProject['createdBy'] = project.createdBy ?? null;
formattedProject['score'] = project.score ?? null;
formattedProject['projectFocusAreas']= project.projectFocusAreas ?? [];
+ formattedProject['osoProjectName'] = project.osoProjectName ?? null;
const tempContributors: any = [];
project?.contributions?.map((mem: any) => {
@@ -175,4 +176,15 @@ const formatToSave = (payload: any) => {
objectToSave['contributions'] = payload?.contributions;
objectToSave['focusAreas'] = [];
return objectToSave;
+}
+
+export const getProjectOsoDetails = async (name: string) => {
+ const requestOptions: RequestInit = { method: "GET", headers: getHeader(""), cache: "no-store" };
+ const response = await fetch(`${process.env.DIRECTORY_API_URL}/v1/oso-metrics/${name}`, requestOptions);
+ if (!response?.ok) {
+ return { error: { statusText: response?.statusText } }
+ }
+
+ const result = await response?.json();
+ return { data: result }
}
\ No newline at end of file