Skip to content

Feature/search page#100#126

Open
muzi55 wants to merge 21 commits intodevfrom
feature/search-page#100
Open

Feature/search page#100#126
muzi55 wants to merge 21 commits intodevfrom
feature/search-page#100

Conversation

@muzi55
Copy link
Copy Markdown
Contributor

@muzi55 muzi55 commented Mar 2, 2026

🛠️ 변경 사항

무엇을 변경했는지 간결하게 설명해주세요.

작업된 내용이 좀 많습니다 허허;;

  • (community-category) 라우트 그룹 신설

  • 검색 페이지

  • sort-group.tsx 시간순 / 인기순 정렬버튼 추가

  • use-query-parmas.tsx 쿼리파람 커스텀훅 추가

  • formatRelativeDate(dateString: string): string 시간 계산 유틸 추가

  • 여기에 설명을 작성해주세요.

📸 스크린샷 (선택)

UI 변경이 있는 경우 스크린샷을 첨부해주세요.

검색 기록이 없을 때

스크린샷 2026-03-02 오후 9 32 20

검색 기록이 있을 때

스크린샷 2026-03-02 오후 9 34 28

✅ 체크리스트

  • 빌드 에러가 발생하지 않는가?
  • 정해진 디자인 시스템(Color, Font)을 준수하였는가?
  • 불필요한 console.log는 제거하였는가?

🔗 연결된 이슈

해당 api 명세서가 없어 일단 해당작업내용만 먼저 올릴게요

Summary by CodeRabbit

릴리스 노트

  • 새 기능

    • 커뮤니티 섹션 추가로 프롬프트 리스트 제공 및 항목별 상세 페이지 링크
    • 프롬프트 검색 UI 및 서버측 예비 로딩으로 초기 로딩 개선
    • 최신순/인기순 정렬 옵션 추가
  • 개선사항

    • 검색어 길면 자동 줄임 및 결과 제목 레이아웃 개선
    • 입력 필드 너비 최적화 및 검색 파라미터 자동 동기화
    • 항목에 상대 시간 표시 추가 (예: "5분 전")

muzi55 and others added 19 commits February 19, 2026 15:01
* chore: 마이페이지 API 타입, 모킹 및 상태관리 설정

* fix: 핸들러 수정

* fix: 하드코딩된 백엔드 URL 제거
* feat: 마이페이지 프로필 및 카드 UI 컴포넌트 추가

* fix: 유저 프로필 스켈레톤 추가 및 피드백 반영

* fix: 피드백 반영 및 접근성 향상

* fix: 피드백 반영 및 접근성 향상

* fix: 의존성 파일 추가

* fix: 타입 안정성 향상 및 중앙정렬 커스텀 클래스 생성

* fix: 이넘타입에 익스포트문 추가

* fix: css 수정 및 상수 통일

* fix: css 수정
@muzi55 muzi55 self-assigned this Mar 2, 2026
@muzi55 muzi55 added this to prog-front Mar 2, 2026
@muzi55 muzi55 added the feature 새로운 기능 구현 label Mar 2, 2026
@muzi55 muzi55 linked an issue Mar 2, 2026 that may be closed by this pull request
1 task
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 2, 2026

📝 Walkthrough

Walkthrough

검색 페이지와 관련된 여러 컴포넌트·훅·유틸을 추가·수정하는 PR입니다. 검색 입력 폼(SearchForm), 검색 섹션(SearchSection), 정렬 컴포넌트(SortGroup), 커뮤니티 리스트 컴포넌트(CommunitySection/CommunityList/CommunityItem)와 이를 지원하는 타입 정의, 날짜 포맷터(formatRelativeDate), 라우트(ROUTES.prompt), 서버-클라이언트 React Query 하이드레이션(page.tsx), 쿼리 파라미터를 조작하는 커스텀 훅(useQueryParams) 및 백엔드 페칭 계층(fetcher, queries/api/prompts, hooks/use-prompt-list) 변경이 포함되어 있습니다. 또한 일부 UI 클래스와 타입(PromptBase/PromptPage) 구조가 조정되었습니다.

Sequence Diagram

sequenceDiagram
    participant User as "User"
    participant SearchForm as "SearchForm"
    participant useQueryParams as "useQueryParams"
    participant NextRouter as "Next Router"
    participant SearchPage as "Search Page (SSR)"
    participant QueryClient as "QueryClient (SSR)"
    participant SearchSection as "SearchSection (Client)"
    participant useGetPrompts as "useGetPrompts (React Query)"
    participant Fetcher as "fetcher / API"
    participant CommunitySection as "CommunitySection"

    User->>SearchForm: 검색어 입력 및 제출
    SearchForm->>useQueryParams: setParam("q", value)
    useQueryParams->>NextRouter: router.push(updatedURL)
    Note right of NextRouter: URL 업데이트 (쿼리 반영)
    NextRouter->>SearchSection: 클라이언트가 q로 렌더링
    SearchSection->>useGetPrompts: 쿼리키 ["prompts","ALL", q]로 요청
    useGetPrompts->>Fetcher: fetchPrompts(category, page, q)
    Fetcher->>Fetcher: 응답 파싱 및 에러 핸들링
    Fetcher-->>useGetPrompts: ApiResponse<PromptPage>
    useGetPrompts-->>SearchSection: 페이지 데이터(무한 스크롤)
    SearchSection->>CommunitySection: props로 prompts 전달
    CommunitySection-->>User: 리스트 렌더링
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

상세 검토 의견

잘된 점 (짧고 위트 있게)

  • 훅과 컴포넌트를 분리해 책임이 명확합니다 — 설계 멋져요.👏
  • 서버 사이드에서 React Query 하이드레이션을 도입해 초기 UX가 개선됩니다.

