Skip to content

[feature] 지원서 제작/수정/불러오기 API 연결하기#499

Merged
oesnuj merged 10 commits intodevelop-fefrom
feature/#498-connect-application-api-MOA-38
Jun 5, 2025
Merged

[feature] 지원서 제작/수정/불러오기 API 연결하기#499
oesnuj merged 10 commits intodevelop-fefrom
feature/#498-connect-application-api-MOA-38

Conversation

@oesnuj
Copy link
Member

@oesnuj oesnuj commented Jun 5, 2025

#️⃣연관된 이슈

#498

📝작업 내용

🔧 주요 변경사항

  • mockData 의존성 제거: 실제 API 데이터를 활용하도록 CreateApplicationForm 컴포넌트 수정
  • useGetApplication 훅 연동: 클럽 지원서 데이터를 실시간으로 불러오는 기능 구현
  • 클럽 지원서 생성/수정 기능: createApplication, updateApplication API 함수 연동
  • 질문 ID 재정렬: 저장 시 질문 순서에 맞게 ID를 자동으로 재정렬하는 기능 추가

🛠️ 기술적 개선사항

  • useAdminClubContext와 useGetApplication 훅을 활용한 상태 관리
  • 필드명 통일 (form_title → title)로 코드 일관성 향상
  • 로딩 상태 및 에러 처리 추가

📋 구현된 기능

  1. 클럽 지원서 데이터 실시간 조회
  2. 지원서 생성 및 수정 기능
  3. 질문 추가/삭제/수정
  4. 질문 순서 재정렬
  5. 성공/실패 알림 메시지

🫡 참고사항

  • useGetApplication 훅과 AdminClubContext를 활용하여 클럽별 지원서 관리
  • 기존 mockData 의존성을 완전히 제거하여 실제 백엔드 API와 연동
  • 질문 생성 시 자동 ID 할당 및 저장 시 순서 재정렬로 데이터 일관성 보장

Summary by CodeRabbit

  • New Features

    • 지원서 생성, 조회, 수정 기능이 추가되었습니다.
    • 지원서 데이터를 동적으로 불러오고 저장할 수 있습니다.
  • Bug Fixes

    • 지원서 폼 제목 필드명이 일관되게 'title'로 변경되었습니다.
    • 모든 질문 항목에 빈 'items' 배열이 기본 포함됩니다.
  • 기타

    • 폼 데이터 구조 및 타입이 개선되어 안정성이 향상되었습니다.

oesnuj and others added 10 commits June 5, 2025 15:43
Co-Authored-By: Seongwon Seo <seongwon0903@gmail.com>
Co-Authored-By: Seongwon Seo <seongwon0903@gmail.com>
Co-Authored-By: Seongwon Seo <seongwon0903@gmail.com>
Co-Authored-By: Seongwon Seo <seongwon0903@gmail.com>
Co-Authored-By: Seongwon Seo <seongwon0903@gmail.com>
1. CreateApplicationForm 컴포넌트에 클럽 지원서 저장(생성/수정) 기능 추가
2. 클럽 ID를 기반으로 지원서 데이터를 불러오도록 useAdminClubContext와 useGetApplication 훅 사용
3. mockData 의존성을 제거하고 실제 API 데이터를 활용하도록 수정
4. form_title 등의 필드명을 title로 통일하여 코드 일관성 유지

Co-Authored-By: Seongwon Seo <seongwon0903@gmail.com>
Co-Authored-By: Seongwon Seo <seongwon0903@gmail.com>
1. mockData 의존성을 제거하고 실제 API 데이터를 활용하도록 수정
2. useGetApplication 훅을 활용해 클럽 지원서 데이터를 불러오도록 구현

Co-Authored-By: Seongwon Seo <seongwon0903@gmail.com>
@oesnuj oesnuj requested review from Copilot and seongwon030 June 5, 2025 06:55
@oesnuj oesnuj added ✨ Feature 기능 개발 📬 API 서버 API 통신 작업 💻 FE Frontend labels Jun 5, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jun 5, 2025

Warning

.coderabbit.yaml has a parsing error

The CodeRabbit configuration file in this repository has a parsing error and default settings were used instead. Please fix the error(s) in the configuration file. You can initialize chat with CodeRabbit to get help with the configuration file.

💥 Parsing errors (1)
Validation error: Invalid regex pattern for base branch. Received: "**" at "reviews.auto_review.base_branches[0]"
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Walkthrough

지원서 생성, 수정, 조회를 위한 API 연동 함수와 React 쿼리 훅이 새로 도입되었습니다. 폼 데이터 구조가 변경되어 form_titletitle로 통일되고, 각 질문 객체에 items 배열이 항상 포함되도록 타입이 수정되었습니다. 폼 작성 및 답변 컴포넌트는 API와 동적으로 연동되며, 로딩·에러·성공 상태 처리가 추가되었습니다.

Changes

