Skip to content

Commit 8c55aaf

Browse files
authored
chore: implement supporters component
1 parent 5c79be3 commit 8c55aaf

File tree

6 files changed

+151
-1
lines changed

6 files changed

+151
-1
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
'use client';
2+
3+
import Avatar from '@node-core/ui-components/Common/AvatarGroup/Avatar';
4+
import type { FC } from 'react';
5+
import { use } from 'react';
6+
7+
import type { Supporters } from '#site/types';
8+
9+
type SupportersProps = {
10+
supporters: Promise<Array<Supporters>>;
11+
};
12+
13+
const SupportersList: FC<SupportersProps> = ({ supporters }) => {
14+
const supportersList = use(supporters);
15+
16+
return (
17+
<div className="flex max-w-full flex-wrap items-center justify-center gap-1">
18+
{supportersList.map(({ name, image, url }, i) => (
19+
<Avatar nickname={name} image={image} url={url} key={`${name}-${i}`} />
20+
))}
21+
</div>
22+
);
23+
};
24+
25+
export default SupportersList;
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import type { FC, PropsWithChildren } from 'react';
2+
3+
import { fetchOpenCollectiveData } from '#site/next-data/generators/supportersData.mjs';
4+
import type { Supporters } from '#site/types';
5+
6+
import SupportersList from './Common/Supporters';
7+
8+
const WithSupporters: FC<PropsWithChildren> = () => {
9+
const supporters = fetchOpenCollectiveData() as Promise<Array<Supporters>>;
10+
11+
return (
12+
<div className="flex max-w-full flex-wrap items-center justify-center gap-1">
13+
<SupportersList supporters={supporters} />
14+
</div>
15+
);
16+
};
17+
18+
export default WithSupporters;
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// This is used to ensure that URLs are always in the correct format
2+
function fixUrl(url) {
3+
if (!url) {
4+
return null;
5+
}
6+
7+
if (!url.startsWith('http://') && !url.startsWith('https://')) {
8+
return `https://${url}`;
9+
}
10+
11+
return url;
12+
}
13+
14+
async function fetchOpenCollectiveData() {
15+
const endpoint = 'https://api.opencollective.com/graphql/v2';
16+
17+
const query = `{
18+
account(slug: "nodejs") {
19+
orders(status: ACTIVE, filter: INCOMING) {
20+
totalCount
21+
nodes {
22+
fromAccount {
23+
name
24+
website
25+
imageUrl
26+
}
27+
amount {
28+
value
29+
}
30+
tier {
31+
slug
32+
}
33+
frequency
34+
totalDonations {
35+
value
36+
}
37+
}
38+
}
39+
}
40+
donations: orders(
41+
account: { slug: "nodejs" }
42+
frequency: ONETIME
43+
status: PAID
44+
filter: INCOMING
45+
) {
46+
totalCount
47+
nodes {
48+
id
49+
updatedAt
50+
frequency
51+
status
52+
amount {
53+
value
54+
currency
55+
}
56+
fromAccount {
57+
name
58+
website
59+
imageUrl
60+
}
61+
}
62+
}
63+
}`;
64+
65+
const response = await fetch(endpoint, {
66+
method: 'POST',
67+
headers: { 'Content-Type': 'application/json' },
68+
body: JSON.stringify({ query }),
69+
});
70+
71+
const payload = await response.json();
72+
73+
const sponsors = payload.data.account.orders.nodes.map(order => ({
74+
name: order.fromAccount.name,
75+
url: fixUrl(order.fromAccount.website),
76+
image: order.fromAccount.imageUrl,
77+
source: 'opencollective',
78+
}));
79+
80+
const donations = payload.data.donations.nodes.map(transaction => ({
81+
name: transaction.fromAccount.name,
82+
url: fixUrl(transaction.fromAccount.website),
83+
image: transaction.fromAccount.imageUrl,
84+
source: 'opencollective',
85+
}));
86+
87+
sponsors.push(...donations);
88+
89+
return sponsors;
90+
}
91+
92+
// TODO: implement github sponsors data fetching
93+
// TODO: implement ramdomizing of supporters
94+
95+
export { fetchOpenCollectiveData };

apps/site/next.mdx.use.mjs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import UpcomingMeetings from './components/MDX/Calendar/UpcomingMeetings';
1212
import WithBadgeGroup from './components/withBadgeGroup';
1313
import WithBanner from './components/withBanner';
1414
import WithNodeRelease from './components/withNodeRelease';
15+
import WithSupporters from './components/withSupporters';
1516

1617
/**
1718
* A full list of React Components that we want to pass through to MDX
@@ -26,6 +27,8 @@ export const mdxComponents = {
2627
WithBanner,
2728
// HOC for providing Badge Data
2829
WithBadgeGroup,
30+
// HOC for providing Backers Data
31+
WithSupporters,
2932
// Shows a list of Node.js Partners with Icons
3033
PartnersIconList,
3134
// Shows a list of Node.js Partners with Logos

apps/site/pages/en/about/partners.mdx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,12 @@ Projects with their logo, name, tier, the description and a CTA button
3737

3838
<PartnersLogoList categories="service" maxLength={null} />
3939

40-
## Backers (Open Collective and GitHub Sponsors)
40+
## Supporters
4141

4242
Show a list of lists direct individual or organizational support that can be done through OpenCollective and GitHub Sponsors
4343

44+
<WithSupporters />
45+
4446
## Become a Partner
4547

4648
this section isn't in the specification

apps/site/types/partners.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,10 @@ export type PartnerCategory =
2424
| 'esp'
2525
| 'release'
2626
| 'service';
27+
28+
export interface Supporters {
29+
name: string;
30+
image: string;
31+
url: string;
32+
source: 'opencollective' | 'github';
33+
}

0 commit comments

Comments
 (0)