Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Fix and clean up profile page #98

Merged
merged 4 commits into from
Aug 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 30 additions & 27 deletions app/(dashboard)/dashboard/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { DashboardHeader } from "@/components/header";
import { DashboardShell } from "@/components/shell";
import UserPointsAndLevelCard from "@/components/ui/userPointsAndLevelCard";
import UserPointsAndLevelCard from "@/components/ui/user-points-and-level-card";
import { authOptions } from "@/lib/auth";
import { getEnrolledRepositories } from "@/lib/enrollment/service";
import { getCurrentUser } from "@/lib/session";
Expand All @@ -10,6 +10,7 @@ import {
} from "@/lib/utils/levelUtils";
import { TLevel } from "@/types/level";
import { TPointTransaction } from "@/types/pointTransaction";
import { TRepository } from "@/types/repository";
import Link from "next/link";
import { redirect } from "next/navigation";

Expand Down Expand Up @@ -49,7 +50,7 @@ export default async function DashboardPage() {
redirect(authOptions?.pages?.signIn || "/login");
}

const repositoriesUserIsEnrolledIn = await getEnrolledRepositories(user.id);
const repositoriesUserIsEnrolledIn: TRepository[] = await getEnrolledRepositories(user.id);

const calculateTotalPointsForCurrentUser = (
currentUserId: string,
Expand Down Expand Up @@ -93,31 +94,33 @@ export default async function DashboardPage() {
};

// Calculate total points,rank,current level for the current user in repositories they are enrolled in.
const pointsAndLevelsPerRepository = repositoriesUserIsEnrolledIn.map((repository) => {
const pointTransactions = repository.pointTransactions || [];

const totalPoints = calculateTotalPointsForCurrentUser(user.id, pointTransactions);
const rank = calculateRankOfCurrentUser(user.id, pointTransactions);
const { currentLevelOfUser, nextLevelForUser } = findCurrentAndNextLevelOfCurrentUser(
repository,
totalPoints
);
const levels = (repository?.levels as TLevel[]) || [];
const modifiedTagsArray = calculateAssignabelNonAssignableIssuesForUserInALevel(levels); //gets all assignable tags be it from the current level and from lower levels.

const assignableTags = modifiedTagsArray.find((item) => item.levelId === currentLevelOfUser?.id); //finds the curent level in the modifiedTagsArray.

return {
id: repository.id,
repositoryName: repository.name,
points: totalPoints,
repositoryLogo: repository.logoUrl,
rank: rank,
currentLevelOfUser: currentLevelOfUser,
nextLevelForUser: nextLevelForUser,
assignableTags: assignableTags?.assignableIssues || [],
};
});
const pointsAndLevelsPerRepository = await Promise.all(
repositoriesUserIsEnrolledIn.map(async (repository) => {
const pointTransactions = repository.pointTransactions || [];
const totalPoints = calculateTotalPointsForCurrentUser(user.id, pointTransactions);
const rank = calculateRankOfCurrentUser(user.id, pointTransactions);

const { currentLevelOfUser, nextLevelForUser } = await findCurrentAndNextLevelOfCurrentUser(
repository.id,
totalPoints
);

const levels = (repository?.levels as TLevel[]) || [];
const modifiedTagsArray = calculateAssignabelNonAssignableIssuesForUserInALevel(levels); // gets all assignable tags, whether from the current level or from lower levels.
const assignableTags = modifiedTagsArray.find((item) => item.levelId === currentLevelOfUser?.id); // finds the current level in the modifiedTagsArray.

return {
id: repository.id,
repositoryName: repository.name,
points: totalPoints,
repositoryLogo: repository.logoUrl,
rank: rank,
currentLevelOfUser: currentLevelOfUser,
nextLevelForUser: nextLevelForUser,
assignableTags: assignableTags?.assignableIssues || [],
};
})
);

return (
<DashboardShell>
Expand Down
2 changes: 1 addition & 1 deletion app/(dashboard)/enroll/[repositoryId]/issues/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import GitHubIssue from "@/components/ui/githubIssue";
import GitHubIssue from "@/components/ui/github-issue";
import { getAllOssGgIssuesOfRepo } from "@/lib/github/service";
import { getRepositoryById } from "@/lib/repository/service";
import { TLevel } from "@/types/level";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use client";

import { Avatar, AvatarImage } from "@/components/ui/avatar";
import UserProfileSummary from "@/components/ui/userProfileSummary";
import UserProfileSummary from "@/components/ui/user-profile-summary";
import { capitalizeEachWord } from "@/lib/utils/textformat";
import { TLevel } from "@/types/level";
import { TPointTransactionWithUser } from "@/types/pointTransaction";
Expand Down
10 changes: 5 additions & 5 deletions app/(dashboard)/enroll/[repositoryId]/levels/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import LevelDetailCard from "@/components/ui/levelDetailCard";
import LevelDetailCard from "@/components/ui/level-detail-card";
import { authOptions } from "@/lib/auth";
import { getPointsForUserInRepoByRepositoryId } from "@/lib/points/service";
import { getPointsForPlayerInRepoByRepositoryId } from "@/lib/points/service";
import { getRepositoryById } from "@/lib/repository/service";
import { getCurrentUser } from "@/lib/session";
import {
Expand Down Expand Up @@ -32,13 +32,13 @@ export default async function Levels({ params: { repositoryId } }) {
const modifiedTagsArray: ModifiedTagsArray[] =
calculateAssignabelNonAssignableIssuesForUserInALevel(sortedLevels);

const totalPointsForUserInThisRepo: number = await getPointsForUserInRepoByRepositoryId(
const totalPointsForUserInThisRepo: number = await getPointsForPlayerInRepoByRepositoryId(
repositoryId,
user.id
);

const { currentLevelOfUser, nextLevelForUser } = findCurrentAndNextLevelOfCurrentUser(
repository,
const { currentLevelOfUser, nextLevelForUser } = await findCurrentAndNextLevelOfCurrentUser(
repository.id,
totalPointsForUserInThisRepo
);

Expand Down
2 changes: 1 addition & 1 deletion app/(dashboard)/issues/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { DashboardHeader } from "@/components/header";
import { DashboardShell } from "@/components/shell";
import { Button } from "@/components/ui/button";
import GitHubIssue from "@/components/ui/githubIssue";
import GitHubIssue from "@/components/ui/github-issue";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { getAllOssGgIssuesOfRepo } from "@/lib/github/service";
import { capitalizeFirstLetter } from "@/lib/utils/textformat";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import UserProfileSummary from "@/components/ui/userProfileSummary";
import UserProfileSummary from "@/components/ui/user-profile-summary";
import { getUsersForRepository } from "@/lib/repository/service";

export const metadata = {
Expand Down
57 changes: 57 additions & 0 deletions app/[githubLogin]/components/level-list.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Avatar, AvatarImage } from "@/components/ui/avatar";
import { Button } from "@/components/ui/button";
import { TLevel } from "@/types/level";
import Image from "next/image";
import React from "react";

interface LevelListProps {
levels: { currentLevelOfUser: TLevel | null; repoLogo: string }[];
}

const LevelList: React.FC<LevelListProps> = ({ levels }) => {
const hasValidLevels = levels.some((level) => level.currentLevelOfUser !== null);

if (!hasValidLevels) {
return (
<div className="h-fit rounded-md bg-zinc-50 py-10 text-center">
<p className="text-sm text-slate-800">You haven&apos;t enrolled yet!</p>
<Button href="/login" className="mt-4">
Start playing 🕹️
</Button>
</div>
);
}

return (
<div className="col-span-1 flex flex-col gap-8 text-center">
{levels.map(
(level, index) =>
level.currentLevelOfUser && (
<div
key={index}
className="relative flex w-11/12 items-center justify-center rounded-lg bg-secondary py-3">
<Avatar className="h-40 w-40">
<AvatarImage
src={level.currentLevelOfUser.iconUrl}
alt={`${level.currentLevelOfUser.name} icon`}
/>
</Avatar>
{level.repoLogo && (
<div className="absolute left-0 top-0 -translate-x-1/3 -translate-y-1/3">
<Image
src={level.repoLogo}
height={40}
width={40}
alt={`Repository logo`}
className="rounded-lg"
/>
</div>
)}
</div>
)
)}
</div>
);
};

export default LevelList;
29 changes: 29 additions & 0 deletions app/[githubLogin]/components/pr-list.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import PullRequest from "@/components/ui/github-pr";
import { TPullRequest } from "@/types/pullRequest";
import React from "react";

interface PullRequestListProps {
pullRequests: TPullRequest[];
profileName: string;
}

const PullRequestList: React.FC<PullRequestListProps> = ({ pullRequests, profileName }) => {
return (
<div className="col-span-4 space-y-12">
{pullRequests.length > 0 ? (
<div>
<h3 className="mb-2 text-xl font-medium">Contributions by {profileName}</h3>
{pullRequests.map((pullRequest) => (
<PullRequest key={pullRequest.href} pullRequest={pullRequest} />
))}
</div>
) : (
<div className="flex h-96 flex-col items-center justify-center space-y-4 rounded-md bg-zinc-50">
<p>{profileName} has not yet contributed to an oss.gg repository 🕹️</p>
</div>
)}
</div>
);
};

export default PullRequestList;
35 changes: 35 additions & 0 deletions app/[githubLogin]/components/profile-info.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { TGithubUserData } from "@/types/githubUser";
import Image from "next/image";

import SocialLinks from "./social-links";

interface ProfileInfoProps {
githubData: TGithubUserData;
}

const ProfileInfoBar: React.FC<ProfileInfoProps> = ({ githubData }) => (
<div className="z-40 -mt-24 grid grid-cols-5 gap-6 text-zinc-50 md:-mt-36">
<Image
src={githubData.avatar_url}
alt="github avatar"
width={180}
height={180}
className="z-50 col-span-2 rounded-md md:col-span-1"
priority
/>

<div className="col-span-3 flex items-center space-x-6 md:col-span-4">
<div>
<h1 className="text-3xl font-bold">{githubData.name}</h1>
<p className="mt-1 text-xs">{githubData.bio}</p>
</div>

<SocialLinks
twitterUsername={githubData.twitter_username}
githubUrl={githubData.html_url || "https://formbricks.com/github"}
/>
</div>
</div>
);

export default ProfileInfoBar;
60 changes: 60 additions & 0 deletions app/[githubLogin]/components/profile-page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
"use server";

import { getPullRequestsByGithubLogin } from "@/lib/github/service";
import { getPointsForPlayerInRepoByRepositoryId } from "@/lib/points/service";
import { getEnrichedGithubUserData } from "@/lib/public-profile/profileData";
import { getAllRepositories } from "@/lib/repository/service";
import { findCurrentAndNextLevelOfCurrentUser } from "@/lib/utils/levelUtils";
import { TLevel } from "@/types/level";
import { TPullRequest } from "@/types/pullRequest";

import LevelList from "./level-list";
import PullRequestList from "./pr-list";
import ProfileInfoBar from "./profile-info";

export default async function ProfilePage({ githubLogin }: { githubLogin: string }) {
// Get & enrich the player data
const enrichedUserData = await getEnrichedGithubUserData(githubLogin);

// Get the level data if user is enrolled in any repositories
let userLevels: { currentLevelOfUser: TLevel | null; repoLogo: string }[] = [];

if (enrichedUserData.enrolledRepositories) {
userLevels = await Promise.all(
enrichedUserData.enrolledRepositories.map(async (enrolledRepository) => {
const totalPointsForUserInThisRepo = await getPointsForPlayerInRepoByRepositoryId(
enrolledRepository.id,
enrichedUserData.playerData?.id || ""
);
const { currentLevelOfUser } = await findCurrentAndNextLevelOfCurrentUser(
enrolledRepository.id,
totalPointsForUserInThisRepo
);
return {
currentLevelOfUser,
repoLogo: enrolledRepository?.logoUrl || "",
};
})
);
}

const ossGgRepositories = await getAllRepositories();

let pullRequests = [] as TPullRequest[];

// Get the 20 most recent PRs of a user for all repositories signed up on oss.gg
if (enrichedUserData.status.githubUserFound) {
const ossGgRepositoriesIds = ossGgRepositories.map((repo) => `${repo.owner}/${repo.name}`);
pullRequests = await getPullRequestsByGithubLogin(ossGgRepositoriesIds, githubLogin);
}

return (
<div>
<ProfileInfoBar githubData={enrichedUserData.githubData} />
<div className="mt-10 grid grid-cols-4 gap-6 md:grid-cols-5">
<LevelList levels={userLevels} />
<PullRequestList pullRequests={pullRequests} profileName={enrichedUserData.githubData.name} />
</div>
</div>
);
}
29 changes: 29 additions & 0 deletions app/[githubLogin]/components/social-links.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import Link from "next/link";
import { FaGithub, FaTwitter } from "react-icons/fa";

interface SocialLinksProps {
twitterUsername?: string;
githubUrl: string;
}

const SocialLinks: React.FC<SocialLinksProps> = ({ twitterUsername, githubUrl }) => {
return (
<>
{twitterUsername && <SocialLink href={`https://twitter.com/${twitterUsername}`} Icon={FaTwitter} />}
<SocialLink href={githubUrl} Icon={FaGithub} />
</>
);
};

interface SocialLinkProps {
href: string;
Icon: React.ElementType;
}

const SocialLink: React.FC<SocialLinkProps> = ({ href, Icon }) => (
<Link href={href} target="_blank" className="hidden md:block">
<Icon className="h-8 w-8 transition-all duration-150 ease-in-out hover:scale-110" strokeWidth="1px" />
</Link>
);

export default SocialLinks;
2 changes: 2 additions & 0 deletions app/[githubLogin]/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"use server";

import { SiteFooter } from "@/components/site-footer";
import { Button } from "@/components/ui/button";
import { getCurrentUser } from "@/lib/session";
Expand Down
Loading
Loading