Skip to content

feat: 메인페이지 api연동#46

Merged
dasosann merged 2 commits intomainfrom
feat/mainpage-api
Mar 16, 2026
Merged

feat: 메인페이지 api연동#46
dasosann merged 2 commits intomainfrom
feat/mainpage-api

Conversation

@dasosann
Copy link
Copy Markdown
Contributor

No description provided.

@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

메인페이지 API 연동 및 동적 데이터 표시

✨ Enhancement

Grey Divider

Walkthroughs

Description
• 메인페이지 API 연동으로 실시간 데이터 표시
• 매칭 히스토리 조회 및 프로필 슬라이더 동적 렌더링
• 보유 티켓 정보 API에서 가져와 표시
• 서버사이드 데이터 프리페칭으로 초기 로딩 최적화
Diagram
flowchart LR
  A["API 엔드포인트"] -->|"/api/items"| B["useItems Hook"]
  A -->|"/api/matching/history"| C["useMatchingHistory Hook"]
  B --> D["MyCoinSection"]
  C --> E["ScreenMainPage"]
  E --> F["ProfileSlider"]
  G["ServerAPI"] -->|"Prefetch"| H["QueryClient"]
  H --> I["HydrationBoundary"]
  I --> E
  D --> J["티켓 개수 표시"]
  F --> K["매칭 파트너 프로필"]
Loading

Grey Divider

File Changes

1. hooks/useItems.ts ✨ Enhancement +42/-0

아이템 조회 API 훅 구현

• 아이템 조회 API 호출 함수 및 타입 정의
• React Query를 활용한 useItems 커스텀 훅 구현
• 무한 캐싱 및 1시간 메모리 유지 설정

hooks/useItems.ts


2. hooks/useMatchingHistory.ts ✨ Enhancement +66/-0

매칭 히스토리 조회 API 훅 구현

• 매칭 히스토리 조회 API 호출 함수 및 타입 정의
• 파트너 정보 및 페이지네이션 데이터 구조 정의
• React Query 기반 useMatchingHistory 훅 구현

hooks/useMatchingHistory.ts


3. app/main/_components/MyCoinSection.tsx ✨ Enhancement +31/-2

보유 티켓 정보 API 연동

useItems 훅으로 실시간 티켓 데이터 조회
• 로딩 상태 스켈레톤 UI 추가
• 하드코딩된 "1개" 값을 API 데이터로 동적 변경

app/main/_components/MyCoinSection.tsx


View more (2)
4. app/main/_components/ScreenMainPage.tsx ✨ Enhancement +26/-99

매칭 히스토리 데이터로 프로필 동적 렌더링

useMatchingHistory 훅으로 매칭 히스토리 데이터 조회
• 모의 데이터 제거 및 API 응답 데이터로 프로필 목록 생성
• 한글 연락빈도를 ContactFrequency 타입으로 변환
• 로딩 상태에서 프로필 슬라이더 조건부 렌더링

app/main/_components/ScreenMainPage.tsx


5. app/main/page.tsx ✨ Enhancement +37/-2

서버사이드 데이터 프리페칭 및 하이드레이션

• 서버 컴포넌트로 변경하여 서버사이드 데이터 프리페칭 구현
• serverApi로 아이템 및 매칭 히스토리 데이터 미리 조회
• HydrationBoundary로 클라이언트 하이드레이션 처리
• React Query 캐시 초기화로 초기 로딩 성능 최적화

app/main/page.tsx


Grey Divider

Qodo Logo


✨ Describe tool usage guide:

Overview:
The describe tool scans the PR code changes, and generates a description for the PR - title, type, summary, walkthrough and labels. The tool can be triggered automatically every time a new PR is opened, or can be invoked manually by commenting on a PR.

When commenting, to edit configurations related to the describe tool (pr_description section), use the following template:

/describe --pr_description.some_config1=... --pr_description.some_config2=...

With a configuration file, use the following template:

