Skip to content

Commit

Permalink
feat: add vertical category view to research
Browse files Browse the repository at this point in the history
  • Loading branch information
benfurber committed Dec 19, 2024
1 parent 5b6ef2f commit 1c44773
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 111 deletions.
81 changes: 11 additions & 70 deletions src/pages/Research/Content/ResearchList.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,23 @@
import { useEffect, useState } from 'react'
import { Link, useSearchParams } from '@remix-run/react'
import { useSearchParams } from '@remix-run/react'
import { observer } from 'mobx-react'
import { Button, Loader } from 'oa-components'
import { AuthWrapper } from 'src/common/AuthWrapper'
import { useCommonStores } from 'src/common/hooks/useCommonStores'
import { isPreciousPlastic } from 'src/config/config'
import { logger } from 'src/logger'
import DraftButton from 'src/pages/common/Drafts/DraftButton'
import useDrafts from 'src/pages/common/Drafts/useDrafts'
import { Box, Flex, Heading, useThemeUI } from 'theme-ui'
import { Box, Flex } from 'theme-ui'

import { ITEMS_PER_PAGE, RESEARCH_EDITOR_ROLES } from '../constants'
import { ITEMS_PER_PAGE } from '../constants'
import { listing } from '../labels'
import { researchService } from '../research.service'
import { ResearchFilterHeader } from './ResearchFilterHeader'
import { ResearchFilterHeader } from './ResearchListHeader'
import ResearchListItem from './ResearchListItem'
import { ResearchSearchParams } from './ResearchSearchParams'

import type { DocumentData, QueryDocumentSnapshot } from 'firebase/firestore'
import type { IResearch, ResearchStatus } from 'oa-shared'
import type { ThemeWithName } from 'oa-themes'
import type { ResearchSortOption } from '../ResearchSortOptions'

