diff --git a/components/Dashboard.tsx b/components/Dashboard.tsx index e8d1433..dd011b4 100644 --- a/components/Dashboard.tsx +++ b/components/Dashboard.tsx @@ -34,17 +34,7 @@ const getLocationFilterParams = query => { return location && locationType ? { type: locationType, value: location } : null; }; -export default function Dashboard({ - host, - hosts, - categories, - collectives, - stories, - locale, - currency, - startYear, - platformTotalCollectives, -}) { +export default function Dashboard({ host, hosts, categories, collectives, stories, locale, currency, startYear }) { const router = useRouter(); const filter: Filter = { slug: host.slug ?? '', @@ -115,14 +105,13 @@ export default function Dashboard({ const setFilter = (filter: Filter) => pushFilterToRouter(filter, router); return ( -
+
diff --git a/components/Header.tsx b/components/Header.tsx index 8e141cd..757d84e 100644 --- a/components/Header.tsx +++ b/components/Header.tsx @@ -2,7 +2,7 @@ import React from 'react'; import HostSwitcher from './HostSwitcher'; -export default function Header({ hosts, platformTotalCollectives, locale, host, categories, filter, setFilter }) { +export default function Header({ hosts, locale, host, categories, filter, setFilter }) { return (

- Discover {host.count.toLocaleString(locale)} - {host.root && *}{' '} - collectives {host.root ? 'on ' : 'hosted by '} - {' '} - making an impact in{' '} + + Discover {host.count.toLocaleString(locale)} collectives + {host.root ? ' on ' : ' hosted by '} + + making an impact in{' '} {categories .filter(c => !c.options && c.tag !== 'ALL') @@ -44,12 +39,7 @@ export default function Header({ hosts, platformTotalCollectives, locale, host, and more.

- {host.root && ( -

- * out of {platformTotalCollectives.toLocaleString(locale)} collectives on Open Collective. Displaying data - from selected Fiscal Hosts. -

- )} + {host.root &&

* Data from selected Fiscal Hosts.

}
); } diff --git a/components/HostSwitcher.tsx b/components/HostSwitcher.tsx index ba2b5a9..2fd15b0 100644 --- a/components/HostSwitcher.tsx +++ b/components/HostSwitcher.tsx @@ -4,7 +4,7 @@ import { useRouter } from 'next/router'; import { ChevronUpDown, CloseIcon } from './Icons'; -export default function HostSwitcher({ host, hosts, platformTotalCollectives, locale }) { +export default function HostSwitcher({ host, hosts, locale }) { const router = useRouter(); const [isOpen, setIsOpen] = useState(false); @@ -15,7 +15,7 @@ export default function HostSwitcher({ host, hosts, platformTotalCollectives, lo function openModal() { setIsOpen(true); } - const hostNameStyles = `relative underline decoration-3 underline-offset-3 transition-colors lg:decoration-4 lg:underline-offset-4 ${host.styles.text}`; + const hostNameStyles = `relative underline tracking-tight decoration-3 underline-offset-3 transition-colors lg:decoration-4 lg:underline-offset-4 ${host.styles.text}`; return ( @@ -25,16 +25,20 @@ export default function HostSwitcher({ host, hosts, platformTotalCollectives, lo const lastWord = i === arr.length - 1; return ( - - {word} - {lastWord && ( + {word} + + {lastWord && ( + + {host.root && *} - )} - + + )} ); @@ -92,9 +96,9 @@ export default function HostSwitcher({ host, hosts, platformTotalCollectives, lo {host.name}

{host.count.toLocaleString(locale)} collectives

- {host.root && ( + {/* {host.root && (

out of {platformTotalCollectives.toLocaleString(locale)} in total

- )} + )} */}
))} diff --git a/components/Updates.tsx b/components/Updates.tsx index 781017d..dea22a1 100644 --- a/components/Updates.tsx +++ b/components/Updates.tsx @@ -3,7 +3,7 @@ import { gql, useQuery } from '@apollo/client'; import { FormattedDate } from 'react-intl'; import sanitizeHtml from 'sanitize-html'; -import { getAllPossibleTagValues } from '../utils/tag-transforms'; +import { getAllPossibleTagValues } from '../utils/tag-helpers'; import CollectiveButton from './CollectiveButton'; import { PaginationControls } from './PaginationControls'; diff --git a/lib/hosts.ts b/lib/hosts.ts index 3540a45..d7432c7 100644 --- a/lib/hosts.ts +++ b/lib/hosts.ts @@ -12,8 +12,8 @@ const defaultExcludeCategoryTags = [ 'community', 'association', 'movement', - 'USA', - 'midwestern USA', + 'usa', + 'midwestern usa', 'illinois', 'europe', 'chicago', @@ -27,8 +27,15 @@ export const hosts: { currency: string; startYear: number; logoSrc: string; - color: string; - styles: { text: string; groupHoverText: string; button: string; brandBox: string; box: string; border: string }; + color: { hex: string; closestPaletteColor: string }; + styles: { + text: string; + groupHoverText: string; + button: string; + brandBox: string; + box: string; + border: string; + }; website?: string; cta?: { text: string; textLonger: string; href: string; buttonLabel: string }; groupTags: { [key: string]: string[] }; @@ -58,7 +65,7 @@ export const hosts: { currency: 'USD', startYear: 2016, logoSrc: '/oc-logo.svg', - color: 'blue', + color: { hex: '#0C2D66', closestPaletteColor: 'blue' }, website: 'https://opencollective.com', styles: { text: 'text-[#0C2D66]', @@ -70,8 +77,8 @@ export const hosts: { }, groupTags: { ...defaultGroupTags, - education: ['education', 'meetup'], 'mutual aid': ['mutual aid', 'covid'], + education: ['education', 'meetup'], }, includeCategoryTags: [], excludeCategoryTags: [...defaultExcludeCategoryTags], @@ -82,7 +89,7 @@ export const hosts: { currency: 'USD', startYear: 2018, logoSrc: '/ocf-logo.svg', - color: 'teal', + color: { hex: '#0C5559', closestPaletteColor: 'teal' }, styles: { text: 'text-[#0C5559]', groupHoverText: 'group-hover:text-[#0C5559]', @@ -110,7 +117,7 @@ export const hosts: { startYear: 2016, logoSrc: '/osc-logo.svg', website: 'https://opencollective.com/opensource', - color: 'purple', + color: { hex: '#4B3084', closestPaletteColor: 'purple' }, styles: { text: 'text-[#4B3084]', groupHoverText: 'group-hover:text-[#4B3084]', @@ -132,7 +139,7 @@ export const hosts: { startYear: 2019, logoSrc: '/oce-logo.svg', website: 'https://opencollective.com/europe', - color: 'blue', + color: { hex: '#0C2D66', closestPaletteColor: 'blue' }, styles: { text: 'text-[#0C2D66]', groupHoverText: 'group-hover:text-[#0C2D66]', @@ -145,6 +152,6 @@ export const hosts: { ...defaultGroupTags, }, includeCategoryTags: [], - excludeCategoryTags: [...defaultExcludeCategoryTags, 'opencollectiveeu'], + excludeCategoryTags: [...defaultExcludeCategoryTags], }, ]; diff --git a/pages/[slug].tsx b/pages/[slug].tsx index 8633edb..5e6bf95 100644 --- a/pages/[slug].tsx +++ b/pages/[slug].tsx @@ -9,7 +9,6 @@ import Layout from '../components/Layout'; import { createCategories } from '../utils/categories'; import { getLocation } from '../utils/location/get-location'; -import { getAllCollectiveStats } from '../utils/stats'; import { getStories } from '../utils/stories'; import { transformTags } from '../utils/tag-transforms'; @@ -32,15 +31,14 @@ export const getStaticProps: GetStaticProps = async ({ params }) => { } const collectives = accounts.nodes.map(collective => { - const stats = getAllCollectiveStats(collective); const location = getLocation(collective); return { name: collective.name, slug: collective.slug, imageUrl: collective.imageUrl.replace('-staging', ''), host: { name: collective.host.name, slug: collective.host.slug }, - tags: transformTags(collective.tags), - ...(stats && { stats }), + tags: transformTags(collective), + stats: collective.stats, ...(location && { location }), }; }); @@ -76,16 +74,7 @@ export async function getStaticPaths() { }; } -export default function Page({ - categories, - stories, - host, - hosts, - collectives, - currency, - startYear, - platformTotalCollectives, -}) { +export default function Page({ categories, stories, host, hosts, collectives, currency, startYear }) { // eslint-disable-next-line no-console const locale = 'en'; return ( @@ -102,7 +91,6 @@ export default function Page({ locale={locale} host={host} hosts={hosts} - platformTotalCollectives={platformTotalCollectives} /> ); diff --git a/scripts/fetch-data.ts b/scripts/fetch-data.ts index 38e46ad..9a3982e 100644 --- a/scripts/fetch-data.ts +++ b/scripts/fetch-data.ts @@ -21,6 +21,8 @@ for (const env of ['local', process.env.NODE_ENV || 'development']) { import { initializeApollo } from '../lib/apollo-client'; import { accountsQuery, totalCountQuery } from '../lib/graphql/queries'; +import { getAllCollectiveStats } from '../utils/stats'; + dayjs.extend(dayjsPluginUTC); dayjs.extend(dayjsPluginIsoWeek); @@ -158,13 +160,25 @@ async function run() { }; } else { data = await fetchDataForPage(host); + + // add total stats to collectives, and filter away collectives with no stats data + data.accounts.nodes = data.accounts.nodes + .map(account => { + const stats = getAllCollectiveStats(account); + return { + ...account, + stats, + }; + }) + .filter(account => account.stats); + if (host.root) { rootData = data; } } if (data) { - collectiveCounts[host.root ? 'ALL' : host.slug] = data.accounts.totalCount; + collectiveCounts[host.root ? 'ALL' : host.slug] = data.accounts.nodes.length; // write data to file const filename = path.join(directory, `${host.root ? 'ALL' : host.slug}.json`); diff --git a/utils/categories.ts b/utils/categories.ts index 84d299a..509606c 100644 --- a/utils/categories.ts +++ b/utils/categories.ts @@ -1,6 +1,6 @@ import { pickColorForCategory } from './colors'; import { getTagCounts } from './tag-counts'; -import { transformToGroupTags } from './tag-transforms'; +import { getGroupTagKeys } from './tag-helpers'; export const createCategories = ({ collectives, @@ -47,7 +47,7 @@ export const createCategories = ({ // Filter away collectives that are part of the tag just added collectivesNotCategorized = collectivesNotCategorized.filter( - coll => !transformToGroupTags(coll.tags, groupTags)?.includes(tag), + coll => !getGroupTagKeys(coll.tags, groupTags)?.includes(tag), ); } @@ -78,6 +78,6 @@ export const createCategories = ({ return categories.map((category, i, arr) => ({ ...category, - color: pickColorForCategory('blue', i, arr.length), + color: pickColorForCategory(host.color.closestPaletteColor, i, arr.length), })); }; diff --git a/utils/colors.ts b/utils/colors.ts index 49e20ff..c393376 100644 --- a/utils/colors.ts +++ b/utils/colors.ts @@ -20,6 +20,6 @@ const colors = [ export const pickColorForCategory = (startColor: string, i: number, numOfCategories: number) => { const startColorIndex = colors.findIndex(c => c.name === startColor); - const step = Math.floor(colors.length / numOfCategories); - return colors[(startColorIndex + i * step) % colors.length]; + const step = colors.length / numOfCategories; + return colors[(startColorIndex + Math.round(i * step)) % colors.length]; }; diff --git a/utils/tag-counts.ts b/utils/tag-counts.ts index ed5c447..fb72c21 100644 --- a/utils/tag-counts.ts +++ b/utils/tag-counts.ts @@ -1,10 +1,10 @@ -import { transformToGroupTags } from './tag-transforms'; +import { getGroupTagKeys } from './tag-helpers'; // Function that returns tag counts for a list of collectives. if a tag is the key of a group, it will return the count of the group export const getTagCounts = (collectives, groupTags?: { [key: string]: string[] }): { [key: string]: number } => { const { groupedCounts, ungroupedCounts } = collectives.reduce( (acc, collective) => { - const groupedTags = transformToGroupTags(collective.tags, groupTags); + const groupedTags = getGroupTagKeys(collective.tags, groupTags); const ungroupedTags = collective.tags; groupedTags?.forEach(tag => { diff --git a/utils/tag-helpers.ts b/utils/tag-helpers.ts new file mode 100644 index 0000000..0699b76 --- /dev/null +++ b/utils/tag-helpers.ts @@ -0,0 +1,31 @@ +import { uniq } from 'lodash'; + +import { tagTransforms } from './tag-transforms'; + +// Transform tags to grouped tags, i.e. if a tag is in a group, return the group key otherwise return the tag +export const getGroupTagKeys = (tags: string[], groupTags: { [key: string]: string[] }) => { + const groupedTagKey = Object.entries(groupTags).reduce((acc, [key, value]) => { + value.forEach(tag => { + acc[tag] = key; + }); + return acc; + }, {}); + return uniq(tags?.map(tag => groupedTagKey[tag] || tag)) ?? null; +}; + +// This is used to reverse the group tags AND the tag transforms when querying the API +export const getAllPossibleTagValues = (tag: string, groupTags: { [key: string]: string[] }): string[] => { + const tags = groupTags[tag] || [tag]; + const acc = [...tags]; + + const reverseTagTransforms = Object.entries(tagTransforms).reduce((acc, [key, value]) => { + if (tags.includes(value)) { + acc.push(key); + } + return acc; + }, []); + + acc.push(...reverseTagTransforms); + + return acc; +}; diff --git a/utils/tag-transforms.ts b/utils/tag-transforms.ts index b510f57..c2ae417 100644 --- a/utils/tag-transforms.ts +++ b/utils/tag-transforms.ts @@ -3,52 +3,17 @@ import { uniq } from 'lodash'; // Tag transforms that are applied to all accounts. // These are intended to fix various inconsistencies of the same thing // For grouping tags under each other, use defaultGroupTags or groupTags in the host config -const tagTransforms = { +export const tagTransforms = { opensource: 'open source', 'open-source': 'open source', - 'Open source': 'open source', - 'Open Source': 'open source', 'covid-19': 'covid', - Covid19: 'covid', covid19: 'covid', - 'COVID-19': 'covid', - 'Covid-19': 'covid', coronavirus: 'covid', - 'Tech meetups': 'meetup', - Climate: 'climate', + 'tech meetups': 'meetup', }; -export const transformTags = (tags: string[]) => { - if (!tags) { - return null; - } - return uniq(tags.map(tag => tagTransforms[tag] || tag)); -}; - -// Transform tags to grouped tags, i.e. if a tag is in a group, return the group key otherwise return the tag -export const transformToGroupTags = (tags: string[], groupTags: { [key: string]: string[] }) => { - const groupedTagKey = Object.entries(groupTags).reduce((acc, [key, value]) => { - value.forEach(tag => { - acc[tag] = key; - }); - return acc; - }, {}); - return uniq(tags?.map(tag => groupedTagKey[tag] || tag)) ?? null; -}; - -// This is used to reverse the group tags AND the tag transforms when querying the API -export const getAllPossibleTagValues = (tag: string, groupTags: { [key: string]: string[] }): string[] => { - const tags = groupTags[tag] || [tag]; - const acc = [...tags]; +export function transformTags(collective) { + const tags = collective.tags?.map(t => t.toLowerCase()).map(tag => tagTransforms[tag] || tag) || []; - const reverseTagTransforms = Object.entries(tagTransforms).reduce((acc, [key, value]) => { - if (tags.includes(value)) { - acc.push(key); - } - return acc; - }, []); - - acc.push(...reverseTagTransforms); - - return acc; -}; + return uniq(tags); +}