206 lines
7.2 KiB
TypeScript

import { useMemo, useRef, useState } from 'react'
import { useLoaderData, useSearchParams } from 'react-router-dom'
import { useLocalStorage } from 'hooks'
import { BlogCardDetails, NSFWFilter, SortBy } from 'types'
import { SearchInput } from '../../components/SearchInput'
import { BlogCard } from '../../components/BlogCard'
import '../../styles/filters.css'
import '../../styles/pagination.css'
import '../../styles/search.css'
import '../../styles/styles.css'
export const BlogsPage = () => {
const blogs = useLoaderData() as Partial<BlogCardDetails>[] | undefined
const [filterOptions, setFilterOptions] = useLocalStorage('filter-blog', {
sort: SortBy.Latest,
nsfw: NSFWFilter.Hide_NSFW
})
// Search
const searchTermRef = useRef<HTMLInputElement>(null)
const [searchParams, setSearchParams] = useSearchParams()
const [searchTerm, setSearchTerm] = useState(searchParams.get('q') || '')
const handleSearch = () => {
const value = searchTermRef.current?.value || '' // Access the input value from the ref
setSearchTerm(value)
if (value) {
searchParams.set('q', value)
} else {
searchParams.delete('q')
}
setSearchParams(searchParams, {
replace: true
})
}
const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
if (event.key === 'Enter') {
handleSearch()
}
}
// Filter
const filteredBlogs = useMemo(() => {
const filterNsfwFn = (blog: Partial<BlogCardDetails>) => {
switch (filterOptions.nsfw) {
case NSFWFilter.Hide_NSFW:
return !blog.nsfw
case NSFWFilter.Only_NSFW:
return blog.nsfw
default:
return blog
}
}
let filtered = blogs?.filter(filterNsfwFn) || []
const lowerCaseSearchTerm = searchTerm.toLowerCase()
if (searchTerm !== '') {
const filterSearchTermFn = (blog: Partial<BlogCardDetails>) =>
(blog.title || '').toLowerCase().includes(lowerCaseSearchTerm) ||
(blog.summary || '').toLowerCase().includes(lowerCaseSearchTerm) ||
(blog.content || '').toLowerCase().includes(lowerCaseSearchTerm) ||
(blog.tTags || []).findIndex((tag) =>
tag.toLowerCase().includes(lowerCaseSearchTerm)
) > -1
filtered = filtered.filter(filterSearchTermFn)
}
if (filterOptions.sort === SortBy.Latest) {
filtered.sort((a, b) =>
a.published_at && b.published_at ? b.published_at - a.published_at : 0
)
} else if (filterOptions.sort === SortBy.Oldest) {
filtered.sort((a, b) =>
a.published_at && b.published_at ? a.published_at - b.published_at : 0
)
}
return filtered
}, [blogs, searchTerm, filterOptions.sort, filterOptions.nsfw])
return (
<div className='InnerBodyMain'>
<div className='ContainerMain'>
<div className='IBMSecMainGroup IBMSecMainGroupAlt'>
<div className='IBMSecMain'>
<div className='SearchMainWrapper'>
<div className='IBMSMTitleMain'>
<h2 className='IBMSMTitleMainHeading'>Blogs</h2>
</div>
<SearchInput
ref={searchTermRef}
handleKeyDown={handleKeyDown}
handleSearch={handleSearch}
/>
</div>
</div>
<div className='IBMSecMain'>
<div className='FiltersMain'>
<div className='FiltersMainElement'>
<div className='dropdown dropdownMain'>
<button
className='btn dropdown-toggle btnMain btnMainDropdown'
aria-expanded='false'
data-bs-toggle='dropdown'
type='button'
>
{filterOptions.sort}
</button>
<div className='dropdown-menu dropdownMainMenu'>
{Object.values(SortBy).map((item, index) => (
<div
key={`sortByItem-${index}`}
className='dropdown-item dropdownMainMenuItem'
onClick={() =>
setFilterOptions((prev) => ({
...prev,
sort: item
}))
}
>
{item}
</div>
))}
</div>
</div>
</div>
<div className='FiltersMainElement'>
<div className='dropdown dropdownMain'>
<button
className='btn dropdown-toggle btnMain btnMainDropdown'
aria-expanded='false'
data-bs-toggle='dropdown'
type='button'
>
{filterOptions.nsfw}
</button>
<div className='dropdown-menu dropdownMainMenu'>
{Object.values(NSFWFilter).map((item, index) => (
<div
key={`nsfwFilterItem-${index}`}
className='dropdown-item dropdownMainMenuItem'
onClick={() =>
setFilterOptions((prev) => ({
...prev,
nsfw: item
}))
}
>
{item}
</div>
))}
</div>
</div>
</div>
</div>
<div className='IBMSecMain IBMSMListWrapper'>
<div className='IBMSMList'>
{filteredBlogs &&
filteredBlogs.map((b) => <BlogCard key={b.id} {...b} />)}
</div>
</div>
<div className='IBMSecMain'>
<div className='PaginationMain'>
<div className='PaginationMainInside'>
<a
className='PaginationMainInsideBox PaginationMainInsideBoxArrows'
href='#'
>
<i className='fas fa-chevron-left'></i>
</a>
<div className='PaginationMainInsideBoxGroup'>
<a className='PaginationMainInsideBox PMIBActive' href='#'>
<p>1</p>{' '}
</a>
<a className='PaginationMainInsideBox' href='#'>
<p>2</p>{' '}
</a>
<a className='PaginationMainInsideBox' href='#'>
<p>3</p>
</a>
<p className='PaginationMainInsideBox PMIBDots'>...</p>
<a className='PaginationMainInsideBox' href='#'>
<p>8</p>
</a>
</div>
<a
className='PaginationMainInsideBox PaginationMainInsideBoxArrows'
href='#'
>
<i className='fas fa-chevron-right'></i>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
)
}