const ResearchList = observer(() => {
const themeUi = useThemeUI()
const theme = themeUi.theme as ThemeWithName
const { userStore } = useCommonStores().stores
const [isFetching, setIsFetching] = useState<boolean>(true)
const [researchItems, setResearchItems] = useState<IResearch.Item[]>([])
const { draftCount, isFetchingDrafts, drafts, showDrafts, handleShowDrafts } =
Expand Down Expand Up @@ -98,63 +90,12 @@ const ResearchList = observer(() => {
}

return (
<>
<Flex my={[18, 26]}>
<Heading
as="h1"
sx={{
width: '100%',
textAlign: 'center',
fontWeight: 'bold',
fontSize: theme.fontSizes[5],
}}
>
{listing.heading}
</Heading>
</Flex>

<Flex
sx={{
flexWrap: 'nowrap',
justifyContent: 'space-between',
flexDirection: ['column', 'column', 'row'],
mb: 3,
}}
>
{!showDrafts ? <ResearchFilterHeader /> : <div></div>}

<Flex sx={{ gap: 2 }} mb={[3, 3, 0]}>
{isPreciousPlastic() ? (
<>
{userStore.activeUser && (
<DraftButton
showDrafts={showDrafts}
draftCount={draftCount}
handleShowDrafts={handleShowDrafts}
/>
)}
<Link to={userStore.activeUser ? '/research/create' : '/sign-up'}>
<Button type="button" variant="primary" data-cy="create">
{listing.create}
</Button>
</Link>
</>
) : (
<AuthWrapper roleRequired={RESEARCH_EDITOR_ROLES}>
<DraftButton
showDrafts={showDrafts}
draftCount={draftCount}
handleShowDrafts={handleShowDrafts}
/>
<Link to="/research/create">
<Button type="button" variant="primary" data-cy="create">
{listing.create}
</Button>
</Link>
</AuthWrapper>
)}
</Flex>
</Flex>
<Flex sx={{ flexDirection: 'column', gap: [2, 3] }}>
<ResearchFilterHeader
draftCount={draftCount}
handleShowDrafts={handleShowDrafts}
showDrafts={showDrafts}
/>

{showDrafts ? (
<ul style={{ listStyle: 'none', padding: 0, margin: 0 }}>
Expand Down Expand Up @@ -197,7 +138,7 @@ const ResearchList = observer(() => {
)}

{(isFetching || isFetchingDrafts) && <Loader />}
</>
</Flex>
)
})
export default ResearchList
Original file line number Diff line number Diff line change
@@ -1,20 +1,31 @@
import { useCallback, useEffect, useState } from 'react'
import { useSearchParams } from '@remix-run/react'
import { Link, useSearchParams } from '@remix-run/react'
import debounce from 'debounce'
import { SearchField, Select } from 'oa-components'
import { CategoryVerticalList, SearchField, Select } from 'oa-components'
import { ResearchStatus } from 'oa-shared'
import { AuthWrapper } from 'src/common/AuthWrapper'
import { FieldContainer } from 'src/common/Form/FieldContainer'
import { Flex } from 'theme-ui'
import { useCommonStores } from 'src/common/hooks/useCommonStores'
import { isPreciousPlastic } from 'src/config/config'
import DraftButton from 'src/pages/common/Drafts/DraftButton'
import { ListHeader } from 'src/pages/common/Layout/ListHeader'
import { Button, Flex } from 'theme-ui'

import { CategoriesSelectV2 } from '../../common/Category/CategoriesSelectV2'
import { RESEARCH_EDITOR_ROLES } from '../constants'
import { listing } from '../labels'
import { researchService } from '../research.service'
import { ResearchSortOptions } from '../ResearchSortOptions'
import { ResearchSearchParams } from './ResearchSearchParams'

import type { SelectValue } from '../../common/Category/CategoriesSelectV2'
import type { ICategory } from 'oa-shared'
import type { ResearchSortOption } from '../ResearchSortOptions'

interface IProps {
draftCount: number
handleShowDrafts: () => void
showDrafts: boolean
}

const researchStatusOptions = [
{ label: 'All', value: '' },
...Object.values(ResearchStatus).map((x) => ({
Expand All @@ -23,33 +34,29 @@ const researchStatusOptions = [
})),
]

export const ResearchFilterHeader = () => {
const [categories, setCategories] = useState<SelectValue[]>([])
export const ResearchFilterHeader = (props: IProps) => {
const { draftCount, handleShowDrafts, showDrafts } = props

const [categories, setCategories] = useState<ICategory[]>([])
const [searchString, setSearchString] = useState<string>('')

const [searchParams, setSearchParams] = useSearchParams()
const categoryParam = searchParams.get(ResearchSearchParams.category)
const category = categories?.find((x) => x.value === categoryParam) ?? null
const category = categories?.find((x) => x._id === categoryParam) ?? null
const q = searchParams.get(ResearchSearchParams.q)
const sort = searchParams.get(ResearchSearchParams.sort) as ResearchSortOption
const status =
(searchParams.get(ResearchSearchParams.status) as ResearchStatus) || ''

// TODO: create a library component for this
const _inputStyle = {
width: ['100%', '100%', '230px'],
mr: [0, 0, 2],
mb: [3, 3, 0],
}
const isUserLoggedIn = useCommonStores().stores.userStore?.user

useEffect(() => {
const initCategories = async () => {
const categories = (await researchService.getResearchCategories()) || []
setCategories(
categories.map((x) => {
return { value: x._id, label: x.label }
}),
const notDeletedCategories = categories.filter(
({ _deleted }) => _deleted === false,
)
setCategories(notDeletedCategories)
}

initCategories()
Expand All @@ -71,7 +78,7 @@ export const ResearchFilterHeader = () => {
const onSearchInputChange = useCallback(
debounce((value: string) => {
searchValue(value)
}, 1000),
}, 500),
[searchParams],
)

Expand All @@ -90,29 +97,62 @@ export const ResearchFilterHeader = () => {
setSearchParams(params)
}

return (
const actionComponents = (
<>
{isPreciousPlastic() ? (
<>
{isUserLoggedIn && (
<DraftButton
showDrafts={showDrafts}
draftCount={draftCount}
handleShowDrafts={handleShowDrafts}
/>
)}
<Link to={isUserLoggedIn ? '/research/create' : '/sign-up'}>
<Button type="button" variant="primary" data-cy="create">
{listing.create}
</Button>
</Link>
</>
) : (
<AuthWrapper roleRequired={RESEARCH_EDITOR_ROLES}>
<DraftButton
showDrafts={showDrafts}
draftCount={draftCount}
handleShowDrafts={handleShowDrafts}
/>
<Link to="/research/create">
<Button type="button" variant="primary" data-cy="create">
{listing.create}
</Button>
</Link>
</AuthWrapper>
)}
</>
)

const categoryComponent = (
<CategoryVerticalList
allCategories={categories}
activeCategory={category}
setActiveCategory={(updatedCategory) =>
updateFilter(
ResearchSearchParams.category,
updatedCategory ? updatedCategory._id : '',
)
}
/>
)

const filteringComponents = (
<Flex
sx={{
flexWrap: 'nowrap',
justifyContent: 'space-between',
gap: 2,
flexDirection: ['column', 'column', 'row'],
mb: 3,
flexWrap: 'wrap',
}}
>
{/* Categories */}
<Flex sx={_inputStyle}>
<CategoriesSelectV2
value={category}
onChange={(updatedCategory) =>
updateFilter(ResearchSearchParams.category, updatedCategory)
}
placeholder={listing.filterCategory}
isForm={false}
categories={categories}
/>
</Flex>
{/* Sort */}
<Flex sx={_inputStyle}>
<Flex sx={{ width: ['100%', '100%', '220px'] }}>
<FieldContainer>
<Select
options={ResearchSortOptions.toArray(!!q)}
Expand All @@ -124,8 +164,8 @@ export const ResearchFilterHeader = () => {
/>
</FieldContainer>
</Flex>
{/* Status filter */}
<Flex sx={_inputStyle}>

<Flex sx={{ width: ['100%', '100%', '220px'] }}>
<FieldContainer>
<Select
options={researchStatusOptions}
Expand All @@ -137,8 +177,8 @@ export const ResearchFilterHeader = () => {
/>
</FieldContainer>
</Flex>
{/* Text search */}
<Flex sx={_inputStyle}>

<Flex sx={{ width: ['100%', '100%', '270px'] }}>
<SearchField
dataCy="research-search-box"
placeHolder={listing.search}
Expand All @@ -156,4 +196,14 @@ export const ResearchFilterHeader = () => {
</Flex>
</Flex>
)

return (
<ListHeader
actionComponents={actionComponents}
showDrafts={showDrafts}
headingTitle={listing.heading}
categoryComponent={categoryComponent}
filteringComponents={filteringComponents}
/>
)
}

0 comments on commit 1c44773

Please sign in to comment.