파일/경로 그룹 변경 요약
frontend/src/apis/application/createApplication.ts
frontend/src/apis/application/updateApplication.ts
지원서 생성 및 수정 API 함수 추가, 에러 핸들링 및 데이터 반환 처리
frontend/src/apis/application/getApplication.ts 지원서 조회 API 함수 추가, 에러 및 데이터 처리
frontend/src/hooks/queries/application/useGetApplication.ts 지원서 폼 조회용 React 쿼리 훅 추가
frontend/src/constants/INITIAL_FORM_DATA.ts
frontend/src/mocks/data/mockData.ts
form_titletitle로 변경, 질문에 items: [] 필드 추가
frontend/src/mocks/api/apply.ts 모킹 API 응답의 폼 타이틀 키를 title로 변경
frontend/src/types/application.ts ApplicationFormData에서 form_titletitle로 변경, Question.items를 필수 필드로 변경
frontend/src/pages/AdminPage/application/CreateApplicationForm.tsx 클럽 컨텍스트와 API 연동, 폼 상태 초기화 및 동적 처리, 질문 추가/수정 구조 변경, 제출 핸들러 추가, 상태별 처리 추가
frontend/src/pages/AdminPage/application/answer/AnswerApplicationForm.tsx 정적 mockData 제거, API 연동 및 로딩/에러 처리 추가, 동적 폼 렌더링

Sequence Diagram(s)

sequenceDiagram
    participant Admin as AdminPage (관리자)
    participant useGet as useGetApplication
    participant API as getApplication API
    participant Form as CreateApplicationForm
    participant createAPI as createApplication API
    participant updateAPI as updateApplication API

    Admin->>useGet: useGetApplication(clubId)
    useGet->>API: getApplication(clubId)
    API-->>useGet: application data
    useGet-->>Admin: application data

    Admin->>Form: CreateApplicationForm(application data)
    Form->>Form: handleSubmit()
    alt 기존 데이터 존재
        Form->>updateAPI: updateApplication(data, clubId)
        updateAPI-->>Form: result
    else 신규 작성
        Form->>createAPI: createApplication(data, clubId)
        createAPI-->>Form: result
    end
Loading

Assessment against linked issues

Objective Addressed Explanation
지원서 최초 작성 API 연동, 기존 지원서 수정 API 연동, 사용자용 지원서 폼 조회 API 연동 (MOA-38)
관리자 모드(제작/수정)와 사용자 모드(입력/제출) 분기 처리 (MOA-38)
질문 유형별 컴포넌트 렌더링 및 상태 관리 (MOA-38)
에러/로딩/성공 상태 처리 (MOA-38)

Possibly related PRs

  • Moadong/moadong#418: application form 타입 설계 및 GET/POST/PUT용 mock API 핸들러 추가로, 본 PR의 API 연동 및 타입 구조 변경과 직접적으로 연결됨.

Suggested reviewers

  • seongwon030
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@netlify
Copy link

netlify bot commented Jun 5, 2025

Deploy Preview for moadong ready!

Name Link
🔨 Latest commit 2fd8f14
🔍 Latest deploy log https://app.netlify.com/projects/moadong/deploys/68413f4d909b42000894274a
😎 Deploy Preview https://deploy-preview-499--moadong.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 42
Accessibility: 87
Best Practices: 92
SEO: 92
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR connects the application form UI to real API endpoints by removing mockData dependencies and integrating the new useGetApplication hook and API functions for creating, updating, and fetching application data. Key changes include updating type definitions (renaming form_title to title and making items required), modifying components to use live API data with loading handling, and implementing API calls for form creation and update.

Reviewed Changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated no comments.

Show a summary per file
File Description
frontend/src/types/application.ts Updated interface definitions: renamed “form_title” to “title” and made “items” a required field.
frontend/src/pages/AdminPage/application/answer/AnswerApplicationForm.tsx Replaced mockData with live API data and added loading UI using the useGetApplication hook.
frontend/src/pages/AdminPage/application/CreateApplicationForm.tsx Removed mockData dependency, integrated API data state management, and added API submit logic.
frontend/src/mocks/data/mockData.ts Updated the application form key to “title” to reflect interface changes.
frontend/src/mocks/api/apply.ts Adjusted the mocked API response to use the new title value but still returns key “form_title”.
frontend/src/hooks/queries/application/useGetApplication.ts Added a new query hook for fetching application form data from the API.
frontend/src/constants/INITIAL_FORM_DATA.ts Updated the initial form data to use “title” instead of “form_title”.
frontend/src/apis/application/updateApplication.ts Created a new API method for updating application data.
frontend/src/apis/application/getApplication.ts Created a new API method for retrieving application data.
frontend/src/apis/application/createApplication.ts Created a new API method for creating application data.
Comments suppressed due to low confidence (4)

frontend/src/mocks/api/apply.ts:28

  • The API mock response still uses the key 'form_title' while the updated interface expects 'title'. Consider aligning the response field name for consistency.
        form_title: mockData.title,

