community.ts 3.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. 'use server';
  2. import { ResultDto } from '@/types/response/common';
  3. import {
  4. StockBoardPostsResponse,
  5. TrendingStocksResponse,
  6. PostPredictionResponse,
  7. TrackRecordResponse,
  8. LeaderboardResponse,
  9. CreateStockPostRequest,
  10. CreateStockPostResponse,
  11. EquippedItemsResponse
  12. } from '@/types/community';
  13. import { fetchJson } from '@/lib/utils/server';
  14. import { fetchPublicJson } from '@/lib/utils/publicFetch';
  15. const JSON_HEADERS = { 'Accept': 'application/json' } as const;
  16. // 종목 가상보드 글 목록 (익명 · SSR) — GET /api/stock-boards/{code}/posts?page=
  17. export async function fetchStockBoardPosts(code: string, params: { page?: number; perPage?: number }): Promise<ResultDto<StockBoardPostsResponse>>
  18. {
  19. const queryParams = new URLSearchParams();
  20. queryParams.set('page', String(params.page ?? 1));
  21. queryParams.set('perPage', String(params.perPage ?? 20));
  22. return await fetchJson<StockBoardPostsResponse>(`/api/stock-boards/${encodeURIComponent(code)}/posts?${queryParams.toString()}`, {
  23. method: 'GET',
  24. headers: JSON_HEADERS
  25. });
  26. }
  27. // 종목 트렌딩 랭킹 (익명 공통 · SSR) — GET /api/stock-boards/trending?count=
  28. // Data Cache(tag 'stock-data', 5분 재검증) — /stock 목록 워터폴의 두 번째 콜을 캐시로 흡수.
  29. export async function fetchTrendingStocks(params: { count?: number } = {}): Promise<ResultDto<TrendingStocksResponse>>
  30. {
  31. const queryParams = new URLSearchParams();
  32. queryParams.set('count', String(params.count ?? 20));
  33. return await fetchPublicJson<TrendingStocksResponse>(`/api/stock-boards/trending?${queryParams.toString()}`, { revalidate: 300, tags: ['stock-data'] });
  34. }
  35. // 글의 예측 메타 + 채점 상태 (익명 · SSR) — GET /api/posts/{id}/prediction
  36. export async function fetchPostPrediction(postID: number): Promise<ResultDto<PostPredictionResponse>>
  37. {
  38. return await fetchJson<PostPredictionResponse>(`/api/posts/${postID}/prediction`, {
  39. method: 'GET',
  40. headers: JSON_HEADERS
  41. });
  42. }
  43. // 회원 트랙레코드 (익명 · SSR · 회원 SID 기준) — GET /api/members/{sid}/track-record
  44. export async function fetchTrackRecord(sid: string): Promise<ResultDto<TrackRecordResponse>>
  45. {
  46. return await fetchJson<TrackRecordResponse>(`/api/members/${encodeURIComponent(sid)}/track-record`, {
  47. method: 'GET',
  48. headers: JSON_HEADERS
  49. });
  50. }
  51. // 적중률 리더보드 (익명 · SSR) — GET /api/track-records/leaderboard?page=
  52. export async function fetchTrackRecordLeaderboard(params: { page?: number; period?: string } = {}): Promise<ResultDto<LeaderboardResponse>>
  53. {
  54. const queryParams = new URLSearchParams();
  55. queryParams.set('page', String(params.page ?? 1));
  56. if (params.period) queryParams.set('period', params.period);
  57. return await fetchJson<LeaderboardResponse>(`/api/track-records/leaderboard?${queryParams.toString()}`, {
  58. method: 'GET',
  59. headers: JSON_HEADERS
  60. });
  61. }
  62. // 종목 가상보드 글 작성 (JWT · SSR) — POST /api/boards/stock/posts
  63. export async function createStockBoardPost(body: CreateStockPostRequest): Promise<ResultDto<CreateStockPostResponse>>
  64. {
  65. return await fetchJson<CreateStockPostResponse>('/api/boards/stock/posts', {
  66. method: 'POST',
  67. headers: { ...JSON_HEADERS, 'Content-Type': 'application/json' },
  68. body: JSON.stringify(body)
  69. });
  70. }
  71. // 작성자 지위 배지 배치 조회 (익명 · SSR) — GET /api/members/equipped-items?ids=1,2,3
  72. export async function fetchEquippedItems(memberIDs: number[]): Promise<ResultDto<EquippedItemsResponse>>
  73. {
  74. const ids = memberIDs.filter(id => id > 0).join(',');
  75. return await fetchJson<EquippedItemsResponse>(`/api/members/equipped-items?ids=${ids}`, {
  76. method: 'GET',
  77. headers: JSON_HEADERS
  78. });
  79. }