page.tsx 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. import '../market/style.scss';
  2. import { Metadata } from 'next';
  3. import MarketNav from '../market/_components/MarketNav';
  4. import MarketFilterTabs from '../market/_components/MarketFilterTabs';
  5. import DisclosureList from '../market/_components/DisclosureList';
  6. import Pager from '../market/_components/Pager';
  7. import { fetchDisclosures } from '@/lib/api/market';
  8. import { CorpClsCode } from '@/types/market';
  9. import { formatNumber } from '@/lib/utils/stock';
  10. export const metadata: Metadata = {
  11. title: '공시 — 개미투자',
  12. description: 'DART 전자공시 피드 — 유가·코스닥·코넥스·기타 법인 최근 공시 (실시간 반영)'
  13. };
  14. const CLS_TABS: { value: ''|CorpClsCode; label: string }[] = [
  15. { value: '', label: '전체' },
  16. { value: 'Y', label: '유가' },
  17. { value: 'K', label: '코스닥' },
  18. { value: 'N', label: '코넥스' },
  19. { value: 'E', label: '기타' }
  20. ];
  21. const PER_PAGE = 20;
  22. type Props = {
  23. searchParams: Promise<{
  24. corpCls?: string;
  25. page?: string;
  26. }>;
  27. };
  28. export default async function DisclosureFeedPage({ searchParams }: Props)
  29. {
  30. const query = await searchParams;
  31. const corpCls = CLS_TABS.some(c => c.value === query.corpCls) ? (query.corpCls as ''|CorpClsCode) : '';
  32. const page = Math.max(Number(query.page) || 1, 1);
  33. const res = await fetchDisclosures({ corpCls: corpCls || undefined, page });
  34. const data = res.success ? res.data : null;
  35. return (
  36. <div className='market'>
  37. <div className='market__head'>
  38. <h1 className='market__title'>공시</h1>
  39. <span className='market__basis'>DART 전자공시 · 최신순</span>
  40. </div>
  41. <MarketNav />
  42. <div className='market__filters'>
  43. <MarketFilterTabs
  44. label='법인구분'
  45. paramKey='corpCls'
  46. tabs={CLS_TABS}
  47. active={corpCls}
  48. basePath='/disclosure'
  49. />
  50. </div>
  51. {!res.success ? (
  52. <div className='market__error' role='alert'>
  53. <strong>공시 목록을 불러오지 못했습니다.</strong>
  54. 잠시 후 다시 시도해 주세요.
  55. </div>
  56. ) : !data || data.list.length === 0 ? (
  57. <div className='market__empty'>표시할 공시가 없습니다.</div>
  58. ) : (
  59. <>
  60. <p className='market__total'>전체 {formatNumber(data.total)}건</p>
  61. <DisclosureList rows={data.list} />
  62. <Pager
  63. total={data.total}
  64. page={page}
  65. perPage={PER_PAGE}
  66. basePath='/disclosure'
  67. query={{ ...(corpCls ? { corpCls } : {}) }}
  68. />
  69. </>
  70. )}
  71. </div>
  72. );
  73. }