stacker.news/components/search.js

147 lines
5.6 KiB
JavaScript

import Container from 'react-bootstrap/Container'
import styles from './search.module.css'
import SearchIcon from '../svgs/search-line.svg'
import { useEffect, useRef, useState } from 'react'
import { Form, Input, Select, DatePicker, SubmitButton } from './form'
import { useRouter } from 'next/router'
export default function Search ({ sub }) {
const router = useRouter()
const [q, setQ] = useState(router.query.q || '')
const inputRef = useRef(null)
useEffect(() => {
inputRef.current?.focus()
}, [])
const search = async values => {
let prefix = ''
if (sub) {
prefix = `/~${sub}`
}
if (values.q?.trim() !== '') {
if (values.what === 'stackers') {
await router.push({
pathname: '/stackers/search',
query: { q, what: 'stackers' }
}, {
pathname: '/stackers/search',
query: { q }
})
return
}
if (values.what === '' || values.what === 'all') delete values.what
if (values.sort === '' || values.sort === 'zaprank') delete values.sort
if (values.when === '' || values.when === 'forever') delete values.when
if (values.when !== 'custom') { delete values.from; delete values.to }
await router.push({
pathname: prefix + '/search',
query: values
})
}
}
const filter = sub !== 'jobs'
const what = router.pathname.startsWith('/stackers') ? 'stackers' : router.query.what || 'all'
const sort = router.query.sort || 'zaprank'
const when = router.query.when || 'forever'
const from = router.query.from || new Date().toISOString()
const to = router.query.to || new Date().toISOString()
const [datePicker, setDatePicker] = useState(when === 'custom')
// The following state is needed for the date picker (and driven by the date picker).
// Substituting router.query or formik values would cause network lag and/or timezone issues.
const [range, setRange] = useState({ start: new Date(from), end: new Date(to) })
return (
<>
<div className={styles.searchSection}>
<Container className={`px-md-0 ${styles.searchContainer}`}>
<Form
initial={{ q, what, sort, when, from, to }}
onSubmit={search}
>
<div className={`${styles.active} my-3`}>
<Input
name='q'
required
autoFocus
groupClassName='me-3 mb-0 flex-grow-1'
className='flex-grow-1'
clear
innerRef={inputRef}
overrideValue={q}
onChange={async (formik, e) => {
setQ(e.target.value?.trim())
}}
/>
<SubmitButton variant='primary' className={styles.search}>
<SearchIcon width={22} height={22} />
</SubmitButton>
</div>
{filter &&
<div className='text-muted fw-bold d-flex align-items-center flex-wrap pb-2'>
<div className='text-muted fw-bold d-flex align-items-center pb-2'>
<Select
groupClassName='me-2 mb-0'
onChange={(formik, e) => search({ ...formik?.values, what: e.target.value })}
name='what'
size='sm'
overrideValue={what}
items={['all', 'posts', 'comments', 'stackers']}
/>
{what !== 'stackers' &&
<>
by
<Select
groupClassName='mx-2 mb-0'
onChange={(formik, e) => search({ ...formik?.values, sort: e.target.value })}
name='sort'
size='sm'
overrideValue={sort}
items={['zaprank', 'match', 'recent', 'comments', 'sats']}
/>
for
<Select
groupClassName='mb-0 mx-2'
onChange={(formik, e) => {
search({ ...formik?.values, when: e.target.value, from: from || new Date().toISOString(), to: to || new Date().toISOString() })
setDatePicker(e.target.value === 'custom')
if (e.target.value === 'custom') setRange({ start: new Date(), end: new Date() })
}}
name='when'
size='sm'
overrideValue={when}
items={['custom', 'forever', 'day', 'week', 'month', 'year']}
/>
</>}
</div>
{datePicker &&
<DatePicker
fromName='from' toName='to'
className='form-control p-0 px-2 mb-2 text-center'
onMount={() => {
setRange({ start: new Date(from), end: new Date(to) })
return [from, to]
}}
onChange={(formik, [start, end], e) => {
setRange({ start, end })
search({ ...formik?.values, from: start && start.toISOString(), to: end && end.toISOString() })
}}
selected={range.start}
startDate={range.start} endDate={range.end}
selectsRange
dateFormat='MM/dd/yy'
maxDate={new Date()}
minDate={new Date('2021-05-01')}
/>}
</div>}
</Form>
</Container>
</div>
</>
)
}