114 lines
3.8 KiB
JavaScript
114 lines
3.8 KiB
JavaScript
import Link from 'next/link'
|
|
import { abbrNum, numWithUnits } from '@/lib/format'
|
|
import styles from './item.module.css'
|
|
import React, { useEffect, useMemo, useState } from 'react'
|
|
import { useQuery } from '@apollo/client'
|
|
import MoreFooter from './more-footer'
|
|
import { useData } from './use-data'
|
|
import Info from './info'
|
|
import { TerritoryInfo } from './territory-header'
|
|
|
|
// all of this nonsense is to show the stat we are sorting by first
|
|
const Revenue = ({ sub }) => (sub.optional.revenue !== null && <span>{abbrNum(sub.optional.revenue)} revenue</span>)
|
|
const Stacked = ({ sub }) => (sub.optional.stacked !== null && <span>{abbrNum(sub.optional.stacked)} stacked</span>)
|
|
const Spent = ({ sub }) => (sub.optional.spent !== null && <span>{abbrNum(sub.optional.spent)} spent</span>)
|
|
const Posts = ({ sub }) => (
|
|
<span>
|
|
{numWithUnits(sub.nposts, { unitSingular: 'post', unitPlural: 'posts' })}
|
|
</span>)
|
|
const Comments = ({ sub }) => (
|
|
<span>
|
|
{numWithUnits(sub.ncomments, { unitSingular: 'comment', unitPlural: 'comments' })}
|
|
</span>)
|
|
const Separator = () => (<span> \ </span>)
|
|
|
|
const STAT_POS = {
|
|
stacked: 0,
|
|
revenue: 1,
|
|
spent: 2,
|
|
posts: 3,
|
|
comments: 4
|
|
}
|
|
const STAT_COMPONENTS = [Stacked, Revenue, Spent, Posts, Comments]
|
|
|
|
function separate (arr, separator) {
|
|
return arr.flatMap((x, i) => i < arr.length - 1 ? [x, separator] : [x])
|
|
}
|
|
|
|
export default function TerritoryList ({ ssrData, query, variables, destructureData, rank }) {
|
|
const { data, fetchMore } = useQuery(query, { variables })
|
|
const dat = useData(data, ssrData)
|
|
const [statComps, setStatComps] = useState(separate(STAT_COMPONENTS, Separator))
|
|
|
|
useEffect(() => {
|
|
// shift the stat we are sorting by to the front
|
|
const comps = [...STAT_COMPONENTS]
|
|
setStatComps(separate([...comps.splice(STAT_POS[variables?.by || 0], 1), ...comps], Separator))
|
|
}, [variables?.by])
|
|
|
|
const { subs, cursor } = useMemo(() => {
|
|
if (!dat) return {}
|
|
if (destructureData) {
|
|
return destructureData(dat)
|
|
} else {
|
|
return dat
|
|
}
|
|
}, [dat])
|
|
|
|
if (!dat) {
|
|
return <SubsSkeleton />
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<div className={styles.grid}>
|
|
{subs?.map((sub, i) => (
|
|
<React.Fragment key={sub.name}>
|
|
{rank
|
|
? (
|
|
<div className={styles.rank}>
|
|
{i + 1}
|
|
</div>)
|
|
: <div />}
|
|
<div className={`${styles.item} mb-2`}>
|
|
<div className={styles.hunk}>
|
|
<div className='d-flex align-items-center'>
|
|
<Link href={`/~${sub.name}`} className={`${styles.title} mb-0 d-inline-flex align-items-center text-reset`}>
|
|
{sub.name}
|
|
</Link>
|
|
<Info className='d-flex'><TerritoryInfo sub={sub} /></Info>
|
|
</div>
|
|
<div className={styles.other}>
|
|
{statComps.map((Comp, i) => <Comp key={i} sub={sub} />)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</React.Fragment>
|
|
))}
|
|
</div>
|
|
<MoreFooter cursor={cursor} count={subs?.length} fetchMore={fetchMore} Skeleton={SubsSkeleton} noMoreText='NO MORE' />
|
|
</>
|
|
)
|
|
}
|
|
|
|
export function SubsSkeleton () {
|
|
const subs = new Array(21).fill(null)
|
|
|
|
return (
|
|
<div>{subs.map((_, i) => (
|
|
<div className={`${styles.item} ${styles.skeleton} mb-2`} key={i}>
|
|
<div className={styles.hunk}>
|
|
<div className={`${styles.name} clouds text-reset`} />
|
|
<div className={styles.other}>
|
|
<span className={`${styles.otherItem} clouds`} />
|
|
<span className={`${styles.otherItem} clouds`} />
|
|
<span className={`${styles.otherItem} ${styles.otherItemLonger} clouds`} />
|
|
<span className={`${styles.otherItem} ${styles.otherItemLonger} clouds`} />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
)
|
|
}
|