import { fetchJson } from '@/lib/utils/server'; import type { BannerActiveListResponse, BannerItem } from '@/types/response/banner/active-list'; import type { LiveChannelListResponse } from '@/types/response/channel/live-list'; import type { WorldIndexRow } from '@/types/worldIndex'; import type { MarketQuoteRow } from '@/types/marketQuote'; import { fetchWorldIndices } from '@/lib/api/worldIndices'; import { fetchMarketQuotes } from '@/lib/api/marketQuotes'; import type { DomesticIndexRow } from '@/types/domesticSummary'; import { fetchDomesticSummary } from '@/lib/api/domesticSummary'; import type { MarketMoversResponse } from '@/types/marketMover'; import { fetchMarketMovers } from '@/lib/api/marketMovers'; import HomeBannerCarousel from './_components/HomeBannerCarousel'; import WorldMarketMap from './_components/WorldMarketMap'; import DomesticSummary from './_components/DomesticSummary'; import MajorQuotesGrid from './_components/MajorQuotesGrid'; import MarketMovers from './_components/MarketMovers'; import LiveChannelGrid from './_components/LiveChannelGrid'; import LiveChannelEmpty from './_components/LiveChannelEmpty'; import { FEATURE_CHANNEL } from '@/constants/features'; import './_components/home.scss'; const BANNER_POSITION_CODE = 'main-top'; const LIVE_PAGE_SIZE = 24; async function loadActiveBanners(): Promise { const res = await fetchJson('/api/banner/items', { method: 'POST', body: JSON.stringify({ code: BANNER_POSITION_CODE, onlyActive: true }) }); if (!res.success || !res.data) { return []; } return res.data.list.filter(b => b.desktopImage !== null || b.mobileImage !== null); } async function loadLiveChannels(): Promise<{ channels: LiveChannelListResponse['channels']; total: number }> { const res = await fetchJson(`/api/channel/live-list?limit=${LIVE_PAGE_SIZE}&offset=0`, { method: 'GET' }); if (!res.success || !res.data) { return { channels: [], total: 0 }; } return { channels: res.data.channels, total: res.data.total }; } async function loadWorldIndices(): Promise { // 백엔드 미기동/데이터 없음이어도 홈은 렌더 — 지도는 데이터 있을 때만 표시 const res = await fetchWorldIndices(); if (!res.success || !res.data) { return []; } return res.data.list; } async function loadMarketQuotes(): Promise { // 백엔드 미기동/데이터 없음이어도 홈은 렌더 — 그리드는 데이터 있을 때만 표시 const res = await fetchMarketQuotes(); if (!res.success || !res.data) { return []; } return res.data.list; } async function loadDomesticSummary(): Promise { const res = await fetchDomesticSummary(); if (!res.success || !res.data) { return []; } return res.data.list; } async function loadMarketMovers(): Promise { // 백엔드 미기동/데이터 없음이어도 홈은 렌더 — 섹션은 데이터 있을 때만 표시 const res = await fetchMarketMovers(); if (!res.success || !res.data) { return null; } return res.data; } export default async function Home() { // 채널 기능 OFF: 라이브 채널 섹션 미노출이므로 조회 생략 const [banners, live, worldIndices, marketQuotes, domesticSummary, marketMovers] = await Promise.all([ loadActiveBanners(), FEATURE_CHANNEL ? loadLiveChannels() : Promise.resolve({ channels: [], total: 0 }), loadWorldIndices(), loadMarketQuotes(), loadDomesticSummary(), loadMarketMovers() ]); return (
{worldIndices.length > 0 && } {domesticSummary.length > 0 && } {marketMovers && } {marketQuotes.length > 0 && } {FEATURE_CHANNEL && ( live.channels.length === 0 ? ( ) : ( ) )}
); }