[pr_description]
some_config1=...
some_config2=...
Enabling\disabling automation
  • When you first install the app, the default mode for the describe tool is:
pr_commands = ["/describe", ...]

meaning the describe tool will run automatically on every PR.

  • Markers are an alternative way to control the generated description, to give maximal control to the user. If you set:
pr_commands = ["/describe --pr_description.use_description_markers=true", ...]

the tool will replace every marker of the form pr_agent:marker_name in the PR description with the relevant content, where marker_name is one of the following:

  • type: the PR type.
  • summary: the PR summary.
  • walkthrough: the PR walkthrough.
  • diagram: the PR sequence diagram (if enabled).

Note that when markers are enabled, if the original PR description does not contain any markers, the tool will not alter the description at all.

Custom labels

The default labels of the describe tool are quite generic: [Bug fix, Tests, Enhancement, Documentation, Other].

If you specify custom labels in the repo's labels page or via configuration file, you can get tailored labels for your use cases.
Examples for custom labels:

  • Main topic:performance - pr_agent:The main topic of this PR is performance
  • New endpoint - pr_agent:A new endpoint was added in this PR
  • SQL query - pr_agent:A new SQL query was added in this PR
  • Dockerfile changes - pr_agent:The PR contains changes in the Dockerfile
  • ...

The list above is eclectic, and aims to give an idea of different possibilities. Define custom labels that are relevant for your repo and use cases.
Note that Labels are not mutually exclusive, so you can add multiple label categories.
Make sure to provide proper title, and a detailed and well-phrased description for each label, so the tool will know when to suggest it.

Inline File Walkthrough 💎

For enhanced user experience, the describe tool can add file summaries directly to the "Files changed" tab in the PR page.
This will enable you to quickly understand the changes in each file, while reviewing the code changes (diffs).

To enable inline file summary, set pr_description.inline_file_summary in the configuration file, possible values are:

  • 'table': File changes walkthrough table will be displayed on the top of the "Files changed" tab, in addition to the "Conversation" tab.
  • true: A collapsable file comment with changes title and a changes summary for each file in the PR.
  • false (default): File changes walkthrough will be added only to the "Conversation" tab.
Utilizing extra instructions

The describe tool can be configured with extra instructions, to guide the model to a feedback tailored to the needs of your project.

Be specific, clear, and concise in the instructions. With extra instructions, you are the prompter. Notice that the general structure of the description is fixed, and cannot be changed. Extra instructions can change the content or style of each sub-section of the PR description.

Examples for extra instructions:

[pr_description]
extra_instructions="""- The PR title should be in the format: '<PR type>: <title>'
- The title should be short and concise (up to 10 words)
- ...
"""

Use triple quotes to write multi-line instructions. Use bullet points to make the instructions more readable.

More PR-Agent commands

To invoke the PR-Agent, add a comment using one of the following commands:

  • /review: Request a review of your Pull Request.
  • /describe: Update the PR title and description based on the contents of the PR.
  • /improve [--extended]: Suggest code improvements. Extended mode provides a higher quality feedback.
  • /ask <QUESTION>: Ask a question about the PR.
  • /update_changelog: Update the changelog based on the PR's contents.
  • /help_docs <QUESTION>: Given a path to documentation (either for this repository or for a given one), ask a question.
  • /add_docs 💎: Generate docstring for new components introduced in the PR.
  • /generate_labels 💎: Generate labels for the PR based on the PR's contents.
  • /analyze 💎: Automatically analyzes the PR, and presents changes walkthrough for each component.

See the tools guide for more details.
To list the possible configuration parameters, add a /config comment.

See the describe usage page for a comprehensive guide on using this tool.

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review bot commented Mar 16, 2026

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Action required

1. SSR prefetch crashes page 🐞 Bug ⛯ Reliability
Description
In app/main/page.tsx, the server component awaits Promise.all of two prefetchQuery calls without any
error handling, so if either /api/items or /api/matching/history fails the whole page render throws
and returns a 500.
This defeats the client components’ graceful loading/error behavior because the page never renders
to the point where React Query can handle it on the client.
Code

