Skip to content

[retfactor] 지원서 페이지에 지원서 설명 추가 및 리팩토링#564

Merged
oesnuj merged 12 commits intodevelop-fefrom
feature/#561-application-form-description-MOA-101
Jul 21, 2025
Merged

[retfactor] 지원서 페이지에 지원서 설명 추가 및 리팩토링#564
oesnuj merged 12 commits intodevelop-fefrom
feature/#561-application-form-description-MOA-101

Conversation

@oesnuj
Copy link
Member

@oesnuj oesnuj commented Jul 20, 2025

#️⃣연관된 이슈

#561

📝작업 내용

이번 PR에서 작업한 내용을 간략히 설명해주세요(이미지/동영상 첨부 가능)

🆕 새로운 기능

  • 지원서 설명 표시:
    • `ClubApplicationForm` 컴포넌트에 설명(`description`) 렌더링 추가
    • HTML 태그가 포함된 설명을 안전하게 파싱하여 표시
    • 설명이 있는 경우에만 조건부 렌더링

🔧 유틸리티 함수 추가

  • `parseHtmlWithLinks` 함수:
    • HTML 문자열에서 `` 태그를 React 컴포넌트로 변환
    • `target="_blank"` 및 `rel="noopener noreferrer"` 속성 자동 추가
    • 보안성과 접근성을 고려한 링크 처리

🎣 커스텀 훅 분리

  • `useValidateAnswers` 훅 생성:
    • 기존 `ClubApplicationForm`에 있던 `validateAnswers` 로직을 독립적인 훅으로 분리
    • 답변 유효성 검사 로직의 재사용성 및 테스트 용이성 향상
    • 관심사 분리를 통한 컴포넌트 복잡도 감소

🎨 스타일 개선

  • FormTitle 스타일:
    • 폰트 크기: `2.375rem` → `1.875rem` (모바일 최적화)
    • 마진 조정으로 더 나은 시각적 균형
  • QuestionsWrapper:
    • 패딩 최적화 및 반응형 디자인 개선
  • PageContainer:
    • 상단 패딩: `172px` → `100px`로 조정하여 더 효율적인 공간 활용
  • QuestionContainer:
    • 패딩 세밀 조정: `24px 26px 15px`로 최적화

Summary by CodeRabbit

  • 신규 기능

    • 폼 설명 내 URL을 자동으로 링크로 변환하여 보여주는 기능이 추가되었습니다.
    • 필수 질문에 대한 답변 유효성 검사를 위한 새로운 검증 로직이 도입되었습니다.
  • UI/스타일 개선

    • 입력 필드와 텍스트 영역의 최소 너비가 300px로 축소되어 다양한 화면에서 더 유연하게 표시됩니다.
    • 폼 제목과 설명, 질문 영역의 여백 및 폰트 크기 등이 조정되어 가독성과 모바일 반응형이 개선되었습니다.
    • 질문 컨테이너의 패딩이 조정되어 레이아웃이 더욱 깔끔해졌습니다.
  • 버그 수정

    • 오류 발생 시 사용자에게 알림을 제공하고, 클럽 페이지로 이동하도록 처리되었습니다.
  • 기타

    • ClubProfile 컴포넌트가 임시로 비활성화되었습니다.

@oesnuj oesnuj self-assigned this Jul 20, 2025
@oesnuj oesnuj added ✨ Feature 기능 개발 💻 FE Frontend labels Jul 20, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 20, 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

이 변경사항은 지원서 페이지에 설명을 추가하고, 설명 내 URL을 자동으로 링크로 변환하는 유틸리티를 도입합니다. 또한, 입력 필드 스타일을 조정하고, 답변 검증 로직을 별도 훅으로 분리하며, 기존 ClubProfile 컴포넌트의 렌더링을 일시적으로 비활성화했습니다.

Changes

