-
Notifications
You must be signed in to change notification settings - Fork 0
포지션, 스킬 태그 관리 ( #issue 336 ) #345
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
""" Walkthrough태그 관리 기능이 대규모로 도입되었습니다. 스킬 태그와 포지션 태그 각각에 대한 CRUD(생성, 수정, 삭제) UI 및 API 연동이 구현되었으며, 관련 라우팅, 스타일, 쿼리 키, 상수, 훅 등이 추가 및 정비되었습니다. 기존 태그 관리 메뉴가 스킬/포지션으로 분리되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant Admin as Admin User
participant UI as AdminTagCRUD
participant API as tag.api.ts
participant Server as Backend
Admin->>UI: 태그명/이미지 입력 및 등록/수정/삭제 클릭
UI->>API: post/put/deleteSkillTag 또는 post/put/deletePositionTag 호출
API->>Server: HTTP 요청 (POST/PUT/DELETE)
Server-->>API: 처리 결과 반환
API-->>UI: Promise resolve/reject
UI-->>Admin: 성공/실패 안내 및 목록 갱신
Assessment against linked issues
Assessment against linked issues: Out-of-scope changes해당 PR의 변경사항은 모두 이슈 #336의 태그 관리 페이지 구현 목적에 부합합니다. Suggested labels
Suggested reviewers
Poem
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
npm error Exit handler never called! ✨ Finishing Touches
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed 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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
🔭 Outside diff range comments (1)
src/components/common/positionButton/PositionButton.tsx (1)
1-6: 타입 네임스페이스 누락으로 컴파일 오류 가능
React.MouseEvent타입을 사용하지만react를 import 하지 않았습니다. TypeScript 5+ 환경에서는 네임스페이스 참조 시import type이 필요합니다.-import * as S from './PositionButton.styled'; +import * as S from './PositionButton.styled'; +import type React from 'react';
🧹 Nitpick comments (18)
src/components/admin/adminTags/positions/AdminPositionItems.styled.ts (1)
1-8: Styled 컴포넌트 네이밍 개선 제안:Container라는 범용 이름이 다른 스타일 컴포넌트와 충돌할 수 있으므로,PositionItemsContainer와 같이 보다 구체적인 이름으로 변경을 권장합니다.src/models/tags.ts (1)
34-36:img타입 간소화 제안:img?: File | undefined대신img?: File로만 선언해도 동일한 의미이므로 타입을 간결하게 유지하는 것을 권장합니다.src/hooks/queries/keys.ts (1)
73-77: 키 네이밍 일관성 제안:Tag보다는TagKey또는tagKeys와 같이 접미사를 붙여 목적을 명확히 구분하는 네이밍을 고려해보세요.src/components/admin/adminTags/AdminTagsBasic.styled.ts (1)
11-19:CRUDContainer명칭이 다른 파일과 중복되어 혼란을 줄 수 있습니다
AdminTagCRUD.styled.ts에도 동일한 이름의CRUDContainer가 존재합니다. import alias 가 달라도 코드리뷰·협업 시 혼동될 수 있으니BasicCRUDContainer등으로 구체화하는 것을 제안합니다.-export const CRUDContainer = styled.section` +export const BasicCRUDContainer = styled.section`src/components/admin/adminTags/AdminTagCRUD.styled.ts (2)
4-7:CRUDContainer이름 충돌 가능성
동일 프로젝트 내에 같은 이름의 styled-component 가 복수 존재합니다. IDE 자동 import 시 잘못된 파일을 가져올 위험이 있으므로, 컨텍스트에 맞는 접두어(예:TagCRUDContainer)를 붙여 구분하는 편이 안전합니다.
24-25: 불필요한 주석 코드는 제거하여 가독성을 높여 주세요
/* align-items: center; */주석은 구현과 무관하므로 삭제를 권장합니다.src/components/admin/adminTags/skills/AdminSkillTagItems.styled.ts (1)
1-4: 빈 styled 컴포넌트 감축 검토
SkillTagItemWrapper에 현재 CSS 스타일이 정의되어 있지 않아 일반<section>태그를 사용하는 것과 기능상 차이가 없습니다. 추후 스타일이 추가될 예정이라면 그대로 두셔도 되지만, 당장 필요 없다면 불필요한 래퍼 제거를 고려해보세요.src/components/user/home/searchFiltering/filteringContents/FilteringContents.tsx (1)
21-31: 이벤트 제네릭 타입이 과도하게 제한적입니다
React.MouseEvent<HTMLDivElement>으로 한정하면e.currentTarget타입 확인에는 도움이 되지만, 실제e.target은<svg>,<span>등 다양한 요소일 수 있습니다. 이미const target = e.target as HTMLElement로 캐스팅하고 있으므로 굳이HTMLDivElement로 좁힐 실익이 적고, 오히려 추후<ul>등 다른 컨테이너로 교체될 때 타입 오류를 유발할 여지가 있습니다.-const handleSkillTagFilterClick = (e: React.MouseEvent<HTMLDivElement>) => { +const handleSkillTagFilterClick = (e: React.MouseEvent<HTMLElement>) => {타입 범위를 한 단계 넓혀 유지보수성을 확보하는 편이 안전합니다.
src/hooks/admin/useAdminTag.ts (1)
14-97: 훅 이름이 실제 역할과 불일치합니다
useAdminSkillTag라는 이름이지만 내부에서 포지션 태그까지 모두 다룹니다. 네이밍은 의도를 표현해야 하므로useAdminTagMutations처럼 범용 이름으로 변경하거나, 두 개의 전용 훅으로 분리하여 관심사를 명확히 하는 편이 좋습니다.src/components/user/projectFormComponents/projectInformationInput/positionComponent/PositionComponent.tsx (1)
31-37: 인덱스 오프셋 하드코딩 대신 ID 직접 사용 권장
idx + 1로 ID 를 보정하고 있는데, 태그 ID 가 배열 순서와 항상 1씩 offset 된다는 보장이 깨질 경우 오류가 발생합니다.position.id값을 직접 넘기는 방식이 더 견고합니다.-const handleClickSelect = ( - e: React.MouseEvent<HTMLButtonElement>, - idx: number -) => { - handleClick(e, idx + 1); +const handleClickSelect = ( + e: React.MouseEvent<HTMLButtonElement>, + id: number +) => { + handleClick(e, id); }맵핑 부분에서도
idx대신position.id를 전달하도록 수정해 주세요.src/components/admin/adminTags/skills/AdminSkillTagItems.tsx (2)
4-7: 타입·컴포넌트 명 오탈자
AdminSKillTagItemsProps처럼 대문자K가 빠져 있습니다. 컴파일에는 영향이 없으나 일관성을 위해 수정해 주세요.-interface AdminSKillTagItemsProps { +interface AdminSkillTagItemsProps {
13-23:data-id파싱 실패 시 안전장치 부족
Number()변환 결과가NaN이면 현재if (!id) return;으로 필터링하지만NaN도 falsy 로 평가되므로 의도대로 동작합니다. 다만0번 태그를 제외하려는 목적이라면isNaN(id) || id === 0처럼 명시적으로 체크해 주면 가독성이 좋아집니다.src/components/admin/adminTags/positions/AdminPositionItems.tsx (1)
12-24: 데이터 로딩 상태 및 빈 배열 처리 필요
useSearchFilteringSkillTag훅은 네트워크 요청 완료 전까지positionTagsData를 빈 배열로 유지합니다. 현재 구현에서는 빈 배열일 경우 아무것도 렌더링되지 않아 관리 페이지가 ‘비어있는 화면’처럼 보일 수 있습니다.아래와 같이 스켈레톤/로딩 UI 또는 “등록된 포지션 태그가 없습니다” 메시지를 추가해 UX 를 개선하는 방안을 고려해 주세요.
+ if (!positionTagsData.length) + return <S.EmptyMessage>포지션 태그가 없습니다.</S.EmptyMessage>;src/components/common/skillTagBox/SkillTagBox.tsx (1)
17-18: width 기본값 하드-코딩 대신 Theme 활용 권장
width='100%'를 매번 기본값으로 두는 대신,styled-components테마에 정의된 레이아웃 변수(예:theme.layout.fullWidth)를 사용하는 것이 재사용성과 일관성을 높입니다.src/api/admin/tag.api.ts (1)
38-45: API 응답값 반환 누락모든 API 함수가
await httpClient.*호출 결과를 반환하지 않고 있습니다. 호출부에서 성공/실패 여부나 메시지를 활용하려면 응답 객체를 그대로 반환하거나 필요한 데이터만 추출해 반환하는 편이 좋습니다.src/components/admin/adminTags/AdminTagsBasic.tsx (2)
10-16:TWitchTag· 오타 및 가독성 문제타입과 변수명이 모두 witch 로 표기돼 있습니다.
Which또는 더 명확한 네이밍(TTagType등)으로 교체하면 오해를 줄일 수 있습니다.
28-54:tagState타입 안정성 개선 필요
type필드를 문자열로 두면 오타로 인한 런타임 오류 가능성이 있습니다.
아래처럼 리터럴 유니온을 활용하면 컴파일 단계에서 오류를 잡을 수 있습니다.type TagKind = 'skill' | 'position'; interface TagState<T> { type: TagKind; /* ... */ }src/components/admin/adminTags/AdminTagCRUD.tsx (1)
150-157:setTimeout사용 불필요입력 초기화에 1 초 지연을 둘 이유가 없습니다. 즉시 초기화하거나, 필요 시
setTimeout 0으로 충분합니다.
지연은 UX 저하·메모리 누수 원인이 될 수 있습니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (32)
src/api/admin/tag.api.ts(1 hunks)src/components/admin/adminTags/AdminTagCRUD.styled.ts(1 hunks)src/components/admin/adminTags/AdminTagCRUD.tsx(1 hunks)src/components/admin/adminTags/AdminTagsBasic.styled.ts(1 hunks)src/components/admin/adminTags/AdminTagsBasic.tsx(1 hunks)src/components/admin/adminTags/positions/AdminPositionItems.styled.ts(1 hunks)src/components/admin/adminTags/positions/AdminPositionItems.tsx(1 hunks)src/components/admin/adminTags/positions/AdminPositionTags.tsx(1 hunks)src/components/admin/adminTags/skills/AdminSkillTagItems.styled.ts(1 hunks)src/components/admin/adminTags/skills/AdminSkillTagItems.tsx(1 hunks)src/components/admin/adminTags/skills/AdminSkillTags.tsx(1 hunks)src/components/common/admin/sidebar/sidebarList/AdminSidebarList.tsx(1 hunks)src/components/common/positionButton/PositionButton.styled.ts(0 hunks)src/components/common/positionButton/PositionButton.tsx(1 hunks)src/components/common/skillTagBox/SkillTagBox.tsx(2 hunks)src/components/user/home/projectCardLists/cardList/CardList.tsx(0 hunks)src/components/user/home/searchFiltering/filteringContents/FilteringContents.tsx(1 hunks)src/components/user/projectFormComponents/projectInformationInput/positionComponent/PositionComponent.tsx(3 hunks)src/constants/admin/sidebar.ts(1 hunks)src/constants/routes.ts(1 hunks)src/constants/user/modalMessage.ts(1 hunks)src/hooks/admin/useAdminInquiry.ts(1 hunks)src/hooks/admin/useAdminNotice.ts(1 hunks)src/hooks/admin/useAdminTag.ts(1 hunks)src/hooks/admin/useGetAllInquiries.ts(1 hunks)src/hooks/queries/keys.ts(1 hunks)src/hooks/user/useSearchFilteringSkillTag.ts(2 hunks)src/models/tags.ts(1 hunks)src/pages/admin/adminTags/AdminTags.tsx(0 hunks)src/pages/admin/adminTags/position/AdminPositionTagsPage.tsx(1 hunks)src/pages/admin/adminTags/skill/AdminSkillTagsPage.tsx(1 hunks)src/routes/AdminRoutes.tsx(2 hunks)
💤 Files with no reviewable changes (3)
- src/components/user/home/projectCardLists/cardList/CardList.tsx
- src/pages/admin/adminTags/AdminTags.tsx
- src/components/common/positionButton/PositionButton.styled.ts
🧰 Additional context used
🧬 Code Graph Analysis (13)
src/components/admin/adminTags/positions/AdminPositionItems.styled.ts (1)
src/components/admin/adminTags/AdminTagsBasic.styled.ts (1)
Container(3-9)
src/hooks/user/useSearchFilteringSkillTag.ts (1)
src/hooks/queries/keys.ts (1)
Tag(73-77)
src/pages/admin/adminTags/skill/AdminSkillTagsPage.tsx (1)
src/pages/admin/CommonAdminPage.tsx (1)
CommonAdminPage(9-20)
src/components/admin/adminTags/skills/AdminSkillTags.tsx (1)
src/components/admin/adminTags/AdminTagsBasic.tsx (1)
AdminTagsBasic(12-89)
src/pages/admin/adminTags/position/AdminPositionTagsPage.tsx (1)
src/pages/admin/CommonAdminPage.tsx (1)
CommonAdminPage(9-20)
src/constants/admin/sidebar.ts (1)
src/constants/routes.ts (1)
ADMIN_ROUTE(34-54)
src/components/admin/adminTags/positions/AdminPositionItems.tsx (2)
src/hooks/user/useSearchFilteringSkillTag.ts (1)
useSearchFilteringSkillTag(11-49)src/components/common/positionButton/PositionButton.tsx (1)
PositionButton(11-29)
src/components/common/positionButton/PositionButton.tsx (1)
src/components/common/positionButton/PositionButton.styled.ts (1)
PositionButton(3-39)
src/components/admin/adminTags/AdminTagsBasic.styled.ts (2)
src/components/admin/adminTags/positions/AdminPositionItems.styled.ts (1)
Container(3-8)src/components/admin/adminTags/AdminTagCRUD.styled.ts (1)
CRUDContainer(4-7)
src/components/admin/adminTags/skills/AdminSkillTagItems.tsx (1)
src/components/common/skillTagBox/SkillTagBox.tsx (1)
SkillTagBox(16-61)
src/hooks/admin/useAdminTag.ts (3)
src/api/admin/tag.api.ts (6)
postSkillTag(5-12)putSkillTag(14-27)deleteSkillTag(29-36)postPositionTag(38-45)putPositionTag(47-60)deletePositionTag(62-69)src/hooks/queries/keys.ts (1)
Tag(73-77)src/models/tags.ts (1)
TagFormType(34-37)
src/components/admin/adminTags/AdminTagCRUD.styled.ts (1)
src/components/user/customerService/inquiry/Inquiry.styled.ts (1)
SendButton(205-222)
src/api/admin/tag.api.ts (3)
src/api/http.api.ts (1)
httpClient(80-80)src/models/apiCommon.ts (1)
ApiCommonBasicType(6-8)src/models/tags.ts (1)
TagFormType(34-37)
🪛 Biome (1.9.4)
src/components/common/skillTagBox/SkillTagBox.tsx
[error] 40-44: Unnecessary use of boolean literals in conditional expression.
Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with
(lint/complexity/noUselessTernary)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: accessibility-test
🔇 Additional comments (16)
src/hooks/admin/useAdminInquiry.ts (1)
7-7: 대소문자 수정으로 인한 런타임 오류 예방 👍파일명 대소문자를
inquiry.api로 통일하여 case-sensitive 환경(Linux, CI)에서 발생할 수 있는MODULE_NOT_FOUND오류를 사전에 차단했습니다. 변경 내용 이상 없습니다.src/hooks/admin/useGetAllInquiries.ts (2)
3-3: 올바른 경로로 수정 완료
inquiry.api로 경로가 정정되어 OS별 모듈 해상도 문제가 해결되었습니다.
10-13:select제거로 반환 데이터량 증가 – 영향 확인 필요기존에는
select옵션으로 상위 5개 항목만 노출했던 것으로 보입니다. 옵션을 제거하면서 전체 문의 목록이 그대로 컴포넌트에 전달됩니다. 데이터 양이 많아질 경우 렌더링·메모리·네트워크 비용이 상승할 수 있으니,
- 실제 소비처에서 페이지네이션/가상 스크롤 등의 보호장치가 있는지
- 불필요하게 모든 데이터를 한 번에 가져올 필요가 없는지
를 한 번 더 점검해주세요.
src/components/admin/adminTags/positions/AdminPositionItems.styled.ts (1)
3-8: 레이아웃 스타일 적절:section요소에 flex-wrap과 gap 설정을 적용해 태그 버튼 배치가 명확해졌습니다. UI 요구사항에 잘 부합하는 선택입니다.src/hooks/admin/useAdminNotice.ts (1)
6-6: 경로 수정 일관성 확인:Notice.api에서notice.api로 import 경로 변경은 파일 시스템 대소문자 일치를 위해 적절합니다. 다른 admin API 훅들도 동일하게 수정되었는지 검토해주세요.src/models/tags.ts (1)
33-37: 새로운TagFormType인터페이스 추가: 태그 생성/수정 시name과 선택적img를 명확히 타입으로 정의한 점이 좋습니다. Form 상태 관리와 확장성도 확보되었습니다.src/constants/user/modalMessage.ts (1)
30-32: 추가된 모달 메시지 검토:duplicationTag,emptyTag,emptySkillImg메시지가 태그 관리 흐름에서 유용하며 기존 메시지 스타일과 일관됩니다.src/constants/routes.ts (1)
40-41: ```shell
#!/bin/bash브래킷 표기법으로 ADMIN_ROUTE.tags 참조 검색
rg -n "ADMIN_ROUTE['tags']"
</details> <details> <summary>src/components/common/admin/sidebar/sidebarList/AdminSidebarList.tsx (1)</summary> `21-22`: **아이콘 키 추가 후 `IconKey` 타입·사이드바 리스트 동기화 확인** `skillTags`, `positionTags`가 `IconKey` 유니온에 자동 반영되었지만, 사이드바를 구성하는 `list` 배열에서도 동일한 키 문자열을 사용해야 타입 오류가 없습니다. 해당 리스트 정의가 모두 업데이트되었는지 확인해 주세요. </details> <details> <summary>src/components/admin/adminTags/skills/AdminSkillTags.tsx (1)</summary> `3-5`: **단순 래퍼 컴포넌트 구현 적절** 별도 로직 없이 `AdminTagsBasic`을 감싸는 구조는 명확하며, 추후 확장을 위한 분리로도 적합해 보입니다. </details> <details> <summary>src/components/admin/adminTags/positions/AdminPositionTags.tsx (1)</summary> `1-5`: **AdminTagsBasic에 태그 타입 전달 검증 필요** `AdminTagsBasic`가 skill/position 구분 없이 내부 로직으로 타입을 처리하는지 확인이 필요합니다. 만약 props로 tagType(예: `'position'`)을 받도록 설계되었다면, 해당 prop 전달을 누락한 것으로 보입니다. 컴포넌트가 예상대로 동작하는지 검증해 주세요. </details> <details> <summary>src/pages/admin/adminTags/skill/AdminSkillTagsPage.tsx (1)</summary> `1-5`: **스킬 태그 관리 페이지 래퍼 구현 적절** `CommonAdminPage`에 `title='스킬 태그 관리'`를 전달하는 단순 래퍼로, 설계 의도에 부합합니다. 추가 로직이나 prop 필요 없이 현재 구조가 명확해 보입니다. </details> <details> <summary>src/pages/admin/adminTags/position/AdminPositionTagsPage.tsx (1)</summary> `1-5`: **포지션 태그 관리 페이지 래퍼 구현 적절** `CommonAdminPage`에 `title='포지션 태그 관리'`를 전달하는 단순 래퍼로, 일관성 있고 명료합니다. </details> <details> <summary>src/hooks/user/useSearchFilteringSkillTag.ts (1)</summary> `17-36`: **중앙화된 Query Key 사용 확인** `useQueries`의 `queryKey`에 inline 배열 대신 `Tag` 상수를 적용하여 캐시 일관성을 개선한 점이 좋습니다. 모든 곳에서 동일한 `Tag` 상수를 사용해 데이터 불일치를 방지하는지 확인하세요. </details> <details> <summary>src/constants/admin/sidebar.ts (1)</summary> `33-41`: **스킬/포지션 태그 항목 분리 👍** 사이드바 항목을 두 개로 나누어 사용자가 각 태그 타입을 명확히 인지할 수 있게 된 점이 좋습니다. 라우트 상수와도 일관되게 연결되어 있어 문제가 없어 보입니다. </details> <details> <summary>src/routes/AdminRoutes.tsx (1)</summary> `122-130`: **새 라우트 상수 확인 필요** `ADMIN_ROUTE.skillTags`·`ADMIN_ROUTE.positionTags` 가 constants 파일에 실제로 정의되어 있는지, 사이드바 메뉴와 URL 패턴이 일치하는지 확인해 주세요. 누락 시 빌드 타임 오류 또는 라우팅 실패가 발생합니다. </details> </blockquote></details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
| } from '../../api/projectSearchFiltering.api'; | ||
| import { Tag } from '../queries/keys'; | ||
|
|
||
| export const useSearchFilteringSkillTag = () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
훅 이름이 반환 데이터 범위와 불일치
현재 useSearchFilteringSkillTag는 skill, position, method 태그를 모두 가져오므로 이름이 과도하게 한정적입니다. 전반적인 태그 필터링을 의미하도록 useSearchFilteringTags 등으로 리네이밍을 권장합니다.
-export const useSearchFilteringSkillTag = () => {
+export const useSearchFilteringTags = () => {🤖 Prompt for AI Agents
In src/hooks/user/useSearchFilteringSkillTag.ts at line 11, the hook name
useSearchFilteringSkillTag is misleading because it returns skill, position, and
method tags, not just skill tags. Rename the hook to useSearchFilteringTags or a
similar name that reflects the broader scope of returned tags to improve clarity
and maintainability.
| $select={ | ||
| (isMain && | ||
| selectedTag?.includes(skillTagData.id) || | ||
| ((isMain && | ||
| searchFiltersSkillTag?.includes(skillTagData.id)) || | ||
| (isCreate && selectedTag?.includes(skillTagData.id)) | ||
| ? true | ||
| : false | ||
| : false) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
불필요한 삼항 연산자 제거 및 가독성 개선
$select 계산식에 중복된 selectedTag?.includes(...) 호출과 삼항 연산자가 있어 복잡도가 증가했습니다. 불필요한 ? true : false 를 없애고 조건을 평탄화하면 코드가 간결해집니다.
- $select={
- selectedTag?.includes(skillTagData.id) ||
- ((isMain &&
- searchFiltersSkillTag?.includes(skillTagData.id)) ||
- (isCreate && selectedTag?.includes(skillTagData.id))
- ? true
- : false)
- }
+ $select={
+ selectedTag?.includes(skillTagData.id) ||
+ (isMain && searchFiltersSkillTag?.includes(skillTagData.id)) ||
+ (isCreate && selectedTag?.includes(skillTagData.id))
+ }📝 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.
| $select={ | |
| (isMain && | |
| selectedTag?.includes(skillTagData.id) || | |
| ((isMain && | |
| searchFiltersSkillTag?.includes(skillTagData.id)) || | |
| (isCreate && selectedTag?.includes(skillTagData.id)) | |
| ? true | |
| : false | |
| : false) | |
| } | |
| $select={ | |
| selectedTag?.includes(skillTagData.id) || | |
| (isMain && searchFiltersSkillTag?.includes(skillTagData.id)) || | |
| (isCreate && selectedTag?.includes(skillTagData.id)) | |
| } |
🧰 Tools
🪛 Biome (1.9.4)
[error] 40-44: Unnecessary use of boolean literals in conditional expression.
Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with
(lint/complexity/noUselessTernary)
🤖 Prompt for AI Agents
In src/components/common/skillTagBox/SkillTagBox.tsx around lines 38 to 45, the
$select expression uses redundant ternary operators and repeated calls to
selectedTag?.includes(skillTagData.id), which complicates the logic. Simplify
the condition by removing the unnecessary '? true : false' and avoid duplicate
includes calls, flattening the condition to improve readability and reduce
complexity.
| const data: CRUDDataType = | ||
| state.type === 'skill' | ||
| ? skillTagsData.filter((list) => list.id === itemId)[0] | ||
| : positionTagsData.filter((list) => list.id === itemId)[0]; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
data 획득 시 안전성 부족
filter(...)[0] 는 일치 항목이 없을 때 undefined 를 반환합니다. 이후 useEffect(167번째 줄)에서 data.name 접근 시 런타임 오류가 발생할 수 있습니다.
find 로 변경하거나 null-check 를 추가해 주세요.
🤖 Prompt for AI Agents
In src/components/admin/adminTags/AdminTagCRUD.tsx around lines 55 to 59, the
code uses filter(...)[0] to get the data item, which returns undefined if no
match is found, causing runtime errors when accessing data.name later. Replace
filter(...)[0] with find(...) to safely get the first matching item or
undefined, and add a null-check before accessing properties of data to prevent
runtime errors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
조건문에 data가 있을때 name에 접근하는건데 무슨 문제가 있어?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@YouD0313 맞습니다! 죄송합니다. 코드를 다시 확인해보니 167번째 줄의 useEffect에서 if (data) 조건문으로 data가 존재할 때만 data.name에 접근하고 있네요.
useEffect(() => {
if (data) { // 여기서 이미 null check를 하고 있음
// ... data.name 접근
}
}, [data, state]);제가 조건문을 놓치고 분석했습니다. 현재 코드는 이미 안전하게 처리되어 있어서 런타임 오류가 발생하지 않을 것 같습니다. 불필요한 제안이었네요.
There was a problem hiding this 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/common/skillTagBox/SkillTagBox.tsx (1)
39-44: 불필요한 삼항 연산자 및 중복 조건 제거 필요
같은 이슈가 이전 커밋에서도 지적되었습니다.기존 코드에서는
selectedTag?.includes(...)조건을 두 번 평가하고,? true : false삼항 연산자가 불필요하게 쓰이고 있습니다. 아래와 같이 간결하게 리팩터링하면 가독성과 성능이 모두 개선됩니다.- $select={ - selectedTag?.includes(skillTagData.id) || - ((isMain && - searchFiltersSkillTag?.includes(skillTagData.id)) || - (isCreate && selectedTag?.includes(skillTagData.id)) - ? true - : false) - } + $select={ + selectedTag?.includes(skillTagData.id) || + (isMain && searchFiltersSkillTag?.includes(skillTagData.id)) + }
🧹 Nitpick comments (5)
src/hooks/user/useSearchFilteringTags.ts (1)
19-35: queryKey를 배열 형태로 통일해 캐싱 일관성을 확보하세요React-Query 문서에서는 queryKey를 배열로 통일해 쓰는 것을 권장합니다.
단일 문자열도 동작은 하지만, 배열(또는 튜플)로 두면 추후 파라미터 추가나 캐시 무효화 전략 변경 시 실수를 줄일 수 있습니다.- queryKey: Tag.skillTag, + queryKey: [Tag.skillTag], ... - queryKey: Tag.positionTag, + queryKey: [Tag.positionTag], ... - queryKey: Tag.method, + queryKey: [Tag.method],src/components/admin/adminTags/AdminTagCRUD.tsx (4)
55-59:filter(...)[0]대신find사용이 간결·성능 모두에 유리
filter로 전체 배열을 만든 뒤[0]로 첫 요소를 꺼내면 불필요한 배열이 생성됩니다.find를 쓰면 매칭되는 첫 요소를 즉시 반환하므로 읽기도 쉽고 성능 낭비도 없습니다.- ? skillTagsData.filter((list) => list.id === itemId)[0] - : positionTagsData.filter((list) => list.id === itemId)[0]; + ? skillTagsData.find((list) => list.id === itemId) + : positionTagsData.find((list) => list.id === itemId);
82-88: 중복 검사 시some으로 빠른 탈출 가능
duplication.length > 0을 확인하려고 전체 배열을 생성하고 있습니다.
Array.some을 사용하면 매칭되는 순간 루프를 종료해 더 효율적입니다.- const duplication = - state.type === 'skill' - ? skillTagsData.filter((data) => data.name === name) - : positionTagsData.filter((data) => data.name === name); - if (duplication.length > 0) { + const isDuplicated = + state.type === 'skill' + ? skillTagsData.some((data) => data.name === name) + : positionTagsData.some((data) => data.name === name); + if (isDuplicated) {
101-106: 수정 시 자기 자신 제외 로직은 👍 그러나 체이닝 중복두 번의
filter체이닝보다, 한 번에 조건을 합쳐 가독성을 높일 수 있습니다.- .filter((data) => data.id !== itemId) - .filter((data) => data.name === name) + .filter((data) => data.id !== itemId && data.name === name)
155-161:setTimeout1 초 지연은 불필요·불안정파일·텍스트 입력 초기화는 동기적으로 수행해도 무방합니다. 지연을 두면 사용자가 빠르게 연속 조작 시 상태 불일치가 발생할 수 있습니다.
- setTimeout(() => { - if (fileInputRef.current) { - fileInputRef.current.value = ''; - } - if (textInputRef.current) { - textInputRef.current.value = ''; - } - }, 1000); + if (fileInputRef.current) fileInputRef.current.value = ''; + if (textInputRef.current) textInputRef.current.value = '';
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
src/api/admin/tag.api.ts(1 hunks)src/components/admin/adminTags/AdminTagCRUD.tsx(1 hunks)src/components/admin/adminTags/AdminTagsBasic.tsx(1 hunks)src/components/admin/adminTags/positions/AdminPositionItems.tsx(1 hunks)src/components/common/skillTagBox/SkillTagBox.tsx(2 hunks)src/components/common/skillTagBox/skillTag/skillTagImg/SkillTagImg.tsx(1 hunks)src/components/user/home/searchFiltering/filteringContents/FilteringContents.tsx(1 hunks)src/components/user/mypage/myProfile/editProfile/EditProfile.tsx(2 hunks)src/components/user/projectFormComponents/projectInformationInput/ProjectInformationInput.tsx(2 hunks)src/hooks/admin/useAdminTag.ts(1 hunks)src/hooks/queries/keys.ts(1 hunks)src/hooks/user/useSearchFilteringTags.ts(1 hunks)
✅ Files skipped from review due to trivial changes (2)
- src/components/user/projectFormComponents/projectInformationInput/ProjectInformationInput.tsx
- src/components/user/mypage/myProfile/editProfile/EditProfile.tsx
🚧 Files skipped from review as they are similar to previous changes (6)
- src/hooks/admin/useAdminTag.ts
- src/components/user/home/searchFiltering/filteringContents/FilteringContents.tsx
- src/components/admin/adminTags/positions/AdminPositionItems.tsx
- src/hooks/queries/keys.ts
- src/components/admin/adminTags/AdminTagsBasic.tsx
- src/api/admin/tag.api.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/components/common/skillTagBox/SkillTagBox.tsx (1)
src/hooks/user/useSearchFilteringTags.ts (1)
useSearchFilteringTags(11-49)
🪛 Biome (1.9.4)
src/components/common/skillTagBox/SkillTagBox.tsx
[error] 40-44: Unnecessary use of boolean literals in conditional expression.
Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with
(lint/complexity/noUselessTernary)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: accessibility-test
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (3)
src/components/common/skillTagBox/skillTag/SkillTag.tsx (1)
17-18:updatedAt미존재 시 캐시 무효화 실패 가능성
updatedAt값이undefined(기존 레코드) 일 경우, 쿼리 파라미터t가 빠져 이미지 캐싱이 계속 유지될 수 있습니다.
백엔드가 모든 태그에updatedAt을 보장하지 않는다면, 기본값을 넣어 안전하게 처리해 주세요.- updatedAt={skillTagData.updatedAt} + updatedAt={skillTagData.updatedAt ?? ''}src/components/admin/adminTags/AdminTagCRUD.tsx (2)
53-57:filter(...)[0]대신find사용 권장첫 번째 일치 항목만 필요하므로
find가 의도에 더 적합하며, 불필요한 배열 생성을 피할 수 있습니다.- state.type === 'skill' - ? skillTagsData.filter((list) => list.id === itemId)[0] - : positionTagsData.filter((list) => list.id === itemId)[0]; + state.type === 'skill' + ? skillTagsData.find((list) => list.id === itemId) + : positionTagsData.find((list) => list.id === itemId);
144-159: 입력 초기화에setTimeout사용 불필요DOM ref 값 초기화를 1 초 지연시킬 이유가 명확하지 않습니다. 즉시 초기화하면 코드 간결성과 사용자 경험이 개선됩니다.
- onGetItemId(null); - setTimeout(() => { - if (fileInputRef.current) { - fileInputRef.current.value = ''; - } - if (textInputRef.current) { - textInputRef.current.value = ''; - } - }, 1000); + onGetItemId(null); + if (fileInputRef.current) fileInputRef.current.value = ''; + if (textInputRef.current) textInputRef.current.value = '';
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
src/components/admin/adminTags/AdminTagCRUD.tsx(1 hunks)src/components/common/skillTagBox/skillTag/SkillTag.tsx(1 hunks)src/components/common/skillTagBox/skillTag/skillTagImg/SkillTagImg.tsx(1 hunks)src/models/tags.ts(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- src/models/tags.ts
- src/components/common/skillTagBox/skillTag/skillTagImg/SkillTagImg.tsx
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: accessibility-test
| type Skill = Omit<SkillTag, 'createdAt'>; | ||
|
|
||
| type CRUDDataType = Skill | PositionTag; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Omit<SkillTag, 'createdAt'> 타입 오류
SkillTag 인터페이스에서 createdAt 필드가 제거되었으므로, 해당 키를 Omit 대상으로 지정하면 컴파일 에러가 발생합니다.
-type Skill = Omit<SkillTag, 'createdAt'>;
+type Skill = SkillTag; // 필요 시 다른 필드로 대체📝 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.
| type Skill = Omit<SkillTag, 'createdAt'>; | |
| type CRUDDataType = Skill | PositionTag; | |
| type Skill = SkillTag; // 필요 시 다른 필드로 대체 | |
| type CRUDDataType = Skill | PositionTag; |
🤖 Prompt for AI Agents
In src/components/admin/adminTags/AdminTagCRUD.tsx around lines 30 to 32, the
use of Omit<SkillTag, 'createdAt'> causes a type error because the SkillTag
interface no longer includes the 'createdAt' field. To fix this, remove the Omit
utility and directly use SkillTag or adjust the type definition to exclude only
existing keys. Ensure the type definition matches the current structure of
SkillTag without referencing non-existent keys.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
src/components/admin/adminTags/AdminTagCRUD.tsx (1)
53-57:filter(...)[0]대신find사용으로 가독성과 성능 모두 개선
filter(...)[0]는 조건을 만족하는 모든 요소를 끝까지 순회한 뒤 첫 번째 값만 사용합니다.Array.prototype.find를 사용하면 일치하는 항목을 만나자마자 순회를 멈추므로 불필요한 반복을 줄일 수 있고 의도도 더 명확하게 드러납니다.- const data: CRUDDataType = - state.type === 'skill' - ? skillTagsData.filter((list) => list.id === itemId)[0] - : positionTagsData.filter((list) => list.id === itemId)[0]; + const data: CRUDDataType | undefined = + state.type === 'skill' + ? skillTagsData.find((list) => list.id === itemId) + : positionTagsData.find((list) => list.id === itemId);
🧹 Nitpick comments (2)
src/components/admin/adminTags/AdminTagCRUD.tsx (2)
168-180:useEffect의존성에 전체state객체를 두면 불필요한 리렌더 유발
state는 부모 컴포넌트에서 매 렌더마다 새로운 객체로 넘어올 가능성이 높습니다. 이 경우 실제 데이터에 변화가 없더라도 effect 가 매번 실행되어 성능 저하가 발생할 수 있습니다.state.type과 같이 실제로 참조하는 필드만 의존성으로 지정해 주세요.- }, [data, state]); + }, [data, state.type]);
144-159:setTimeout으로 입력 필드 초기화 → 즉시 처리로 간단화 가능1 초 딜레이를 둘 명확한 이유가 없다면 타이머를 제거하고 바로 값을 초기화하는 편이 단순‧안정적입니다. 타임아웃은 테스트 플래키(flaky) 원인이 될 수도 있습니다.
- setTimeout(() => { - if (fileInputRef.current) { - fileInputRef.current.value = ''; - } - if (textInputRef.current) { - textInputRef.current.value = ''; - } - }, 1000); + if (fileInputRef.current) fileInputRef.current.value = ''; + if (textInputRef.current) textInputRef.current.value = '';
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/components/admin/adminTags/AdminTagCRUD.tsx(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: accessibility-test
구현내용
포지션, 스킬 태그 관리
연관이슈
close #336
Summary by CodeRabbit
신규 기능
UI/스타일
버그 수정/개선
기타