app/main/page.tsx[R16-34]

+  // 서버사이드에서 데이터를 미리 가져와서 캐시에 채워줍니다.
+  await Promise.all([
+    queryClient.prefetchQuery({
+      queryKey: ["items"],
+      queryFn: async () => {
+        const res = await serverApi.get<ItemsResponse>({ path: "/api/items" });
+        return res.data;
+      },
+    }),
+    queryClient.prefetchQuery({
+      queryKey: ["matchingHistory"],
+      queryFn: async () => {
+        const res = await serverApi.get<MatchingHistoryResponse>({
+          path: "/api/matching/history",
+        });
+        return res.data;
+      },
+    }),
+  ]);
Evidence
MainPage awaits both prefetches via Promise.all; any rejection aborts SSR. serverApi.request
explicitly re-throws Axios errors, so network/API failures propagate up to the page render.

app/main/page.tsx[13-34]
lib/server-api.ts[122-140]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`app/main/page.tsx` does SSR React Query prefetching with an unguarded `await Promise.all([...])`. Because `serverApi` re-throws request errors, any transient backend failure causes the entire MainPage SSR render to throw (500), preventing the page from rendering at all.

### Issue Context
- `serverApi` throws Axios errors in its `request()` implementation.
- The main page UI already has client-side loading/error handling, but SSR failure prevents it from running.

### Fix Focus Areas
- app/main/page.tsx[16-34]

### Implementation notes
- Replace `Promise.all` with `Promise.allSettled`, or wrap each `prefetchQuery` in its own `try/catch`.
- Optionally log the error (server-side) and continue.
- Keep dehydration/hydration behavior unchanged when prefetch succeeds.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

이 PR은 메인 페이지의 핵심 컴포넌트들이 더 이상 정적 목업 데이터를 사용하지 않고 실제 백엔드 API와 연동하여 동적인 데이터를 표시하도록 개선합니다. 이를 통해 사용자에게 최신 아이템 정보와 매칭 히스토리를 제공하며, React Query를 활용한 효율적인 데이터 관리와 서버 사이드 프리페칭으로 초기 로딩 성능을 향상시켰습니다.

Highlights

  • 메인 페이지 API 연동: 메인 페이지에 사용자 아이템(코인/티켓) 및 매칭 히스토리 데이터를 백엔드 API와 연동하여 동적으로 표시하도록 구현했습니다.
  • React Query를 이용한 데이터 관리: useItemsuseMatchingHistory 커스텀 훅을 추가하여 React Query를 통해 API 데이터를 효율적으로 가져오고 캐싱합니다.
  • 서버 사이드 데이터 프리페칭: page.tsx에서 HydrationBoundaryQueryClient를 사용하여 메인 페이지 로드 시 필요한 데이터를 서버에서 미리 가져와 클라이언트에서 즉시 사용할 수 있도록 했습니다.
  • UI 개선: 데이터 로딩 중 로딩 스켈레톤 UI를 추가하고, API 응답에 따라 실제 티켓 수를 표시하도록 MyCoinSection 컴포넌트를 업데이트했습니다.
