Skip to content

Commit

Permalink
Merge pull request #449 from memser-spaceport/feat/project-oso
Browse files Browse the repository at this point in the history
Feat/project oso
  • Loading branch information
Thangaraj-Ideas2it authored Dec 20, 2024
2 parents e5cabe6 + a2a50bd commit 406a79a
Show file tree
Hide file tree
Showing 8 changed files with 205 additions and 5 deletions.
2 changes: 2 additions & 0 deletions app/projects/[id]/page.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
25 changes: 20 additions & 5 deletions app/projects/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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 <Error />;
Expand All @@ -36,7 +38,7 @@ export default async function ProjectDetails({ params }: any) {
<div className={styles.project__container__details}>
<div className={styles.project__container__details__primary}>
<Header project={project} userHasEditRights={hasEditAccess} userHasDeleteRights={hasDeleteAccess} user={userInfo} authToken={authToken} />
<Description description={project?.description} project={project} userHasEditRights={hasEditAccess} user={userInfo}/>
<Description description={project?.description} project={project} userHasEditRights={hasEditAccess} user={userInfo} />
</div>

{project?.projectLinks?.length > 0 && (
Expand All @@ -58,6 +60,12 @@ export default async function ProjectDetails({ params }: any) {
</div>
)}

{showProjectStats && (
<div className={styles.project__container__details__stats}>
<ProjectStats stats={osoInfo} />
</div>
)}

<div className={styles.project__container__details__additionalDetails}>
<AdditionalDetails project={project} userHasEditRights={hasEditAccess} authToken={authToken} user={userInfo} />
</div>
Expand Down Expand Up @@ -86,14 +94,14 @@ 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 = [];
let focusAreas: IFocusArea[] = [];

try {
const [projectResponse, focusAreaResponse] = await Promise.all([getProject(projectId, {}), getFocusAreas('Project', {})]);

if (projectResponse?.error || focusAreaResponse?.error) {
return {
isError: true,
Expand Down Expand Up @@ -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);
Expand All @@ -137,6 +151,7 @@ const getPageData = async (projectId: string) => {
project,
focusAreas,
authToken,
osoInfo,
};
} catch (error) {
return {
Expand All @@ -148,11 +163,11 @@ const getPageData = async (projectId: string) => {
project,
focusAreas,
authToken,
osoInfo,
};
}
};


type IGenerateMetadata = {
params: { id: string };
searchParams: { [key: string]: string | string[] | undefined };
Expand Down
89 changes: 89 additions & 0 deletions components/page/project-details/stats-card.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<>
<div className="statsCard">
<p className="statsCard__count">
{count} {statsName === 'Contributors' && newContributors > 0 && <span className="statsCard__count__new">{`(${newContributors} New)`}</span>}
</p>
<div className="statsCard__cn">
<Image className="statsCard__cn__img" src={icon} alt="icon" height={16} width={16} />
<span className="statsCard__cn__name">{statsName}</span>
</div>
{(statsName === 'Contributors' && newContributors > 0) && <span className="statsCard__duration">Last 6 months</span>}
</div>
<style jsx>{`
.statsCard {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
border-radius: 4px;
border: 1px solid #E2E8F0;
}
.statsCard__count {
font-size: 24px;
font-weight: 700;
line-height: 32px;
letter-spacing: 0px;
color: #0f172a;
display: flex;
align-items: center;
gap: 2px;
}
.statsCard__count__new {
font-size: 10px;
font-weight: 600;
line-height: 18px;
color: #30C593;
}
.statsCard__cn{
display: flex;
align-items: center;
justify-content: center;
gap 1px;
}
.statsCard__cn__name {
font-size: 13px;
font-weight: 400;
line-height: 18px;
color: #64748B;
}
.statsCard__duration{
padding: 4px;
font-size: 10px;
font-weight: 400;
line-height: 18px;
color: #0F172A;
background-color: #F1F5F9;
padding-left: 4px;
padding-right: 4px;
}
`}</style>
</>
);
};

export default StatsCard;
69 changes: 69 additions & 0 deletions components/page/project-details/stats.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
'use client';

import StatsCard from './stats-card';

interface IProjectStats {
stats: any;
}

const ProjectStats = (props: IProjectStats) => {
const stats = props?.stats;

return (
<>
<div className="stats">
<h6 className="stats__title">Project Stats</h6>
<div className="stats__container">
<div className="stats__container__card">
<StatsCard statsName="Forks" count={stats?.forkCount ?? 0} icon="/icons/fork.svg" />
</div>
<div className="stats__container__card">
<StatsCard statsName="Stars" count={stats?.starCount ?? 0} icon="/icons/star-outline-gray.svg" />
</div>
<div className="stats__container__card">
<StatsCard statsName="Repos" count={stats?.repositoryCount ?? 0} icon="/icons/repos.svg" />
</div>
<div className="stats__container__card">
<StatsCard statsName="Contributors" count={stats?.contributorCount ?? 0} icon="/icons/contributors.svg" newContributors={stats?.newContributorCount6Months ?? 0} />
</div>
</div>
</div>
<style jsx>{`
.stats {
display: flex;
flex-direction: column;
gap: 8px;
}
.stats__title {
font-size: 14px;
font-weight: 500;
line-height: 20px;
letter-spacing: 0px;
color: #64748b;
}
.stats__container {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 10px;
}
.stats__container__card {
width: 159px;
height: 88px;
}
@media (min-width: 1024px) {
.stats__container__card {
width: 206.75px;
height: 88px;
}
}
`}</style>
</>
);
};

export default ProjectStats;
4 changes: 4 additions & 0 deletions public/icons/contributors.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions public/icons/fork.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions public/icons/repos.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions services/projects.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down Expand Up @@ -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 }
}

0 comments on commit 406a79a

Please sign in to comment.