Skip to content

Commit 5afafcb

Browse files
committed
provisional ranks
1 parent c71d8e0 commit 5afafcb

File tree

12 files changed

+157
-34
lines changed

12 files changed

+157
-34
lines changed

app/by/[rankingType]/[page]/components/profile-avatar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export const ProfileAvatar: FC<ProfileAvatarProps> = ({ url, initials }) => {
2121
return (
2222
<Avatar>
2323
<AvatarImage src={url} className={cn('rounded-full', { 'animate-spin': pending })} width={36} height={36} />
24-
<AvatarFallback>{initials}</AvatarFallback>
24+
<AvatarFallback className="flex items-center justify-center">{initials}</AvatarFallback>
2525
</Avatar>
2626
);
2727
};

app/profile/[login]/components/layout-left-column.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { Avatar, AvatarImage } from '@/components/ui/avatar';
88
import { Button } from '@/components/ui/button';
99
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
1010
import { UserQuery } from '@/types/generated/graphql';
11+
import { ensureLinkProtocol } from '@/utils/ensure-link-protocol';
1112

1213
import { FetchUserButtonForProfilePage } from './fetch-user-button';
1314
import { ProfileListItem } from './profile-list-item';
@@ -81,7 +82,7 @@ export const LayoutLeftColumn: FC<LayoutLeftColumnProps> = ({ user, children, cl
8182
<div className="flex flex-col gap-1.5">
8283
<h4 className="text-lg font-semibold">Contacts</h4>
8384
<ProfileListItem value={user.email} url={`mailto:${user.email}`} Icon={Mail} />
84-
<ProfileListItem value={user.websiteUrl} url={user.websiteUrl!} Icon={Link2} />
85+
<ProfileListItem value={user.websiteUrl} url={ensureLinkProtocol(user.websiteUrl)} Icon={Link2} />
8586
{user.socialAccounts?.nodes?.map((account) => (
8687
<ProfileListItem
8788
key={`${account.provider}${account.displayName}`}

app/profile/[login]/components/profile-timeline.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ type ProfileTimelineDescriptionProps = {
2222
changeset: ChangeSetItemType;
2323
};
2424

25-
const parseChangesetItem = (changesetItem: ChangeItemType) => {
25+
const parseChangesetItem = (changesetItem: ChangeItemType, type: ChangeItemType) => {
2626
if (isObject<NonNullable<SocialAccountChangeItem>>(changesetItem)) {
2727
if (!changesetItem.totalCount) {
2828
return null;
@@ -33,6 +33,10 @@ const parseChangesetItem = (changesetItem: ChangeItemType) => {
3333
.join('; ');
3434
}
3535

36+
if (Array.isArray(changesetItem) && type === 'repoRemoved') {
37+
return changesetItem.map((repo) => `${repo.name}${repo.stargazers.toLocaleString('en-US')}`).join('; ');
38+
}
39+
3640
if (typeof changesetItem === 'number') {
3741
return changesetItem.toLocaleString('en-US');
3842
}
@@ -45,8 +49,8 @@ const parseChangesetItem = (changesetItem: ChangeItemType) => {
4549
};
4650

4751
const ProfileTimelineDescription: FC<ProfileTimelineDescriptionProps> = ({ type, changeset }) => {
48-
const before = parseChangesetItem(changeset.b);
49-
const after = parseChangesetItem(changeset.a);
52+
const before = parseChangesetItem(changeset.b, type);
53+
const after = parseChangesetItem(changeset.a, type);
5054

5155
if (type === 'avatarUrl') {
5256
return (
@@ -63,7 +67,7 @@ const ProfileTimelineDescription: FC<ProfileTimelineDescriptionProps> = ({ type,
6367
<span>
6468
{!!before && (
6569
<span className="opacity-50">
66-
{before} {!after && '(removed)'}
70+
{before} {!after && type !== 'repoRemoved' && '(removed)'}
6771
</span>
6872
)}
6973
{!!before && !!after && <ArrowRight size={12} className="inline" />} {after}

app/profile/[login]/components/ranks-overview.tsx

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { FC } from 'react';
22

33
import { Link } from '@/components/link/link';
4-
import { RankDelta } from '@/components/rank-delta/rank-delta';
4+
import { RankNumber } from '@/components/rank-number/rank-number';
55
import { UserQuery } from '@/types/generated/graphql';
66

77
import { ProfileCard, ProfileCardActions, ProfileCardContent, ProfileCardHeader } from './profile-card';
@@ -16,18 +16,31 @@ export const RanksOverview: FC<RanksOverviewProps> = ({ ranksData, login }) => {
1616
<ProfileCard>
1717
<ProfileCardHeader>Ranks</ProfileCardHeader>
1818
<ProfileCardContent>
19-
<p>
20-
⭐&nbsp;&nbsp;Stars rank: {ranksData?.ownedStars?.toLocaleString('en-US')}{' '}
21-
<RankDelta current={ranksData?.ownedStars} previous={ranksData?.ownedStarsM} />
22-
</p>
23-
<p>
24-
🔀&nbsp;&nbsp;Contributor rank: {ranksData?.contributedStars?.toLocaleString('en-US')}{' '}
25-
{false && <RankDelta current={ranksData?.contributedStars} previous={ranksData?.contributedStarsM} />}
26-
</p>
27-
<p>
28-
👥&nbsp;&nbsp;Followers rank: {ranksData?.followersCount?.toLocaleString('en-US')}{' '}
29-
<RankDelta current={ranksData?.followersCount} previous={ranksData?.followersCountM} />
30-
</p>
19+
<div className="flex items-center">
20+
⭐&nbsp;&nbsp;Stars rank:&nbsp;
21+
<RankNumber
22+
rank={ranksData?.ownedStars}
23+
rankPrevious={ranksData?.ownedStarsM}
24+
rankProvisional={ranksData?.ownedStarsProvisional}
25+
/>
26+
</div>
27+
<div className="flex items-center">
28+
🔀&nbsp;&nbsp;Contributor rank:&nbsp;
29+
<RankNumber
30+
rank={ranksData?.contributedStars}
31+
rankPrevious={ranksData?.contributedStarsM}
32+
rankProvisional={ranksData?.contributedStarsProvisional}
33+
showDelta={false}
34+
/>
35+
</div>
36+
<div className="flex items-center">
37+
👥&nbsp;&nbsp;Followers rank:&nbsp;
38+
<RankNumber
39+
rank={ranksData?.followersCount}
40+
rankPrevious={ranksData?.followersCountM}
41+
rankProvisional={ranksData?.followersCountProvisional}
42+
/>
43+
</div>
3144
</ProfileCardContent>
3245
<ProfileCardActions>
3346
<Link href={`/profile/${login}/ranks`}>View Details</Link>

app/profile/[login]/profile-summary.gql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,15 @@ query User($login: String!) {
7575
}
7676
rank {
7777
ownedStars
78+
ownedStarsProvisional
7879
ownedStarsM
7980
ownedStarsY
8081
contributedStars
82+
contributedStarsProvisional
8183
contributedStarsM
8284
contributedStarsY
8385
followersCount
86+
followersCountProvisional
8487
followersCountM
8588
followersCountY
8689
}

app/profile/[login]/ranks/components/rank-card.tsx

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Star, TrendingUp, Trophy } from 'lucide-react';
22
import { FC } from 'react';
33

44
import { RankDelta } from '@/components/rank-delta/rank-delta';
5+
import { RankNumber } from '@/components/rank-number/rank-number';
56
import { getPercentileRank } from '@/utils/get-percentile-rank';
67

78
import { RankCardItem } from './rank-card-item';
@@ -11,24 +12,38 @@ type RankCardProps = {
1112
rank?: number | null;
1213
rankM?: number | null;
1314
rankY?: number | null;
15+
rankProvisional?: number | null;
16+
showDelta?: boolean;
1417
title: string;
1518
entityValue?: number | null;
1619
entityName: string;
1720
description: string;
1821
};
1922

20-
export const RankCard: FC<RankCardProps> = ({ rank, rankM, rankY, title, entityValue, entityName, description }) => {
23+
export const RankCard: FC<RankCardProps> = ({
24+
rank,
25+
rankProvisional,
26+
rankM,
27+
rankY,
28+
title,
29+
entityValue,
30+
entityName,
31+
showDelta,
32+
description,
33+
}) => {
2134
const rankPercentile = getPercentileRank(rank);
2235

2336
return (
2437
<ProfileCard>
2538
<ProfileCardHeader>{title}</ProfileCardHeader>
2639
<ProfileCardContent>
27-
<h2 className="text-3xl font-semibold mb-4">#{rank?.toLocaleString('en-US')}</h2>
40+
<h2 className="text-3xl font-semibold mb-4 flex">
41+
#<RankNumber rank={rank} rankProvisional={rankProvisional} showDelta={false} className="items-start" />
42+
</h2>
2843
{!!rankPercentile && (
2944
<RankCardItem Icon={Trophy}>You&apos;re in the top {rankPercentile}% of all users!</RankCardItem>
3045
)}
31-
{(rank !== rankM || rank !== rankY) && (
46+
{(rank !== rankM || rank !== rankY) && showDelta !== false && (
3247
<RankCardItem Icon={TrendingUp}>
3348
<span>
3449
Trend:{' '}

app/profile/[login]/ranks/page.tsx

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,20 @@ export default async function ProfileRanks({ params }: { params: Promise<{ login
1717
notFound();
1818
}
1919

20-
const { ownedStars, contributedStars, followersCount, ownedStarsM, followersCountM, ownedStarsY, followersCountY } =
21-
user.rank ?? {};
20+
const {
21+
ownedStars,
22+
contributedStars,
23+
contributedStarsM,
24+
contributedStarsY,
25+
followersCount,
26+
ownedStarsProvisional,
27+
contributedStarsProvisional,
28+
followersCountProvisional,
29+
ownedStarsM,
30+
followersCountM,
31+
ownedStarsY,
32+
followersCountY,
33+
} = user.rank ?? {};
2234

2335
const bestRankType = getBestRankType({ ownedStars, contributedStars, followersCount });
2436

@@ -30,6 +42,7 @@ export default async function ProfileRanks({ params }: { params: Promise<{ login
3042
rank={ownedStars}
3143
rankM={ownedStarsM}
3244
rankY={ownedStarsY}
45+
rankProvisional={ownedStarsProvisional}
3346
title="Stars rank"
3447
entityValue={user.ownedStars}
3548
entityName="stars"
@@ -40,6 +53,8 @@ export default async function ProfileRanks({ params }: { params: Promise<{ login
4053
rank={followersCount}
4154
rankM={followersCountM}
4255
rankY={followersCountY}
56+
rankProvisional={followersCountProvisional}
57+
showDelta={false}
4358
title="Followers rank"
4459
entityValue={user.followersCount}
4560
entityName="followers"
@@ -48,8 +63,9 @@ export default async function ProfileRanks({ params }: { params: Promise<{ login
4863

4964
<RankCard
5065
rank={contributedStars}
51-
rankM={contributedStars} // TODO: change to contributedStarsM when ranks are fully fetched
52-
rankY={contributedStars} // TODO: change to contributedStarsY when ranks are fully fetched
66+
rankM={contributedStarsM}
67+
rankY={contributedStarsY}
68+
rankProvisional={contributedStarsProvisional}
5369
title="Contributor rank"
5470
entityValue={user.contributedStars}
5571
entityName="stars"
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
'use client';
2+
import { FC } from 'react';
3+
4+
import { cn } from '@/lib/utils';
5+
6+
import { RankDelta } from '../rank-delta/rank-delta';
7+
import { Badge } from '../ui/badge';
8+
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../ui/tooltip';
9+
10+
type RankNumberProps = {
11+
rank?: number | null;
12+
rankProvisional?: number | null;
13+
rankPrevious?: number | null;
14+
showDelta?: boolean;
15+
className?: string;
16+
};
17+
18+
export const RankNumber: FC<RankNumberProps> = ({ rank, rankPrevious, rankProvisional, showDelta, className }) => {
19+
if (!rankProvisional || rankProvisional === rank) {
20+
return (
21+
<>
22+
{rank?.toLocaleString('en-US')}
23+
{showDelta !== false && (
24+
<>
25+
&nbsp;
26+
<RankDelta current={rank} previous={rankPrevious} />
27+
</>
28+
)}
29+
</>
30+
);
31+
}
32+
33+
return (
34+
<span className={cn('flex gap-2 items-center', className)}>
35+
{rankProvisional?.toLocaleString('en-US')}{' '}
36+
<TooltipProvider>
37+
<Tooltip>
38+
<TooltipTrigger asChild>
39+
<Badge variant="secondary" className="px-1">
40+
provisional
41+
</Badge>
42+
</TooltipTrigger>
43+
<TooltipContent>
44+
<p className="max-w-44">
45+
Temporary estimate based on other users’ current ranks. A precise ranking replaces it after the next daily
46+
calculation.
47+
</p>
48+
</TooltipContent>
49+
</Tooltip>
50+
</TooltipProvider>
51+
</span>
52+
);
53+
};

components/signin-button/signin-button.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigge
1313
export default function SigninButton() {
1414
const { data: session } = useSession();
1515

16-
console.log('session', session);
17-
1816
return (
1917
<div>
2018
{session ? (

0 commit comments

Comments
 (0)