Changelog
  • app/main/_components/MyCoinSection.tsx
    • useItems 훅을 사용하여 사용자 아이템 데이터를 가져오도록 변경했습니다.
    • 로딩 중 스켈레톤 UI를 표시하고, 에러 발생 시 컴포넌트를 렌더링하지 않도록 처리했습니다.
    • 하드코딩된 티켓 수 대신 API에서 가져온 matchingTicketCountoptionTicketCount를 표시하도록 업데이트했습니다.
  • app/main/_components/ScreenMainPage.tsx
    • useMatchingHistory 훅을 임포트하고 사용하여 매칭 히스토리 데이터를 가져오도록 했습니다.
    • 기존의 목업 프로필 데이터를 주석 처리하고, useMatchingHistory에서 가져온 데이터를 기반으로 profileList를 동적으로 생성하도록 변경했습니다.
    • ProfileSlider 컴포넌트가 isLoading 상태가 아닐 때만 렌더링되도록 조건을 추가했습니다.
    • ContactFrequency 타입을 임포트했습니다.
  • app/main/page.tsx
    • QueryClient를 초기화하고 serverApi를 사용하여 itemsmatchingHistory 데이터를 서버에서 미리 가져오도록 prefetchQuery를 구현했습니다.
    • HydrationBoundary를 사용하여 프리페칭된 데이터를 클라이언트 컴포넌트에서 사용할 수 있도록 설정했습니다.
  • hooks/useItems.ts
    • 사용자 아이템 정보를 가져오는 fetchItems 비동기 함수와 이를 사용하는 useItems React Query 훅을 새로 추가했습니다.
    • staleTimegcTime을 설정하여 데이터 캐싱 전략을 정의했습니다.
  • hooks/useMatchingHistory.ts
    • 매칭 히스토리 정보를 가져오는 fetchMatchingHistory 비동기 함수와 이를 사용하는 useMatchingHistory React Query 훅을 새로 추가했습니다.
    • MatchingPartner, MatchingHistoryItem, MatchingHistoryResponse 인터페이스를 정의했습니다.
    • staleTimegcTime을 설정하여 데이터 캐싱 전략을 정의했습니다.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

메인 페이지 API 연동을 위한 변경 사항 잘 확인했습니다. React Query를 활용한 서버 사이드 데이터 프리패칭 및 클라이언트 하이드레이션 패턴을 잘 적용하셨습니다. 코드의 유지보수성과 가독성을 더욱 향상시킬 수 있는 몇 가지 제안 사항을 리뷰에 남겼습니다.

  • ScreenMainPage.tsx: 컴포넌트 내 데이터 변환 로직을 더 명확하고 간결하게 개선하는 것을 제안합니다.
  • useMatchingHistory.ts: 코드 스타일 일관성을 위한 함수 정의 형식 수정을 제안합니다.

Comment on lines +69 to +85
// 매칭 히스토리 데이터에서 파트너 정보를 추출하여 프로필 목록 생성
const profileList: ProfileData[] =
historyData?.data.content.map((item) => ({
...item.partner,
// API 응답의 partner 정보를 ProfileData 형식에 맞춤
nickname: item.partner.nickname,
birthDate: item.partner.birthDate ?? undefined,
intro: item.partner.intro ?? undefined,
profileImageUrl: item.partner.profileImageUrl ?? undefined,
socialType: item.partner.socialType ?? undefined,
socialAccountId: item.partner.socialAccountId ?? "",
contactFrequency: (item.partner.contactFrequency === "자주"
? "FREQUENT"
: item.partner.contactFrequency === "보통"
? "NORMAL"
: "RARE") as ContactFrequency,
})) || [];
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

API 응답 데이터를 UI 모델(ProfileData)로 변환하는 로직을 더 간결하고 효율적으로 개선할 수 있습니다.

  1. 데이터 변환 로직 분리: contactFrequency를 변환하는 3항 연산자 체인 대신, 가독성 높은 매핑 객체를 사용하면 의도를 명확히 할 수 있습니다. 이 매핑 객체를 map 콜백 바깥에 선언하면 렌더링 시마다 객체가 불필요하게 재생성되는 것을 방지할 수 있습니다.
  2. 중복 할당 제거: ...item.partner 스프레드 연산으로 대부분의 속성이 이미 복사되므로, 불필요한 재할당을 제거하여 코드를 간결하게 만들 수 있습니다.

