|
2 | 2 |
|
3 | 3 | import { unstable_cacheLife as cacheLife } from 'next/cache'; |
4 | 4 |
|
5 | | -import { Page } from '@/components/page/page'; |
6 | | -import { RankDelta } from '@/components/rank-delta/rank-delta'; |
7 | | -import { |
8 | | - Pagination, |
9 | | - PaginationContent, |
10 | | - PaginationItem, |
11 | | - PaginationNext, |
12 | | - PaginationPrevious, |
13 | | -} from '@/components/ui/pagination'; |
14 | | -import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'; |
15 | | -import { fetchCountryList } from '@/graphql/helpers/fetch-countries'; |
| 5 | +import { Pagination } from '@/components/pagination/pagination'; |
| 6 | +import { RankingTable } from '@/components/ranking-table/ranking-table'; |
| 7 | +import { fetchCountries } from '@/graphql/helpers/fetch-countries'; |
16 | 8 | import { graphqlDirect } from '@/lib/graphql/graphql-direct'; |
17 | | -import { GlobalRankingsDocument, RankOrder } from '@/types/generated/graphql'; |
18 | | -import { getInitials } from '@/utils/get-initials'; |
19 | | - |
20 | | -import { ClickableRow } from './components/clickale-row'; |
21 | | -import { LinkWithStopPropagation } from './components/link-with-stop-propagation'; |
22 | | -import { ProfileAvatar } from './components/profile-avatar'; |
23 | | -import { getCountryFlag } from './utils/get-country-flag'; |
| 9 | +import { GlobalRankingsDocument } from '@/types/generated/graphql'; |
| 10 | +import { RankingTypeClient } from '@/types/ranking.types'; |
| 11 | +import { getRankingOrder } from '@/utils/get-ranking-config-by-type'; |
24 | 12 |
|
25 | 13 | const ITEMS_PER_PAGE = 100; |
26 | 14 |
|
27 | | -function getConfigByRankingType(rankingType: string) { |
28 | | - let propName: 'c' | 'f' | 's'; |
29 | | - let queryOrder: RankOrder; |
30 | | - let title: string; |
31 | | - let subtitle: string; |
32 | | - let rankingBaseEntity: string; |
33 | | - |
34 | | - switch (rankingType) { |
35 | | - case 'contributions': |
36 | | - queryOrder = RankOrder.Contributions; |
37 | | - propName = 'c'; |
38 | | - title = 'Contribution ranking'; |
39 | | - subtitle = "Rank is based on the stars from repositories where you've merged pull requests — excluding your own."; |
40 | | - rankingBaseEntity = 'Stars'; |
41 | | - break; |
42 | | - case 'followers': |
43 | | - queryOrder = RankOrder.Followers; |
44 | | - propName = 'f'; |
45 | | - title = 'Followers ranking'; |
46 | | - subtitle = 'Rank is based on the number of followers the user has on GitHub.'; |
47 | | - rankingBaseEntity = 'Followers'; |
48 | | - break; |
49 | | - case 'stars': |
50 | | - default: |
51 | | - queryOrder = RankOrder.Stars; |
52 | | - propName = 's'; |
53 | | - title = 'Star ranking'; |
54 | | - subtitle = 'Rank is based on the total number of stars across repositories owned by a user.'; |
55 | | - rankingBaseEntity = 'Stars'; |
56 | | - break; |
57 | | - } |
58 | | - |
59 | | - return [queryOrder, propName, title, subtitle, rankingBaseEntity] as const; |
60 | | -} |
| 15 | +type GlobalRankingProps = { |
| 16 | + params: Promise<{ rankingType: RankingTypeClient; page: string }>; |
| 17 | +}; |
61 | 18 |
|
62 | | -export default async function GlobalRanking({ params }: { params: Promise<{ rankingType: string; page: string }> }) { |
| 19 | +export default async function GlobalRanking({ params }: GlobalRankingProps) { |
63 | 20 | cacheLife('hours'); |
64 | 21 |
|
65 | 22 | const { rankingType, page: pageParam } = await params; |
66 | 23 | const page = parseInt(pageParam, 10); |
67 | | - const [queryOrder, rankPropName, title, subtitle, rankingBaseEntity] = getConfigByRankingType(rankingType); |
| 24 | + const queryOrder = getRankingOrder(rankingType); |
68 | 25 | const offset = (page - 1) * ITEMS_PER_PAGE; |
69 | 26 | const [{ globalRankings }, countries] = await Promise.all([ |
70 | 27 | graphqlDirect(GlobalRankingsDocument, { order: queryOrder, offset }), |
71 | | - fetchCountryList(), |
| 28 | + fetchCountries(), |
72 | 29 | ]); |
73 | 30 |
|
74 | 31 | return ( |
75 | | - <Page className="max-w-5xl gap-6"> |
76 | | - <div> |
77 | | - <h1 className="text-2xl font-semibold">{title}</h1> |
78 | | - <div>{`${subtitle} Login or Search to see your rank.`}</div> |
79 | | - </div> |
80 | | - |
81 | | - <Table> |
82 | | - <TableHeader className="[&_tr]:border-b-0"> |
83 | | - <TableRow> |
84 | | - <TableHead className="w-[100px]">#</TableHead> |
85 | | - <TableHead>Login</TableHead> |
86 | | - <TableHead className="hidden sm:table-cell">Location</TableHead> |
87 | | - <TableHead className="text-right">{rankingBaseEntity}</TableHead> |
88 | | - </TableRow> |
89 | | - </TableHeader> |
90 | | - <TableBody> |
91 | | - {globalRankings.map((item) => { |
92 | | - const { githubId, user } = item; |
93 | | - return ( |
94 | | - <ClickableRow key={githubId} className="border-b-0" href={`/profile/${user?.login}`}> |
95 | | - <TableCell className="font-medium"> |
96 | | - <div className="flex items-end gap-1"> |
97 | | - {item[rankPropName]} |
98 | | - {rankingType !== 'contributions' && ( // TODO remove this condition when contributions is fixed |
99 | | - <RankDelta current={item[rankPropName]} previous={item[`${rankPropName}M`]} /> |
100 | | - )} |
101 | | - </div> |
102 | | - </TableCell> |
103 | | - <TableCell> |
104 | | - <LinkWithStopPropagation href={`/profile/${user?.login}`}> |
105 | | - <ProfileAvatar url={user?.avatarUrl} initials={getInitials(user?.login)} /> |
106 | | - {user?.login} |
107 | | - </LinkWithStopPropagation> |
108 | | - </TableCell> |
109 | | - <TableCell className="hidden sm:table-cell break-all whitespace-normal"> |
110 | | - {getCountryFlag(countries, user?.country)} {user?.location} |
111 | | - </TableCell> |
112 | | - <TableCell className="text-right">{user?.[rankPropName]?.toLocaleString('en-US')}</TableCell> |
113 | | - </ClickableRow> |
114 | | - ); |
115 | | - })} |
116 | | - </TableBody> |
117 | | - </Table> |
118 | | - |
119 | | - <Pagination> |
120 | | - <PaginationContent> |
121 | | - {page > 1 && ( |
122 | | - <PaginationItem> |
123 | | - <PaginationPrevious href={`/by/${rankingType}/${page - 1}`} /> |
124 | | - </PaginationItem> |
125 | | - )} |
126 | | - <PaginationItem> |
127 | | - <PaginationNext href={`/by/${rankingType}/${page + 1}`} /> |
128 | | - </PaginationItem> |
129 | | - </PaginationContent> |
130 | | - </Pagination> |
131 | | - </Page> |
| 32 | + <> |
| 33 | + <RankingTable rankingType={rankingType} data={globalRankings} countries={countries} /> |
| 34 | + <Pagination |
| 35 | + prev={page > 1 ? `/by/${rankingType}/${page - 1}` : undefined} |
| 36 | + next={globalRankings?.length === ITEMS_PER_PAGE ? `/by/${rankingType}/${page + 1}` : undefined} |
| 37 | + /> |
| 38 | + </> |
132 | 39 | ); |
133 | 40 | } |
0 commit comments