frontend/src/pages/AdminPage/application/CreateApplicationForm.tsx:31

  • [nitpick] The 'nextId' state is initialized based on API data which may be updated later. Consider recalculating 'nextId' when the API data changes to ensure IDs remain consistent.
  const [nextId, setNextId] = useState(() => {

frontend/src/pages/AdminPage/application/CreateApplicationForm.tsx:117

  • [nitpick] In handleSubmit, question IDs are reassigned sequentially using the index. Verify that this reordering aligns with backend expectations and does not unintentionally affect existing data.
  const handleSubmit = async () => {

frontend/src/types/application.ts:13

  • The 'items' field on Question is now required; please ensure that all implementations provide an array (even if empty) to avoid runtime issues.
  items: { value: string }[];

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 9

🔭 Outside diff range comments (1)
frontend/src/pages/AdminPage/application/answer/AnswerApplicationForm.tsx (1)

28-30: 🛠️ Refactor suggestion

에러 상태 처리 개선 필요

isError 상태가 사용되지 않고 있습니다. useGetApplication에서 반환되는 에러 상태도 함께 처리해야 합니다.

다음과 같이 개선하세요:

  if (error) {
    return <div>에러가 발생했습니다.</div>;
  }
+ 
+ if (isError) {
+   return <div>지원서를 불러오는 중 오류가 발생했습니다.</div>;
+ }
🧹 Nitpick comments (6)
frontend/src/hooks/queries/application/useGetApplication.ts (1)

8-8: 재시도 정책 재검토 권장

retry: false 설정은 네트워크 일시적 오류 시 사용자 경험을 저해할 수 있습니다. 적어도 1-2회 재시도를 허용하는 것을 고려해보세요.

더 나은 사용자 경험을 위해 다음과 같이 수정을 권장합니다:

-    retry: false,
+    retry: 1,

또는 더 세밀한 제어를 원한다면:

-    retry: false,
+    retry: (failureCount, error) => failureCount < 2 && error.status !== 404,
frontend/src/pages/AdminPage/application/answer/AnswerApplicationForm.tsx (2)

24-26: 로딩 상태 처리 개선 제안

현재 로딩 상태 처리가 너무 단순합니다. 사용자 경험을 위해 스켈레톤 UI나 스피너를 사용하는 것을 고려해보세요.

다음과 같이 개선할 수 있습니다:

- if (!clubId || isLoading || !formData || !clubDetail) {
-   return <div>로딩 중...</div>;
- }
+ if (!clubId) {
+   return <div>잘못된 접근입니다.</div>;
+ }
+ 
+ if (isLoading) {
+   return <div>지원서를 불러오는 중...</div>; // 또는 스켈레톤 UI
+ }
+ 
+ if (!formData || !clubDetail) {
+   return <div>데이터를 찾을 수 없습니다.</div>;
+ }

45-45: 타입 안전성 개선

Question 타입을 명시적으로 지정한 것은 좋습니다. 하지만 이미 formData.questions가 Question[] 타입이므로 타입 어노테이션이 불필요할 수 있습니다.

다음과 같이 간소화할 수 있습니다:

- {formData.questions.map((q: Question) => (
+ {formData.questions.map((q) => (
frontend/src/apis/application/getApplication.ts (1)

13-15: FIXME 해결 필요

지원서가 존재하지 않는 경우의 에러 처리가 명시되어 있습니다. 이 경우를 별도로 처리하는 것을 고려해보세요.

다음과 같이 개선할 수 있습니다:

  } catch (error) {
-   // [x] FIXME:
-   // {"statuscode":"800-1","message":"지원서가 존재하지 않습니다.","data":null}
-   console.error('Error fetching club details', error);
-   throw error;
+   console.error('Error fetching application', error);
+   
+   // 지원서가 존재하지 않는 경우 특별 처리
+   if (error instanceof Error && error.message.includes('800-1')) {
+     throw new Error('APPLICATION_NOT_FOUND');
+   }
+   
+   throw error;
  }

이 FIXME를 해결하는 이슈를 생성해드릴까요?

frontend/src/apis/application/updateApplication.ts (1)

21-23: 에러 메시지 개선 제안

에러 메시지가 사용자 친화적이지만 디버깅을 위한 정보가 부족합니다.

다음과 같이 개선할 수 있습니다:

  if (!response.ok) {
-   throw new Error('지원서 수정에 실패했습니다.');
+   throw new Error(`지원서 수정에 실패했습니다. (${response.status}: ${response.statusText})`);
  }
frontend/src/apis/application/createApplication.ts (1)

28-28: 프로덕션 환경에서의 에러 로깅 개선 필요

console.error는 프로덕션 환경에서 민감한 정보를 노출할 수 있습니다. 적절한 로깅 서비스를 사용하거나 에러 정보를 필터링하는 것을 고려해주세요.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9ec8768 and 2fd8f14.

📒 Files selected for processing (10)
  • frontend/src/apis/application/createApplication.ts (1 hunks)
  • frontend/src/apis/application/getApplication.ts (1 hunks)
  • frontend/src/apis/application/updateApplication.ts (1 hunks)
  • frontend/src/constants/INITIAL_FORM_DATA.ts (1 hunks)
  • frontend/src/hooks/queries/application/useGetApplication.ts (1 hunks)
  • frontend/src/mocks/api/apply.ts (1 hunks)
  • frontend/src/mocks/data/mockData.ts (1 hunks)
  • frontend/src/pages/AdminPage/application/CreateApplicationForm.tsx (6 hunks)
  • frontend/src/pages/AdminPage/application/answer/AnswerApplicationForm.tsx (2 hunks)
  • frontend/src/types/application.ts (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
frontend/src/mocks/api/apply.ts (1)
frontend/src/mocks/data/mockData.ts (1)
  • mockData (25-122)
frontend/src/pages/AdminPage/application/answer/AnswerApplicationForm.tsx (3)
frontend/src/hooks/queries/club/useGetClubDetail.ts (1)
  • useGetClubDetail (6-20)
frontend/src/hooks/queries/application/useGetApplication.ts (1)
  • useGetApplication (4-10)
frontend/src/hooks/useAnswers.ts (1)
  • useAnswers (4-33)
🔇 Additional comments (12)
frontend/src/mocks/data/mockData.ts (1)

26-26: 속성명 통일화 완료

form_title에서 title로의 변경이 타입 정의와 일관성을 맞추기 위한 적절한 수정입니다.

frontend/src/constants/INITIAL_FORM_DATA.ts (2)

4-4: 속성명 통일화 완료

form_title에서 title로의 변경이 타입 정의와 일관성을 맞추기 위한 적절한 수정입니다.


12-12: 타입 일관성을 위한 적절한 추가

SHORT_TEXT 타입 질문에 빈 items 배열을 추가한 것은 타입 정의에서 items가 필수 속성으로 변경된 것에 맞춘 적절한 수정입니다.

frontend/src/hooks/queries/application/useGetApplication.ts (1)

4-10: 훅 구현 검토 완료

React Query 훅의 기본 구조와 쿼리 키 설정이 적절하게 구현되었습니다. 클럽별 애플리케이션 데이터 관리에 효과적인 구조입니다.

frontend/src/types/application.ts (1)

13-13:

Details

✅ Verification successful

타입 변경사항 검증 필요

items 속성을 필수로 변경한 것은 좋은 개선입니다. 모든 질문이 items 배열을 가져야 한다는 것이 명확해졌습니다.

다음 스크립트로 코드베이스 전반에서 items 속성 사용이 일관되게 적용되었는지 확인해주세요:


🏁 Script executed:

#!/bin/bash
# Question 타입 사용 시 items 속성이 항상 제공되는지 확인

# Question 객체 생성 패턴 검색
rg -A 5 -B 5 "Question\[|Question\s*=|:\s*Question" --type ts --type tsx

# items 속성 없이 Question 객체를 생성하는 패턴 확인
ast-grep --pattern $'{
  $$$
  type: $_,
  $$$
}' | grep -v "items:"

Length of output: 170


다음 스크립트로 .ts/​.tsx 파일 전반에서 Question 타입 객체 할당 시 items 속성 누락 여부를 재검증해주세요.


🏁 Script executed:

#!/bin/bash
# .ts/.tsx 파일에서 Question 타입 객체 할당 시 items 속성 누락 확인

# Question 타입 객체를 선언/할당한 위치를 찾고, 이후 20줄 내에 items 속성이 있는지 검사
rg -l -g '*.ts' -g '*.tsx' ":\s*Question\s*=\s*{" | while read -r file; do
  rg -n ":\s*Question\s*=\s**{" "$file" | while IFS=':' read -r f ln _; do
    sed -n "${ln},$((ln+20))p" "$file" \
      | grep -q "items:" \
      || echo "⚠️ items 누락: ${file}:${ln}"
  done
done

Length of output: 170


아래 수정된 스크립트로 다시 한 번 Question 타입 할당부에서 items 누락 여부를 검증해주세요. 이번엔 중괄호 리터럴을 올바르게 이스케이프 해줬습니다.


🏁 Script executed:

#!/usr/bin/env bash
# .ts/.tsx 파일에서 Question 타입 객체 할당 시 items 속성 누락 확인

# .ts/.tsx 전체 검색
rg -n -g '*.ts' -g '*.tsx' ':\s*Question\s*=\s*\{' | while IFS=: read -r file ln _; do
  # 할당부로부터 20줄 이내에 items: 이 있는지 검사
  if ! sed -n "${ln},$((ln+20))p" "$file" | grep -q 'items:'; then
    echo "⚠️ items 누락: ${file}:${ln}"
  fi
done

Length of output: 208


items 속성 변경사항 일관 적용 확인됨

자동 검증 스크립트 실행 결과, Question = { … } 할당부마다 20줄 이내에 items:가 모두 포함되어 있어 누락 사례가 없습니다.
해당 타입 변경은 코드베이스 전반에 안전하게 적용된 것으로 확인되었습니다.

frontend/src/pages/AdminPage/application/answer/AnswerApplicationForm.tsx (2)

9-10: 적절한 훅과 타입 import

useGetApplication 훅과 Question 타입을 올바르게 import했습니다. API 데이터로의 전환이 잘 이루어졌습니다.


15-19: 훅 사용법 개선

구조 분해 할당을 통해 필요한 상태들을 깔끔하게 추출했습니다.

frontend/src/apis/application/getApplication.ts (1)

6-8: 에러 처리 개선

HTTP 응답 상태 확인과 에러 처리가 적절합니다.

frontend/src/apis/application/updateApplication.ts (3)

5-8: 함수 시그니처 적절함

ApplicationFormData 타입을 사용하고 clubId를 매개변수로 받는 함수 시그니처가 적절합니다.


10-19: secureFetch 사용 및 요청 구성

인증이 필요한 요청에 대해 secureFetch를 사용하고, PUT 메서드와 적절한 헤더를 설정한 것이 좋습니다.


27-30: 일관된 에러 처리

에러 로깅과 재발생 처리가 적절합니다. getApplication.ts와 일관된 패턴을 사용하고 있습니다.

frontend/src/pages/AdminPage/application/CreateApplicationForm.tsx (1)

10-14: Context와 Hook 사용이 적절합니다

useAdminClubContextuseGetApplication 훅을 통해 상태 관리가 잘 구성되어 있고, clubId가 없을 때 early return 처리도 적절합니다.

Also applies to: 16-18

{
clubId,
form_title: mockData.form_title,
form_title: mockData.title,
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

API 응답 구조 불일치 문제

mockData.title을 참조하면서도 API 응답에서는 여전히 form_title 키를 사용하고 있습니다. 이는 클라이언트 코드와의 불일치를 야기할 수 있습니다.

다음과 같이 수정하여 일관성을 맞춰주세요:

-        form_title: mockData.title,
+        title: mockData.title,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
form_title: mockData.title,
title: mockData.title,
🤖 Prompt for AI Agents
In frontend/src/mocks/api/apply.ts at line 28, the key 'form_title' is used
while referencing mockData.title, causing inconsistency with the API response
structure. Rename the key from 'form_title' to 'title' to match the mockData
property and ensure consistency with the client code.


export interface ApplicationFormData {
form_title: string;
title: string;
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

프로퍼티 이름 변경 검증 필요

form_titletitle로 변경한 것은 명명 일관성 측면에서 좋은 개선입니다.

다음 스크립트로 모든 파일에서 form_title 사용이 완전히 제거되었는지 확인해주세요:


🏁 Script executed:

#!/bin/bash
# form_title 사용이 남아있는지 확인

echo "=== form_title 사용 검색 ==="
rg "form_title" --type ts --type tsx

echo "=== ApplicationFormData 타입 사용 검색 ==="
rg -A 3 -B 3 "ApplicationFormData" --type ts --type tsx

Length of output: 290


다음 스크립트로 form_titleApplicationFormData가 남아있는지 TS/TSX 파일을 대상으로 재확인해주세요:


🏁 Script executed:

#!/bin/bash
# form_title 사용 여부 확인
echo "=== form_title 검색 ==="
rg "form_title" -g '*.ts' -g '*.tsx'

# ApplicationFormData 타입 사용 여부 확인
echo "=== ApplicationFormData 검색 ==="
rg -A3 -B3 "ApplicationFormData" -g '*.ts' -g '*.tsx'

Length of output: 5635


form_title 잔여 참조 수정 필요

form_titletitle로 변경한 것은 올바른 개선이지만, 아래 파일들에서 여전히 form_title을 사용하고 있어 런타임 에러나 테스트 실패를 일으킬 수 있습니다. 해당 참조를 모두 title로 대체해주세요:

• frontend/src/mocks/api/apply.ts

  • form_title: mockData.title,
    • frontend/src/mocks/api/applyHandlers.test.ts
  • form_title: string;
  • expect((data as ClubApplyResponse).form_title)… (여러 테스트)

위 파일들 외에도 다른 mock/data나 테스트 코드에 남아있는지 한 번 더 확인 부탁드립니다.

🤖 Prompt for AI Agents
In frontend/src/types/application.ts at line 49, the property name was changed
from form_title to title for consistency, but there are still references to
form_title in other files causing potential runtime errors and test failures.
Search for all occurrences of form_title in the codebase, especially in
frontend/src/mocks/api/apply.ts and
frontend/src/mocks/api/applyHandlers.test.ts, and replace them with title to
ensure consistency and prevent errors. Also verify no other mock or test files
contain form_title and update those references accordingly.


const getApplication = async (clubId: string) => {
try {
const response = await fetch(`${API_BASE_URL}/api/club/${clubId}/apply`);
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

API 엔드포인트 일관성 확인 필요

/api/club/${clubId}/apply 엔드포인트를 사용하고 있는데, updateApplication.ts에서는 /api/club/${clubId}/application을 사용합니다. 일관성을 확인해주세요.

다음 스크립트로 API 엔드포인트 사용 패턴을 확인해주세요:


🏁 Script executed:

#!/bin/bash
# API 엔드포인트 패턴 확인

echo "=== application 관련 API 엔드포인트 검색 ==="
rg "/api/club.*/(apply|application)" --type ts --type tsx -A 2 -B 2

echo "=== API 엔드포인트 상수 확인 ==="
rg "application|apply" frontend/src/constants/ --type ts

Length of output: 397


아래 스크립트로 updateApplication.ts 파일에서 사용 중인 API 엔드포인트를 확인해주세요.


🏁 Script executed:

#!/bin/bash
# updateApplication.ts 위치 찾기
echo "=== updateApplication.ts 파일 경로 ==="
update_file=$(fd updateApplication.ts)
echo "$update_file"

# 해당 파일에서 fetch 사용 부분 추출
echo "=== updateApplication.ts 내 fetch 호출 스니펫 ==="
rg "fetch" -n "$update_file"

Length of output: 441


updateApplication.ts 파일에서 실제 사용 중인 API 엔드포인트를 확인하기 위해 아래 스크립트를 실행해주세요.


🏁 Script executed:

#!/bin/bash
# updateApplication.ts에서 API 엔드포인트 확인

file="frontend/src/apis/application/updateApplication.ts"
echo "=== 파일 경로 ==="
echo "$file"

echo "=== '/api/club' 포함 라인 확인 ==="
rg "/api/club" -n "$file"

Length of output: 404


API 엔드포인트 일관성 유지 필요

getApplication.tsupdateApplication.ts에서 동일한 리소스를 가리키면서도 각각 /apply/application을 사용하고 있습니다. 둘 중 하나로 통일해주세요.

  • getApplication.ts (5행)
    - const response = await fetch(`${API_BASE_URL}/api/club/${clubId}/apply`);
    + const response = await fetch(`${API_BASE_URL}/api/club/${clubId}/application`);
  • updateApplication.ts (11행)
    `${API_BASE_URL}/api/club/${clubId}/application`

위 예시처럼 두 파일 모두 /application을 사용하거나, 반대로 /apply로 통일하시기 바랍니다.

🤖 Prompt for AI Agents
In frontend/src/apis/application/getApplication.ts at line 5, the API endpoint
uses `/apply` while updateApplication.ts uses `/application`. To maintain
consistency, change the endpoint in getApplication.ts from `/apply` to
`/application` so both files use the same `/api/club/${clubId}/application`
endpoint.

Comment on lines +5 to +9
export const createApplication = async (
data: ApplicationFormData,
clubId: string,
) => {
try {
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

입력 파라미터 검증 추가 필요

dataclubId 파라미터에 대한 검증이 없습니다. 잘못된 데이터로 API 호출이 발생할 수 있습니다.

다음과 같이 입력 검증을 추가하는 것을 권장합니다:

export const createApplication = async (
  data: ApplicationFormData,
  clubId: string,
) => {
+  if (!clubId || !clubId.trim()) {
+    throw new Error('clubId가 필요합니다.');
+  }
+  if (!data || !data.title || !data.questions) {
+    throw new Error('유효하지 않은 지원서 데이터입니다.');
+  }
  try {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const createApplication = async (
data: ApplicationFormData,
clubId: string,
) => {
try {
export const createApplication = async (
data: ApplicationFormData,
clubId: string,
) => {
if (!clubId || !clubId.trim()) {
throw new Error('clubId가 필요합니다.');
}
if (!data || !data.title || !data.questions) {
throw new Error('유효하지 않은 지원서 데이터입니다.');
}
try {
// …
🤖 Prompt for AI Agents
In frontend/src/apis/application/createApplication.ts around lines 5 to 9, there
is no validation for the input parameters `data` and `clubId`, which may lead to
API calls with invalid data. Add validation checks to ensure `data` conforms to
the expected ApplicationFormData structure and `clubId` is a non-empty string
before proceeding with the API call. If validation fails, handle the error
appropriately, such as throwing an error or returning early.

Comment on lines +25 to +26
const result = await response.json();
return result.data;
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

API 응답 구조 확인 필요

result.data를 반환하고 있는데, 백엔드 API가 실제로 이런 구조로 응답하는지 확인이 필요합니다.

다음 스크립트를 실행하여 API 응답 구조를 확인해주세요:


🏁 Script executed:

#!/bin/bash
# Description: API 응답 구조 확인을 위해 관련 코드 검색

# updateApplication과 getApplication의 응답 처리 방식 확인
echo "=== Checking response handling in other API files ==="
rg -A 5 "result\.data|response\.json\(\)" --glob "frontend/src/apis/application/*.ts"

# 백엔드 API 응답 구조 관련 타입 정의 확인
echo -e "\n=== Checking API response type definitions ==="
fd -e ts -e tsx . frontend/src/types | xargs rg -l "ApiResponse|Response" | head -5 | xargs cat

Length of output: 2025


🏁 Script executed:

#!/bin/bash
# 1. List any type definition files under src
echo "=== Listing type definition files under src ==="
find frontend/src -type f \( -name "*type*.ts" -o -name "*types*.ts" \) | sed 's/^/FOUND: /'

# 2. Search for generic ApiResponse or Response interfaces
echo -e "\n=== Searching for ApiResponse or Response interface definitions ==="
rg -H "interface .*Response" frontend/src
rg -H "type .*Response" frontend/src

# 3. Search for ApiResponse<T> usage
echo -e "\n=== Searching for ApiResponse< usage ==="
rg -H "ApiResponse<" frontend/src

# 4. Search for 'statuscode' string in code to find sample payloads
echo -e "\n=== Searching for sample payloads with 'statuscode' ==="
rg -H "statuscode" -A2 frontend/src

Length of output: 1537


🏁 Script executed:

#!/bin/bash
# Display contents of the mock API handlers to inspect response structures for createApplication
echo "=== Showing mock API handlers for application endpoints ==="
sed -n '1,200p' frontend/src/mocks/api/applyHandlers.test.ts

Length of output: 4973


API 응답 구조에 맞춰 반환값 수정 필요

createApplication.ts에서 result.data를 반환하고 있는데, 실제 MSW 핸들러 및 백엔드 API는 { data: … } 래퍼 없이 응답 본문을 바로 반환합니다. 따라서 result.dataundefined가 되어 올바른 값을 얻지 못합니다.

  • 수정 대상:

    • frontend/src/apis/application/createApplication.ts (25–26줄)
  • 변경 제안:

- const result = await response.json();
- return result.data;
+ const result = await response.json();
+ return result;

동일한 패턴을 사용하는 getApplication.tsupdateApplication.ts도 함께 검토 후 일관되게 수정해주세요.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const result = await response.json();
return result.data;
const result = await response.json();
return result;
🤖 Prompt for AI Agents
In frontend/src/apis/application/createApplication.ts at lines 25-26, the code
returns result.data, but the actual API response does not wrap the data inside a
data property; it returns the response body directly. To fix this, change the
return statement to return the entire result object instead of result.data.
Also, review and apply the same fix to getApplication.ts and
updateApplication.ts to maintain consistency in handling API responses.

try {
if (data) {
await updateApplication(payload, clubId);
alert('지원서가 성공적으로 수정되었습니다.');
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

alert() 대신 토스트 알림 사용 권장

브라우저의 alert()는 사용자 경험을 저해합니다. 토스트 알림이나 모달을 사용하는 것이 좋습니다.

토스트 알림 라이브러리를 사용하거나 커스텀 알림 컴포넌트를 구현하시겠습니까?

Also applies to: 134-134, 137-137

🤖 Prompt for AI Agents
In frontend/src/pages/AdminPage/application/CreateApplicationForm.tsx at lines
131, 134, and 137, replace the use of browser alert() calls with a toast
notification system to improve user experience. Choose a toast notification
library or implement a custom toast component, then update these lines to
trigger toast messages instead of alert dialogs for success or error feedback.

Comment on lines +117 to +140
const handleSubmit = async () => {
if (!clubId) return;
const reorderedQuestions = formData.questions.map((q, idx) => ({
...q,
id: idx + 1,
}));

const payload: ApplicationFormData = {
...formData,
questions: reorderedQuestions,
};
try {
if (data) {
await updateApplication(payload, clubId);
alert('지원서가 성공적으로 수정되었습니다.');
} else {
await createApplication(payload, clubId);
alert('지원서가 성공적으로 생성되었습니다.');
}
} catch (error) {
alert('지원서 저장에 실패했습니다.');
console.error(error);
}
};
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

API 호출 중 로딩 상태 추가 필요

API 호출 중에 로딩 상태가 없어 사용자가 여러 번 클릭하거나 중복 제출이 발생할 수 있습니다.

다음과 같이 로딩 상태를 추가하세요:

+  const [isSubmitting, setIsSubmitting] = useState(false);
+
  const handleSubmit = async () => {
    if (!clubId) return;
+    if (isSubmitting) return;
+    
+    setIsSubmitting(true);
    const reorderedQuestions = formData.questions.map((q, idx) => ({
      ...q,
      id: idx + 1,
    }));

    const payload: ApplicationFormData = {
      ...formData,
      questions: reorderedQuestions,
    };
    try {
      if (data) {
        await updateApplication(payload, clubId);
        alert('지원서가 성공적으로 수정되었습니다.');
      } else {
        await createApplication(payload, clubId);
        alert('지원서가 성공적으로 생성되었습니다.');
      }
    } catch (error) {
      alert('지원서 저장에 실패했습니다.');
      console.error(error);
+    } finally {
+      setIsSubmitting(false);
    }
  };

그리고 버튼에 로딩 상태를 반영하세요:

-          <Styled.submitButton onClick={handleSubmit}>
-            저장하기
+          <Styled.submitButton onClick={handleSubmit} disabled={isSubmitting}>
+            {isSubmitting ? '저장 중...' : '저장하기'}
          </Styled.submitButton>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleSubmit = async () => {
if (!clubId) return;
const reorderedQuestions = formData.questions.map((q, idx) => ({
...q,
id: idx + 1,
}));
const payload: ApplicationFormData = {
...formData,
questions: reorderedQuestions,
};
try {
if (data) {
await updateApplication(payload, clubId);
alert('지원서가 성공적으로 수정되었습니다.');
} else {
await createApplication(payload, clubId);
alert('지원서가 성공적으로 생성되었습니다.');
}
} catch (error) {
alert('지원서 저장에 실패했습니다.');
console.error(error);
}
};
// add loading state
const [isSubmitting, setIsSubmitting] = useState(false);
const handleSubmit = async () => {
if (!clubId) return;
if (isSubmitting) return;
setIsSubmitting(true);
const reorderedQuestions = formData.questions.map((q, idx) => ({
...q,
id: idx + 1,
}));
const payload: ApplicationFormData = {
...formData,
questions: reorderedQuestions,
};
try {
if (data) {
await updateApplication(payload, clubId);
alert('지원서가 성공적으로 수정되었습니다.');
} else {
await createApplication(payload, clubId);
alert('지원서가 성공적으로 생성되었습니다.');
}
} catch (error) {
alert('지원서 저장에 실패했습니다.');
console.error(error);
} finally {
setIsSubmitting(false);
}
};
// ...
<Styled.submitButton onClick={handleSubmit} disabled={isSubmitting}>
{isSubmitting ? '저장 중...' : '저장하기'}
</Styled.submitButton>
🤖 Prompt for AI Agents
In frontend/src/pages/AdminPage/application/CreateApplicationForm.tsx around
lines 117 to 140, the handleSubmit function lacks a loading state during API
calls, which can cause multiple submissions if the user clicks repeatedly. Add a
loading state variable (e.g., isLoading) to the component state, set it to true
before starting the API call, and set it back to false after the call completes
or fails. Also, update the submit button to reflect this loading state by
disabling it and optionally showing a loading indicator while isLoading is true.

Comment on lines +19 to +20
const { data, isLoading, isError } = useGetApplication(clubId);

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

로딩 및 에러 상태 처리 필요

isLoadingisError 상태를 활용하지 않고 있습니다. 사용자 경험 개선을 위해 이러한 상태들을 UI에 반영해야 합니다.

다음과 같이 로딩 및 에러 상태를 처리하세요:

  const { data, isLoading, isError } = useGetApplication(clubId);

+  if (isLoading) {
+    return <div>로딩 중...</div>;
+  }
+
+  if (isError) {
+    return <div>지원서를 불러오는 중 오류가 발생했습니다.</div>;
+  }
+
  const [formData, setFormData] =
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { data, isLoading, isError } = useGetApplication(clubId);
const { data, isLoading, isError } = useGetApplication(clubId);
if (isLoading) {
return <div>로딩 중...</div>;
}
if (isError) {
return <div>지원서를 불러오는 중 오류가 발생했습니다.</div>;
}
const [formData, setFormData] =
🤖 Prompt for AI Agents
In frontend/src/pages/AdminPage/application/CreateApplicationForm.tsx around
lines 19 to 20, the isLoading and isError states from useGetApplication are not
being handled. Update the component to display appropriate UI feedback during
loading (e.g., a spinner or loading message) and error states (e.g., an error
message) to improve user experience.

Comment on lines +119 to +122
const reorderedQuestions = formData.questions.map((q, idx) => ({
...q,
id: idx + 1,
}));
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

질문 ID 재정렬의 영향 확인 필요

저장할 때마다 질문 ID를 1부터 순차적으로 재정렬하고 있습니다. 다른 곳에서 이 ID를 참조하거나 백엔드에서 특정 ID 값에 의존하는 경우 문제가 발생할 수 있습니다.

다음 스크립트를 실행하여 질문 ID 사용 현황을 확인해주세요:


🏁 Script executed:

#!/bin/bash
# Description: 질문 ID가 다른 곳에서 참조되는지 확인

# 질문 ID 참조 패턴 검색
echo "=== Searching for question ID references ==="
rg -A 3 "question\.id|q\.id|questionId" --glob "frontend/src/**/*.{ts,tsx}" | grep -v "CreateApplicationForm"

# 백엔드 API에서 질문 ID 처리 방식 확인
echo -e "\n=== Checking backend question ID handling ==="
fd -e ts -e js . backend/src | xargs rg -A 3 "question.*id|questionId" | head -20

Length of output: 4395


질문 ID 재정렬 중단 및 안정적 ID 유지 필요

저장할 때마다 질문 ID를 1부터 다시 매기면, 아래 컴포넌트들이 기존 ID로 데이터를 조회·처리하기 때문에 의도치 않은 동작(답안 손실, 키 재생성 등)이 발생할 수 있습니다.
기존 ID를 그대로 유지하고, 새 질문 추가 시에만 고유 ID를 부여하도록 수정해 주세요.

  • 영향을 받는 위치

    • frontend/src/pages/AdminPage/application/answer/AnswerApplicationForm.tsx
      • key={q.id}
      • selectedAnswers={getAnswersById(q.id)}
    • frontend/src/pages/AdminPage/application/components/QuestionAnswerer/QuestionAnswerer.tsx
      • id={question.id}
      • onAnswerChange={(value) => onChange(question.id, value)}
  • 제안하는 수정 예시

- const reorderedQuestions = formData.questions.map((q, idx) => ({
-   ...q,
-   id: idx + 1,
- }));
+ // ID 재정렬 제거: 기존 ID 유지
+ const reorderedQuestions = formData.questions;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const reorderedQuestions = formData.questions.map((q, idx) => ({
...q,
id: idx + 1,
}));
// ID 재정렬 제거: 기존 ID 유지
const reorderedQuestions = formData.questions;
🤖 Prompt for AI Agents
In frontend/src/pages/AdminPage/application/CreateApplicationForm.tsx around
lines 119 to 122, the code currently reassigns question IDs sequentially
starting from 1 on every save, which can break references in other components
relying on stable IDs. To fix this, stop reordering the question IDs on save and
preserve the existing IDs as they are. When adding new questions, assign them
unique IDs without altering existing ones, ensuring consistent ID usage across
components like AnswerApplicationForm.tsx and QuestionAnswerer.tsx.

@oesnuj oesnuj requested a review from PororoAndFriends June 5, 2025 09:19
Copy link
Collaborator

@PororoAndFriends PororoAndFriends left a comment

Choose a reason for hiding this comment

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

고생하셨습니다

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

📬 API 서버 API 통신 작업 💻 FE Frontend ✨ Feature 기능 개발

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

Comments