import { useInfiniteQuery } from '@tanstack/react-query'
import MobileHeader from '../../layouts/NhLayout/MobileHeader'
import { userPostListQueryKey } from '@/queries/user-queries'
import { NH_BIZ, NH_CATEGORY_NEWS } from '../../main'
import { css } from '@emotion/react'
import {
WindowScroller as _WindowScroller,
AutoSizer as _AutoSizer,
List as _List,
CellMeasurer as _CellMeasurer,
CellMeasurerCache,
WindowScrollerProps,
AutoSizerProps,
ListProps,
CellMeasurerProps,
} from 'react-virtualized'
import { FC, useCallback, useEffect } from 'react'
import { SessionStorage } from '@/utils/storage-utils'
import { color, reset } from '@/styles/mixins'
import Link from 'next/link'
import CommonPostItem from './CommonPostItem'
import Loading from '@/components/user/ui-components/Loading'
import { CircularProgress } from '@mui/material'
import { momentKR } from '@/utils/basic-utils'
import DateSeparator from './DateSeparator'
import NewsPostItem from './NewsPostItem'
import NewChip from '../../components/NewChip'
import Router from 'next/router'
import { postService } from '@/services'
const biz = NH_BIZ
const WindowScroller = _WindowScroller as unknown as FC<WindowScrollerProps>
const AutoSizer = _AutoSizer as unknown as FC<AutoSizerProps>
const List = _List as unknown as FC<ListProps>
const CellMeasurer = _CellMeasurer as unknown as FC<CellMeasurerProps>
const cache = new CellMeasurerCache({
fixedWidth: true,
})
const getEnglishLocaleDateStr = (dateStr: string) => {
return momentKR(dateStr).locale('En').format('YYYY.MM.DD ddd').toUpperCase()
}
const styles = {
wrapper: css({ paddingBottom: 30 }),
box: css({}),
}
type Props = {
categorySlug: string
}
const NhPostList = ({ categorySlug }: Props) => {
const pageSize = categorySlug === NH_CATEGORY_NEWS ? 10 : 5
const {
data: infiniteQueryResult,
fetchNextPage,
hasNextPage,
isFetchingNextPage,
isLoading,
} = useInfiniteQuery({
queryKey: [...userPostListQueryKey(biz), 'category-infinite', biz],
queryFn: ({ pageParam }) =>
postService.getPostListByCategoryForUser(biz, {
slug: categorySlug,
pageSize,
pageNumber: pageParam,
}),
initialPageParam: 0,
getNextPageParam: (lastPage, allPages) => {
if (lastPage.result.items.length < pageSize) {
return undefined
}
return allPages.length
},
})
const data = infiniteQueryResult?.pages.map((page) => page.result.items).flat() ?? []
const rowRenderer: ListProps['rowRenderer'] = ({ index, key, parent, style }) => {
const prevIndex = index - 1
const post = data[index]
const prevPost = data[prevIndex]
const postDateStr = getEnglishLocaleDateStr(post.publishedAt)
const prevPostDateStr = prevPost ? getEnglishLocaleDateStr(prevPost.publishedAt) : ''
return (
<CellMeasurer cache={cache} parent={parent} key={key} columnIndex={0} rowIndex={index}>
{({ registerChild }) => (
<div ref={registerChild as any} style={style}>
{categorySlug === NH_CATEGORY_NEWS ? (
<>
{postDateStr !== prevPostDateStr ? <DateSeparator dateStr={postDateStr} /> : null}
<Link href={`/nh/post/view/${post.slug}`} css={[reset.link]}>
<NewsPostItem
post={post}
isNew={index === 0 && momentKR(post.publishedAt).isSame(momentKR(), 'day')}
/>
</Link>
</>
) : (
<div css={{ marginTop: 30 }}>
<Link href={`/nh/post/view/${post.slug}`} css={[reset.link]} data-id={post.id}>
<CommonPostItem post={post} isNew={momentKR(post.publishedAt).isAfter(momentKR().subtract(1, 'd'))} />
</Link>
</div>
)}
</div>
)}
</CellMeasurer>
)
}
const handleList = useCallback((node: _List) => {
if (node) {
cache.clearAll()
node.forceUpdate()
node.measureAllRows()
window.setTimeout(() => {
window.scrollTo(0, SessionStorage.postScrollY)
}, 0)
}
}, [])
useEffect(() => {
let lastWindowInnerWidth = window.innerWidth
const resizeHandler = () => {
const currentWindowInnerWidth = window.innerWidth
if (currentWindowInnerWidth !== lastWindowInnerWidth) {
cache.clearAll()
lastWindowInnerWidth = currentWindowInnerWidth
}
}
const scrollEventHandler = () => {
if (window.scrollY !== 0) {
SessionStorage.postScrollY = window.scrollY
}
}
window.addEventListener('resize', resizeHandler)
window.addEventListener('scroll', scrollEventHandler)
return () => {
window.removeEventListener('resize', resizeHandler)
window.removeEventListener('scroll', scrollEventHandler)
}
}, [])
if (isLoading) return <Loading pageLoading />
return (
<>
<MobileHeader categorySlug={categorySlug} customPrev={() => Router.push('/nh')} />
<WindowScroller>
{({ height, scrollTop, isScrolling, onChildScroll, registerChild }) => (
<div ref={registerChild as any} css={styles.wrapper}>
<AutoSizer disableHeight>
{({ width }) => (
<>
<List
ref={handleList}
autoHeight
height={height}
width={width}
isScrolling={isScrolling}
overscanRowCount={0}
onScroll={onChildScroll}
scrollTop={scrollTop}
rowCount={data.length}
rowHeight={cache.rowHeight}
rowRenderer={rowRenderer}
defferedMeasurementCache={cache}
style={{ overflowY: 'auto' }}
/>
</>
)}
</AutoSizer>
{hasNextPage ? (
<button
type="button"
disabled={isFetchingNextPage}
css={[
reset.button,
{
width: '100%',
border: `1px solid ${color.BB30}`,
borderRadius: 10,
padding: `10px 0`,
fontSize: 18,
lineHeight: 1.5,
color: color.BB700,
marginTop: 30,
},
]}
onClick={() => fetchNextPage()}
>
{isFetchingNextPage ? <CircularProgress size="1em" color="inherit" /> : '더 보기'}
</button>
) : null}
</div>
)}
</WindowScroller>
</>
)
}
export default NhPostList