mirror of
https://github.com/CompassConnections/Compass.git
synced 2026-03-25 10:02:27 -04:00
133 lines
4.3 KiB
TypeScript
133 lines
4.3 KiB
TypeScript
import clsx from 'clsx'
|
|
import {type Stats} from 'common/stats'
|
|
import {useEffect, useState} from 'react'
|
|
import {Col} from 'web/components/layout/col'
|
|
import {PageBase} from 'web/components/page-base'
|
|
import {SEO} from 'web/components/SEO'
|
|
import ChartMembers from 'web/components/widgets/charts'
|
|
import StatBox from 'web/components/widgets/stat-box'
|
|
import {api} from 'web/lib/api'
|
|
import {useT} from 'web/lib/locale'
|
|
import {getCount} from 'web/lib/supabase/users'
|
|
|
|
export default function Stats() {
|
|
const t = useT()
|
|
const [data, setData] = useState<Record<string, number | null>>({})
|
|
const [statsData, setStatsData] = useState<Stats | undefined>(undefined)
|
|
|
|
useEffect(() => {
|
|
async function load() {
|
|
const tables = [
|
|
'profiles',
|
|
'active_members',
|
|
'bookmarked_searches',
|
|
'private_user_message_channels',
|
|
'profile_comments',
|
|
'compatibility_prompts',
|
|
'compatibility_answers',
|
|
'votes',
|
|
'vote_results',
|
|
] as const
|
|
|
|
const [settled, statsResult] = await Promise.allSettled([
|
|
Promise.allSettled(tables.map((t) => getCount(t))),
|
|
api('stats', {}),
|
|
])
|
|
|
|
const result: Record<string, number | null> = {}
|
|
if (settled.status === 'fulfilled') {
|
|
settled.value.forEach((res, i) => {
|
|
const key = tables[i]
|
|
if (res.status === 'fulfilled') result[key] = res.value
|
|
else result[key] = null
|
|
})
|
|
}
|
|
|
|
if (statsResult.status === 'fulfilled') {
|
|
setStatsData(statsResult.value)
|
|
}
|
|
|
|
setData(result)
|
|
}
|
|
|
|
void load()
|
|
}, [])
|
|
|
|
return (
|
|
<PageBase trackPageView={'stats'}>
|
|
<SEO
|
|
title={t('stats.seo.title', 'Stats')}
|
|
description={t('stats.seo.description', 'Stats')}
|
|
url={`/stats`}
|
|
/>
|
|
<h1 className="text-3xl font-semibold text-center mb-6">
|
|
{t('stats.title', 'Growth & Stats')}
|
|
</h1>
|
|
<Col className={'sm:mx-4 mx-1 mb-8'}>
|
|
<ChartMembers />
|
|
</Col>
|
|
<Col className={'mx-4 mb-8'}>
|
|
<Col
|
|
className={clsx(
|
|
'pb-[58px] lg:pb-0', // bottom bar padding
|
|
'text-ink-1000 mx-auto w-full grid grid-cols-1 gap-8 max-w-3xl sm:grid-cols-2 lg:min-h-0 lg:pt-4 mt-4',
|
|
)}
|
|
>
|
|
{!!data.profiles && (
|
|
<StatBox value={data.profiles} label={t('stats.members', 'Members')} />
|
|
)}
|
|
{!!data.active_members && (
|
|
<StatBox
|
|
value={data.active_members}
|
|
label={t('stats.active_members', 'Active Members (last month)')}
|
|
/>
|
|
)}
|
|
{!!data.private_user_message_channels && (
|
|
<StatBox
|
|
value={data.private_user_message_channels}
|
|
label={t('stats.discussions', 'Discussions')}
|
|
/>
|
|
)}
|
|
{!!statsData?.messages && (
|
|
<StatBox value={statsData?.messages} label={t('stats.messages', 'Messages')} />
|
|
)}
|
|
{!!data.compatibility_prompts && (
|
|
<StatBox
|
|
value={data.compatibility_prompts}
|
|
label={t('stats.compatibility_prompts', 'Compatibility Prompts')}
|
|
/>
|
|
)}
|
|
{!!data.compatibility_answers && (
|
|
<StatBox
|
|
value={data.compatibility_answers}
|
|
label={t('stats.prompts_answered', 'Prompts Answered')}
|
|
/>
|
|
)}
|
|
{!!data.votes && <StatBox value={data.votes} label={t('stats.proposals', 'Proposals')} />}
|
|
{!!data.vote_results && (
|
|
<StatBox value={data.vote_results} label={t('stats.votes', 'Votes')} />
|
|
)}
|
|
{!!data.bookmarked_searches && (
|
|
<StatBox
|
|
value={data.bookmarked_searches}
|
|
label={t('stats.searches_bookmarked', 'Searches Bookmarked')}
|
|
/>
|
|
)}
|
|
{!!data.profile_comments && (
|
|
<StatBox
|
|
value={data.profile_comments}
|
|
label={t('stats.endorsements', 'Endorsements')}
|
|
/>
|
|
)}
|
|
{!!statsData?.genderRatio && (
|
|
<StatBox
|
|
value={`${statsData.genderRatio.male ?? 0} / ${statsData.genderRatio.female ?? 0}`}
|
|
label={t('stats.gender_ratio', 'Male / Female Ratio')}
|
|
/>
|
|
)}
|
|
</Col>
|
|
</Col>
|
|
</PageBase>
|
|
)
|
|
}
|