개선 권장 항목 (문제, 원인, 개선안)

  1. proxy.ts — 개발 인증 우회
  • 문제: 개발 환경에서 isSignIn을 무조건 true로 설정하면 인증 경로 테스트가 왜곡됩니다.
  • 권장 개선:
    • 명시적 환경변수 기반 플래그 사용: NEXT_PUBLIC_DEV_BYPASS_AUTH
    • 또는 로컬에서만 동작하는 별도 미들웨어로 제한
  • 참고: 환경변수 문서(Next.js)로 안전한 설정 권장.
  1. formatRelativeDate — 로깅 및 예외 처리
  • 문제: catch에서 단순 console.log 사용, 프로덕션 노이즈 가능.
  • 권장 개선:
    • process.env.NODE_ENV 체크 후 console.error 사용 또는 중앙 로깅 서비스 전송
    • 입력이 빈값/유효하지 않음에 대한 유닛 테스트 추가
  • 변경 예:
    • if (process.env.NODE_ENV === "development") console.error(...)
  1. useQueryParams — router.push 사용 시 history 관리
  • 문제: setParam이 항상 router.push를 호출하면 불필요한 히스토리 쌓임 가능.
  • 권장 개선:
    • 검색 입력 변경(타이핑) 중에는 replace 옵션 (router.replace) 사용 고려
    • 사용자 조작(검색 제출) 시에만 push 사용
  • 참고: Next.js useRouter('push' vs 'replace') 문서.
  1. SearchForm / SearchTitle — 길이 상수 불일치
  • 문제: SearchForm maxLength=100인데 SearchTitle의 MAX_SEARCH_LENGTH는 다름(예: 50).
  • 권장 개선:
    • 상수화(constants/search.ts)로 MAX_LENGTH와 DISPLAY_TRUNCATE_LENGTH 분리해 공유
  1. CommunityList / CommunityItem — 데이터 변환 및 키 안정성
  • 문제: SearchSection에서 API 응답을 CommunityPromptItem으로 매핑하긴 했으나 컴포넌트가 props에 대해 방어적이지 않음(예: missing authorNickname).
  • 권장 개선:
    • CommunityItem에서 필수 필드가 없을 때의 폴백(예: authorNickname ?? "익명")
    • prop 타입을 좁히고 필요시 PropTypes/타입 가드 추가
  1. useGetPrompts 및 쿼리/페처 변경사항
  • 문제: useGetPrompts의 initialPageParam 변경(0 기반)과 getNextPageParam 로직이 백엔드 응답 형태에 의존함.
  • 권장 개선:
    • getNextPageParam 로직에 더 명확한 방어 코드(명시적 타입 가드) 추가
    • fetchPrompts에 대한 유닛·통합 테스트로 페이지네이션 경계 확인
  1. fetcher의 afterResponse 에러 처리
  • 문제: 백엔드 에러 스키마에 의존적이며, 예상 외 포맷일 경우 generic Error로 던짐.
  • 권장 개선:
    • 에러 파싱 실패 시 원본 응답 텍스트를 로깅/첨부하여 디버깅 용이성 향상
    • TOKEN_EXPIRED 처리 후 재시도/리프레시 토큰 흐름 명시

테스트 권장

  • SearchSection의 무한 스크롤(fetchNextPage 트리거)에 대한 통합/유닛 테스트
  • formatRelativeDate 경계(방금 전, 1분, 59분, 1시간, 1일 등) 유닛 테스트
  • useQueryParams의 set/delete/clear 동작에 대한 라우터 대체 동작 테스트

참고 자료

짧게: 구조와 분리가 좋아요. 인증 우회, 예외 로깅, 상수화, 라우터 히스토리 제어 부분만 정리하면 배포 준비 OK입니다.

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (2 warnings, 1 inconclusive)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning proxy.ts의 개발 모드 인증 로직 변경, RankList.tsx의 데이터 구조 수정 등 검색 페이지 범위와 무관한 변경 사항들이 포함되어 있습니다. proxy.ts와 RankList.tsx 변경은 별도 PR로 분리하고, 이 PR은 검색 페이지 및 관련 유틸/훅만 포함하도록 수정해주세요.
Docstring Coverage ⚠️ Warning Docstring coverage is 29.41% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive 제목이 이슈 번호만 포함하고 변경 사항의 핵심을 명확하게 설명하지 못하고 있습니다. '검색 페이지' 구현이라는 주요 변경 사항을 반영하지 않은 모호한 제목입니다. 제목을 'Implement search page with filtering and sorting' 또는 '검색 페이지 구현 (정렬, 필터링 포함)' 같이 변경하여 핵심 변경 사항을 명확하게 표현해주세요.
✅ Passed checks (2 passed)
Check name Status Explanation
Description check ✅ Passed PR 설명이 템플릿 구조를 따르고 있으며, 변경 사항, 스크린샷, 연결된 이슈를 포함하고 있습니다. 다만 체크리스트 항목들이 미완료 상태이고 '여기에 설명을 작성해주세요' 플레이스홀더가 남아있습니다.
Linked Issues check ✅ Passed PR의 변경 사항(검색 페이지 구현, 정렬 기능, 쿼리 파라미터 훅, 상대 시간 유틸)이 이슈 #100의 '검색 페이지 작업' 목표와 일치하며, 제공된 Figma 디자인과도 대응됩니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/search-page#100
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch feature/search-page#100

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

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

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

🧹 Nitpick comments (7)
app/(afterLogin)/(dashboard)/(community-category)/_components/community.tsx (3)

30-51: 더미 데이터 관리 방안

API 스펙이 없어 더미 데이터를 사용 중인 것은 이해하지만, 나중에 실제 데이터로 교체 시 이 부분을 찾기 쉽도록 별도 파일이나 명확한 주석을 추가하는 것을 권장합니다.

// TODO: API 연동 후 제거 - Issue `#100`
// `@see` https://api-docs.example.com/community
const dummyData: CommunityPromptItem[] = [...]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/`(afterLogin)/(dashboard)/(community-category)/_components/community.tsx
around lines 30 - 51, Extract the inline dummyData array (typed as
CommunityPromptItem) out of the component file and place it into a dedicated
module (e.g., community dummy data module) that exports dummyData, and update
the component to import it; in the new module add a clear TODO comment with an
issue number and API docs link (e.g., "// TODO: remove after API integration -
Issue `#100`" and a reference URL) so future removal/replacement is obvious—update
any references to dummyData in the component to use the imported symbol.

