Conversation
📝 WalkthroughWalkthrough이 PR은 프롬프트 정렬 기능을 개선하고, Radix UI Select 기반의 새로운 선택 필드를 도입하며, URL 기반의 상태 관리를 추가합니다. 또한 API 타입을 업데이트하고 여러 컴포넌트의 스타일과 레이아웃을 조정합니다. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 8
🤖 Fix all issues with AI agents
In `@src/components/Card/Card.tsx`:
- Line 85: The hover translate utility in the Card component's className moves
the card down; change the utility token from hover:translate-y-0.5 to
hover:-translate-y-0.5 inside the className string in
src/components/Card/Card.tsx (the Card component) so the card lifts upward on
hover and matches the hover:shadow behavior.
In `@src/components/Input/Input.tsx`:
- Around line 74-76: InputField is receiving a flex-based CommonStyle (from
Input.styles.ts) which contains "flex items-center justify-between
min-w-[140px]" and that breaks input layout and removed the original w-full;
update InputField to avoid applying those flex-specific utilities to the raw
<input>: either remove/replace CommonStyle usage in the InputField component so
it uses input-appropriate classes (e.g., restore w-full and remove
flex/items-center/justify-between/min-w) or split CommonStyle into separate
container vs input styles and apply only the input style to InputField; check
consumer pages such as CreatePromptForm.tsx after the change to ensure layout is
restored.
- Around line 22-26: The check icon wrapped by the span with className "absolute
right-3" (SelectPrimitive.ItemIndicator) can overlap long
SelectPrimitive.ItemText; update the item container (the element that renders
SelectPrimitive.ItemText / the item row component) to add right padding (e.g.,
pr-8) so text has room before the absolute-positioned indicator, and ensure the
container is position: relative so the indicator stays anchored to the item.
- Around line 54-58: SelectPrimitive.Content is using position="popper", which
doesn't auto-match trigger width; update the Content styling to use the Radix
CSS variable so the dropdown matches the trigger width (replace the current
fixed/min-w utility with min-width: var(--radix-select-trigger-width) or
equivalent inline style/class) when rendering SelectPrimitive.Content with
position="popper" so the dropdown aligns with the trigger.
In `@src/components/Layout/Layout.tsx`:
- Around line 16-20: The conditional class string passed to cn in the Layout
component leaves the main-page class "md:w-4xl" active on non-main pages because
tailwind-merge does not remove it; update the non-main-page class list (the
conditional in className in Layout.tsx where cn(...) is called) to explicitly
override the md breakpoint (e.g., add a desired "md:w-5xl" or other md:w-* value
alongside "lg:w-7xl") so the md size changes on non-main pages; modify the
conditional branch that builds the non-main-page classes used with cn to include
the explicit md:w-* override.
In `@src/config/constants.ts`:
- Around line 24-37: SORT_OPTIONS 배열의 라벨 불일치 문제: '최신순'과 '좋아요 순'에는 '순' 접미사가 있는 반면
'조회수'만 예외이므로 사용자 표시 텍스트를 일관되게 맞춥니다; src 상수의 SORT_OPTIONS 항목 중 label 값을 찾아 '조회수'를
'조회수 순' 또는 '조회순'(팀 스타일에 맞춰 선택)으로 변경하고 다른 라벨들의 공백/접미사 스타일과 일치하도록 수정하세요.
In `@src/pages/PromptList/PromptListPage.tsx`:
- Around line 82-87: The Select is being rendered as a controlled component by
passing value={sortOrder}, so remove the redundant defaultValue prop from
Input.SelectField to avoid warnings; update the component instance
(Input.SelectField) to only use value={sortOrder}, options={SORT_OPTIONS}, and
onValueChange={handleSortChange}, and ensure the initial sortOrder state (where
it's initialized) is set to SORT_OPTIONS[0].value if you need a default.
- Around line 19-20: The code currently casts searchParams.get('sort') to
SortType without runtime validation; change the logic that sets sortOrder to
validate the raw value against the allowed keys in SORT_OPTIONS and fall back to
'latest' if invalid. Specifically, replace the direct cast of sortOrder (where
searchParams.get('sort') is used) with a small check like: read rawSort =
searchParams.get('sort'), if rawSort is a key/value present in SORT_OPTIONS then
set sortOrder = rawSort as SortType else sortOrder = 'latest'; keep the page
extraction unchanged. This ensures SortType, searchParams.get('sort'),
SORT_OPTIONS, and sortOrder are used to gate allowed values before calling the
API.
🧹 Nitpick comments (7)
src/components/Input/Input.styles.ts (1)
1-2:CommonStyle이 Select 전용으로 변경되어 InputField/TextField에 부적절한 스타일이 적용됨
CommonStyle에flex items-center justify-between min-w-[140px]가 포함되어 있는데, 이 스타일은 SelectField 트리거에는 적합하지만:
<textarea>:items-center로 인해 여러 줄 텍스트가 수직 중앙 정렬되어 어색할 수 있습니다.<input>/<textarea>:justify-between과min-w-[140px]은 일반 입력 필드에 의미 없거나 제약적입니다.w-full이 제거되어 기존 InputField/TextField가 전체 너비를 차지하지 않게 됩니다.SelectField 전용 스타일과 공통 스타일(border, rounded, transition 등)을 분리하는 것을 권장합니다.
src/components/Input/Input.types.ts (2)
4-10: React 19에서ref명시적 추가는 중복됨React 19에서는
ComponentPropsWithRef에 이미ref가 포함되어 있으므로,& { ref?: React.Ref<...> }교차 타입은 불필요합니다. 기능적으로 문제는 없지만 코드 의도가 불명확해질 수 있습니다.♻️ 정리 제안
-export type InputFieldProps = ComponentPropsWithRef<'input'> & { - ref?: React.Ref<HTMLInputElement>; -}; +export type InputFieldProps = ComponentPropsWithRef<'input'>; -export type TextFieldProps = ComponentPropsWithRef<'textarea'> & { - ref?: React.Ref<HTMLTextAreaElement>; -}; +export type TextFieldProps = ComponentPropsWithRef<'textarea'>;
17-22:SelectFieldProps의ref타입이HTMLButtonElement로 되어 있는데, 실제 연결 대상 확인 필요
ref가React.Ref<HTMLButtonElement>로 선언되어 있고,Input.tsx에서SelectPrimitive.Trigger에 전달됩니다. Radix Select의 Trigger가<button>을 렌더링하므로 타입은 맞지만,ComponentPropsWithRef<typeof SelectPrimitive.Root>를 확장하면서 Root의 props와 Trigger의 ref가 혼재되어 있어 API가 혼란스러울 수 있습니다.src/components/Input/Input.tsx (1)
16-20:SelectItem의 className 구성에 불필요한 공백 및 가독성 문제템플릿 리터럴 내 멀티라인 클래스 문자열에 들여쓰기로 인한 불필요한 공백이 포함됩니다.
cn()유틸리티가 이미 프로젝트에 존재하므로(Layout.tsx에서 import) 이를 활용하면 가독성과 안전한 클래스 병합이 가능합니다.♻️ cn() 유틸리티 활용 제안
<SelectPrimitive.Item ref={ref} - className={`relative flex w-full cursor-default select-none items-center rounded-sm text-sm outline-none px-4 py-2 text-left justify-between transition-colors focus:bg-brand-purple-light focus:text-brand-purple data-[state=checked]:bg-brand-purple-light data-[state=checked]:text-brand-purple data-disabled:pointer-events-none data-disabled:opacity-50 - ${className ?? ''} - `} + className={cn( + 'relative flex w-full cursor-default select-none items-center rounded-sm text-sm outline-none px-4 py-2 text-left justify-between transition-colors focus:bg-brand-purple-light focus:text-brand-purple data-[state=checked]:bg-brand-purple-light data-[state=checked]:text-brand-purple data-disabled:pointer-events-none data-disabled:opacity-50', + className + )} {...props}>src/pages/CreatePrompt/_components/CreatePromptForm.tsx (2)
139-151: PlatformController도 category와 동일한{...field}스프레드 이슈가 있습니다.위 카테고리
Controller에 대한 코멘트와 동일하게, 필요한 props만 명시적으로 전달하는 것을 권장합니다.♻️ 동일한 패턴 적용 제안
render={({ field }) => ( <Input.SelectField - {...field} + value={field.value} placeholder="플랫폼을 선택하세요" options={safePlatformOptions} onValueChange={field.onChange} /> )}
124-136: SelectField에{...field}스프레드 시 불필요한 props를 명시적으로 처리하는 것이 권장됩니다.
SelectField컴포넌트는 받은 props를 그대로SelectPrimitive.Root에 전달합니다.{...field}를 스프레드하면onChange,onBlur,name등 Radix Select가 인식하지 못하는 props도 함께 전달됩니다. Radix UI는 일반적으로 미인식 props를 무시하지만, 필요한 props만 명시적으로 전달하는 것이 더 명확하고 유지보수하기 좋습니다.♻️ 명시적 props 전달 방식 제안
render={({ field }) => ( <Input.SelectField - {...field} + value={field.value} placeholder="카테고리를 선택하세요" options={safeCategoryOptions} onValueChange={field.onChange} /> )}src/pages/PromptList/PromptListPage.tsx (1)
43-57:setSearchParams가 기존 파라미터를 모두 교체합니다.현재는
sort와page만 사용하므로 문제가 없지만, 향후 검색어나 필터 등 추가 파라미터가 생길 경우 기존 값이 유실됩니다. 확장성을 고려하면 기존 파라미터를 유지하는 패턴이 더 안전합니다.♻️ 기존 파라미터를 유지하는 방식 제안
const handleSortChange = (newSort: string) => { - setSearchParams({ - sort: newSort, - page: '1', + setSearchParams((prev) => { + prev.set('sort', newSort); + prev.set('page', '1'); + return prev; }); }; const handlePageChange = (newPage: number) => { - setSearchParams({ - sort: sortOrder, - page: String(newPage), + setSearchParams((prev) => { + prev.set('page', String(newPage)); + return prev; }); window.scrollTo(0, 0); };
| <article | ||
| key={id} | ||
| className="flex flex-col h-58 gap-3 px-5 pt-5 pb-4 group bg-white rounded-2xl border border-gray-200 overflow-hidden cursor-pointer transition-all shadow-[0_1px_3px_0_rgba(0,0,0,0.04)] hover:shadow-[0_8px_24px_-4px_rgba(109,91,208,0.12),0_4px_8px_-2px_rgba(109,91,208,0.08)] hover:-translate-y-0.5 hover:border-brand-purple-border" | ||
| className="flex flex-col h-58 gap-3 px-5 pt-5 pb-4 group bg-white rounded-2xl border border-gray-200 overflow-hidden cursor-pointer transition-all shadow-[0_1px_3px_0_rgba(0,0,0,0.04)] hover:shadow-[0_8px_24px_-4px_rgba(109,91,208,0.12),0_4px_8px_-2px_rgba(109,91,208,0.08)] hover:translate-y-0.5 hover:border-brand-purple-border" |
There was a problem hiding this comment.
호버 시 카드가 아래로 이동하는 것은 의도된 동작인지 확인 필요
hover:translate-y-0.5는 호버 시 카드를 아래로 이동시킵니다. 일반적으로 카드 호버 효과는 hover:-translate-y-0.5로 카드를 위로 들어올려 부유(lift) 효과를 줍니다. 현재 호버 시 그림자가 커지면서(hover:shadow-[...]) 카드가 아래로 이동하는 것은 시각적으로 모순됩니다. 기존의 -translate-y-0.5에서 - 부호가 실수로 제거된 것으로 보입니다.
🐛 수정 제안
- className="flex flex-col h-58 gap-3 px-5 pt-5 pb-4 group bg-white rounded-2xl border border-gray-200 overflow-hidden cursor-pointer transition-all shadow-[0_1px_3px_0_rgba(0,0,0,0.04)] hover:shadow-[0_8px_24px_-4px_rgba(109,91,208,0.12),0_4px_8px_-2px_rgba(109,91,208,0.08)] hover:translate-y-0.5 hover:border-brand-purple-border"
+ className="flex flex-col h-58 gap-3 px-5 pt-5 pb-4 group bg-white rounded-2xl border border-gray-200 overflow-hidden cursor-pointer transition-all shadow-[0_1px_3px_0_rgba(0,0,0,0.04)] hover:shadow-[0_8px_24px_-4px_rgba(109,91,208,0.12),0_4px_8px_-2px_rgba(109,91,208,0.08)] hover:-translate-y-0.5 hover:border-brand-purple-border"📝 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.
| className="flex flex-col h-58 gap-3 px-5 pt-5 pb-4 group bg-white rounded-2xl border border-gray-200 overflow-hidden cursor-pointer transition-all shadow-[0_1px_3px_0_rgba(0,0,0,0.04)] hover:shadow-[0_8px_24px_-4px_rgba(109,91,208,0.12),0_4px_8px_-2px_rgba(109,91,208,0.08)] hover:translate-y-0.5 hover:border-brand-purple-border" | |
| className="flex flex-col h-58 gap-3 px-5 pt-5 pb-4 group bg-white rounded-2xl border border-gray-200 overflow-hidden cursor-pointer transition-all shadow-[0_1px_3px_0_rgba(0,0,0,0.04)] hover:shadow-[0_8px_24px_-4px_rgba(109,91,208,0.12),0_4px_8px_-2px_rgba(109,91,208,0.08)] hover:-translate-y-0.5 hover:border-brand-purple-border" |
🤖 Prompt for AI Agents
In `@src/components/Card/Card.tsx` at line 85, The hover translate utility in the
Card component's className moves the card down; change the utility token from
hover:translate-y-0.5 to hover:-translate-y-0.5 inside the className string in
src/components/Card/Card.tsx (the Card component) so the card lifts upward on
hover and matches the hover:shadow behavior.
| <span className="absolute right-3"> | ||
| <SelectPrimitive.ItemIndicator> | ||
| <Icon name="check" size="sm" /> | ||
| </SelectPrimitive.ItemIndicator> | ||
| </span> |
There was a problem hiding this comment.
체크 아이콘 absolute right-3 위치가 ItemText와 겹칠 수 있음
SelectPrimitive.ItemText의 텍스트가 길 경우, absolute right-3으로 배치된 체크 아이콘과 겹칠 수 있습니다. 아이템에 pr-8 등의 오른쪽 패딩을 추가하여 텍스트와 아이콘 간 충돌을 방지해 주세요.
♻️ 패딩 추가 제안
- className={`relative flex w-full cursor-default select-none items-center rounded-sm text-sm outline-none px-4 py-2 text-left justify-between transition-colors ...`}
+ className={`relative flex w-full cursor-default select-none items-center rounded-sm text-sm outline-none pl-4 pr-8 py-2 text-left justify-between transition-colors ...`}🤖 Prompt for AI Agents
In `@src/components/Input/Input.tsx` around lines 22 - 26, The check icon wrapped
by the span with className "absolute right-3" (SelectPrimitive.ItemIndicator)
can overlap long SelectPrimitive.ItemText; update the item container (the
element that renders SelectPrimitive.ItemText / the item row component) to add
right padding (e.g., pr-8) so text has room before the absolute-positioned
indicator, and ensure the container is position: relative so the indicator stays
anchored to the item.
| <SelectPrimitive.Portal> | ||
| <SelectPrimitive.Content | ||
| className="relative overflow-hidden text-gray-900 left-0 bg-white border border-gray-200 rounded-lg shadow-lg z-50 min-w-50 py-1 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2" | ||
| position="popper" | ||
| sideOffset={4}> |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check for tailwindcss-animate in package.json and dependencies
if [ -f "package.json" ]; then
echo "=== Checking package.json for tailwindcss-animate ==="
rg "tailwindcss-animate" package.json
echo ""
echo "=== Checking package.json for any animate-related packages ==="
rg "animate" package.json
fiRepository: promlog/promlog-client
Length of output: 183
🏁 Script executed:
#!/bin/bash
# Check for Tailwind config file
echo "=== Looking for Tailwind config files ==="
fd -e "config.js" -e "config.ts" -e "config.mjs" | grep -i tail
echo ""
echo "=== Listing tailwind-related files ==="
fd -e "tailwind" -e "tw-"Repository: promlog/promlog-client
Length of output: 147
🏁 Script executed:
#!/bin/bash
# Check the actual Input component to see context
echo "=== Examining Input.tsx file ==="
if [ -f "src/components/Input/Input.tsx" ]; then
cat -n src/components/Input/Input.tsx | head -80
fiRepository: promlog/promlog-client
Length of output: 3982
🏁 Script executed:
#!/bin/bash
# Search more broadly for Tailwind configuration
echo "=== Checking for any config files (broader search) ==="
fd "config" | head -20
echo ""
echo "=== Checking package.json location and full content ==="
cat package.json | head -50Repository: promlog/promlog-client
Length of output: 1921
🏁 Script executed:
#!/bin/bash
# Look for CSS files and PostCSS config
echo "=== Looking for CSS and config files ==="
fd -e "css" -e "postcss.config" -e "tailwind.config" -e "vite.config" -e "tsconfig" | head -30Repository: promlog/promlog-client
Length of output: 121
🏁 Script executed:
#!/bin/bash
# Check if there's any Tailwind class definitions in CSS files
echo "=== Searching for animation-related CSS definitions ==="
rg "animate-in|animate-out|fade-in|zoom-in" --type css -A 2Repository: promlog/promlog-client
Length of output: 121
🏁 Script executed:
#!/bin/bash
echo "=== Checking global.css content ==="
cat -n src/global.cssRepository: promlog/promlog-client
Length of output: 4156
🏁 Script executed:
#!/bin/bash
echo "=== Checking vite.config.ts ==="
cat -n vite.config.tsRepository: promlog/promlog-client
Length of output: 1734
🏁 Script executed:
#!/bin/bash
echo "=== Checking radix-ui version ==="
rg "radix-ui" package.json -A 1Repository: promlog/promlog-client
Length of output: 149
🏁 Script executed:
#!/bin/bash
echo "=== Searching for any width-related CSS or configurations for SelectField ==="
rg "radix-select-trigger-width|select.*width|content.*width" -A 2Repository: promlog/promlog-client
Length of output: 287
position="popper" 사용 시 Content 너비가 트리거와 일치하지 않을 수 있음
position="popper" 모드에서는 드롭다운 Content의 너비가 트리거 너비와 자동으로 일치하지 않습니다. CSS 변수 --radix-select-trigger-width를 활용하여 Content 너비를 트리거에 맞출 수 있습니다:
min-width: var(--radix-select-trigger-width)🤖 Prompt for AI Agents
In `@src/components/Input/Input.tsx` around lines 54 - 58, SelectPrimitive.Content
is using position="popper", which doesn't auto-match trigger width; update the
Content styling to use the Radix CSS variable so the dropdown matches the
trigger width (replace the current fixed/min-w utility with min-width:
var(--radix-select-trigger-width) or equivalent inline style/class) when
rendering SelectPrimitive.Content with position="popper" so the dropdown aligns
with the trigger.
| const InputField = ({ className, ref, ...restProps }: InputFieldProps) => { | ||
| return <input ref={ref} className={`py-3 ${CommonStyle} ${className ?? ''}`} {...restProps} />; | ||
| }; |
There was a problem hiding this comment.
InputField에 flex 기반 CommonStyle이 적용되어 입력 필드 레이아웃이 깨질 수 있음
Input.styles.ts 리뷰에서 언급한 것과 동일한 이슈입니다. CommonStyle의 flex items-center justify-between min-w-[140px]은 <input> 요소에 적합하지 않으며, 기존의 w-full이 제거되어 입력 필드가 전체 너비를 차지하지 않습니다. 기존 InputField를 사용하는 페이지(예: CreatePromptForm.tsx)에서 레이아웃이 깨지는지 확인이 필요합니다.
🤖 Prompt for AI Agents
In `@src/components/Input/Input.tsx` around lines 74 - 76, InputField is receiving
a flex-based CommonStyle (from Input.styles.ts) which contains "flex
items-center justify-between min-w-[140px]" and that breaks input layout and
removed the original w-full; update InputField to avoid applying those
flex-specific utilities to the raw <input>: either remove/replace CommonStyle
usage in the InputField component so it uses input-appropriate classes (e.g.,
restore w-full and remove flex/items-center/justify-between/min-w) or split
CommonStyle into separate container vs input styles and apply only the input
style to InputField; check consumer pages such as CreatePromptForm.tsx after the
change to ensure layout is restored.
| className={cn( | ||
| 'max-w-7xl mx-auto px-4 py-8 sm:px-6 lg:px-8', | ||
| 'max-w-7xl mx-auto px-4 py-8 sm:px-6 lg:px-8 lg:w-6xl md:w-4xl sm:w-2xl', | ||
| !isMainPage && | ||
| 'lg:w-7xl min-h-[calc(100vh-4rem)] bg-white/95 backdrop-blur-sm border-x border-gray-200 shadow-[0_1px_3px_0_rgba(0,0,0,0.05)] flex justify-center sm:w-4xl' | ||
| )}> |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Find and read the Button.styles file to understand cn utility
find src -name "*Button*" -type f | head -20Repository: promlog/promlog-client
Length of output: 328
🏁 Script executed:
# Also check for the cn utility definition
rg "export.*cn\s*=" src/ -A 3Repository: promlog/promlog-client
Length of output: 48
🏁 Script executed:
# Read the Layout.tsx file to verify the code
cat -n src/components/Layout/Layout.tsx | head -50Repository: promlog/promlog-client
Length of output: 1123
🏁 Script executed:
# Read Button.styles.ts to see the cn implementation
cat -n src/components/Button/Button.styles.tsRepository: promlog/promlog-client
Length of output: 1209
비 메인 페이지에서 md:w-4xl이 명시적으로 오버라이드되지 않음
cn 함수가 tailwind-merge를 사용하므로, 메인 페이지 클래스(Line 17)의 md:w-4xl이 비 메인 페이지 조건(Line 19)에서도 그대로 적용됩니다. 현재 상태에서 비 메인 페이지의 반응형 너비는 sm:w-4xl → md:w-4xl (변화 없음) → lg:w-7xl이 되어, md 브레이크포인트에서 스케일링이 제대로 되지 않습니다. 의도에 맞게 비 메인 페이지의 md 브레이크포인트를 명시적으로 오버라이드하세요.
예: Line 19에 md:w-5xl (또는 다른 값) 추가
🤖 Prompt for AI Agents
In `@src/components/Layout/Layout.tsx` around lines 16 - 20, The conditional class
string passed to cn in the Layout component leaves the main-page class
"md:w-4xl" active on non-main pages because tailwind-merge does not remove it;
update the non-main-page class list (the conditional in className in Layout.tsx
where cn(...) is called) to explicitly override the md breakpoint (e.g., add a
desired "md:w-5xl" or other md:w-* value alongside "lg:w-7xl") so the md size
changes on non-main pages; modify the conditional branch that builds the
non-main-page classes used with cn to include the explicit md:w-* override.
| export const SORT_OPTIONS = [ | ||
| { | ||
| label: '최신순', | ||
| value: 'latest', | ||
| }, | ||
| { | ||
| label: '좋아요 순', | ||
| value: 'likes', | ||
| }, | ||
| { | ||
| label: '조회수', | ||
| value: 'views', | ||
| }, | ||
| ]; |
There was a problem hiding this comment.
정렬 옵션 라벨의 일관성 부족
최신순, 좋아요 순에는 '순' 접미사가 있지만, 조회수에는 없습니다. 사용자에게 표시되는 텍스트이므로 조회수 순 또는 조회순으로 통일하는 것이 좋습니다.
✏️ 수정 제안
{
- label: '조회수',
+ label: '조회수 순',
value: 'views',
},📝 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.
| export const SORT_OPTIONS = [ | |
| { | |
| label: '최신순', | |
| value: 'latest', | |
| }, | |
| { | |
| label: '좋아요 순', | |
| value: 'likes', | |
| }, | |
| { | |
| label: '조회수', | |
| value: 'views', | |
| }, | |
| ]; | |
| export const SORT_OPTIONS = [ | |
| { | |
| label: '최신순', | |
| value: 'latest', | |
| }, | |
| { | |
| label: '좋아요 순', | |
| value: 'likes', | |
| }, | |
| { | |
| label: '조회수 순', | |
| value: 'views', | |
| }, | |
| ]; |
🤖 Prompt for AI Agents
In `@src/config/constants.ts` around lines 24 - 37, SORT_OPTIONS 배열의 라벨 불일치 문제:
'최신순'과 '좋아요 순'에는 '순' 접미사가 있는 반면 '조회수'만 예외이므로 사용자 표시 텍스트를 일관되게 맞춥니다; src 상수의
SORT_OPTIONS 항목 중 label 값을 찾아 '조회수'를 '조회수 순' 또는 '조회순'(팀 스타일에 맞춰 선택)으로 변경하고 다른
라벨들의 공백/접미사 스타일과 일치하도록 수정하세요.
| const page = Number(searchParams.get('page')) || 1; | ||
| const sortOrder = (searchParams.get('sort') as SortType) || 'latest'; |
There was a problem hiding this comment.
URL에서 가져온 sort 값에 대한 타입 검증이 없습니다.
as SortType은 런타임 검증 없이 타입만 단언합니다. 사용자가 URL에 ?sort=invalid를 직접 입력하면 검증되지 않은 값이 API에 그대로 전달됩니다.
🛡️ SortType 유효성 검증 추가 제안
+import { SORT_OPTIONS } from '../../config/constants';
+
+const isValidSortType = (value: string | null): value is SortType =>
+ SORT_OPTIONS.some((opt) => opt.value === value);
+
const page = Number(searchParams.get('page')) || 1;
- const sortOrder = (searchParams.get('sort') as SortType) || 'latest';
+ const rawSort = searchParams.get('sort');
+ const sortOrder: SortType = isValidSortType(rawSort) ? rawSort : 'latest';참고: SORT_OPTIONS는 이미 Line 10에서 import되어 있으므로 별도 import는 불필요합니다.
📝 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.
| const page = Number(searchParams.get('page')) || 1; | |
| const sortOrder = (searchParams.get('sort') as SortType) || 'latest'; | |
| const isValidSortType = (value: string | null): value is SortType => | |
| SORT_OPTIONS.some((opt) => opt.value === value); | |
| const page = Number(searchParams.get('page')) || 1; | |
| const rawSort = searchParams.get('sort'); | |
| const sortOrder: SortType = isValidSortType(rawSort) ? rawSort : 'latest'; |
🤖 Prompt for AI Agents
In `@src/pages/PromptList/PromptListPage.tsx` around lines 19 - 20, The code
currently casts searchParams.get('sort') to SortType without runtime validation;
change the logic that sets sortOrder to validate the raw value against the
allowed keys in SORT_OPTIONS and fall back to 'latest' if invalid. Specifically,
replace the direct cast of sortOrder (where searchParams.get('sort') is used)
with a small check like: read rawSort = searchParams.get('sort'), if rawSort is
a key/value present in SORT_OPTIONS then set sortOrder = rawSort as SortType
else sortOrder = 'latest'; keep the page extraction unchanged. This ensures
SortType, searchParams.get('sort'), SORT_OPTIONS, and sortOrder are used to gate
allowed values before calling the API.
| <Input.SelectField | ||
| defaultValue={SORT_OPTIONS[0].value} | ||
| value={sortOrder} | ||
| options={SORT_OPTIONS} | ||
| onValueChange={handleSortChange} | ||
| /> |
There was a problem hiding this comment.
defaultValue와 value를 동시에 사용하고 있습니다.
Radix UI Select에서 value를 전달하면 제어 컴포넌트(controlled component)로 동작합니다. 이 경우 defaultValue는 무시되거나 경고를 발생시킬 수 있습니다. value={sortOrder}가 이미 있으므로 defaultValue를 제거하세요.
🔧 defaultValue 제거 제안
<Input.SelectField
- defaultValue={SORT_OPTIONS[0].value}
value={sortOrder}
options={SORT_OPTIONS}
onValueChange={handleSortChange}
/>📝 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.
| <Input.SelectField | |
| defaultValue={SORT_OPTIONS[0].value} | |
| value={sortOrder} | |
| options={SORT_OPTIONS} | |
| onValueChange={handleSortChange} | |
| /> | |
| <Input.SelectField | |
| value={sortOrder} | |
| options={SORT_OPTIONS} | |
| onValueChange={handleSortChange} | |
| /> |
🤖 Prompt for AI Agents
In `@src/pages/PromptList/PromptListPage.tsx` around lines 82 - 87, The Select is
being rendered as a controlled component by passing value={sortOrder}, so remove
the redundant defaultValue prop from Input.SelectField to avoid warnings; update
the component instance (Input.SelectField) to only use value={sortOrder},
options={SORT_OPTIONS}, and onValueChange={handleSortChange}, and ensure the
initial sortOrder state (where it's initialized) is set to SORT_OPTIONS[0].value
if you need a default.
✅ 체크리스트
(latest/likes/views)📝 작업 상세 내용
1. Select 컴포넌트 radix-ui 사용해 리팩토링
2. 프롬프트 정렬 기능 구현
✅ 셀프 체크리스트
이슈 번호: #49
Summary by CodeRabbit
릴리스 노트
새로운 기능
개선 사항