LatestPosts.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. 'use client';
  2. import './style.scss';
  3. import '../../board/_component/style.scss';
  4. import Link from 'next/link';
  5. import { useSearchParams } from 'next/navigation';
  6. import { useState, useEffect, useMemo, useCallback } from 'react';
  7. import useErrorAlert from '@/hooks/useErrorAlert';
  8. import { BoardListMeta } from '@/types/forum/boardMeta';
  9. import Post from '@/types/forum/post';
  10. import PostLatest from '@/types/forum/latestPost';
  11. import { LatestPostsResponse } from '@/types/response/forum/board'
  12. import { fetchApi } from '@/lib/utils/client';
  13. import Loading from '@/app/component/Loading';
  14. import DefaultListLayout from '@/app/(main)/(forum)/board/_component/DefaultListLayout';
  15. import QnAListLayout from '@/app/(main)/(forum)/board/_component/QnAListLayout';
  16. import AlbumListLayout from '@/app/(main)/(forum)/board/_component/AlbumListLayout';
  17. import { BoardLayout } from '@/constants/forum';
  18. type Props = {
  19. boardListMeta: BoardListMeta;
  20. boardID: number;
  21. boardCode: string;
  22. postID?: number|null;
  23. }
  24. function toPost(item: PostLatest): Post {
  25. return {
  26. ...item,
  27. num: item.no,
  28. boardName: '',
  29. boardPrefix: item.boardPrefixName ? { id: item.boardPrefixID!, boardID: item.boardID, name: item.boardPrefixName, color: null, posts: 0 } : null,
  30. content: '',
  31. blames: 0,
  32. };
  33. }
  34. export default function LatestPosts(params : Props)
  35. {
  36. const searchParams = useSearchParams();
  37. const { setError } = useErrorAlert();
  38. const [loading, setLoading] = useState<boolean>(false);
  39. const [latestPosts, setLatestPosts] = useState<LatestPostsResponse>({
  40. list: []
  41. });
  42. useEffect(() => {
  43. setLoading(true);
  44. const queryParams = new URLSearchParams();
  45. queryParams.set('boardID', String(params.boardID));
  46. const page = searchParams.get('page');
  47. const perPage = searchParams.get('perPage');
  48. const boardPrefixID = searchParams.get('boardPrefixID');
  49. const sortParam = searchParams.get('sort');
  50. const searchParam = searchParams.get('search');
  51. const keywordParam = searchParams.get('keyword');
  52. if (page) queryParams.set('page', page);
  53. if (perPage) queryParams.set('perPage', perPage);
  54. if (boardPrefixID) queryParams.set('boardPrefixID', boardPrefixID);
  55. if (sortParam) queryParams.set('sort', sortParam);
  56. if (searchParam) queryParams.set('search', searchParam);
  57. if (keywordParam) queryParams.set('keyword', keywordParam);
  58. fetchApi<LatestPostsResponse>(`/api/forum/posts?${queryParams.toString()}`).then((res) => {
  59. setLatestPosts(res.data as LatestPostsResponse);
  60. }).catch((err) => {
  61. setError(err.message);
  62. }).finally(() => {
  63. setLoading(false);
  64. });
  65. }, [params.boardID, searchParams]);
  66. const posts = useMemo<Post[]>(() =>
  67. latestPosts.list.map(toPost)
  68. , [latestPosts.list]);
  69. const query = useMemo(() =>
  70. Object.fromEntries(searchParams.entries())
  71. , [searchParams]);
  72. const startIndex = latestPosts.list[0]?.no ?? posts.length;
  73. const renderLayout = useCallback(() => {
  74. switch (params.boardListMeta.layout) {
  75. case BoardLayout.Media:
  76. return <AlbumListLayout boardListMeta={params.boardListMeta} list={posts} />;
  77. case BoardLayout.QnA:
  78. return <QnAListLayout boardListMeta={params.boardListMeta} list={posts} startIndex={startIndex} />;
  79. default:
  80. return <DefaultListLayout boardListMeta={params.boardListMeta} list={posts} startIndex={startIndex} />;
  81. }
  82. }, [params.boardListMeta, posts, startIndex]);
  83. if (latestPosts.list.length <= 0) {
  84. return null;
  85. }
  86. return (
  87. <>
  88. <div id="latestPosts">
  89. {loading && <Loading />}
  90. <article>
  91. {renderLayout()}
  92. </article>
  93. <article>
  94. <Link href={{
  95. pathname: '/board/' + params.boardCode,
  96. query: {
  97. ...query
  98. }
  99. }} className='btn btn-default'>목록으로</Link>
  100. </article>
  101. </div>
  102. </>
  103. );
  104. }