'use server'; import { ResultDto } from '@/types/response/common'; import { StockBoardPostsResponse, TrendingStocksResponse, PostPredictionResponse, TrackRecordResponse, LeaderboardResponse, CreateStockPostRequest, CreateStockPostResponse, EquippedItemsResponse } from '@/types/community'; import { fetchJson } from '@/lib/utils/server'; import { fetchPublicJson } from '@/lib/utils/publicFetch'; const JSON_HEADERS = { 'Accept': 'application/json' } as const; // 종목 가상보드 글 목록 (익명 · SSR) — GET /api/stock-boards/{code}/posts?page= export async function fetchStockBoardPosts(code: string, params: { page?: number; perPage?: number }): Promise> { const queryParams = new URLSearchParams(); queryParams.set('page', String(params.page ?? 1)); queryParams.set('perPage', String(params.perPage ?? 20)); return await fetchJson(`/api/stock-boards/${encodeURIComponent(code)}/posts?${queryParams.toString()}`, { method: 'GET', headers: JSON_HEADERS }); } // 종목 트렌딩 랭킹 (익명 공통 · SSR) — GET /api/stock-boards/trending?count= // Data Cache(tag 'stock-data', 5분 재검증) — /stock 목록 워터폴의 두 번째 콜을 캐시로 흡수. export async function fetchTrendingStocks(params: { count?: number } = {}): Promise> { const queryParams = new URLSearchParams(); queryParams.set('count', String(params.count ?? 20)); return await fetchPublicJson(`/api/stock-boards/trending?${queryParams.toString()}`, { revalidate: 300, tags: ['stock-data'] }); } // 글의 예측 메타 + 채점 상태 (익명 · SSR) — GET /api/posts/{id}/prediction export async function fetchPostPrediction(postID: number): Promise> { return await fetchJson(`/api/posts/${postID}/prediction`, { method: 'GET', headers: JSON_HEADERS }); } // 회원 트랙레코드 (익명 · SSR · 회원 SID 기준) — GET /api/members/{sid}/track-record export async function fetchTrackRecord(sid: string): Promise> { return await fetchJson(`/api/members/${encodeURIComponent(sid)}/track-record`, { method: 'GET', headers: JSON_HEADERS }); } // 적중률 리더보드 (익명 · SSR) — GET /api/track-records/leaderboard?page= export async function fetchTrackRecordLeaderboard(params: { page?: number; period?: string } = {}): Promise> { const queryParams = new URLSearchParams(); queryParams.set('page', String(params.page ?? 1)); if (params.period) queryParams.set('period', params.period); return await fetchJson(`/api/track-records/leaderboard?${queryParams.toString()}`, { method: 'GET', headers: JSON_HEADERS }); } // 종목 가상보드 글 작성 (JWT · SSR) — POST /api/boards/stock/posts export async function createStockBoardPost(body: CreateStockPostRequest): Promise> { return await fetchJson('/api/boards/stock/posts', { method: 'POST', headers: { ...JSON_HEADERS, 'Content-Type': 'application/json' }, body: JSON.stringify(body) }); } // 작성자 지위 배지 배치 조회 (익명 · SSR) — GET /api/members/equipped-items?ids=1,2,3 export async function fetchEquippedItems(memberIDs: number[]): Promise> { const ids = memberIDs.filter(id => id > 0).join(','); return await fetchJson(`/api/members/equipped-items?ids=${ids}`, { method: 'GET', headers: JSON_HEADERS }); }