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