Skip to content

Conversation

imddoy
Copy link
Contributor

@imddoy imddoy commented Mar 17, 2025

🤫 쉿, 나한테만 말해줘요. 이슈넘버

🧐 어떤 것을 변경했어요~?

  • state로 관리하던 query parmeter를 쿼리스트링을 사용하여 넘겨주는 형식으로 변경했습니다.

🤔 그렇다면, 어떻게 구현했어요~?

  • 기존의 useQueryParams를 사용해서 쿼리스트링을 붙였습니다.

❤️‍🔥 당신이 생각하는 PR포인트, 내겐 매력포인트.

📸 스크린샷, 없으면 이것 참,, 섭섭한데요?

imddoy added 3 commits March 13, 2025 18:28
- usePageQueryParams 사용
- 검색어 상태 2개에서 1개로 변경
- 선택된 값 쿼리스트링으로 가져오기
- request에 맞는 값으로 쿼리키 변경
Copy link

height bot commented Mar 17, 2025

Link Height tasks by mentioning a task ID in the pull request title or commit messages, or description and comments with the keyword link (e.g. "Link T-123").

💡Tip: You can also use "Close T-X" to automatically close a task when the pull request is merged.

Copy link

✨✨ 스토리북으로 확인하기 ✨✨

Copy link

🚀 프리뷰 배포 확인하기 🚀

https://4e923437.sopt-internal-dev.pages.dev

Copy link
Member

@seong-hui seong-hui left a comment

Choose a reason for hiding this comment

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

기존에 state로만 관리하던 필터들을 query params로 잘 수정해주시느라 고생 많으셨습니다!! 기존의 코드들을 이해하고 코드의 일부분을 수정하는게 쉬운 일이 아닌데 너무 잘 구현해 주신 것 같습니다! 남겨드린 코멘트만 확인 부탁드립니다👍

};
const { data, isLoading } = useGetMembersCoffeeChat(queryParams);

const formatQueryParams = (query: ParsedUrlQuery): { [key: string]: string } => {
Copy link
Member

Choose a reason for hiding this comment

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

현재 코드에서 normalizeCareer, normalizeSection...===('전체') return undefined; 등 값을 변환하는 로직이 반복적으로 적용이 되고 있어서 해당 로직을 합쳐서 처리한다면 중복 코드가 제거되고 가독성이 올라갈 수 있을 것 같아요!


if (typeof strValue !== 'string') return [key, undefined];

switch (key) {
Copy link
Member

Choose a reason for hiding this comment

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

현재는 각각 다르게 normalize를 진행하기 위해서 case를 나누었는데 모든 case에 적용할 수 있는 normalize로직으로 수정한다면 해당 부분도 아래와 같이 표현할 수 있을 것 같네요!

return Object.fromEntries(
      Object.entries(query)
        .map(([key, value]) => {
          const strValue = Array.isArray(value) ? value[0] : value;

          if (typeof strValue !== 'string') return [key, undefined];

          return [key, normalizeValue(key, strValue)];
        })
        .filter(([_, value]) => value !== undefined), // undefined 값 제거
    );

const formatQueryParams = (query: ParsedUrlQuery): { [key: string]: string } => {
const normalizeCareer = (career: string | undefined): string | undefined => {
if (!career || career === '전체') return undefined;
return career === '인턴' ? '인턴 경험만 있어요' : career === '아직 없음' ? '아직 없어요' : career;
Copy link
Member

@seong-hui seong-hui Mar 19, 2025

Choose a reason for hiding this comment

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

해당 부분을 상수화해서 아래와 같은 객체로 정의하여 CAREER_MAPPING['인턴']처럼 조회를 할 수 있게하면 좋을 것 같아요!

 const CAREER_MAPPING: Record<string, string> = {
    '인턴': '인턴 경험만 있어요',
    '아직 없음': '아직 없어요',
  };

  const SECTION_MAPPING: Record<string, string> = {
    '프론트엔드': '프론트',
  };

@seong-hui
Copy link
Member

@coderabbitai review

Copy link

coderabbitai bot commented Jun 18, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

coderabbitai bot commented Jun 18, 2025

Summary by CodeRabbit

  • Refactor
    • 필터 상태가 URL 쿼리 파라미터와 동기화되어, 필터 변경 시 URL이 자동으로 업데이트되고, 페이지 새로고침 또는 공유 시 동일한 필터 상태가 유지됩니다.
    • 필터 UI(드롭다운, 모바일 필터, 검색창)에서 선택 및 검색 시 URL이 즉시 반영됩니다.
    • 브라우저의 뒤로/앞으로 이동 시 필터 상태가 올바르게 복원됩니다.

Walkthrough

커피챗 메인 페이지의 필터 상태 관리가 기존의 로컬 상태에서 Next.js 라우터의 URL 쿼리 파라미터와 동기화되도록 리팩토링되었습니다. 필터 값은 쿼리에서 초기화되고, 변경 시 URL 쿼리 파라미터가 직접 수정됩니다. 필터 UI와 데이터 패칭 흐름이 이에 맞게 조정되었습니다.

Changes

파일/경로 변경 요약
src/components/coffeechat/CoffeeChatCategory/index.tsx 필터 상태를 쿼리 파라미터와 동기화, URL 기반 상태 관리 및 데이터 패칭 로직 리팩토링, 관련 헬퍼 함수 추가 및 기존 로컬 상태 제거

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CoffeeChatCategory
    participant NextRouter
    participant useGetMembersCoffeeChat

    User->>CoffeeChatCategory: 페이지 진입/필터 변경/검색
    CoffeeChatCategory->>NextRouter: 쿼리 파라미터 읽기/수정
    NextRouter-->>CoffeeChatCategory: 쿼리 파라미터 전달
    CoffeeChatCategory->>useGetMembersCoffeeChat: 정규화된 쿼리 파라미터 전달
    useGetMembersCoffeeChat-->>CoffeeChatCategory: 데이터 반환
    CoffeeChatCategory-->>User: 필터 UI 및 카드 목록 렌더링
Loading

Assessment against linked issues

Objective Addressed Explanation
쿼리파라미터 사용하여 수정하기, 필터(state) 구조 → 쿼리 파라미터 구조로 변경 (#1772)

Poem

🐇
URL에 춤추는 필터의 행진,
쿼리와 함께하는 커피챗의 신진!
뒤로 가도 앞으로 가도
필터는 그대로,
토끼는 기뻐 깡충깡충 뛰네—
쿼리 속에 숨은 커피향 따라
오늘도 우린 연결되네! ☕✨

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

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: 2

♻️ Duplicate comments (1)
src/components/coffeechat/CoffeeChatCategory/index.tsx (1)

73-82: 값 변환(normalize) 로직 중복 – 상수 매핑으로 통합 권장
normalizeCareer, normalizeSection 함수가 하드코딩된 조건문을 반복하고 있습니다.
이전 리뷰에서 제안된 것처럼 매핑 객체를 활용하면 가독성과 유지보수성이 향상됩니다.

const CAREER_MAP = { '인턴': '인턴 경험만 있어요', '아직 없음': '아직 없어요' } as const;
const SECTION_MAP = { '프론트엔드': '프론트' } as const;

const normalize = (map: Record<string,string>, value?: string) =>
  !value || value === '전체' ? undefined : map[value] ?? value;

그리고 switch 대신 공통 normalize 함수를 적용하면 중복이 크게 줄어듭니다.
이 부분은 과거에도 동일 지적이 있었으므로 참고 부탁드립니다.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 61f2874 and a2fd720.

📒 Files selected for processing (1)
  • src/components/coffeechat/CoffeeChatCategory/index.tsx (14 hunks)

Comment on lines 242 to +248
onSubmit={() => {
logSubmitEvent('searchCoffeeChat', {
search_content: clientSearch,
search_content: search,
});
setSearch(clientSearch);
addQueryParamsToUrl({ search: clientSearch || undefined });
}}
onReset={() => setClientSearch('')}
onReset={() => handleFilterChange('seasrch', '')}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

onReset 키 오타로 모바일에서 검색 초기화 실패

'seasrch''search' 오타 때문에 모바일 필터에서 검색어가 제대로 초기화되지 않습니다.

- onReset={() => handleFilterChange('seasrch', '')}
+ onReset={() => handleFilterChange('search', undefined)}
📝 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
onSubmit={() => {
logSubmitEvent('searchCoffeeChat', {
search_content: clientSearch,
search_content: search,
});
setSearch(clientSearch);
addQueryParamsToUrl({ search: clientSearch || undefined });
}}
onReset={() => setClientSearch('')}
onReset={() => handleFilterChange('seasrch', '')}
onSubmit={() => {
logSubmitEvent('searchCoffeeChat', {
search_content: search,
});
addQueryParamsToUrl({ search: clientSearch || undefined });
}}
onReset={() => handleFilterChange('search', undefined)}
🤖 Prompt for AI Agents
In src/components/coffeechat/CoffeeChatCategory/index.tsx around lines 242 to
248, there is a typo in the onReset handler where 'seasrch' is used instead of
'search'. Correct the key from 'seasrch' to 'search' in the handleFilterChange
call to ensure the search filter resets properly on mobile devices.

Comment on lines +229 to 234
search_content: search,
});
setSearch(clientSearch);
addQueryParamsToUrl({ search: clientSearch || undefined });
}}
onReset={() => setClientSearch('')}
onReset={() => handleFilterChange('search', '')}
/>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

검색 초기화 시 search 쿼리 파라미터가 남습니다

handleFilterChange('search', '')로 빈 문자열을 전달하면 skipNull: true 옵션에도 불구하고 '' 값이 그대로 URL에 유지됩니다.
또한 로그에 실제 입력값이 아닌 기존 search 값을 사용하고 있어 분석 데이터가 부정확할 수 있습니다.

-  logSubmitEvent('searchCoffeeChat', {
-    search_content: search,
-  });
-  addQueryParamsToUrl({ search: clientSearch || undefined });
+  logSubmitEvent('searchCoffeeChat', {
+    search_content: clientSearch,
+  });
+  addQueryParamsToUrl({ search: clientSearch || undefined });
...
- onReset={() => handleFilterChange('search', '')}
+ onReset={() => handleFilterChange('search', undefined)}

이렇게 수정하면

  1. 실제 사용자가 입력한 값을 로그에 남기고
  2. 검색어를 비울 때 쿼리 파라미터가 완전히 제거됩니다.
📝 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
search_content: search,
});
setSearch(clientSearch);
addQueryParamsToUrl({ search: clientSearch || undefined });
}}
onReset={() => setClientSearch('')}
onReset={() => handleFilterChange('search', '')}
/>
logSubmitEvent('searchCoffeeChat', {
search_content: clientSearch,
});
addQueryParamsToUrl({ search: clientSearch || undefined });
}}
onReset={() => handleFilterChange('search', undefined)}
/>
🤖 Prompt for AI Agents
In src/components/coffeechat/CoffeeChatCategory/index.tsx around lines 229 to
234, the onReset handler calls handleFilterChange with an empty string, but this
leaves the 'search' query parameter in the URL and logs the old search value
instead of the actual input. To fix this, update the onReset function to pass
undefined or null instead of an empty string to handleFilterChange so that the
'search' parameter is removed from the URL, and ensure the logging uses the
current input value to accurately reflect user actions.

@seong-hui seong-hui changed the base branch from main to develop September 1, 2025 13:06
Copy link
Contributor

@ljh0608 ljh0608 left a comment

Choose a reason for hiding this comment

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

할당된 태스크 외에도 코드를 개선하는 모습이 멋집니다 또이님!

Comment on lines 52 to 67
const handleSelectSection = (selected: string) => {
addQueryParamsToUrl({ section: selected !== '전체' ? selected : undefined });
};

const handleSelectTopic = (selected: string) => {
addQueryParamsToUrl({ topicType: selected !== '전체' ? selected : undefined });
};

const handleSelectCareer = (selected: string) => {
addQueryParamsToUrl({ career: selected !== '전체' ? selected : undefined });
};

const handleSelectPart = (selected: string) => {
addQueryParamsToUrl({ part: selected !== '전체' ? selected : undefined });
};

Copy link
Contributor

Choose a reason for hiding this comment

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

위 4개의 함수 아래처럼 로직 작성한다면 반복되는 로직 제거하고 가독성을 높일 수 있을 것 같아요!

const handleSelect = (key: string, selected: string) => {
  addQueryParamsToUrl({
    [key]: selected !== '전체' ? selected : undefined,
  });
};

};

const handleSelectCareer = (selected: string) => {
addQueryParamsToUrl({ career: selected !== '전체' ? selected : undefined });
Copy link
Contributor

Choose a reason for hiding this comment

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

해당 로직이 다른 코드에서는 아래와 같이 사용돼서 같은 목적의 사용이라면 호출부가 통일되었으면 좋겠다는 생각을 했습니다.

    addQueryParamsToUrl({ search: '' });

분명 qs의 querystring 메소드는 "" 값을 받으면 key값을 지우는게 아니라 search= 방식으로 남아있는것으로 알고있었는데 내부 로직에 lodash-es의 isEmpty가 nullable한 값들을 모두 걸러주면서 정상 작동하고 있더군요!
해당 로직을 일관성있게 처리하려면

  1. isEmpty를 사용하지 않거나, (qs.stringify는 undefined 값을 가진 key는 자동으로 serialize 대상에서 제외하기때문에 ""와 같은 사용은 문제를 일으킴)

  2. addQueryParamsToUrl의 파라미터 타입을 아래와 같이 변경하는 방법이 있을 것 같습니다.
    다만 아래의 방법은 기존의 NextRouter["query"] 타입을 사용하는것보다 직관성이나 가독성이 떨어지기 때문에 트레이드 오프가 있을 것 같군요...

export type SafeQueryParamValue = string & { __nonEmpty?: never } | null | undefined;
export type SafeQueryParams = Record<string, SafeQueryParamValue>;

제가 코드 파악하면서 스윽 둘러본 것이니 이 리뷰는 간단한 코멘트만 남겨주시고 그냥 무시하셔도 좋습니다.!

PS) NextRouter의 query 타입 뭐 대단한게 있나 보았는데 간단하네여

type ParsedUrlQuery = { [key: string]: string | string[] | undefined };
interface NextRouter {
  query: ParsedUrlQuery;
  // ... 그 외 push, pathname 등
}

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.

fix: 커피챗 메인 페이지 필터 state → query parameter로 변경

3 participants