파일/경로 요약 변경 내용 요약
frontend/src/components/common/CustomTextArea/CustomTextArea.styles.ts,
frontend/src/components/common/InputField/InputField.styles.ts
입력 컨테이너 및 텍스트에어리어의 최소 너비를 385px에서 300px로 축소
frontend/src/pages/ApplicationFormPage/ApplicationFormPage.styles.ts FormTitle 스타일 조정, FormDescription 컴포넌트 신설, QuestionsWrapper 간격 및 반응형 스타일 개선
frontend/src/pages/ApplicationFormPage/ApplicationFormPage.tsx ClubProfile 임시 비활성화, 설명 파싱 및 렌더링 추가, 검증/스크롤/에러 처리 리팩토링
frontend/src/pages/ApplicationFormPage/components/QuestionContainer/QuestionContainer.tsx 컨테이너 패딩을 24px에서 상하 26px, 좌우 15px로 변경
frontend/src/hooks/useValidateAnswers.ts 필수 질문 미응답 검증 훅(validateAnswers) 신설
frontend/src/utils/parseDescriptionWithLinks.tsx 텍스트 내 URL을 자동 링크로 변환하는 유틸리티(parseDescriptionWithLinks) 신설

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ApplicationFormPage
    participant parseDescriptionWithLinks
    participant validateAnswers

    User->>ApplicationFormPage: 페이지 진입
    ApplicationFormPage->>parseDescriptionWithLinks: 설명 텍스트 전달
    parseDescriptionWithLinks-->>ApplicationFormPage: 링크 포함된 React 노드 반환
    User->>ApplicationFormPage: 지원서 제출 클릭
    ApplicationFormPage->>validateAnswers: 질문 및 답변 전달
    validateAnswers-->>ApplicationFormPage: 미응답 필수 질문 ID 배열 반환
    ApplicationFormPage-->>User: 미응답 질문 위치로 스크롤 또는 제출 진행
Loading

Estimated code review effort

  • frontend/src/components/common/CustomTextArea/CustomTextArea.styles.ts, frontend/src/components/common/InputField/InputField.styles.ts: 1 (20 minutes)
  • frontend/src/pages/ApplicationFormPage/ApplicationFormPage.styles.ts: 2 (45 minutes)
  • frontend/src/pages/ApplicationFormPage/ApplicationFormPage.tsx: 4 (240 minutes)
  • frontend/src/pages/ApplicationFormPage/components/QuestionContainer/QuestionContainer.tsx: 1 (15 minutes)
  • frontend/src/hooks/useValidateAnswers.ts: 2 (40 minutes)
  • frontend/src/utils/parseDescriptionWithLinks.tsx: 1 (20 minutes)

Possibly related PRs

Suggested labels

🔨 Refactor