아래와 같이 수정하면 코드가 더 깔끔해지고 성능적으로도 미세하게나마 이점이 있습니다.

  const contactFrequencyMap: Record<string, ContactFrequency> = {
    "자주": "FREQUENT",
    "보통": "NORMAL",
    "적음": "RARE",
  };

  // 매칭 히스토리 데이터에서 파트너 정보를 추출하여 프로필 목록 생성
  const profileList: ProfileData[] =
    historyData?.data.content.map((item) => ({
      ...item.partner,
      socialAccountId: item.partner.socialAccountId ?? "",
      contactFrequency: contactFrequencyMap[item.partner.contactFrequency] ?? "RARE",
    })) || [];
References
  1. 컴포넌트 로직을 복잡하게 만드는 데이터 변환 로직을 분리하고, 중복 코드를 제거하여 코드 스타일과 유지보수성을 개선해야 합니다. 이는 Senior Front-end Engineer로서 깨끗하고 효율적인 코드를 작성하는 것과 관련이 있습니다. (link)
  2. Pure functions, such as validation logic, should be extracted into common utility files to improve reusability and separate concerns. The suggestion to use a mapping object outside the map callback aligns with improving separation of concerns and efficiency for data transformation.
  3. Prioritize code readability over conciseness, even if it means some code duplication. The suggestion improves readability by using a clear mapping object instead of a ternary chain and simplifies the code by removing redundant assignments.

Comment on lines +51 to +57
export const fetchMatchingHistory =
async (): Promise<MatchingHistoryResponse> => {
const { data } = await api.get<MatchingHistoryResponse>(
"/api/matching/history",
);
return data;
};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

fetchMatchingHistory 함수의 정의 형식이 일반적이지 않습니다. export const fetchMatchingHistory = 다음에 줄바꿈이 있어 코드를 읽는 데 혼란을 줄 수 있습니다. 일관성 있고 표준적인 코드 스타일을 위해 아래와 같이 수정하는 것을 권장합니다.

export const fetchMatchingHistory = async (): Promise<MatchingHistoryResponse> => {
  const { data } = await api.get<MatchingHistoryResponse>(
    "/api/matching/history",
  );
  return data;
};
References
  1. 일관되고 가독성 좋은 코드 스타일을 유지하는 것은 클린 코드 원칙의 일부입니다. 비표준적인 서식은 코드의 가독성을 해칠 수 있으므로 수정이 필요합니다. (link)

Comment on lines +16 to +34
// 서버사이드에서 데이터를 미리 가져와서 캐시에 채워줍니다.
await Promise.all([
queryClient.prefetchQuery({
queryKey: ["items"],
queryFn: async () => {
const res = await serverApi.get<ItemsResponse>({ path: "/api/items" });
return res.data;
},
}),
queryClient.prefetchQuery({
queryKey: ["matchingHistory"],
queryFn: async () => {
const res = await serverApi.get<MatchingHistoryResponse>({
path: "/api/matching/history",
});
return res.data;
},
}),
]);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Ssr prefetch crashes page 🐞 Bug ⛯ Reliability

In app/main/page.tsx, the server component awaits Promise.all of two prefetchQuery calls without any
error handling, so if either /api/items or /api/matching/history fails the whole page render throws
and returns a 500.
This defeats the client components’ graceful loading/error behavior because the page never renders
to the point where React Query can handle it on the client.
Agent Prompt
### Issue description
`app/main/page.tsx` does SSR React Query prefetching with an unguarded `await Promise.all([...])`. Because `serverApi` re-throws request errors, any transient backend failure causes the entire MainPage SSR render to throw (500), preventing the page from rendering at all.

### Issue Context
- `serverApi` throws Axios errors in its `request()` implementation.
- The main page UI already has client-side loading/error handling, but SSR failure prevents it from running.

### Fix Focus Areas
- app/main/page.tsx[16-34]

### Implementation notes
- Replace `Promise.all` with `Promise.allSettled`, or wrap each `prefetchQuery` in its own `try/catch`.
- Optionally log the error (server-side) and continue.
- Keep dehydration/hydration behavior unchanged when prefetch succeeds.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@dasosann dasosann merged commit 5890c55 into main Mar 16, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant