Skip to content

[기능] 공고 북마크 추가 #43

Open
Cori1304-Seong wants to merge 6 commits intodevelopfrom
feat/#42-recruitment-bookmark
Open

[기능] 공고 북마크 추가 #43
Cori1304-Seong wants to merge 6 commits intodevelopfrom
feat/#42-recruitment-bookmark

Conversation

@Cori1304-Seong
Copy link
Contributor

@Cori1304-Seong Cori1304-Seong commented Aug 7, 2025

🚀 주요 변경 사항

공고 북마크 추가

  • 주요 기능

🚨 리뷰어에게

📸 스크린샷 (선택 사항)

스크린샷 2025-08-08 오전 2 11 26 스크린샷 2025-08-08 오전 2 11 22

Summary by CodeRabbit

  • 신규 기능

    • 채용 공고에 북마크(즐겨찾기) 기능이 추가되었습니다. 이제 채용 공고를 북마크로 저장하거나 해제할 수 있습니다.
    • 채용 목록에서 북마크된 공고만 필터링하여 볼 수 있는 기능이 추가되었습니다.
    • 각 채용 공고 항목과 상세 보기에서 북마크 버튼이 제공되며, 북마크 상태에 따라 아이콘이 변경됩니다.
  • 스타일

    • 북마크 버튼 및 관련 UI 요소의 스타일이 추가 및 개선되었습니다.
  • 버그 수정

    • 채용 공고 중복 표시가 방지되고, 데이터 로딩 및 상태 관리가 개선되었습니다.

@Cori1304-Seong Cori1304-Seong self-assigned this Aug 7, 2025
@Cori1304-Seong Cori1304-Seong added the 기능 개발 기능을 처음으로 구현합니다. label Aug 7, 2025
@coderabbitai
Copy link

coderabbitai bot commented Aug 7, 2025

Walkthrough

이 변경사항은 채용 공고 즐겨찾기(북마크) 기능을 전반적으로 도입하는 것으로, API 서비스 모듈과 글로벌 컨텍스트, 여러 컴포넌트 및 스타일 파일에 걸쳐 북마크 관련 로직과 UI, 상태 관리가 추가되었습니다. 채용 리스트, 상세, 아이템 컴포넌트 모두 북마크 기능과 연동되며, 페이지 단에서는 필터링, 데이터 중복 제거, 네비게이션 개선 등이 포함되었습니다.

Changes

Cohort / File(s) Change Summary
Bookmark API Service
src/api/recruitmentBookmarkService.js
신규 모듈로 북마크 추가/삭제/조회 API 함수 3종(addRecruitmentBookmark, removeRecruitmentBookmark, getUserRecruitmentBookmarks)을 구현. 에러 로깅 및 예외 처리 포함.
Bookmark Context 및 Provider
src/contexts/BookmarkContext.jsx
북마크 상태와 로딩, 토글, 추가/삭제, 새로고침 기능을 제공하는 글로벌 컨텍스트 및 커스텀 훅(useBookmark) 추가. 마운트 시 북마크 목록 조회, 에러 로깅, 상태 관리 구현.
RecruitmentList 및 북마크 필터링
src/components/recruitment/recruitment_map/RecruitmentList.jsx
북마크만 보기 토글, 북마크 필터 버튼, 필터링된 리스트 및 상태 메시지 처리, onFilteredJobsChange 콜백 prop 추가. 각 아이템에 북마크 상태 전달.
RecruitmentItem 북마크 UI 및 prop 추가
src/components/recruitment/recruitment_map/RecruitmentItem.jsx
isBookmarked prop 추가, 북마크 버튼 및 아이콘, 토글 핸들러, 북마크 상태에 따른 UI 분기, 제목/로고 레이아웃 변경.
RecruitmentDetail 북마크 UI 및 핸들러
src/components/recruitment/recruitment_map/RecruitmentDetail.jsx
북마크 버튼 및 아이콘, 북마크 상태 확인 및 토글 핸들러, 버튼 로딩 상태 처리, 접근성 라벨 분기, 버튼 레이아웃 그룹화.
RecruitmentMapPage 북마크 연동 및 데이터 관리
src/pages/recruitment/RecruitmentMap.jsx
BookmarkProvider로 전체 트리 감싸기, 북마크 필터/상태 반영, 데이터 중복 제거, 리스트/맵 연동, 네비게이션 개선, API 응답 구조 통일, 북마크 모드 시 페이지네이션 제한 등 복합적 로직 추가.
RecruitmentList 스타일: 필터 버튼
src/components/recruitment/recruitment_map/RecruitmentList.module.scss
북마크 필터 버튼 및 컨테이너 스타일 신규 추가, hover/active/아이콘 스타일 정의.
RecruitmentItem 스타일: 북마크/로고/타이틀
src/components/recruitment/recruitment_map/RecruitmentItem.module.scss
북마크 버튼/아이콘, 타이틀-북마크 래퍼, 소스로고 크기 및 정렬 등 레이아웃 및 인터랙션 스타일 추가.
RecruitmentDetail 스타일: 헤더 버튼
src/components/recruitment/recruitment_map/RecruitmentDetail.module.scss
헤더 버튼(북마크/닫기) 컨테이너, 북마크 버튼/아이콘, 비활성화 상태 등 스타일 신규 정의.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant RecruitmentList
    participant RecruitmentItem
    participant BookmarkContext
    participant BookmarkAPI

    User->>RecruitmentList: 북마크 필터 버튼 클릭
    RecruitmentList->>BookmarkContext: 북마크 상태 확인
    RecruitmentList->>RecruitmentItem: isBookmarked prop 전달

    User->>RecruitmentItem: 북마크 버튼 클릭
    RecruitmentItem->>BookmarkContext: toggleBookmark(jobId)
    BookmarkContext->>BookmarkAPI: add/removeRecruitmentBookmark(jobId)
    BookmarkAPI-->>BookmarkContext: 성공/실패 응답
    BookmarkContext-->>RecruitmentItem: 상태 업데이트
    RecruitmentItem-->>User: 북마크 아이콘/상태 반영

    User->>RecruitmentDetail: 북마크 버튼 클릭
    RecruitmentDetail->>BookmarkContext: toggleBookmark(jobId)
    BookmarkContext->>BookmarkAPI: add/removeRecruitmentBookmark(jobId)
    BookmarkAPI-->>BookmarkContext: 성공/실패 응답
    BookmarkContext-->>RecruitmentDetail: 상태 업데이트
    RecruitmentDetail-->>User: 북마크 아이콘/상태 반영
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40분

Suggested reviewers

  • jam9582
  • hueyjeong

Poem

🐰
즐겨찾기 별을 달아
채용 공고 반짝반짝
리스트도, 상세도,
북마크로 쏙쏙!
버튼 누르면 노란빛
토글하며 춤추네
개발자 토끼, 기분 최고!
⭐️✨

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/#42-recruitment-bookmark

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.
  • 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.

Support

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

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 generate unit tests to generate unit tests for 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.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • 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

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.

Copy link

@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: 5

🧹 Nitpick comments (1)
src/contexts/BookmarkContext.jsx (1)

8-18: 북마크 컨텍스트 구조가 잘 설계되었습니다.

Set 자료구조를 사용한 효율적인 ID 관리와 적절한 상태 초기화가 구현되어 있습니다. 다만 디버그용 console.log는 제거해야 합니다.

다음 수정사항을 적용해주세요:

   useEffect(() => {
     loadBookmarks();
-    console.log("bookmarkedJobs",bookmarkedJobs);
   }, []);
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 02c06ff and e4d0288.

📒 Files selected for processing (9)
  • src/api/recruitmentBookmarkService.js (1 hunks)
  • src/components/recruitment/recruitment_map/RecruitmentDetail.jsx (3 hunks)
  • src/components/recruitment/recruitment_map/RecruitmentDetail.module.scss (1 hunks)
  • src/components/recruitment/recruitment_map/RecruitmentItem.jsx (3 hunks)
  • src/components/recruitment/recruitment_map/RecruitmentItem.module.scss (2 hunks)
  • src/components/recruitment/recruitment_map/RecruitmentList.jsx (2 hunks)
  • src/components/recruitment/recruitment_map/RecruitmentList.module.scss (1 hunks)
  • src/contexts/BookmarkContext.jsx (1 hunks)
  • src/pages/recruitment/RecruitmentMap.jsx (11 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (6)
src/contexts/BookmarkContext.jsx (2)
src/api/recruitmentBookmarkService.js (3)
  • getUserRecruitmentBookmarks (35-46)
  • addRecruitmentBookmark (8-15)
  • removeRecruitmentBookmark (21-28)
src/components/recruitment/recruitment_map/RecruitmentList.jsx (1)
  • useBookmark (10-10)
src/components/recruitment/recruitment_map/RecruitmentList.jsx (3)
src/contexts/BookmarkContext.jsx (3)
  • useBookmark (100-106)
  • checkIsBookmarked (36-39)
  • isLoading (12-12)
src/components/recruitment/recruitment_map/RecruitmentItem.jsx (1)
  • useBookmark (10-10)
src/pages/recruitment/RecruitmentMap.jsx (3)
  • showOnlyBookmarked (46-46)
  • selectedJob (31-31)
  • isLastPage (50-50)
src/components/recruitment/recruitment_map/RecruitmentDetail.jsx (3)
src/contexts/BookmarkContext.jsx (3)
  • useBookmark (100-106)
  • toggleBookmark (74-80)
  • checkIsBookmarked (36-39)
src/components/recruitment/recruitment_map/RecruitmentList.jsx (1)
  • useBookmark (10-10)
src/components/recruitment/recruitment_map/RecruitmentItem.jsx (2)
  • useBookmark (10-10)
  • handleToggleBookmark (13-19)
src/api/recruitmentBookmarkService.js (1)
src/api/axiosInstance.js (1)
  • api (4-7)
src/components/recruitment/recruitment_map/RecruitmentItem.jsx (3)
src/components/recruitment/recruitment_map/RecruitmentList.jsx (1)
  • useBookmark (10-10)
src/components/recruitment/recruitment_map/RecruitmentDetail.jsx (1)
  • handleToggleBookmark (54-60)
src/contexts/BookmarkContext.jsx (1)
  • toggleBookmark (74-80)
src/pages/recruitment/RecruitmentMap.jsx (5)
src/components/recruitment/recruitment_map/RecruitmentList.jsx (1)
  • showOnlyBookmarked (11-11)
src/components/recruitment/recruitment_map/RecruitmentDetail.jsx (3)
  • loading (13-13)
  • error (14-14)
  • filterDataLoading (16-16)
src/components/recruitment/recruitment_map/MapContainer.jsx (1)
  • loading (23-26)
src/api/recruitmentService.js (6)
  • isLastPage (116-116)
  • params (22-22)
  • validateAndBuildParams (11-100)
  • validateAndBuildParams (11-100)
  • getRecruitments (102-129)
  • getRecruitments (102-129)
src/contexts/BookmarkContext.jsx (1)
  • BookmarkProvider (8-97)
🔇 Additional comments (17)
src/api/recruitmentBookmarkService.js (2)

8-15: 깔끔한 API 함수 구현입니다.

POST 요청과 에러 핸들링이 잘 구현되어 있습니다.


21-28: 삭제 함수도 적절하게 구현되었습니다.

DELETE 요청과 에러 핸들링 패턴이 일관적입니다.

src/components/recruitment/recruitment_map/RecruitmentList.module.scss (1)

8-41: 필터 버튼 스타일이 잘 구현되었습니다.

flexbox 레이아웃, hover 효과, active 상태 스타일링이 적절하게 구현되어 있고, 기존 스타일과 일관된 색상 테마를 사용하고 있습니다.

src/components/recruitment/recruitment_map/RecruitmentDetail.module.scss (1)

14-53: 헤더 버튼 레이아웃과 북마크 버튼 스타일이 잘 구현되었습니다.

flexbox를 이용한 버튼 배치, hover 효과, disabled 상태 처리가 적절하게 구현되어 있습니다. 북마크 아이콘의 노란색 색상 선택도 시각적으로 구분하기 좋습니다.

src/components/recruitment/recruitment_map/RecruitmentItem.module.scss (2)

21-58: 아이템 레이아웃 업데이트가 잘 구현되었습니다.

제목과 북마크 버튼을 위한 새로운 레이아웃 구조가 적절하게 구현되었고, 북마크 버튼 스타일이 다른 컴포넌트와 일관성을 유지하고 있습니다.


67-78: 소스 로고 레이아웃 조정이 적절합니다.

전체 너비 사용과 오른쪽 정렬, 로고 크기 축소가 새로운 레이아웃 구조에 잘 맞습니다.

src/contexts/BookmarkContext.jsx (5)

21-33: 북마크 로드 함수가 잘 구현되었습니다.

API 호출과 에러 핸들링, Set 자료구조로의 변환이 적절하게 구현되어 있습니다.


35-39: 북마크 확인 함수가 효율적으로 구현되었습니다.

null/undefined 체크와 Set의 O(1) 조회를 활용한 효율적인 구현입니다.


42-71: 북마크 추가/삭제 함수들이 잘 구현되었습니다.

API 호출, 상태 업데이트, 에러 핸들링이 일관되게 구현되어 있고, 불변성을 지키며 새로운 Set을 생성하는 방식이 적절합니다.


74-80: 토글 함수가 간결하게 구현되었습니다.

기존 상태를 확인하여 적절한 함수를 호출하는 로직이 명확합니다.


100-106: 커스텀 훅이 적절하게 구현되었습니다.

컨텍스트 사용 검증과 에러 처리가 잘 구현되어 있습니다.

src/pages/recruitment/RecruitmentMap.jsx (2)

174-186: 효과적인 중복 제거 구현

Map을 사용한 ID 기반 중복 제거 로직이 잘 구현되었습니다.


369-384: 좌표 검증 로직 우수

한국 좌표 범위 검증 및 좌표 스왑 감지 로직이 잘 구현되었습니다. 잘못된 좌표 데이터를 효과적으로 처리합니다.

src/components/recruitment/recruitment_map/RecruitmentDetail.jsx (4)

5-7: 북마크 기능을 위한 import가 적절히 추가되었습니다.

useBookmark 훅과 북마크 아이콘들이 올바르게 import되어 북마크 기능 구현에 필요한 의존성이 잘 설정되었습니다.


15-15: 북마크 컨텍스트 연동이 올바르게 구현되었습니다.

useBookmark 훅에서 필요한 함수들과 상태를 적절히 destructuring하고 있으며, isLoading을 isBookmarkLoading으로 rename하여 기존 loading 상태와의 충돌을 방지한 것이 좋습니다.


53-60: 북마크 토글 핸들러가 잘 구현되었습니다.

이벤트 버블링 방지(e.stopPropagation())와 job ID 유효성 검사를 통해 안전한 북마크 토글 기능을 제공하고 있습니다. 다른 컴포넌트들과 일관성 있는 구현입니다.


190-202: 북마크 버튼 UI가 사용성과 접근성을 고려하여 잘 구현되었습니다.

다음과 같은 좋은 구현 요소들이 포함되어 있습니다:

  • 북마크 상태에 따른 아이콘 조건부 렌더링
  • 로딩 중 버튼 비활성화 처리
  • 접근성을 위한 aria-label 동적 설정
  • 헤더 버튼들의 일관성 있는 그룹화

Comment on lines +35 to +46
export async function getUserRecruitmentBookmarks() {


try {
const response = await api.get("/api/v1/recruitments/bookmarks");
console.log("response",response);
return response.data.data;
} catch (error) {
console.error("Error fetching recruitment filters:", error);
throw error;
}
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

코드 정리 및 일관성 개선이 필요합니다.

다음 사항들을 수정해주세요:

  1. 불필요한 빈 줄들 (36-37행)
  2. 디버그용 console.log 제거
  3. 에러 메시지가 다른 함수들과 일치하지 않음

다음과 같이 수정하는 것을 권장합니다:

 export async function getUserRecruitmentBookmarks() {
-
-
   try {
     const response = await api.get("/api/v1/recruitments/bookmarks");
-    console.log("response",response);
     return response.data.data;
   } catch (error) {
-    console.error("Error fetching recruitment filters:", error);
+    console.error('사용자 채용공고 즐겨찾기 조회 실패:', error);
     throw error;
   }
 }
📝 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 async function getUserRecruitmentBookmarks() {
try {
const response = await api.get("/api/v1/recruitments/bookmarks");
console.log("response",response);
return response.data.data;
} catch (error) {
console.error("Error fetching recruitment filters:", error);
throw error;
}
}
export async function getUserRecruitmentBookmarks() {
try {
const response = await api.get("/api/v1/recruitments/bookmarks");
return response.data.data;
} catch (error) {
console.error('사용자 채용공고 즐겨찾기 조회 실패:', error);
throw error;
}
}
🤖 Prompt for AI Agents
In src/api/recruitmentBookmarkService.js between lines 35 and 46, remove the
unnecessary blank lines at 36 and 37, delete the debug console.log statement
logging the response, and update the error message in the catch block to match
the format used in other functions for consistency.

Comment on lines +63 to +72
{job.recruitmentSourceId && (
<div className={styles.sourceLogoContainer}>
{job.recruitmentSourceId.includes('wanted') && (
<img src={wantedLogo} alt="Wanted" className={styles.sourceLogo} />
)}
{job.recruitmentSourceId.includes('jumpit') && (
<img src={jumpitLogo} alt="Jumpit" className={styles.sourceLogo} />
)}
</div>
)}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

잠재적인 null 참조 오류 방지 필요

recruitmentSourceId가 문자열이 아닐 경우 includes 메서드 호출 시 오류가 발생할 수 있습니다.

타입 체크를 추가하여 안전하게 처리하세요:

-      {job.recruitmentSourceId && (
+      {job.recruitmentSourceId && typeof job.recruitmentSourceId === 'string' && (
           <div className={styles.sourceLogoContainer}>
             {job.recruitmentSourceId.includes('wanted') && (
               <img src={wantedLogo} alt="Wanted" className={styles.sourceLogo} />
             )}
             {job.recruitmentSourceId.includes('jumpit') && (
               <img src={jumpitLogo} alt="Jumpit" className={styles.sourceLogo} />
             )}
           </div>
         )}
🤖 Prompt for AI Agents
In src/components/recruitment/recruitment_map/RecruitmentItem.jsx around lines
63 to 72, the code calls includes on job.recruitmentSourceId without confirming
it is a string, which may cause runtime errors if it is null or not a string.
Add a type check to ensure job.recruitmentSourceId is a string before calling
includes, for example by using typeof or a utility function, to safely handle
cases where recruitmentSourceId might be null or another type.

Comment on lines +56 to +68
const filteredJobs = showOnlyBookmarked
? jobs.filter(job => checkIsBookmarked(job.id))
: jobs;

// 북마크 필터 상태가 변경될 때만 상위 컴포넌트에 알림
useEffect(() => {
if (onFilteredJobsChange) {
const filtered = showOnlyBookmarked
? jobs.filter(job => checkIsBookmarked(job.id))
: jobs;
onFilteredJobsChange(filtered, showOnlyBookmarked);
}
}, [showOnlyBookmarked, jobs, checkIsBookmarked, onFilteredJobsChange]);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

중복된 필터링 로직 제거 및 성능 최적화 필요

필터링 로직이 중복되어 있고, 매 렌더링마다 불필요한 재계산이 발생할 수 있습니다.

useMemo를 사용하여 필터링 로직을 최적화하고 중복을 제거하세요:

+import React, { useState, useEffect, useRef, useCallback, useMemo } from "react";

-  // 필터링된 채용 공고 목록
-  const filteredJobs = showOnlyBookmarked
-    ? jobs.filter(job => checkIsBookmarked(job.id))
-    : jobs;
+  // 필터링된 채용 공고 목록 (메모이제이션)
+  const filteredJobs = useMemo(() => {
+    return showOnlyBookmarked
+      ? jobs.filter(job => checkIsBookmarked(job.id))
+      : jobs;
+  }, [showOnlyBookmarked, jobs, checkIsBookmarked]);
    
   // 북마크 필터 상태가 변경될 때만 상위 컴포넌트에 알림
   useEffect(() => {
     if (onFilteredJobsChange) {
-      const filtered = showOnlyBookmarked
-        ? jobs.filter(job => checkIsBookmarked(job.id))
-        : jobs;
-      onFilteredJobsChange(filtered, showOnlyBookmarked);
+      onFilteredJobsChange(filteredJobs, showOnlyBookmarked);
     }
-  }, [showOnlyBookmarked, jobs, checkIsBookmarked, onFilteredJobsChange]);
+  }, [filteredJobs, showOnlyBookmarked, onFilteredJobsChange]);
🤖 Prompt for AI Agents
In src/components/recruitment/recruitment_map/RecruitmentList.jsx around lines
56 to 68, the job filtering logic is duplicated and recalculated on every
render, causing unnecessary performance overhead. Refactor by using useMemo to
memoize the filteredJobs array based on showOnlyBookmarked, jobs, and
checkIsBookmarked dependencies. Then, use this memoized filteredJobs both for
rendering and inside the useEffect callback to avoid redundant filtering and
improve performance.

Comment on lines +71 to +75
const handleSelectJob = useCallback((job) => {
setSelectedJob(job);
};
setMapCenter({ lat: job.latitude, lng: job.longitude });
navigate(`/recruitment/map/${job.id}`);
}, []);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

useCallback 의존성 배열에 navigate 추가 필요

navigate 함수가 의존성 배열에 누락되어 있습니다.

   const handleSelectJob = useCallback((job) => {
     setSelectedJob(job);
     setMapCenter({ lat: job.latitude, lng: job.longitude });
     navigate(`/recruitment/map/${job.id}`);
-  }, []);
+  }, [navigate]);
📝 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 handleSelectJob = useCallback((job) => {
setSelectedJob(job);
};
setMapCenter({ lat: job.latitude, lng: job.longitude });
navigate(`/recruitment/map/${job.id}`);
}, []);
const handleSelectJob = useCallback((job) => {
setSelectedJob(job);
setMapCenter({ lat: job.latitude, lng: job.longitude });
navigate(`/recruitment/map/${job.id}`);
}, [navigate]);
🤖 Prompt for AI Agents
In src/pages/recruitment/RecruitmentMap.jsx around lines 71 to 75, the
useCallback hook for handleSelectJob is missing the navigate function in its
dependency array. Add navigate to the dependency array to ensure the callback
updates correctly when navigate changes.

Comment on lines +234 to +236
if (content.length > 0) {
setRecruitments(prev => [...prev, ...content]);
setPage(nextPage);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

추가 데이터 로드 시 중복 제거 로직 누락

fetchRecruitments와 달리 loadMoreRecruitments에서는 중복 제거 로직이 적용되지 않아 중복 데이터가 발생할 수 있습니다.

중복 제거 로직을 일관되게 적용하세요:

       if (content.length > 0) {
-        setRecruitments(prev => [...prev, ...content]);
+        setRecruitments(prev => {
+          const allItems = [...prev, ...content];
+          return Array.from(new Map(allItems.map(item => [item.id, item])).values());
+        });
         setPage(nextPage);
       }
📝 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
if (content.length > 0) {
setRecruitments(prev => [...prev, ...content]);
setPage(nextPage);
if (content.length > 0) {
setRecruitments(prev => {
const allItems = [...prev, ...content];
return Array.from(new Map(allItems.map(item => [item.id, item])).values());
});
setPage(nextPage);
}
🤖 Prompt for AI Agents
In src/pages/recruitment/RecruitmentMap.jsx around lines 234 to 236, the
loadMoreRecruitments function appends new recruitment data without removing
duplicates, unlike fetchRecruitments. To fix this, modify the setRecruitments
call to merge the existing and new content arrays while filtering out duplicate
entries based on a unique identifier, ensuring consistent deduplication when
loading more data.

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

Labels

기능 개발 기능을 처음으로 구현합니다.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments