page.tsx 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. import { fetchJson } from '@/lib/utils/server';
  2. import type { BannerActiveListResponse, BannerItem } from '@/types/response/banner/active-list';
  3. import type { LiveChannelListResponse } from '@/types/response/channel/live-list';
  4. import type { WorldIndexRow } from '@/types/worldIndex';
  5. import { fetchWorldIndices } from '@/lib/api/worldIndices';
  6. import HomeBannerCarousel from './_components/HomeBannerCarousel';
  7. import WorldMarketMap from './_components/WorldMarketMap';
  8. import LiveChannelGrid from './_components/LiveChannelGrid';
  9. import LiveChannelEmpty from './_components/LiveChannelEmpty';
  10. import { FEATURE_CHANNEL } from '@/constants/features';
  11. import './_components/home.scss';
  12. const BANNER_POSITION_CODE = 'main-top';
  13. const LIVE_PAGE_SIZE = 24;
  14. async function loadActiveBanners(): Promise<BannerItem[]> {
  15. const res = await fetchJson<BannerActiveListResponse>('/api/banner/items', {
  16. method: 'POST',
  17. body: JSON.stringify({ code: BANNER_POSITION_CODE, onlyActive: true })
  18. });
  19. if (!res.success || !res.data) {
  20. return [];
  21. }
  22. return res.data.list.filter(b => b.desktopImage !== null || b.mobileImage !== null);
  23. }
  24. async function loadLiveChannels(): Promise<{ channels: LiveChannelListResponse['channels']; total: number }> {
  25. const res = await fetchJson<LiveChannelListResponse>(`/api/channel/live-list?limit=${LIVE_PAGE_SIZE}&offset=0`, { method: 'GET' });
  26. if (!res.success || !res.data) {
  27. return { channels: [], total: 0 };
  28. }
  29. return { channels: res.data.channels, total: res.data.total };
  30. }
  31. async function loadWorldIndices(): Promise<WorldIndexRow[]> {
  32. // 백엔드 미기동/데이터 없음이어도 홈은 렌더 — 지도는 데이터 있을 때만 표시
  33. const res = await fetchWorldIndices();
  34. if (!res.success || !res.data) {
  35. return [];
  36. }
  37. return res.data.list;
  38. }
  39. export default async function Home() {
  40. // 채널 기능 OFF: 라이브 채널 섹션 미노출이므로 조회 생략
  41. const [banners, live, worldIndices] = await Promise.all([
  42. loadActiveBanners(),
  43. FEATURE_CHANNEL ? loadLiveChannels() : Promise.resolve({ channels: [], total: 0 }),
  44. loadWorldIndices()
  45. ]);
  46. return (
  47. <div className="home">
  48. <div className="home__inner">
  49. {worldIndices.length > 0 && <WorldMarketMap rows={worldIndices} />}
  50. <HomeBannerCarousel items={banners} />
  51. {FEATURE_CHANNEL && (
  52. live.channels.length === 0 ? (
  53. <LiveChannelEmpty />
  54. ) : (
  55. <LiveChannelGrid
  56. initialChannels={live.channels}
  57. initialTotal={live.total}
  58. pageSize={LIVE_PAGE_SIZE}
  59. />
  60. )
  61. )}
  62. </div>
  63. </div>
  64. );
  65. }