22-26: 주석 처리된 코드 정리 필요

검색 결과 유무에 따른 조건부 렌더링이 주석으로 처리되어 있습니다. 실제 구현 시 조건부 렌더링으로 전환하거나, 현재 단계에서 필요 없다면 제거해주세요.

export function CommunitySection({ isEmpty }: { isEmpty: boolean }) {
  if (isEmpty) {
    return (
      <div className="py-5.5">
        <SearchEmpty />
      </div>
    );
  }
  
  return (
    <div className="border p-5 rounded-10 bg-white mt-7">
      <CommunityList />
    </div>
  );
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/`(afterLogin)/(dashboard)/(community-category)/_components/community.tsx
around lines 22 - 26, The commented-out conditional rendering for empty search
results should be implemented or removed: update the CommunitySection component
to accept the prop isEmpty and render the SearchEmpty block when isEmpty is
true, otherwise render the existing CommunityList wrapper; locate the
CommunitySection function and replace the commented JSX with a proper if
(isEmpty) return (...) branch (using SearchEmpty) and the existing return for
CommunityList, or if unused remove the commented lines entirely to keep the code
clean.

1-2: 파일 상단 날짜/파일명 주석 제거 권장

community-type.ts와 동일한 패턴입니다. Git에서 추적되므로 불필요합니다.

-// 2026-03-02
-// community.tsx
 "use client";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/`(afterLogin)/(dashboard)/(community-category)/_components/community.tsx
around lines 1 - 2, community.tsx contains redundant top-of-file comments with
date and filename; remove those lines (the "// 2026-03-02" and "//
community.tsx" comments) so the file follows the same pattern as
community-type.ts, ensure no extra blank lines are left at the top, and commit
the change.
app/(afterLogin)/(dashboard)/_types/community-type.ts (2)

30-31: CommunityPrompt 타입 별칭의 필요성 검토

현재 CommunityPromptCommunityPromptItem과 완전히 동일합니다. 주석에는 "API 응답값으로 사용"이라고 되어 있는데, 실제 API 응답에 pagination이나 meta 정보가 추가될 예정이라면 다음과 같이 확장하는 것이 좋습니다:

// API 응답 타입 (pagination 등 메타 정보 포함)
export interface CommunityPromptResponse {
  items: CommunityPromptItem[];
  totalCount: number;
  page: number;
  // ...
}

현재 상태로는 중복되어 혼란을 줄 수 있으니, API 스펙이 확정되면 실제 응답 구조에 맞게 수정하시면 됩니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/`(afterLogin)/(dashboard)/_types/community-type.ts around lines 30 - 31,
The alias CommunityPrompt currently duplicates CommunityPromptItem; verify
intended use and either remove the alias or replace it with a proper API
response interface (e.g., CommunityPromptResponse) that wraps items:
CommunityPromptItem[] plus pagination/meta fields like totalCount and page;
update any consumers that import CommunityPrompt to use CommunityPromptItem (if
alias removed) or CommunityPromptResponse (if API response shape is required)
and adjust names in the module to avoid the confusing duplicate type.

1-2: 파일 상단 주석 제거 권장

날짜와 파일명 주석은 버전 관리 시스템(Git)에서 자동으로 추적되므로 불필요합니다. 유지보수 시 outdated 정보가 될 수 있어요.

-// 2026-03-02
-// community-type.ts
-
 // 커뮤니티 게시글 기본 타입
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/`(afterLogin)/(dashboard)/_types/community-type.ts around lines 1 - 2,
Remove the redundant top-of-file comment lines ("// 2026-03-02" and "//
community-type.ts") from community-type.ts; simply delete those two comment
lines so the file starts with its actual TypeScript code (or exports/types) and
commit the change with a clear message like "chore: remove outdated file header
comments".
app/hooks/use-query-parmas.tsx (1)

43-43: router.push vs router.replace 고려

현재 모든 파라미터 변경에 router.push를 사용하고 있어서, 정렬 옵션 변경 같은 minor한 조작도 브라우저 히스토리에 쌓입니다.

사용자가 뒤로가기 시 이전 정렬 상태로 돌아가길 원하면 현재 방식이 맞지만, 필터/정렬 변경은 히스토리에 쌓지 않는 것이 일반적인 UX입니다.

♻️ router.replace 옵션 추가 제안
const setParam = useCallback(
  (key: string, value: string, replace = false) => {
    const params = createParams();
    params.set(key, value);
    const url = `${pathname}?${params.toString()}`;
    replace ? router.replace(url) : router.push(url);
  },
  [createParams, pathname, router]
);

Also applies to: 55-55, 66-66, 77-77

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/hooks/use-query-parmas.tsx` at line 43, The current setParam
implementations call router.push (e.g., the call at
router.push(`${pathname}?${params.toString()}`) and similar calls at the other
occurrences) which indiscriminately adds history entries; modify the setter(s)
(the useCallback function(s) that call createParams, set the param, build url
using pathname and params.toString()) to accept an optional replace boolean
(default false) and call router.replace(url) when replace is true, otherwise
router.push(url); update all occurrences (the calls at lines shown) and any
callers to optionally pass replace for filter/sort changes that should not
create history entries.
app/(afterLogin)/(dashboard)/(community-category)/_components/sort-group.tsx (1)

31-51: 정렬 토글 버튼에 상태 접근성 속성을 추가해 주세요

지금도 동작은 좋습니다(깔끔해요 👍). 다만 선택 상태를 스크린리더가 알 수 있도록 aria-pressed를 넣고, 안전하게 type="button"을 명시하는 편이 좋습니다.

수정 예시
-      <button onClick={() => handleSortChange("latest")}>
+      <button
+        type="button"
+        aria-pressed={isActive("latest")}
+        onClick={() => handleSortChange("latest")}
+      >
...
-      <button onClick={() => handleSortChange("popular")}>
+      <button
+        type="button"
+        aria-pressed={isActive("popular")}
+        onClick={() => handleSortChange("popular")}
+      >
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/`(afterLogin)/(dashboard)/(community-category)/_components/sort-group.tsx
around lines 31 - 51, Add explicit type="button" and an aria-pressed attribute
to each sort toggle button so screen readers can detect selection state; update
the two <button> elements that call handleSortChange("latest") and
handleSortChange("popular") to include type="button" and
aria-pressed={isActive("latest")} and aria-pressed={isActive("popular")}
respectively (use the existing isActive function to supply the boolean), leaving
the cn(BASE_STYLE, isActive(...) ? ACTIVE_STYLE : INACTIVE_STYLE) logic
unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/`(afterLogin)/(dashboard)/(community-category)/_components/community.tsx:
- Around line 71-97: The Link currently wraps an interactive button (the <Link>
element that uses ROUTES.prompt.DETAIL(...) contains the <button> with
ThumbsUpIcon and like count), which breaks accessibility and causes navigation
when the button is clicked; fix by moving the like button out of the Link so the
Link only wraps the title (or by restructuring the container into a non-link
wrapper and placing a separate <Link> around the heading), ensure the like
button's click handler is on the standalone button (or if you must keep it
inside the Link temporarily, add e.preventDefault() and e.stopPropagation() in
the button's onClick) and keep other metadata (authorNickname,
formatRelativeDate(createdAt)) visually aligned with CSS after the refactor.

In
`@app/`(afterLogin)/(dashboard)/(community-category)/_components/sort-group.tsx:
- Around line 17-27: currentSort is taken with a raw type assertion from
getParam("sort") which allows invalid values (e.g. ?sort=foo) to produce no
active option; add a normalization/validation step that maps the raw string to a
proper SortType or falls back to "latest" (e.g. create a small normalizeSort
helper that checks the string against the allowed SortType values and returns
"latest" for anything else), use that normalized value in currentSort and in
isActive, and ensure handleSortChange / setParams continues to set only valid
SortType values (or omit the param for "latest") so the component never sees an
unexpected sort value.

In
`@app/`(afterLogin)/(dashboard)/(community-category)/search/_components/search-form.tsx:
- Around line 19-24: The handleSearch function currently builds the query by
concatenating search into `${pathname}?q=${search}`, which can produce unencoded
characters and overwrite existing query params; instead, read and clone the
existing searchParams (the searchParams variable), create a URLSearchParams
instance, set the "q" key to the trimmed search value (which will be URL-encoded
by URLSearchParams) and preserve other params, then navigate using router.push
with `${pathname}?${params.toString()}` (or pass the params as a query object)
so special characters are encoded and existing query parameters are retained;
update the handleSearch function and reference search, searchParams, pathname,
and router accordingly.
- Around line 25-41: Wrap the search controls in a semantic <form> and wire its
onSubmit to the existing handleSearch so Enter triggers searches: move the
IconInput and BaseButton into a <form onSubmit={handleSubmit}> (or set
onSubmit={handleSearch} if you update handleSearch to accept and call
event.preventDefault()), change the BaseButton to type="submit" (remove or keep
onClick as redundant), and ensure handleSearch calls event.preventDefault() when
used as a form handler; update references to IconInput, BaseButton,
handleSearch, search, and setSearch accordingly.
- Around line 14-15: The input state initialized with const [search, setSearch]
= useState(q || "") only captures the URL param on first render so the input can
drift when the URL's q changes (back/forward). Fix by adding an effect that
watches q and updates setSearch(q || "") whenever q changes (ensure you
reference search, setSearch and q in the component), so the controlled input
stays in sync with the URL; keep existing handlers for user typing unchanged.

In
`@app/`(afterLogin)/(dashboard)/(community-category)/search/_components/search-section.tsx:
- Line 15: The SearchTitle is being given q?.length (the search string length)
instead of the number of results; replace the searchLength prop usage with a
real results count (e.g., results.length or searchResults?.length ?? 0) when
rendering SearchTitle and/or add a resultCount prop so it receives the actual
number (default 0) rather than q?.length; update the render that calls
SearchTitle and adjust SearchTitle's props/type if needed to consume the new
result count prop.

In `@app/hooks/use-query-parmas.tsx`:
- Line 1: File name has a typo: rename the file from use-query-parmas.tsx to
use-query-params.tsx and update all imports referencing use-query-parmas to the
corrected name; ensure any export/import statements that reference the hook file
(e.g., imports like import useQueryParams from "app/hooks/use-query-parmas") are
updated to "app/hooks/use-query-params" and run a project-wide search to catch
all usages.

In `@components/search/search-empty.tsx`:
- Line 30: The class "min-w-49.25" used on the BaseButton is not a defined
Tailwind spacing token; update the className in the BaseButton JSX (where
BaseButton and handleClick are used) to use a valid Tailwind arbitrary value
like "min-w-[197px]" or alternatively add a custom spacing token in the theme
config and use that token; make the change in the component's className string
so the rendered button uses a valid Tailwind class.

In `@lib/format-date.ts`:
- Around line 15-40: formatRelativeDate currently doesn't detect Invalid Date
(new Date(...) returns an Invalid Date rather than throwing) and negative diffs
for future dates; validate target by checking isNaN(target.getTime()) and return
"날짜 오류" immediately if invalid, then compute diffMinutes/diffHours/diffDays and
clamp negative values to zero (e.g., diffMinutes = Math.max(0, diffMinutes)) so
future dates are treated consistently (e.g., "방금 전") before applying the
existing branches; reference function formatRelativeDate and variables target,
diffMinutes, diffHours, diffDays when making the changes.

In `@lib/routes.ts`:
- Around line 39-41: The CommunityItem component is using the wrong route
constant (ROUTES.prompt.DETAIL) which points to a nonexistent /prompt/[id] path;
update the usage to ROUTES.community.DETAIL so community items navigate to the
correct /community/[id] route. Locate the reference in CommunityItem (around the
component code that builds item links) and replace ROUTES.prompt.DETAIL with
ROUTES.community.DETAIL, ensuring any link construction or parameter
interpolation still uses the same id argument.

In `@proxy.ts`:
- Around line 10-11: isSignIn currently conflates real auth state with a dev
bypass (isSignIn = isDevelopment ? true : !!session), causing dev mode to appear
signed-in and breaking sign-in/sign-up flows; change this to compute a real
boolean isSignedIn = !!session and a separate dev bypass flag (e.g., devBypass =
isDevelopment && <optional dev-only condition>), then update the redirect logic
that uses isSignIn/isAuthRoute/isNewUser so it only treats a user as
authenticated when isSignedIn is true and only skips protection when devBypass
is explicitly enabled (i.e., use !isSignedIn && isAuthRoute && !devBypass for
redirect decisions).

---

Nitpick comments:
In `@app/`(afterLogin)/(dashboard)/_types/community-type.ts:
- Around line 30-31: The alias CommunityPrompt currently duplicates
CommunityPromptItem; verify intended use and either remove the alias or replace
it with a proper API response interface (e.g., CommunityPromptResponse) that
wraps items: CommunityPromptItem[] plus pagination/meta fields like totalCount
and page; update any consumers that import CommunityPrompt to use
CommunityPromptItem (if alias removed) or CommunityPromptResponse (if API
response shape is required) and adjust names in the module to avoid the
confusing duplicate type.
- Around line 1-2: Remove the redundant top-of-file comment lines ("//
2026-03-02" and "// community-type.ts") from community-type.ts; simply delete
those two comment lines so the file starts with its actual TypeScript code (or
exports/types) and commit the change with a clear message like "chore: remove
outdated file header comments".

In `@app/`(afterLogin)/(dashboard)/(community-category)/_components/community.tsx:
- Around line 30-51: Extract the inline dummyData array (typed as
CommunityPromptItem) out of the component file and place it into a dedicated
module (e.g., community dummy data module) that exports dummyData, and update
the component to import it; in the new module add a clear TODO comment with an
issue number and API docs link (e.g., "// TODO: remove after API integration -
Issue `#100`" and a reference URL) so future removal/replacement is obvious—update
any references to dummyData in the component to use the imported symbol.
- Around line 22-26: The commented-out conditional rendering for empty search
results should be implemented or removed: update the CommunitySection component
to accept the prop isEmpty and render the SearchEmpty block when isEmpty is
true, otherwise render the existing CommunityList wrapper; locate the
CommunitySection function and replace the commented JSX with a proper if
(isEmpty) return (...) branch (using SearchEmpty) and the existing return for
CommunityList, or if unused remove the commented lines entirely to keep the code
clean.
- Around line 1-2: community.tsx contains redundant top-of-file comments with
date and filename; remove those lines (the "// 2026-03-02" and "//
community.tsx" comments) so the file follows the same pattern as
community-type.ts, ensure no extra blank lines are left at the top, and commit
the change.

In
`@app/`(afterLogin)/(dashboard)/(community-category)/_components/sort-group.tsx:
- Around line 31-51: Add explicit type="button" and an aria-pressed attribute to
each sort toggle button so screen readers can detect selection state; update the
two <button> elements that call handleSortChange("latest") and
handleSortChange("popular") to include type="button" and
aria-pressed={isActive("latest")} and aria-pressed={isActive("popular")}
respectively (use the existing isActive function to supply the boolean), leaving
the cn(BASE_STYLE, isActive(...) ? ACTIVE_STYLE : INACTIVE_STYLE) logic
unchanged.

In `@app/hooks/use-query-parmas.tsx`:
- Line 43: The current setParam implementations call router.push (e.g., the call
at router.push(`${pathname}?${params.toString()}`) and similar calls at the
other occurrences) which indiscriminately adds history entries; modify the
setter(s) (the useCallback function(s) that call createParams, set the param,
build url using pathname and params.toString()) to accept an optional replace
boolean (default false) and call router.replace(url) when replace is true,
otherwise router.push(url); update all occurrences (the calls at lines shown)
and any callers to optionally pass replace for filter/sort changes that should
not create history entries.

ℹ️ Review info

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between db5f654 and 3bc4b50.

📒 Files selected for processing (13)
  • app/(afterLogin)/(dashboard)/(community-category)/_components/community.tsx
  • app/(afterLogin)/(dashboard)/(community-category)/_components/sort-group.tsx
  • app/(afterLogin)/(dashboard)/(community-category)/search/_components/search-form.tsx
  • app/(afterLogin)/(dashboard)/(community-category)/search/_components/search-section.tsx
  • app/(afterLogin)/(dashboard)/(community-category)/search/page.tsx
  • app/(afterLogin)/(dashboard)/_types/community-type.ts
  • app/hooks/use-query-parmas.tsx
  • components/search/search-empty.tsx
  • components/search/search-title.tsx
  • components/shared/inputs.tsx
  • lib/format-date.ts
  • lib/routes.ts
  • proxy.ts

Comment thread app/(afterLogin)/(dashboard)/(community-category)/_components/sort-group.tsx Outdated
Comment thread app/hooks/use-query-params.tsx
Comment thread components/search/search-empty.tsx
Comment thread lib/format-date.ts
Comment thread lib/routes.ts
Comment thread proxy.ts
Copy link
Copy Markdown

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/hooks/use-query-params.tsx`:
- Around line 72-76: The forEach callback inside deleteParams currently uses an
expression body (keys.forEach((key) => params.delete(key))) which causes an
implicit return and violates Biome's useIterableCallbackReturn rule; change the
callback to a block body so it returns void (e.g., keys.forEach((key) => {
params.delete(key); })), keeping the rest of deleteParams and createParams usage
unchanged to avoid altering behavior.

In `@components/header/header-search.tsx`:
- Line 24: The current call to setParam("q", trimAndSanitizedValue(searchValue))
over-sanitizes queries and leaves an empty q param; change it to use only
trimming and remove the param when empty by calling setParam("q", trimmed) only
if trimmed !== "" (otherwise delete/remove the "q" param), stop using
trimAndSanitizedValue here (or replace with a local trimmed variable), and rely
on URLSearchParams/router for encoding; keep sanitization/XSS handling to output
encoding/server-side validation instead of mutating the search term in the
header-search component.

ℹ️ Review info

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3bc4b50 and 5f28dff.

📒 Files selected for processing (4)
  • app/(afterLogin)/(dashboard)/(community-category)/_components/sort-group.tsx
  • app/(afterLogin)/(dashboard)/(community-category)/search/_components/search-form.tsx
  • app/hooks/use-query-params.tsx
  • components/header/header-search.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/(afterLogin)/(dashboard)/(community-category)/search/_components/search-form.tsx

Comment thread app/hooks/use-query-params.tsx
Comment thread components/header/header-search.tsx Outdated
Copy link
Copy Markdown
Contributor

@fryzke fryzke left a comment

Choose a reason for hiding this comment

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

작업량 많으셨을텐데 수고 많으셨습니다! ㅜㅜ
확장성까지 고려된 깔끔한 코드였습니다. 👍
로컬에서도 실행해봤는데 페이지 문제 없이 잘 보였습니다!
변경된 라우트에 맞춰서 저도 Rank 페이지 프롬프트 클릭 시 페이지가 이동되도록 바로 작업해둘게요. 혹시 진행하시다가 추가로 수정하신 부분이 생기셨다면 알려주세요~!

@muzi55
Copy link
Copy Markdown
Contributor Author

muzi55 commented Mar 3, 2026

아직 api 명세서가 제대로 나오지 않아서
여러곳 더 만져봐야할거같습니다.

prompt쪽은 .... 명세서가 아직 작성이 안되서 ...
오늘한번 얘기해봐야겠네요 😢

Copy link
Copy Markdown

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
hooks/use-prompt-list.ts (3)

129-131: ⚠️ Potential issue | 🟡 Minor

동일하게 에러 핸들러에서 toasts.error를 사용해야 합니다.

🐛 수정 제안
     onError: (error: Error) => {
-      toasts.success(error.message);
+      toasts.error(error.message);
     },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@hooks/use-prompt-list.ts` around lines 129 - 131, The onError handler in the
usePromptList hook currently calls toasts.success with the error message; change
it to call toasts.error so errors are shown correctly. Locate the onError
callback inside usePromptList (the function where onError: (error: Error) => {
... } is defined) and replace toasts.success(error.message) with
toasts.error(error.message), keeping the error parameter and message unchanged.

58-86: ⚠️ Potential issue | 🟠 Major

Optimistic update의 데이터 구조가 실제 응답 구조와 일치하지 않습니다.

useGetPromptsApiResponse<PromptPage>를 반환하므로, optimistic update에서 page.items 대신 page.data.items에 접근해야 합니다. 현재 코드는 타입도 InfiniteData<PromptPage>로 되어있어 실제 구조와 맞지 않습니다.

🐛 수정 제안
       const previousPrompts = queryClient.getQueriesData<
-        InfiniteData<PromptPage>
+        InfiniteData<ApiResponse<PromptPage>>
       >({
         queryKey: ["prompts"],
       });

-      queryClient.setQueriesData<InfiniteData<PromptPage>>(
+      queryClient.setQueriesData<InfiniteData<ApiResponse<PromptPage>>>(
         { queryKey: ["prompts"] },
         (old) => {
           if (!old) return old;
           return {
             ...old,
-            pages: old.pages.map((page: PromptPage) => ({
+            pages: old.pages.map((page: ApiResponse<PromptPage>) => ({
               ...page,
-              items: page.items.map((item: PromptBase) =>
+              data: {
+                ...page.data,
+                items: page.data.items.map((item: PromptBase) =>
-                item.id === promptId
+                  item.id === promptId
-                  ? {
+                    ? {
                       ...item,
                       isLiked: !isLiked,
                       likes: isLiked
                         ? Math.max((item.likes ?? 0) - 1, 0)
                         : (item.likes ?? 0) + 1,
                     }
-                  : item
+                    : item
-              ),
+                ),
+              },
             })),
           };
         }
       );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@hooks/use-prompt-list.ts` around lines 58 - 86, The optimistic update in the
setQueriesData block assumes pages contain PromptPage directly but useGetPrompts
returns ApiResponse<PromptPage>, so update the cache shape: read and restore
previous data via queryClient.getQueriesData/getQueryData for the "prompts" key,
treat each page as ApiResponse<PromptPage> (i.e., access page.data.items), and
when toggling a prompt ID in queryClient.setQueriesData (called in your hook
around useGetPrompts / setQueriesData), update page.data.items instead of
page.items and keep the outer ApiResponse wrapper and types (replace
InfiniteData<PromptPage> usage with InfiniteData<ApiResponse<PromptPage>> or the
correct generic) so the cached structure matches the real response.

96-96: ⚠️ Potential issue | 🟡 Minor

에러 핸들러에서 toasts.success 대신 toasts.error를 사용해야 합니다.

에러 상황에서 성공 토스트를 표시하면 사용자에게 혼란을 줍니다.

🐛 수정 제안
     onError: (err, newLike, context) => {
       if (context?.previousPrompts) {
         context.previousPrompts.forEach(([key, data]) => {
           queryClient.setQueryData(key, data);
         });
       }
-      toasts.success("좋아요 처리에 실패했습니다.");
+      toasts.error("좋아요 처리에 실패했습니다.");
     },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@hooks/use-prompt-list.ts` at line 96, In the usePromptList hook, replace the
incorrect success toast call with an error toast in the error handler: change
the toasts.success("좋아요 처리에 실패했습니다.") call to toasts.error(...) where the
failure is handled (look for the handler around functions like
handleLike/toggleLike or the rejection/catch block inside usePromptList). Ensure
the error toast carries the same message and is used wherever the "좋아요 처리에
실패했습니다." failure message is emitted.
🧹 Nitpick comments (2)
components/header/header-search.tsx (1)

10-13: 사용되지 않는 trimAndSanitizedValue 함수를 제거하세요.

이전 리뷰 피드백을 반영하여 trim()만 사용하도록 개선되었지만, 기존 trimAndSanitizedValue 함수가 데드 코드로 남아있습니다.

♻️ 제거 제안
-function trimAndSanitizedValue(value: string) {
-  // eslint-disable-next-line no-useless-escape
-  return value.trim().replace(/[<>\"\'&]/g, "");
-}
-
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/header/header-search.tsx` around lines 10 - 13, Remove the dead
helper function trimAndSanitizedValue from the header-search component: delete
the function declaration and any associated unused imports/exports or
references, and replace any call sites (if any remain) with value.trim() (the
new intended behaviour). After removal, run TypeScript/ESLint to ensure no
unused symbol or import warnings remain and update tests or typings that
referenced trimAndSanitizedValue.
lib/fetcher.ts (1)

9-15: 사용되지 않는 PagedResponse<T> 인터페이스 제거를 검토하세요.

이 인터페이스는 코드베이스 어디에서도 참조되지 않고 있습니다. 향후 사용 계획이 없다면 제거하는 것이 좋습니다. 사용되지 않는 타입 정의는 코드 복잡도를 높이고 유지보수 비용을 증가시키므로, 필요할 때 충분히 시간을 두고 추가할 수 있습니다. 만약 나중에 필요하다면 git 히스토리에서 언제든 복구할 수 있으니 과감하게 정리해도 괜찮습니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/fetcher.ts` around lines 9 - 15, The PagedResponse<T> interface is unused
and should be removed to reduce dead code; delete the interface declaration
named PagedResponse<T> from lib/fetcher.ts, run TypeScript checks (tsc) and your
test suite to ensure no references remain, and commit the change with a brief
message like "chore: remove unused PagedResponse<T> interface".
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/`(afterLogin)/(dashboard)/(community-category)/search/page.tsx:
- Around line 19-25: You are calling the React hook useGetPrompts inside
queryClient.prefetchInfiniteQuery in the server component
(queryClient.prefetchInfiniteQuery, useGetPrompts) which is illegal and also
using a different queryKey than the client (server: ["prompts","search", q] vs
client in search-section.tsx: ["prompts","ALL", currentSearch]); replace the
hook call with the plain async data-fetcher (e.g., getPrompts / fetchPrompts —
the non-hook function that returns a Promise) as the queryFn and make the
queryKey identical to the client (or change the client key to match) so the
server-prefetched data is reused by the client; ensure queryFn accepts
pageParams and returns the same shape the client expects for infinite queries
(no React hooks used).

In `@lib/fetcher.ts`:
- Around line 73-79: The if-block checking errorData.error.errorClassName for
"TOKEN_EXPIRED"/"INVALID_TOKEN" is empty; implement token-expiry handling by
invoking your auth flow: call a refresh function (e.g., refreshAuthToken()) and,
if it succeeds, retry the original request, otherwise call logoutUser() (or emit
an auth failure event via authEventEmitter/onAuthFailure) and throw or return a
clear AuthError so callers can show UI feedback; place this logic inside the
existing if that references errorData.error.errorClassName and add a TODO
fallback if refresh endpoint is not yet available.

---

Outside diff comments:
In `@hooks/use-prompt-list.ts`:
- Around line 129-131: The onError handler in the usePromptList hook currently
calls toasts.success with the error message; change it to call toasts.error so
errors are shown correctly. Locate the onError callback inside usePromptList
(the function where onError: (error: Error) => { ... } is defined) and replace
toasts.success(error.message) with toasts.error(error.message), keeping the
error parameter and message unchanged.
- Around line 58-86: The optimistic update in the setQueriesData block assumes
pages contain PromptPage directly but useGetPrompts returns
ApiResponse<PromptPage>, so update the cache shape: read and restore previous
data via queryClient.getQueriesData/getQueryData for the "prompts" key, treat
each page as ApiResponse<PromptPage> (i.e., access page.data.items), and when
toggling a prompt ID in queryClient.setQueriesData (called in your hook around
useGetPrompts / setQueriesData), update page.data.items instead of page.items
and keep the outer ApiResponse wrapper and types (replace
InfiniteData<PromptPage> usage with InfiniteData<ApiResponse<PromptPage>> or the
correct generic) so the cached structure matches the real response.
- Line 96: In the usePromptList hook, replace the incorrect success toast call
with an error toast in the error handler: change the toasts.success("좋아요 처리에
실패했습니다.") call to toasts.error(...) where the failure is handled (look for the
handler around functions like handleLike/toggleLike or the rejection/catch block
inside usePromptList). Ensure the error toast carries the same message and is
used wherever the "좋아요 처리에 실패했습니다." failure message is emitted.

---

Nitpick comments:
In `@components/header/header-search.tsx`:
- Around line 10-13: Remove the dead helper function trimAndSanitizedValue from
the header-search component: delete the function declaration and any associated
unused imports/exports or references, and replace any call sites (if any remain)
with value.trim() (the new intended behaviour). After removal, run
TypeScript/ESLint to ensure no unused symbol or import warnings remain and
update tests or typings that referenced trimAndSanitizedValue.

In `@lib/fetcher.ts`:
- Around line 9-15: The PagedResponse<T> interface is unused and should be
removed to reduce dead code; delete the interface declaration named
PagedResponse<T> from lib/fetcher.ts, run TypeScript checks (tsc) and your test
suite to ensure no references remain, and commit the change with a brief message
like "chore: remove unused PagedResponse<T> interface".
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: ca8cf9a8-e68a-4ce9-b204-ae99e0a69290

📥 Commits

Reviewing files that changed from the base of the PR and between 5f28dff and 7b09ff6.

📒 Files selected for processing (10)
  • app/(afterLogin)/(dashboard)/(community-category)/_components/community.tsx
  • app/(afterLogin)/(dashboard)/(community-category)/rank/RankList.tsx
  • app/(afterLogin)/(dashboard)/(community-category)/search/_components/search-section.tsx
  • app/(afterLogin)/(dashboard)/(community-category)/search/page.tsx
  • app/hooks/use-query-params.tsx
  • app/types/type.ts
  • components/header/header-search.tsx
  • hooks/use-prompt-list.ts
  • lib/fetcher.ts
  • queries/api/prompts.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • app/(afterLogin)/(dashboard)/(community-category)/_components/community.tsx
  • app/hooks/use-query-params.tsx

Comment on lines +19 to +25
if (q) {
await queryClient.prefetchInfiniteQuery({
queryKey: ["prompts", "search", q],
queryFn: () => useGetPrompts(q),
initialPageParam: 0,
});
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🚨 치명적 오류: React Hook을 서버 컴포넌트의 queryFn으로 사용하고 있습니다.

useGetPrompts는 React Hook입니다. 서버 컴포넌트에서 queryFn으로 호출하면 런타임 에러가 발생합니다. 또한 쿼리 키 불일치 문제가 있습니다:

  • 서버 prefetch: ["prompts", "search", q]
  • 클라이언트 (search-section.tsx): ["prompts", "ALL", currentSearch]

이로 인해 서버에서 prefetch한 데이터가 클라이언트에서 재사용되지 않습니다.

🐛 수정 제안
 import {
   dehydrate,
   HydrationBoundary,
   QueryClient,
 } from "@tanstack/react-query";

-import { useGetPrompts } from "@/hooks/use-prompt-list";
+import { fetchPrompts } from "@/queries/api/prompts";

 import { SearchSection } from "./_components/search-section";

 export default async function SearchPage({
   searchParams,
 }: {
   searchParams: Promise<{ q?: string }>;
 }) {
   const { q } = await searchParams;
   const queryClient = new QueryClient();

   if (q) {
     await queryClient.prefetchInfiniteQuery({
-      queryKey: ["prompts", "search", q],
-      queryFn: () => useGetPrompts(q),
+      queryKey: ["prompts", "ALL", q],
+      queryFn: ({ pageParam = 0 }) => fetchPrompts("ALL", pageParam as number, q),
       initialPageParam: 0,
     });
   }

   return (
     <HydrationBoundary state={dehydrate(queryClient)}>
       <SearchSection q={q} />
     </HydrationBoundary>
   );
 }

참고: TanStack Query - SSR Guide

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/`(afterLogin)/(dashboard)/(community-category)/search/page.tsx around
lines 19 - 25, You are calling the React hook useGetPrompts inside
queryClient.prefetchInfiniteQuery in the server component
(queryClient.prefetchInfiniteQuery, useGetPrompts) which is illegal and also
using a different queryKey than the client (server: ["prompts","search", q] vs
client in search-section.tsx: ["prompts","ALL", currentSearch]); replace the
hook call with the plain async data-fetcher (e.g., getPrompts / fetchPrompts —
the non-hook function that returns a Promise) as the queryFn and make the
queryKey identical to the client (or change the client key to match) so the
server-prefetched data is reused by the client; ensure queryFn accepts
pageParams and returns the same shape the client expects for infinite queries
(no React hooks used).

Comment thread lib/fetcher.ts
Comment on lines +73 to +79
if (
["TOKEN_EXPIRED", "INVALID_TOKEN"].includes(
errorData.error.errorClassName
)
) {
// 예: 로그아웃 처리 또는 토큰 재발급 로직 호출
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

토큰 만료 처리 로직이 비어있습니다.

TOKEN_EXPIRED, INVALID_TOKEN 에러를 감지하지만 실제 처리 로직(로그아웃 또는 토큰 재발급)이 구현되지 않았습니다. 현재 상태에서는 인증 실패 시 사용자가 아무런 피드백 없이 작업이 실패하게 됩니다.

💡 최소한의 개선 제안
             if (
               ["TOKEN_EXPIRED", "INVALID_TOKEN"].includes(
                 errorData.error.errorClassName
               )
             ) {
-              // 예: 로그아웃 처리 또는 토큰 재발급 로직 호출
+              // 클라이언트 사이드에서만 리다이렉트 처리
+              if (typeof window !== "undefined") {
+                window.location.href = "/login";
+              }
             }

PR 설명에서 API 명세가 아직 준비되지 않았다고 언급되어 있으니, 추후 토큰 재발급 로직 구현 시 이 부분을 함께 처리하시면 됩니다.

이 부분에 대한 구현을 도와드릴까요? 또는 TODO 이슈를 생성해드릴까요?

📝 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 (
["TOKEN_EXPIRED", "INVALID_TOKEN"].includes(
errorData.error.errorClassName
)
) {
// 예: 로그아웃 처리 또는 토큰 재발급 로직 호출
}
if (
["TOKEN_EXPIRED", "INVALID_TOKEN"].includes(
errorData.error.errorClassName
)
) {
// 클라이언트 사이드에서만 리다이렉트 처리
if (typeof window !== "undefined") {
window.location.href = "/login";
}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/fetcher.ts` around lines 73 - 79, The if-block checking
errorData.error.errorClassName for "TOKEN_EXPIRED"/"INVALID_TOKEN" is empty;
implement token-expiry handling by invoking your auth flow: call a refresh
function (e.g., refreshAuthToken()) and, if it succeeds, retry the original
request, otherwise call logoutUser() (or emit an auth failure event via
authEventEmitter/onAuthFailure) and throw or return a clear AuthError so callers
can show UI feedback; place this logic inside the existing if that references
errorData.error.errorClassName and add a TODO fallback if refresh endpoint is
not yet available.

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

Labels

feature 새로운 기능 구현

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

[Feature] 검색 페이지 작업

2 participants