stacker.news/components/sub-select.js
Edward Kung 9905e6eafe
Top cowboys territory selector fix (#1972)
* fix territory selector when in top/cowboys

* redirect /~sub/top/cowboys to /top/cowboys

* check if pathname ends with /top/cowboys

Co-authored-by: ekzyis <ek@stacker.news>

* fix territory selector in top/stackers and top/territories

* better routing logic

---------

Co-authored-by: ekzyis <ek@stacker.news>
2025-03-19 08:19:19 -05:00

137 lines
4.3 KiB
JavaScript

import { useEffect, useState } from 'react'
import { useRouter } from 'next/router'
import { Select } from './form'
import { EXTRA_LONG_POLL_INTERVAL, SSR } from '@/lib/constants'
import { SUBS } from '@/fragments/subs'
import { useQuery } from '@apollo/client'
import styles from './sub-select.module.css'
import { useMe } from './me'
export function SubSelectInitial ({ sub }) {
const router = useRouter()
sub = sub || router.query.sub || 'pick territory'
return {
sub
}
}
const DEFAULT_PREPEND_SUBS = []
const DEFAULT_APPEND_SUBS = []
const DEFAULT_FILTER_SUBS = () => true
export function useSubs ({ prependSubs = DEFAULT_PREPEND_SUBS, sub, filterSubs = DEFAULT_FILTER_SUBS, appendSubs = DEFAULT_APPEND_SUBS }) {
const { data, refetch } = useQuery(SUBS, SSR
? {}
: {
pollInterval: EXTRA_LONG_POLL_INTERVAL,
nextFetchPolicy: 'cache-and-network'
})
const { me } = useMe()
useEffect(() => {
refetch()
}, [me?.privates?.nsfwMode])
const [subs, setSubs] = useState([
...prependSubs.filter(s => s !== sub),
...(sub ? [sub] : []),
...appendSubs.filter(s => s !== sub)])
useEffect(() => {
if (!data) return
const joined = data.subs.filter(filterSubs).filter(s => !s.meMuteSub).map(s => s.name)
const muted = data.subs.filter(filterSubs).filter(s => s.meMuteSub).map(s => s.name)
const mutedSection = muted.length ? [{ label: 'muted', items: muted }] : []
setSubs([
...prependSubs,
...joined,
...mutedSection,
...appendSubs])
}, [data])
return subs
}
export default function SubSelect ({ prependSubs, sub, onChange, size, appendSubs, filterSubs, className, ...props }) {
const router = useRouter()
const subs = useSubs({ prependSubs, sub, filterSubs, appendSubs })
const valueProps = props.noForm
? {
value: sub
}
: {
overrideValue: sub
}
// If logged out user directly visits a nsfw sub, subs will not contain `sub`, so manually add it
// to display the correct sub name in the sub selector
const subItems = !sub || subs.find((s) => s === sub) ? subs : [sub].concat(subs)
return (
<Select
onChange={onChange || ((_, e) => {
const sub = ['home', 'pick territory'].includes(e.target.value) ? undefined : e.target.value
if (sub === 'create') {
router.push('/territory')
return
}
let asPath
// are we currently in a sub (ie not home)
if (router.query.sub) {
// are we going to a sub or home?
const subReplace = sub ? `/~${sub}` : ''
// if we are going to a sub, replace the current sub with the new one
asPath = router.asPath.replace(`/~${router.query.sub}`, subReplace)
// if we're going to home, just go there directly
if (asPath === '') {
router.push('/')
return
}
} else {
// we're currently on the home sub
// if in /top/cowboys, /top/territories, or /top/stackers
// and a territory is selected, go to /~sub/top/posts/day
if (router.pathname.startsWith('/~/top/cowboys')) {
router.push(sub ? `/~${sub}/top/posts/day` : '/top/cowboys')
return
} else if (router.pathname.startsWith('/~/top/stackers')) {
router.push(sub ? `/~${sub}/top/posts/day` : 'top/stackers/day')
return
} else if (router.pathname.startsWith('/~/top/territories')) {
router.push(sub ? `/~${sub}/top/posts/day` : '/top/territories/day')
return
} else if (router.pathname.startsWith('/~')) {
// are we in a sub aware route?
// if we are, go to the same path but in the sub
asPath = `/~${sub}` + router.asPath
} else {
// otherwise, just go to the sub
router.push(sub ? `/~${sub}` : '/')
return
}
}
const query = {
...router.query,
sub
}
delete query.nodata
router.push({
pathname: router.pathname,
query
}, asPath)
})}
name='sub'
size='sm'
{...valueProps}
{...props}
className={`${className} ${styles.subSelect} ${size === 'large' ? styles.subSelectLarge : size === 'medium' ? styles.subSelectMedium : ''}`}
items={subItems}
/>
)
}