stacker.news/pages/users/[when].js

215 lines
5.8 KiB
JavaScript
Raw Normal View History

2022-12-01 21:31:04 +00:00
import { gql } from '@apollo/client'
import { getGetServerSideProps } from '../../api/ssrApollo'
import Layout from '../../components/layout'
import { LineChart, Line, XAxis, YAxis, Tooltip, Legend, ResponsiveContainer, AreaChart, Area } from 'recharts'
import { Col, Row } from 'react-bootstrap'
import { abbrNum } from '../../lib/format'
import { UsageHeader } from '../../components/usage-header'
import { useRouter } from 'next/router'
export const getServerSideProps = getGetServerSideProps(
gql`
query Growth($when: String!)
{
registrationGrowth(when: $when) {
time
data {
name
value
}
}
itemGrowth(when: $when) {
time
data {
name
value
}
}
spendingGrowth(when: $when) {
time
data {
name
value
}
}
spenderGrowth(when: $when) {
time
data {
name
value
}
}
stackingGrowth(when: $when) {
time
data {
name
value
}
}
stackerGrowth(when: $when) {
time
data {
name
value
}
}
}`)
// todo: this needs to accomodate hours, days, months now
const dateFormatter = when => {
return timeStr => {
const date = new Date(timeStr)
switch (when) {
case 'week':
case 'month':
return `${('0' + (date.getMonth() % 12 + 1)).slice(-2)}/${date.getDate()}`
case 'year':
case 'forever':
return `${('0' + (date.getMonth() % 12 + 1)).slice(-2)}/${String(date.getFullYear()).slice(-2)}`
default:
2022-12-01 22:22:13 +00:00
return `${date.getHours() % 12 || 12}${date.getHours() >= 12 ? 'pm' : 'am'}`
2022-12-01 21:31:04 +00:00
}
}
}
function xAxisName (when) {
switch (when) {
case 'week':
case 'month':
return 'days'
case 'year':
case 'forever':
return 'months'
default:
return 'hours'
}
}
const transformData = data => {
return data.map(entry => {
const obj = { time: entry.time }
entry.data.forEach(entry1 => {
obj[entry1.name] = entry1.value
})
return obj
})
}
export default function Growth ({
data: { registrationGrowth, itemGrowth, spendingGrowth, spenderGrowth, stackingGrowth, stackerGrowth }
}) {
return (
<Layout>
<UsageHeader />
<Row>
<Col className='mt-3'>
<div className='text-center text-muted font-weight-bold'>stackers</div>
<GrowthLineChart data={stackerGrowth} />
</Col>
<Col className='mt-3'>
<div className='text-center text-muted font-weight-bold'>stacking</div>
<GrowthAreaChart data={stackingGrowth} />
</Col>
</Row>
<Row>
<Col className='mt-3'>
<div className='text-center text-muted font-weight-bold'>spenders</div>
<GrowthLineChart data={spenderGrowth} />
</Col>
<Col className='mt-3'>
<div className='text-center text-muted font-weight-bold'>spending</div>
<GrowthAreaChart data={spendingGrowth} />
</Col>
</Row>
<Row>
<Col className='mt-3'>
<div className='text-center text-muted font-weight-bold'>registrations</div>
<GrowthAreaChart data={registrationGrowth} />
</Col>
<Col className='mt-3'>
<div className='text-center text-muted font-weight-bold'>items</div>
<GrowthAreaChart data={itemGrowth} />
</Col>
</Row>
</Layout>
)
}
const COLORS = [
'var(--secondary)',
'var(--info)',
'var(--success)',
'var(--boost)',
'var(--grey)'
]
function GrowthAreaChart ({ data }) {
const router = useRouter()
if (!data || data.length === 0) {
return null
}
// transform data into expected shape
data = transformData(data)
// need to grab when
const when = router.query.when
return (
<ResponsiveContainer width='100%' height={300} minWidth={300}>
<AreaChart
data={data}
margin={{
top: 5,
right: 5,
left: 0,
bottom: 0
}}
>
<XAxis
dataKey='time' tickFormatter={dateFormatter(when)} name={xAxisName(when)}
tick={{ fill: 'var(--theme-grey)' }}
/>
<YAxis tickFormatter={abbrNum} tick={{ fill: 'var(--theme-grey)' }} />
<Tooltip labelFormatter={dateFormatter(when)} contentStyle={{ color: 'var(--theme-color)', backgroundColor: 'var(--theme-body)' }} />
<Legend />
{Object.keys(data[0]).filter(v => v !== 'time' && v !== '__typename').map((v, i) =>
<Area key={v} type='monotone' dataKey={v} name={v} stackId='1' stroke={COLORS[i]} fill={COLORS[i]} />)}
</AreaChart>
</ResponsiveContainer>
)
}
function GrowthLineChart ({ data }) {
const router = useRouter()
if (!data || data.length === 0) {
return null
}
// transform data into expected shape
data = transformData(data)
// need to grab when
const when = router.query.when
return (
<ResponsiveContainer width='100%' height={300} minWidth={300}>
<LineChart
data={data}
margin={{
top: 5,
right: 5,
left: 0,
bottom: 0
}}
>
<XAxis
dataKey='time' tickFormatter={dateFormatter(when)} name={xAxisName(when)}
tick={{ fill: 'var(--theme-grey)' }}
/>
<YAxis tickFormatter={abbrNum} tick={{ fill: 'var(--theme-grey)' }} />
<Tooltip labelFormatter={dateFormatter(when)} contentStyle={{ color: 'var(--theme-color)', backgroundColor: 'var(--theme-body)' }} />
<Legend />
{Object.keys(data[0]).filter(v => v !== 'time' && v !== '__typename').map((v, i) =>
<Line key={v} type='monotone' dataKey={v} name={v} stroke={COLORS[i]} fill={COLORS[i]} />)}
</LineChart>
</ResponsiveContainer>
)
}