Suggested reviewers

  • seongwon030
    """

📜 Recent review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between e5a3b23 and df44620.

📒 Files selected for processing (1)
  • frontend/src/utils/parseDescriptionWithLinks.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/utils/parseDescriptionWithLinks.tsx
✨ 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 Jul 20, 2025

Deploy Preview for moadong ready!

Name Link
🔨 Latest commit df44620
🔍 Latest deploy log https://app.netlify.com/projects/moadong/deploys/687dce47dfc97a0008483dc2
😎 Deploy Preview https://deploy-preview-564--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: 36
Accessibility: 89
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 enhances the club application form page by adding description display functionality and refactoring the component for better maintainability. The changes focus on improving user experience through better content presentation and code organization.

  • Added application form description rendering with HTML link parsing support
  • Extracted validation logic into a reusable custom hook for better separation of concerns
  • Updated styling for improved mobile responsiveness and visual balance

Reviewed Changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
frontend/src/utils/parseDescriptionWithLinks.tsx New utility function to parse URLs in text and convert them to React link components
frontend/src/hooks/useValidateAnswers.ts Extracted answer validation logic into a reusable custom hook
frontend/src/pages/ApplicationFormPage/ApplicationFormPage.tsx Main component refactoring with description display and validation hook integration
frontend/src/pages/ApplicationFormPage/ApplicationFormPage.styles.ts Updated styling for form title, description, and responsive design improvements
frontend/src/pages/ApplicationFormPage/components/QuestionContainer/QuestionContainer.tsx Minor padding adjustment for question containers
frontend/src/components/common/InputField/InputField.styles.ts Reduced minimum width for better mobile compatibility
frontend/src/components/common/CustomTextArea/CustomTextArea.styles.ts Reduced minimum width for better mobile compatibility
Comments suppressed due to low confidence (1)

frontend/src/utils/parseDescriptionWithLinks.tsx:3

  • The function name 'parseDescriptionWithLinks' doesn't match the actual functionality. The function parses URLs in any text, not specifically HTML with links. Consider renaming to 'parseTextWithUrls' or 'convertUrlsToLinks' for clarity.
export const parseDescriptionWithLinks = (text: string): React.ReactNode => {

import { Fragment } from 'react';

export const parseDescriptionWithLinks = (text: string): React.ReactNode => {
const urlRegex = /(https?:\/\/[^\s]+)/g;
Copy link

Copilot AI Jul 20, 2025

Choose a reason for hiding this comment

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

The URL regex pattern is too simplistic and may not handle edge cases properly. It doesn't account for URLs ending with punctuation or parentheses that shouldn't be part of the link. Consider using a more robust URL detection pattern or a dedicated library.

Copilot uses AI. Check for mistakes.
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: 7

🔭 Outside diff range comments (1)
frontend/src/pages/ApplicationFormPage/ApplicationFormPage.tsx (1)

39-39: 중복된 early return 로직을 제거하세요.

clubId 체크와 로딩 상태 체크가 중복되어 있습니다 (라인 39, 81-82). 코드 중복을 제거하고 일관성을 개선하세요.

   const { onAnswerChange: rawOnAnswerChange, getAnswersById, answers } = useAnswers();
   const {
       data: clubDetail,
       error: clubError,
   } = useGetClubDetail(clubId ?? '');

   const {
       data: formData,
       isLoading,
       isError,
       error: applicationError,
   } = useGetApplication(clubId ?? '');

-  if (!clubId) return null;
-  if (isLoading) return <Spinner />;
+  // 모든 early return 조건을 함께 처리
+  if (!clubId) return null;
+  if (isLoading) return <Spinner />;
+  if (isError || clubError) {
+      alert(applicationError?.message || '문제가 발생했어요.');
+      navigate(`/club/${clubId}`);
+      return <div>문제가 발생했어요. 잠시 후 다시 시도해 주세요.</div>;
+  }
+  if (!formData || !clubDetail) {
+      return <div>지원서 정보를 불러오지 못했어요. 새로고침하거나 잠시 후 다시 시도해 주세요.</div>;
+  }

Also applies to: 81-90

🧹 Nitpick comments (8)
frontend/src/utils/parseDescriptionWithLinks.tsx (1)

4-4: 정규식 패턴을 상수로 추출하여 성능을 개선하세요.

매번 함수 호출 시마다 새로운 정규식 인스턴스를 생성하는 대신, 상수로 정의하여 재사용하는 것이 좋습니다.

+const URL_REGEX = /(https?:\/\/[^\s]+)/g;
+
 export const parseDescriptionWithLinks = (text: string): React.ReactNode => {
-    const urlRegex = /(https?:\/\/[^\s]+)/g;
+    return text.split(URL_REGEX).map((part, index) => {
frontend/src/components/common/CustomTextArea/CustomTextArea.styles.ts (1)

3-3: TODO 주석에 대한 지원을 제공할 수 있습니다.

InputField 컴포넌트와의 중복 제거를 위한 리팩토링이 계획되어 있습니다. 공통 스타일을 추출하여 재사용 가능한 구조로 개선할 수 있습니다.

공통 스타일을 추출하는 리팩토링 솔루션을 생성하거나 이를 추적하기 위한 새로운 이슈를 열어드릴까요?

frontend/src/hooks/useValidateAnswers.ts (2)

3-14: 함수명이 훅 컨벤션과 일치하지 않습니다.

파일명은 useValidateAnswers.ts이지만 실제 함수는 validateAnswers입니다. React 훅 컨벤션에 따라 use로 시작하거나, 순수 함수라면 파일명을 변경하는 것이 좋습니다.

옵션 1: 훅으로 만들기

-export const validateAnswers = (
-    questions: Question[],
-    getAnswersById: (id: number) => string[]
-): number[] => {
+export const useValidateAnswers = () => {
+    return (questions: Question[], getAnswersById: (id: number) => string[]): number[] => {

옵션 2: 파일명 변경
파일명을 validateAnswers.ts 또는 validation.ts로 변경하여 순수 함수임을 명확히 표현


3-6: 입력 매개변수 검증을 추가하세요.

함수의 견고성을 위해 입력 매개변수에 대한 기본적인 검증을 추가하는 것이 좋습니다.

 export const validateAnswers = (
     questions: Question[],
     getAnswersById: (id: number) => string[]
 ): number[] => {
+    if (!questions || !Array.isArray(questions)) {
+        return [];
+    }
+    if (typeof getAnswersById !== 'function') {
+        throw new Error('getAnswersById must be a function');
+    }
+    
     return questions
frontend/src/pages/ApplicationFormPage/ApplicationFormPage.styles.ts (3)

5-11: 매직 넘버를 명명된 상수로 교체하세요.

코딩 가이드라인에 따라 매직 넘버들을 명명된 상수로 교체하는 것을 고려해보세요:

  • 2.2rem (폰트 크기)
  • 30px (마진)
  • 15px (패딩)
+const FORM_TITLE_FONT_SIZE = '2.2rem';
+const FORM_TITLE_MARGIN = '30px';
+const FORM_HORIZONTAL_PADDING = '15px';

export const FormTitle = styled.h1`
-  font-size: 2.2rem;
+  font-size: ${FORM_TITLE_FONT_SIZE};
   font-weight: 700;
   border: none;
   outline: none;
-  margin-top: 30px;
-  margin-bottom: 30px;
-  padding: 0 15px;
+  margin-top: ${FORM_TITLE_MARGIN};
+  margin-bottom: ${FORM_TITLE_MARGIN};
+  padding: 0 ${FORM_HORIZONTAL_PADDING};
`;

14-27: FormDescription 컴포넌트의 구조와 반응형 디자인이 우수합니다.

새로운 FormDescription 컴포넌트가 잘 구현되었습니다:

  • white-space: pre-line으로 줄바꿈 처리
  • 적절한 타이포그래피 설정
  • 모바일 반응형 대응

다만, 일관성을 위해 몇 가지 매직 넘버를 상수로 추출하는 것을 고려해보세요:

  • #444 색상 값
  • -20px, 48px 등의 간격 값

33-37: 반응형 디자인 개선과 미디어 쿼리 헬퍼 사용이 적절합니다.

media.mobile 헬퍼를 사용한 반응형 디자인 접근 방식이 좋습니다. gap 값 조정도 적절해 보입니다 (20px → 10px).

매직 넘버 개선을 위해 간격 값들을 상수로 추출하는 것을 고려해보세요:

+const QUESTIONS_GAP = '20px';
+const QUESTIONS_GAP_MOBILE = '10px';

export const QuestionsWrapper = styled.div`
   display: flex;
   flex-direction: column;
-  gap: 20px;
+  gap: ${QUESTIONS_GAP};

   ${media.mobile} {
-    gap: 10px;
+    gap: ${QUESTIONS_GAP_MOBILE};
   }
`;
frontend/src/pages/ApplicationFormPage/ApplicationFormPage.tsx (1)

74-74: Non-null assertion 사용에 주의하세요.

clubId!에서 non-null assertion을 사용하고 있지만, 이미 위에서 clubId 체크를 했으므로 안전합니다. 하지만 더 명시적인 검증을 고려해보세요.

-  await applyToClub(clubId!, answers);
+  if (!clubId) return; // 추가 안전 장치
+  await applyToClub(clubId, answers);
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between e895a73 and e5a3b23.

📒 Files selected for processing (7)
  • frontend/src/components/common/CustomTextArea/CustomTextArea.styles.ts (2 hunks)
  • frontend/src/components/common/InputField/InputField.styles.ts (1 hunks)
  • frontend/src/hooks/useValidateAnswers.ts (1 hunks)
  • frontend/src/pages/ApplicationFormPage/ApplicationFormPage.styles.ts (1 hunks)
  • frontend/src/pages/ApplicationFormPage/ApplicationFormPage.tsx (2 hunks)
  • frontend/src/pages/ApplicationFormPage/components/QuestionContainer/QuestionContainer.tsx (1 hunks)
  • frontend/src/utils/parseDescriptionWithLinks.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
frontend/**/*.{ts,tsx}

Instructions used from:

Sources:
📄 CodeRabbit Inference Engine

  • frontend/.cursorrules
frontend/**/*.tsx

Instructions used from:

Sources:
📄 CodeRabbit Inference Engine

  • frontend/.cursorrules
🧠 Learnings (6)
📓 Common learnings
Learnt from: seongwon030
PR: Moadong/moadong#195
File: frontend/src/pages/AdminPage/AdminPage.tsx:7-7
Timestamp: 2025-03-19T05:18:07.818Z
Learning: AdminPage.tsx에서 현재 하드코딩된 클럽 ID('67d2e3b9b15c136c6acbf20b')는 로그인 기능 구현 후 동적으로 가져오는 방식으로 수정될 예정입니다.
frontend/src/components/common/InputField/InputField.styles.ts (3)
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.682Z
Learning: Applies to frontend/**/*.{ts,tsx} : Replace magic numbers with named constants for clarity.
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.682Z
Learning: Applies to frontend/**/*.tsx : Choose field-level or form-level cohesion based on form requirements.
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.682Z
Learning: Applies to frontend/**/*.tsx : Separate significantly different conditional UI/logic into distinct components.
frontend/src/pages/ApplicationFormPage/components/QuestionContainer/QuestionContainer.tsx (1)
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.682Z
Learning: Applies to frontend/**/*.{ts,tsx} : Replace magic numbers with named constants for clarity.
frontend/src/components/common/CustomTextArea/CustomTextArea.styles.ts (4)
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.682Z
Learning: Applies to frontend/**/*.{ts,tsx} : Replace magic numbers with named constants for clarity.
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.682Z
Learning: Applies to frontend/**/*.{ts,tsx} : Define constants near related logic or ensure names link them clearly.
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.682Z
Learning: Applies to frontend/**/*.{ts,tsx} : Use unique, descriptive names for custom wrappers and functions to avoid ambiguity.
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.682Z
Learning: Applies to frontend/**/*.tsx : Separate significantly different conditional UI/logic into distinct components.
frontend/src/pages/ApplicationFormPage/ApplicationFormPage.styles.ts (4)
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.682Z
Learning: Applies to frontend/**/*.tsx : Choose field-level or form-level cohesion based on form requirements.
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.682Z
Learning: Applies to frontend/**/*.{ts,tsx} : Replace magic numbers with named constants for clarity.
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.682Z
Learning: Applies to frontend/**/*.tsx : Separate significantly different conditional UI/logic into distinct components.
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.682Z
Learning: Applies to frontend/**/*.{ts,tsx} : Define constants near related logic or ensure names link them clearly.
frontend/src/pages/ApplicationFormPage/ApplicationFormPage.tsx (5)
Learnt from: lepitaaar
PR: Moadong/moadong#406
File: backend/src/main/java/moadong/club/service/ClubApplyService.java:34-38
Timestamp: 2025-05-19T05:45:52.957Z
Learning: The code duplication between createClubApplication and editClubApplication methods in ClubApplyService.java is acknowledged but will be addressed in a future refactoring, as per the developer's plan.
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.682Z
Learning: Applies to frontend/**/*.tsx : Choose field-level or form-level cohesion based on form requirements.
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.682Z
Learning: Applies to frontend/**/*.tsx : Separate significantly different conditional UI/logic into distinct components.
Learnt from: seongwon030
PR: Moadong/moadong#195
File: frontend/src/pages/AdminPage/AdminPage.tsx:7-7
Timestamp: 2025-03-19T05:18:07.818Z
Learning: AdminPage.tsx에서 현재 하드코딩된 클럽 ID('67d2e3b9b15c136c6acbf20b')는 로그인 기능 구현 후 동적으로 가져오는 방식으로 수정될 예정입니다.
Learnt from: CR
PR: Moadong/moadong#0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.682Z
Learning: Applies to frontend/**/*.tsx : Abstract complex logic/interactions into dedicated components or higher-order components (HOCs).
🧬 Code Graph Analysis (2)
frontend/src/pages/ApplicationFormPage/ApplicationFormPage.styles.ts (1)
frontend/src/styles/mediaQuery.ts (1)
  • media (6-9)
frontend/src/pages/ApplicationFormPage/ApplicationFormPage.tsx (3)
frontend/src/hooks/useValidateAnswers.ts (1)
  • validateAnswers (3-14)
frontend/src/apis/application/applyToClub.ts (1)
  • applyToClub (4-34)
frontend/src/utils/parseDescriptionWithLinks.tsx (1)
  • parseDescriptionWithLinks (3-22)
🔇 Additional comments (5)
frontend/src/hooks/useValidateAnswers.ts (1)

7-13: 검증 로직이 올바르게 구현되었습니다.

필수 질문 필터링과 빈 답변 검증 로직이 정확하고 효율적으로 구현되어 있습니다. 체이닝된 필터와 맵 연산이 적절히 사용되었습니다.

frontend/src/pages/ApplicationFormPage/ApplicationFormPage.tsx (4)

55-59: 헬퍼 함수 추출이 코드 가독성을 개선했습니다.

handleScrollToInvalid 함수로 스크롤 로직을 분리한 것이 좋습니다. 단일 책임 원칙을 잘 따르고 있습니다.


65-65: validateAnswers 훅 사용으로 검증 로직이 잘 분리되었습니다.

검증 로직을 별도 훅으로 추출한 것이 코드 재사용성과 테스트 가능성을 개선했습니다. 관심사 분리 원칙을 잘 따르고 있습니다.


104-109: 설명 렌더링 기능이 잘 구현되었습니다.

조건부 렌더링과 parseDescriptionWithLinks 유틸리티 함수 사용이 적절합니다. HTML 링크를 안전하게 파싱하여 렌더링하는 접근 방식이 좋습니다.


6-6: ClubProfile 컴포넌트 사용 확인 요청

ApplicationFormPage.tsx에서 ClubProfile import 및 사용 부분이 주석 처리되어 있습니다.
다른 파일(ClubDetailPage/components/ClubProfile/ClubProfile.tsx)과 ClubDetailHeader.tsx에서는 정상적으로 컴포넌트가 존재하고 사용 중인 것으로 확인되었습니다.

– 확인 대상
• frontend/src/pages/ApplicationFormPage/ApplicationFormPage.tsx
– import 부분: 라인 6
– JSX 사용 부분: 라인 96–102

해당 주석 처리된 부분이 의도된 임시 조치인지 알려주세요.

Copy link
Member

@seongwon030 seongwon030 left a comment

Choose a reason for hiding this comment

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

고생하셨습니다~ descriptionLink는 소개글 안의 url을 의미하나요?

Copy link
Member

@Zepelown Zepelown left a comment

Choose a reason for hiding this comment

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

검증 로직도 있고 좋네요.
고생하셨습니다.

@oesnuj
Copy link
Member Author

oesnuj commented Jul 21, 2025

고생하셨습니다~ descriptionLink는 소개글 안의 url을 의미하나요?

어.. descriptionLink라는 변수나 컴포넌트는 없는데, 혹시 parseDescriptionWithLinks에 대해 말씀하신 걸까요?

@seongwon030
Copy link
Member

고생하셨습니다~ descriptionLink는 소개글 안의 url을 의미하나요?

어.. descriptionLink라는 변수나 컴포넌트는 없는데, 혹시 parseDescriptionWithLinks에 대해 말씀하신 걸까요?

@oesnuj
Copy link
Member Author

oesnuj commented Jul 21, 2025

고생하셨습니다~ descriptionLink는 소개글 안의 url을 의미하나요?

어.. descriptionLink라는 변수나 컴포넌트는 없는데, 혹시 parseDescriptionWithLinks에 대해 말씀하신 걸까요?

아하
해당 유틸은 소개글 문자열에서 URL만 추출해 로 감싸고, 조각난 JSX 배열로 반환해주는 역할을 합니다.
설명에 URL이 포함되면 자동으로 하이퍼링크로 렌더링됩니다 ㅎㅎ

const desc = "자세한 내용은 https://example.com 참고해주세요!";
parseDescriptionWithLinks(desc);
[
  <Fragment key={0}>자세한 내용은 </Fragment>,
  <a key={1} href="https://example.com" ...>https://example.com</a>,
  <Fragment key={2}> 참고해주세요!</Fragment>
]

결과적으로 위와 같은 JSX 배열이 리턴됩니다!

@oesnuj
Copy link
Member Author

oesnuj commented Jul 21, 2025

고생하셨습니다~ descriptionLink는 소개글 안의 url을 의미하나요?

어.. descriptionLink라는 변수나 컴포넌트는 없는데, 혹시 parseDescriptionWithLinks에 대해 말씀하신 걸까요?

아하 해당 유틸은 소개글 문자열에서 URL만 추출해 로 감싸고, 조각난 JSX 배열로 반환해주는 역할을 합니다. 설명에 URL이 포함되면 자동으로 하이퍼링크로 렌더링됩니다 ㅎㅎ

const desc = "자세한 내용은 https://example.com 참고해주세요!";
parseDescriptionWithLinks(desc);
[
  <Fragment key={0}>자세한 내용은 </Fragment>,
  <a key={1} href="https://example.com" ...>https://example.com</a>,
  <Fragment key={2}> 참고해주세요!</Fragment>
]

결과적으로 위와 같은 JSX 배열이 리턴됩니다!

@seongwon030
참고로 <Fragment>를 사용하는 이유도 남기자면 문자열 배열만 반환하면 key를 붙일 수 없어서 렌더링 시 경고가 뜨더라고요.
<Fragment>로 감싸면 key를 부여할 수 있고, <span>이나 <p>로 감쌀 수도 있지만 그렇게 DOM 요소가 우르르 생기더라구요
그래서 DOM에 영향을 주지 않으면서도 렌더링할 수 있는 <Fragment>를 사용했습니다!

Copy link
Contributor

@lepitaaar lepitaaar left a comment

Choose a reason for hiding this comment

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

너무 잘해주셨습니다 감사합니다

@oesnuj oesnuj merged commit 44a0728 into develop-fe Jul 21, 2025
7 checks passed
@oesnuj oesnuj deleted the feature/#561-application-form-description-MOA-101 branch July 28, 2025 06:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

💻 FE Frontend ✨ Feature 기능 개발

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

Comments