From 670af677adf70c222936e2288877b86ed6a12887 Mon Sep 17 00:00:00 2001 From: durumi99 Date: Sun, 8 Feb 2026 19:24:29 +0900 Subject: [PATCH] feat: Replace mock data with real API calls in StockZipyoPanel - Add SectorAverageResponse, SectorPercentileResponse, MonthlyAverageResponse types - Add fetchSectorAverage, fetchSectorPercentile, fetchMonthlyAverage API functions - Add useStockZipyoDataQuery hook using Promise.all for parallel API calls - Update StockZipyoPanel to use real API data instead of mock data Co-Authored-By: Claude Sonnet 4.5 --- src/components/Page/Stock/Tab/Zipyo/Zipyo.tsx | 22 +++---------- src/controllers/stocks/api.ts | 22 ++++++++++++- src/controllers/stocks/query.ts | 32 ++++++++++++++++++- src/controllers/stocks/types.ts | 26 +++++++++++++++ 4 files changed, 82 insertions(+), 20 deletions(-) diff --git a/src/components/Page/Stock/Tab/Zipyo/Zipyo.tsx b/src/components/Page/Stock/Tab/Zipyo/Zipyo.tsx index 1615204a..d8a1a211 100644 --- a/src/components/Page/Stock/Tab/Zipyo/Zipyo.tsx +++ b/src/components/Page/Stock/Tab/Zipyo/Zipyo.tsx @@ -1,9 +1,8 @@ -import { STOCK_SECTOR_MAP, StockSectorKey } from '@ts/StockSector'; import { getDiffText } from '@utils/Number'; import { deltaToCaret } from '@utils/ScoreConvert'; import useAboutHumanZipyo from '@components/Modal/CenterTutorial/AboutHumanZipyo/useAboutHumanZipyo'; import GuageChart from '@components/Search/GuageChart/GuageChart'; -import { useScoreQuery } from '@controllers/stocks/query'; +import { useScoreQuery, useStockZipyoDataQuery } from '@controllers/stocks/query'; import { StockDetailInfo } from '@controllers/stocks/types'; import { StockItemContainer } from '../../Common.Style'; import StockItemTitle from '../../ItemTitle'; @@ -17,25 +16,12 @@ import { const StockZipyoPanel = ({ stockInfo: { stockId, country, symbolName } }: { stockInfo: StockDetailInfo }) => { const { data: stockScore } = useScoreQuery(stockId, country); + const { data: zipyoData } = useStockZipyoDataQuery(stockId, country); const { Modal: AboutHumanZipyoModal, openModal: openAboutHumanZipyoModal } = useAboutHumanZipyo(); - if (!stockScore) return null; + if (!stockScore || !zipyoData) return null; - // 목업 데이터 (실제로는 API에서 가져와야 함) - const mock: { - industryType: StockSectorKey; - industryAverage: number; - stockRanking: number; - monthlyAverage: number; - } = { - industryType: 'IT_SERVICE', - industryAverage: 45, - stockRanking: 68, - monthlyAverage: 51, - }; - - const { industryType, industryAverage, stockRanking, monthlyAverage } = mock; - const industryName = STOCK_SECTOR_MAP[industryType].text; + const { industryName, industryAverage, stockRanking, monthlyAverage } = zipyoData; const monthlyAverageDiff = stockScore.score - monthlyAverage; const monthlyAverageDiffText = getDiffText({ valueDiff: monthlyAverageDiff }); const sentiment = !monthlyAverageDiff ? '유지되고' : monthlyAverageDiff > 0 ? '개선되고' : '약화되고'; diff --git a/src/controllers/stocks/api.ts b/src/controllers/stocks/api.ts index 2bd6a04a..17bc665b 100644 --- a/src/controllers/stocks/api.ts +++ b/src/controllers/stocks/api.ts @@ -11,7 +11,14 @@ import { fetchSearchSymbolNameMock, fetchSearchWordCloudMock, } from './mock'; -import { PERIOD_CODE, PopularStocks, StockDetailInfo } from './types'; +import { + MonthlyAverageResponse, + PERIOD_CODE, + PopularStocks, + SectorAverageResponse, + SectorPercentileResponse, + StockDetailInfo, +} from './types'; export const fetchScore = async (id: number, country: string) => { if (enableMock) return fetchScoreMock; @@ -87,3 +94,16 @@ export const fetchPopularKeywords = (country: string): Promise => { if (enableMock) return Promise.resolve(fetchKeywordsMock); return fetchData(`/keyword/popular/${country}`); }; + +export const fetchSectorAverage = (country: string, sector: string): Promise => { + return fetchData(`/stock/sector/average/${country}/${sector}`); +}; + +export const fetchSectorPercentile = (stockId: number): Promise => { + return fetchData(`/stock/${stockId}/sector/percentile`); +}; + +export const fetchMonthlyAverage = (stockId: number, yearMonth?: string): Promise => { + const queryParam = yearMonth ? `?yearMonth=${yearMonth}` : ''; + return fetchData(`/stock/${stockId}/average/month${queryParam}`); +}; diff --git a/src/controllers/stocks/query.ts b/src/controllers/stocks/query.ts index 7fbbac0a..d6cab99e 100644 --- a/src/controllers/stocks/query.ts +++ b/src/controllers/stocks/query.ts @@ -8,6 +8,7 @@ import { STOCK_FETCH_FUNCTIONS, queryOptions } from '../common/query'; import { fetchAutoComplete, fetchKeywordRankings, + fetchMonthlyAverage, fetchPopularKeywords, fetchPopularStocks, fetchRelevant, @@ -15,12 +16,15 @@ import { fetchSearchKeyword, fetchSearchSymbolName, fetchSearchWordCloud, + fetchSectorAverage, + fetchSectorPercentile, fetchStockChart, fetchStockInfo, fetchStockSummary, fetchStockTable, } from './api'; -import { AutoCompleteItem, PERIOD_CODE, PopularItems, StockDetailInfo, StockInfo, StockTableInfo } from './types'; +import type { AutoCompleteItem, PopularItems, StockDetailInfo, StockInfo, StockTableInfo } from './types'; +import { PERIOD_CODE } from './types'; export const useSymbolNameSearchQuery = (name: string, country: StockCountryKey) => { return useQuery(['symbolNameSearch', name, country], () => fetchSearchSymbolName(name, country), { @@ -291,3 +295,29 @@ export const useKeywordRankingsQuery = () => { placeholderData: [], }); }; + +export const useStockZipyoDataQuery = (stockId: number, country: StockCountryKey) => { + return useQuery( + ['stockZipyoData', stockId, country], + async () => { + const [sectorPercentile, monthlyAverage] = await Promise.all([ + fetchSectorPercentile(stockId), + fetchMonthlyAverage(stockId), + ]); + + const sectorAverage = await fetchSectorAverage(country, sectorPercentile.sector); + + return { + industryType: sectorPercentile.sector, + industryName: sectorPercentile.sectorName, + industryAverage: sectorAverage.averageScore, + stockRanking: sectorPercentile.topPercent, + monthlyAverage: monthlyAverage.averageScore, + }; + }, + { + ...queryOptions, + enabled: !!stockId && !!country, + }, + ); +}; diff --git a/src/controllers/stocks/types.ts b/src/controllers/stocks/types.ts index cb5e7aa5..d6c44823 100644 --- a/src/controllers/stocks/types.ts +++ b/src/controllers/stocks/types.ts @@ -105,3 +105,29 @@ export interface StockPreferenceStatus { isBookmarked: boolean; isNotificationOn: boolean; } + +export interface SectorAverageResponse { + sector: string; + sectorName: string; + averageScore: number; + count: number; +} + +export interface SectorPercentileResponse { + stockId: number; + sector: string; + sectorName: string; + score: number; + rank: number; + total: number; + topPercent: number; +} + +export interface MonthlyAverageResponse { + stockId: number; + symbolName: string; + country: StockCountryKey; + yearMonth: string; + dataCount: number; + averageScore: number; +}