Conversation
|
""" Walkthrough이 변경사항은 이미지 업로드 기능을 위한 커스텀 훅 추가, ChoiceChip 및 ProfileCircle 등 디자인 시스템 컴포넌트의 props 구조 개선, 날짜 및 시간 포맷팅 로직의 통합, API 응답 타입 및 에러 코드 처리 강화, 여러 페이지에서 빈 상태 메시지 및 동적 데이터 렌더링 개선, 그리고 파일 업로드·드래그 앤 드롭 로직 리팩토링 등을 포함합니다. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant FileUpload
participant useImageUpload
participant uploadFile
participant ParentComponent
User->>FileUpload: 파일 드래그/선택
FileUpload->>useImageUpload: handleFileChange/handleDrop
useImageUpload->>uploadFile: 파일 검증 후 업로드
uploadFile-->>useImageUpload: 업로드 성공 시 URL 반환
useImageUpload->>FileUpload: previewUrl 상태 업데이트
useImageUpload->>ParentComponent: onSuccess 콜백 호출 (URL 전달)
sequenceDiagram
participant User
participant MultilineTextField
participant EventTag
User->>MultilineTextField: 텍스트 입력(조합 시작)
MultilineTextField->>EventTag: onCompositionStart
EventTag->>EventTag: isComposing = true
User->>MultilineTextField: Enter 입력(조합 중)
MultilineTextField->>EventTag: onKeyDown
EventTag->>EventTag: Enter 무시 (isComposing)
User->>MultilineTextField: 조합 종료
MultilineTextField->>EventTag: onCompositionEnd
EventTag->>EventTag: isComposing = false
User->>MultilineTextField: Enter 입력(조합 아님)
MultilineTextField->>EventTag: onKeyDown
EventTag->>EventTag: 태그 추가 처리
Possibly related PRs
Suggested reviewers
Poem
Note ⚡️ AI Code Reviews for VS Code, Cursor, WindsurfCodeRabbit now has a plugin for VS Code, Cursor and Windsurf. This brings AI code reviews directly in the code editor. Each commit is reviewed immediately, finding bugs before the PR is raised. Seamless context handoff to your AI code agent ensures that you can easily incorporate review feedback. Note ⚡️ Faster reviews with cachingCodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 30th. To opt out, configure 📜 Recent review detailsConfiguration used: CodeRabbit UI ⛔ Files ignored due to path filters (2)
📒 Files selected for processing (5)
✅ Files skipped from review due to trivial changes (2)
🚧 Files skipped from review as they are similar to previous changes (2)
⏰ Context from checks skipped due to timeout of 90000ms (1)
🔇 Additional comments (3)
✨ 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.
Actionable comments posted: 3
🔭 Outside diff range comments (2)
design-system/stories/ChoiceChip.stories.tsx (1)
18-19: 🛠️ Refactor suggestionargTypes의 defaultValue도 업데이트가 필요합니다.
옵션 형식을 객체 배열로 변경했지만, argTypes의 defaultValue는 여전히 문자열 배열 형식입니다. 일관성을 위해 이 부분도 업데이트하는 것이 좋겠습니다.
defaultValue: ['Option 1', 'Option 2'], +defaultValue: [{ label: 'Option 1', value: 'option_1' }, { label: 'Option 2', value: 'option_2' }],src/pages/event/ui/EventDetailsPage.tsx (1)
108-108:⚠️ Potential issue보안 위험: dangerouslySetInnerHTML 사용 검토 필요
HTML 콘텐츠를 직접 삽입하는
dangerouslySetInnerHTML은 XSS(Cross-Site Scripting) 공격에 취약할 수 있습니다. 신뢰할 수 없는 소스에서 가져온 데이터를 렌더링할 때 특히 위험합니다.다음과 같이 DOMPurify 같은 라이브러리를 사용하여 HTML을 안전하게 처리하는 것을 권장합니다:
- <div - className="text-sm md:text-base py-3" - dangerouslySetInnerHTML={{ __html: event.result.description }} - ></div> + import DOMPurify from 'dompurify'; + + <div className="text-sm md:text-base py-3" + dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(event.result.description) }} + ></div>
🧹 Nitpick comments (3)
design-system/ui/ChoiceChip.tsx (1)
52-52: 불필요한 폴백 로직이 있습니다.인터페이스에서
value를 필수 속성으로 정의했으므로option.value || ''폴백은 불필요합니다.-onClick={() => handleClick(option.value || '')} +onClick={() => handleClick(option.value)}src/shared/lib/date.ts (1)
17-23: 날짜/시간 포맷팅을 위한 유틸리티 함수 추가새로운
formatISO함수는 날짜와 시간 문자열을 결합하여 KST(UTC+9) 타임존이 적용된 ISO 문자열을 반환합니다. 이 함수는 애플리케이션 전체에서 날짜/시간 포맷팅 로직을 중앙화하여 일관성을 개선합니다.상수를 사용하여 코드의 의도를 더 명확하게 표현할 수 있습니다:
- const kstDate = new Date(newDate.getTime() + 9 * 60 * 60 * 1000); // UTC+9 + const KST_OFFSET_MS = 9 * 60 * 60 * 1000; // UTC+9 in milliseconds + const kstDate = new Date(newDate.getTime() + KST_OFFSET_MS);src/pages/event/ui/host/HostCreationPage.tsx (1)
63-81: 이미지 업로드 UI 개선이미지 업로드 UI를 동적으로 미리보기를 표시하도록 개선했습니다. 파일 입력을 숨기고 버튼 클릭으로 트리거하는 패턴을 사용하여 사용자 경험을 향상시켰습니다.
이미지 업로드 중에 로딩 상태를 표시하는 기능을 추가하면 사용자 경험을 더욱 향상시킬 수 있습니다. 다음과 같이 로딩 상태를 추가하는 것을 고려해보세요:
- const { previewUrl, fileInputRef, handleFileChange } = useImageUpload({ + const { previewUrl, fileInputRef, handleFileChange, isLoading } = useImageUpload({ value: hostState.profileImageUrl, onSuccess: url => { setHostState(prev => ({ ...prev, profileImageUrl: url, })); }, }); // UI 부분 - <img - src={previewUrl || basicProfile} - alt="기본 프로필 이미지" - className="w-24 h-24 object-cover rounded-full" - /> + {isLoading ? ( + <div className="w-24 h-24 flex items-center justify-center rounded-full bg-gray-100"> + <div className="w-8 h-8 border-4 border-t-primary border-r-transparent border-b-primary border-l-transparent rounded-full animate-spin"></div> + </div> + ) : ( + <img + src={previewUrl || basicProfile} + alt="기본 프로필 이미지" + className="w-24 h-24 object-cover rounded-full" + /> + )}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (3)
public/assets/banners/1.pngis excluded by!**/*.pngpublic/assets/banners/2.pngis excluded by!**/*.pngpublic/assets/banners/3.pngis excluded by!**/*.png
📒 Files selected for processing (28)
design-system/stories/ChoiceChip.stories.tsx(2 hunks)design-system/ui/ChoiceChip.tsx(2 hunks)design-system/ui/Profile.tsx(2 hunks)design-system/ui/textFields/MultilineTextField.tsx(3 hunks)src/entities/event/hook/useEventHook.ts(1 hunks)src/entities/event/hook/useEventListHook.ts(1 hunks)src/features/event/ui/DatePicker.tsx(5 hunks)src/features/event/ui/EventTag.tsx(3 hunks)src/features/event/ui/FileUpload.tsx(3 hunks)src/features/event/ui/ShareEventModal.tsx(3 hunks)src/features/home/ui/EventSliderSection.tsx(2 hunks)src/features/ticket/hooks/useTicketHook.ts(3 hunks)src/features/ticket/model/ticket.ts(1 hunks)src/features/ticket/ui/TicketDatePicker.tsx(3 hunks)src/pages/bookmark/ui/BookmarkPage.tsx(1 hunks)src/pages/dashboard/ui/ticket/TicketCreatePage.tsx(0 hunks)src/pages/event/ui/EventDetailsPage.tsx(1 hunks)src/pages/event/ui/host/HostCreationPage.tsx(3 hunks)src/pages/home/ui/MainPage.tsx(2 hunks)src/pages/menu/ui/MyTicketPage.tsx(3 hunks)src/pages/menu/ui/myHost/MyHostPage.tsx(1 hunks)src/pages/search/ui/SearchPage.tsx(2 hunks)src/shared/hooks/useImageUpload.ts(1 hunks)src/shared/lib/date.ts(1 hunks)src/shared/types/api/apiResponse.ts(1 hunks)src/shared/types/api/http-client.ts(2 hunks)src/shared/ui/backgrounds/HostDetailLayout.tsx(2 hunks)src/widgets/main/ui/Banner.tsx(2 hunks)
💤 Files with no reviewable changes (1)
- src/pages/dashboard/ui/ticket/TicketCreatePage.tsx
🧰 Additional context used
🧬 Code Graph Analysis (5)
src/features/ticket/hooks/useTicketHook.ts (2)
src/shared/types/api/apiResponse.ts (1)
ApiResponse(1-5)src/features/ticket/model/ticket.ts (1)
CreateTicketRequest(1-10)
src/pages/home/ui/MainPage.tsx (3)
src/app/provider/authStore.ts (1)
useAuthStore(17-33)src/shared/types/mainCardButtonType.ts (1)
cardButtons(1-26)design-system/ui/buttons/VerticalCardButton.tsx (1)
VerticalCardButton(13-56)
src/features/event/ui/DatePicker.tsx (1)
src/shared/lib/date.ts (1)
formatISO(17-23)
src/shared/hooks/useImageUpload.ts (1)
src/features/event/hooks/usePresignedUrlHook.ts (1)
uploadFile(37-52)
src/features/ticket/ui/TicketDatePicker.tsx (1)
src/shared/lib/date.ts (1)
formatISO(17-23)
🪛 Biome (1.9.4)
src/pages/event/ui/EventDetailsPage.tsx
[error] 112-112: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: storybook
🔇 Additional comments (63)
design-system/ui/textFields/MultilineTextField.tsx (3)
9-10: IME 입력을 위한 프로퍼티 추가, 좋은 개선입니다.한글, 중국어, 일본어와 같은 조합형 문자 입력을 위한 이벤트 핸들러를 추가했습니다. IME 입력 처리를 위해 필요한 속성을 적절하게 타입화했습니다.
25-26: 새 프로퍼티 구조 분해 할당 확인.새로 추가된 컴포지션 이벤트 핸들러를 컴포넌트의 props에 올바르게 포함시켰습니다.
46-47: TextArea 요소에 이벤트 핸들러 전달.컴포지션 이벤트 핸들러가 내부 textarea 요소에 올바르게 전달되었습니다. 이는 IME 입력 처리를 위한 필수적인 단계입니다.
src/features/event/ui/EventTag.tsx (3)
12-12: IME 입력 상태 추적을 위한 상태 변수 추가.
isComposing상태 변수를 통해 사용자가 한글과 같은 조합형 문자를 입력 중인지 추적합니다. 이는 비영어권 사용자의 입력 경험을 개선하는 좋은 접근법입니다.
22-22: Enter 키 처리 로직 개선.Enter 키 처리 시
!isComposing조건을 추가하여 한글과 같은 조합형 문자 입력 중에는 Enter 키가 태그 제출을 트리거하지 않도록 개선했습니다. 이는 사용자 경험을 크게 향상시키는 중요한 수정입니다.
61-62: 컴포지션 이벤트 핸들러 구현.
onCompositionStart와onCompositionEnd이벤트 핸들러가 적절하게 구현되었습니다. 한글 주석이 추가된 것도 코드 이해도를 높이는 좋은 방식입니다.핸들러 함수가 인라인으로 정의되어 있지만, 이 경우에는 간단한 상태 업데이트이므로 적절합니다.
design-system/stories/ChoiceChip.stories.tsx (2)
32-35: 옵션 데이터 구조 개선이 잘 이루어졌습니다.문자열 배열에서
label과value를 명확히 분리한 객체 배열로 변경한 것은 좋은 개선입니다. 이는 UI 표시와 실제 데이터 값을 분리하여 더 명확한 타입 안전성을 제공합니다.
45-49: 옵션 데이터 구조가 일관되게 적용되었습니다.ThreeOptions에서도 동일하게
label과value를 가진 객체 배열로 변경되어 일관성이 유지되었습니다.design-system/ui/ChoiceChip.tsx (3)
4-5: 타입 안전성 개선이 잘 이루어졌습니다.
ChoiceChipOption인터페이스에서label과value를 필수 문자열 속성으로 정의하고, 각 속성의 용도를 명확히 주석으로 표시한 것은 좋은 개선입니다.
35-38: handleClick 함수 타입이 인터페이스와 일치합니다.
handleClick함수가 문자열 값을 받아 상태를 업데이트하고onSelect콜백을 호출하는 방식이 인터페이스와 잘 일치합니다.
44-56: 조건부 스타일링이 value 기반으로 잘 구현되었습니다.
selected === option.value를 사용하여 선택된 항목의 스타일을 결정하는 방식이 새로운 데이터 구조와 잘 맞습니다.design-system/ui/Profile.tsx (3)
10-10: ProfileImageUrl 속성 추가ProfileProps 인터페이스에 profileImageUrl 속성이 추가되어 프로필 이미지 URL을 통한 동적 이미지 표시 기능이 구현되었습니다.
16-24: Props 구조 개선컴포넌트 매개변수에 profileImageUrl을 추가하고 구조분해할당을 통해 가독성을 개선했습니다.
44-50: 조건부 렌더링 추가profileImageUrl 존재 여부에 따라 이미지를 렌더링하거나 기존 UI로 대체하는 조건부 렌더링 로직이 잘 구현되었습니다. 이미지 태그에 적절한 스타일링이 적용되어 있습니다.
src/pages/search/ui/SearchPage.tsx (5)
16-25: 이벤트 필터링 로직 개선필터링 로직을 JSX 외부로 분리하여 가독성과 성능을 향상시켰습니다. flatMap을 사용하여 페이지네이션 데이터를 효율적으로 처리하고, 제목, 주소, 호스트 채널명에서 키워드를 검색하는 포괄적인 필터링을 구현했습니다.
27-30: 호스트 필터링 로직 개선호스트 필터링 로직이 JSX 외부로 분리되어 코드 가독성이 향상되었습니다. 호스트 채널명에서 키워드를 검색하는 필터링이 깔끔하게 구현되었습니다.
81-105: 이벤트 섹션 리팩토링이벤트 섹션의 렌더링 로직이 간소화되었습니다. 사전 필터링된 배열을 사용하여 코드가 더 깔끔해졌고, 마지막 요소에 대한 참조 설정도 명확해졌습니다. 로딩 상태 표시가 적절히 추가되었습니다.
107-123: 호스트 섹션 리팩토링호스트 섹션이 깔끔하게 리팩토링되었습니다. ProfileCircle 컴포넌트에 profileImageUrl 속성을 전달하여 프로필 이미지를 표시하는 기능이 추가되었습니다.
125-128: 검색 결과 없음 메시지 추가검색 결과가 없을 때 사용자에게 적절한 메시지를 표시하도록 개선되었습니다. 이벤트와 호스트 모두 검색 결과가 없을 때만 메시지를 표시하는 논리가 명확합니다.
src/shared/hooks/useImageUpload.ts (5)
1-12: 이미지 업로드 커스텀 훅 구현이미지 업로드를 위한 재사용 가능한 커스텀 훅이 잘 구현되었습니다. 상태 관리와 초기화 로직이 깔끔하게 처리되었습니다. 특히 value prop을 통해 초기 이미지 URL을 설정하는 부분이 유용합니다.
13-23: 파일 유효성 검사 로직파일 크기(500KB 제한)와 유형(jpg, jpeg, png) 검사가 잘 구현되었습니다. 사용자에게 적절한 오류 메시지를 표시하여 UX가 향상되었습니다.
25-38: 파일 업로드 핸들러 구현useCallback을 사용하여 최적화된 파일 업로드 핸들러가 잘 구현되었습니다. 파일 유효성 검사, 비동기 업로드 처리, 성공 콜백 실행 등의 흐름이 명확합니다.
40-50: 파일 변경 및 드래그 앤 드롭 핸들링파일 input 변경 이벤트와 드래그 앤 드롭 이벤트를 적절히 처리하는 핸들러가 잘 구현되었습니다. 사용자 경험을 향상시키는 다양한 파일 업로드 방식을 지원합니다.
52-61: 훅 반환 값 구조화훅의 반환 값이 잘 구조화되어 있어 컴포넌트에서 필요한 상태와 핸들러를 쉽게 활용할 수 있습니다. 이는 코드 재사용성과 유지보수성을 크게 향상시킵니다.
src/entities/event/hook/useEventListHook.ts (1)
1-1: import 경로 업데이트EventList 타입의 import 경로가 업데이트되었습니다. 이는 프로젝트 구조 개선을 위한 모델 파일 위치 변경을 반영합니다.
src/shared/types/api/apiResponse.ts (1)
8-8: 오류 코드 속성 추가로 향상된 에러 처리 기능코드 속성을 추가함으로써 API 오류 응답에서 더 상세한 오류 식별이 가능해졌습니다. 이는 특히 특정 오류 코드(예: TOKEN4001)를 기반으로 토큰 갱신 로직을 트리거하는 데 유용합니다.
src/features/home/ui/EventSliderSection.tsx (2)
34-39: 코드 가독성 개선코드 포맷팅 변경은 로직을 변경하지 않으면서 가독성을 향상시켰습니다. 들여쓰기가 일관되게 적용되어 체인된 함수 호출의 구조가 더 명확해졌습니다.
58-58: 이벤트 위치 정보 속성 변경
locationprop이event.address에서event.onlineType으로 변경되었습니다. 이는 물리적 주소 대신 온라인 이벤트 유형을 표시하기 위한 변경으로 보입니다.이 변경이 이벤트 카드에 올바른 위치 정보를 표시하는지 확인해주세요.
EventCard컴포넌트가onlineType속성을 적절히 처리하는지 검증이 필요합니다.src/features/ticket/model/ticket.ts (2)
1-10: 티켓 생성 요청 인터페이스 간소화
CreateTicketRequest인터페이스에서startTime과endTime속성이 제거되었습니다. 이는 시간 처리 로직이 다른 곳으로 이동되었거나 간소화되었음을 의미합니다.시간 정보가 여전히 필요하다면,
startDate와endDate속성에 ISO 문자열 형식으로 시간 정보가 포함되어 있는지 확인해주세요. 또한 관련 컴포넌트들이 이 변경에 맞게 업데이트되었는지 확인이 필요합니다.
12-18: ReadTicketResponse 인터페이스 포맷팅 조정
ReadTicketResponse인터페이스는 기능적인 변경 없이 포맷팅이 조정되었습니다. 코드의 일관성과 가독성이 향상되었습니다.src/entities/event/hook/useEventHook.ts (1)
15-15: 쿼리 활성화 조건 개선사용자 ID와 이벤트 ID가 모두 유효한 경우에만 쿼리를 실행하도록 조건을 개선하여 불필요한 API 호출을 방지했습니다. 이는 React Query의 조건부 쿼리 실행 모범 사례를 따른 적절한 변경입니다.
src/pages/event/ui/EventDetailsPage.tsx (1)
112-117: 위치 정보 조건부 렌더링 개선위치 좌표값(locationLat, locationLng)이 0이 아닐 때만 위치 정보와 지도를 표시하도록 조건부 렌더링을 추가했습니다. 이는 좌표 정보가 없는 이벤트의 경우 불필요한 지도 컴포넌트를 표시하지 않아 사용자 경험을 개선합니다.
🧰 Tools
🪛 Biome (1.9.4)
[error] 112-112: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
src/widgets/main/ui/Banner.tsx (2)
15-15: 배너 컨테이너 높이 스타일 간소화배너 컨테이너의 높이 스타일을 수정하여 모바일과 데스크톱 환경에서 일관된 레이아웃을 제공합니다. 이전에는 복잡한 반응형 높이 스타일이 적용되었을 것으로 보이나, 현재는 기본 높이와 대형 화면에서의 높이만 지정하여 간결해졌습니다.
31-31: 이미지 표시 방식 개선이미지 스타일을
object-cover에서object-contain으로 변경하여 이미지가 잘리지 않고 전체가 표시되도록 개선했습니다. 이는 다양한 비율의 동적 이미지를 처리할 때 더 적합한 방식입니다.src/shared/types/api/http-client.ts (2)
37-37: 에러 정보 객체에 코드 속성 추가서버 응답에서 에러 코드를 추출하여 에러 정보 객체에 포함시켰습니다. 이는 보다 세부적인 에러 처리 로직을 구현할 수 있게 해줍니다.
43-45: 토큰 리프레시 로직 개선HTTP 상태 코드 401 대신 구체적인 에러 코드 'TOKEN4001'을 확인하도록 변경하여 토큰 갱신 로직을 더 정확하게 트리거합니다. 또한 원본 요청에 재시도 플래그(
_retry)를 설정하여 무한 재시도 루프를 방지했습니다.src/pages/menu/ui/myHost/MyHostPage.tsx (1)
21-35: 데이터 존재 여부에 따른 조건부 렌더링 개선데이터가 존재하는지 확인하는 조건부 렌더링을 추가하여 사용자 경험을 향상시켰습니다. 호스트 정보가 없을 때 명확한 메시지를 표시하는 방식은 좋은 UX 패턴입니다.
- ProfileCircle 컴포넌트에 profileImageUrl prop을 전달하여 프로필 이미지를 동적으로 표시
- 빈 상태 처리를 통해 데이터가 없을 때 적절한 피드백 제공
src/pages/home/ui/MainPage.tsx (3)
16-28: 정적 배너 이미지에서 동적 데이터 기반 배너로 리팩토링하드코딩된 배너 이미지를 API에서 가져온 실제 이벤트 데이터로 교체한 점이 좋습니다. 이를 통해 배너 이미지가 항상 최신 이벤트를 반영할 수 있게 되었습니다.
- useEventList 훅을 사용하여 최신 이벤트 데이터 가져오기
- 최대 4개의 최신 이벤트를 배너 이미지로 활용
- 각 배너에 해당 이벤트 상세 페이지로 연결되는 링크 추가
55-55: 배너 이미지 존재 여부에 따른 조건부 렌더링배너 이미지가 있을 때만 Banner 컴포넌트를 렌더링하도록 수정한 것은 좋은 접근입니다. 이렇게 하면 이벤트 데이터가 없을 때 빈 배너가 표시되는 것을 방지할 수 있습니다.
63-63: 네비게이션 호출 방식 개선카테고리 네비게이션을 더 명확하게 수정했습니다. state 객체를 통해 카테고리 정보를 전달하는 방식이 적절합니다.
src/pages/bookmark/ui/BookmarkPage.tsx (1)
23-40: 북마크 데이터 존재 여부에 따른 UI 처리 개선북마크된 이벤트가 있는지 확인하는 조건부 렌더링을 추가하여 사용자 경험을 개선했습니다. 데이터가 없을 때 적절한 안내 메시지를 표시하는 방식은 좋은 UX 패턴입니다.
- 데이터 존재 여부에 따라 이벤트 카드 또는 안내 메시지 표시
- col-span-2 클래스를 활용하여 메시지가 그리드 전체 너비를 차지하도록 설정
- 반응형 디자인을 고려한 텍스트 크기 적용 (text-sm md:text-base)
src/shared/ui/backgrounds/HostDetailLayout.tsx (2)
34-38: ProfileCircle 컴포넌트에 동적 프로필 이미지 지원 추가ProfileCircle 컴포넌트에 profileImageUrl prop을 전달하여 호스트 프로필 이미지를 동적으로 표시할 수 있도록 개선했습니다. 이는 UI 일관성을 높이고 사용자 경험을 향상시킵니다.
47-47: 컨텐츠 컨테이너 위치 조정컨텐츠 컨테이너의 top 위치를
calc(100%-2vh)에서calc(100%-1vh)로 조정하여 레이아웃을 미세하게 개선했습니다. 이로 인해 컨텐츠가 약간 위로 이동하여 시각적으로 더 좋은 배치가 되었습니다.src/features/event/ui/ShareEventModal.tsx (1)
77-78: UI 표시에 동적 데이터 적용 개선이벤트 상세 정보를 가져와서 UI에 동적으로 적용하도록 개선된 부분입니다. 이는 사용자에게 항상 최신 데이터를 보여줄 수 있도록 하는 긍정적인 변화입니다.
src/features/event/ui/DatePicker.tsx (3)
6-6: 날짜 포맷팅 로직 개선날짜 포맷팅 로직을
formatISO유틸리티 함수로 중앙화하여 코드 일관성과 재사용성을 향상시켰습니다. 이는 날짜와 시간 처리의 복잡성을 감추고 동일한 포맷팅 로직을 여러 컴포넌트에서 일관되게 사용할 수 있게 해줍니다.Also applies to: 74-75
29-32: 날짜 초기 상태 개선날짜 초기값을 null 대신 실제 Date 객체로 설정하여 예상치 못한 null 참조 오류를 방지하고, 사용자 경험을 향상시켰습니다.
107-107: 자동완성 비활성화 개선DatePicker 컴포넌트에
autoComplete="off"속성을 추가하여 브라우저의 자동완성 기능이 캘린더 UI와 충돌하는 문제를 방지했습니다. 이는 사용자 경험을 향상시키는 좋은 개선 사항입니다.Also applies to: 155-155
src/pages/menu/ui/MyTicketPage.tsx (2)
22-23: 따옴표 스타일 일관성 개선타입 정의와 에러 메시지에서 따옴표 스타일을 일관성 있게 단일 따옴표로 통일하여 코드 스타일의 일관성을 향상시켰습니다.
Also applies to: 27-27, 42-42
52-85: 빈 상태 처리 개선티켓 목록이 비어 있을 때 적절한 메시지를 표시하도록 조건부 렌더링을 추가했습니다. 이는 사용자 경험을 향상시키는 좋은 UX 패턴입니다. 사용자가 데이터가 없는 상태를 이해하고 다음 단계를 취할 수 있도록 합니다.
src/pages/event/ui/host/HostCreationPage.tsx (1)
10-10: 이미지 업로드 로직 중앙화
useImageUpload커스텀 훅을 사용하여 이미지 업로드 로직을 중앙화했습니다. 이는 코드 재사용성과 유지보수성을 향상시키는 좋은 변화입니다. 파일 유효성 검사, 미리보기 생성, 업로드 처리 등의 복잡한 로직을 추상화하여 컴포넌트의 가독성이 향상되었습니다.Also applies to: 37-45
src/features/ticket/hooks/useTicketHook.ts (3)
3-5: 타입 시스템 개선 및 임포트 구조 수정
TicketResponse대신ApiResponse<null>을 사용하고,Error대신 더 구체적인AxiosError를 사용함으로써 타입 안전성이 향상되었습니다. 이는 API 응답 처리와 에러 핸들링을 위한 일관된 패턴을 제공합니다.
16-16: API 응답 타입 개선
ApiResponse<null>타입과AxiosError를 사용하여 뮤테이션 함수의 타입 안전성이 개선되었습니다. 이는 백엔드 API와의 일관된 인터페이스를 제공합니다.
29-29: API 응답 타입 개선
useDeleteTicket함수도 동일하게ApiResponse<null>타입과AxiosError를 사용하여 타입 안전성이 개선되었습니다. 이러한 일관된 접근 방식은 코드 유지보수성을 높여줍니다.src/features/ticket/ui/TicketDatePicker.tsx (7)
6-6: 날짜 포맷팅 로직 중앙화개별 컴포넌트에서 날짜 포맷팅 로직을 구현하는 대신 공유 유틸리티 함수
formatISO를 사용함으로써 코드 중복을 줄이고 일관성을 높였습니다.
16-22: 컴포넌트 선언 스타일 개선컴포넌트 선언 구문이 깔끔하게 정리되었습니다. 각 파라미터가 별도 라인에 배치되어 가독성이 향상되었습니다.
26-30: 날짜/시간 초기값 개선시간 값에 대한 명확한 기본값('06:00'과 '23:00')을 설정하여 예측 가능한 동작을 보장합니다. 또한 endDate 초기화 로직이 startDate와 일관되게 변경되었습니다.
47-49: 날짜 포맷팅 로직 중앙화 적용이전 직접 구현된 날짜 포맷팅 코드 대신 공유 유틸리티 함수
formatISO를 사용하여 코드의 일관성과 재사용성을 높였습니다.
51-56: 상태 업데이트 로직 단순화불필요한 프로퍼티를 제거하고 필요한 값만 업데이트하도록 변경되었습니다. 이는 코드를 더 간결하고 명확하게 만듭니다.
58-64: 콜백 호출 로직 개선조건 검사 없이 항상
onDateChange콜백을 호출하도록 변경되었습니다. 이는 컴포넌트의 동작을 더 예측 가능하게 만들고 부모 컴포넌트와의 통합을 개선합니다.
65-66: 의존성 배열 명시적 선언useEffect의 의존성 배열이 모든 관련 상태를 포함하도록 명시적으로 업데이트되었습니다. ESLint 규칙 비활성화 주석이 필요한 부분에 추가되었습니다.
다만, ESLint 규칙을 비활성화한 이유가 명확하지 않습니다. 가능하다면
setTicketState와onDateChange를 메모이제이션하여 의존성 배열에 포함시키는 것이 더 좋을 수 있습니다.src/features/event/ui/FileUpload.tsx (3)
3-3: 이미지 업로드 로직 중앙화이미지 업로드 로직을 재사용 가능한 커스텀 훅으로 추출함으로써 코드 중복을 줄이고 일관된 업로드 경험을 제공합니다.
12-18: 파일 업로드 로직 리팩토링여러 상태 변수와 핸들러 함수를 커스텀 훅
useImageUpload로 대체하여 코드가 크게 간소화되었습니다. 이제 초기 이미지 값과 성공 콜백만 훅에 전달하면 됩니다.성공 콜백에서는 부모에게 변경 사항을 알리고 이벤트 상태를 업데이트합니다. 이 접근 방식은 컴포넌트 간의 책임을 명확히 분리합니다.
28-37: 드래그 이벤트 핸들러 단순화드래그 이벤트 핸들러가 인라인 함수로 변경되어 코드 가독성이 향상되었습니다. 훅에서 제공하는
setIsDragging함수를 활용하여 드래그 상태를 간단히 관리합니다.
There was a problem hiding this comment.
Actionable comments posted: 1
🔭 Outside diff range comments (1)
src/pages/event/ui/EventDetailsPage.tsx (1)
107-109:⚠️ Potential issueXSS 보안 위험이 있는 dangerouslySetInnerHTML 사용을 개선하세요.
dangerouslySetInnerHTML은 악의적인, 필터링되지 않은 HTML을 주입하여 XSS(Cross-Site Scripting) 공격의 위험을 초래할 수 있습니다. 특히 외부 소스에서 가져온 콘텐츠를 표시할 때는 더욱 위험합니다.새로 추가된
stripHtml함수를 활용하여 다음과 같이-<div - className="text-sm md:text-base py-3" - dangerouslySetInnerHTML={{ __html: event.result.description }} -></div> +<div className="text-sm md:text-base py-3"> + {stripHtml(event.result.description)} +</div>또는 안전한 HTML 렌더링 라이브러리를 사용하세요:
+import DOMPurify from 'dompurify'; ... -<div - className="text-sm md:text-base py-3" - dangerouslySetInnerHTML={{ __html: event.result.description }} -></div> +<div + className="text-sm md:text-base py-3" + dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(event.result.description) }} +></div>이렇게 하면 신뢰할 수 없는 HTML 콘텐츠로부터 XSS 공격을 방지할 수 있습니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/features/event/lib/stripHtml.ts(1 hunks)src/features/event/ui/ShareEventModal.tsx(2 hunks)src/pages/event/ui/EventDetailsPage.tsx(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/features/event/ui/ShareEventModal.tsx
🧰 Additional context used
🪛 Biome (1.9.4)
src/pages/event/ui/EventDetailsPage.tsx
[error] 112-112: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
🔇 Additional comments (2)
src/pages/event/ui/EventDetailsPage.tsx (2)
112-117: 위치 정보 조건부 렌더링 개선이 잘 되었습니다.위치 정보가 유효한 경우에만 위치 섹션을 표시하도록 조건부 렌더링을 추가한 것은 좋은 개선입니다. 사용자 경험이 향상될 것입니다.
🧰 Tools
🪛 Biome (1.9.4)
[error] 112-112: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
144-144: 이벤트 속성명 변경이 일관되게 적용되었습니다.
eventName에서title로 속성명을 변경한 것은 상태 변수명과 일치시켜 코드 일관성을 높인 좋은 변경입니다.
| const stripHtml = (html: string): string => { | ||
| const tmp = document.createElement('div'); | ||
| tmp.innerHTML = html; | ||
| return tmp.textContent || tmp.innerText || ''; | ||
| }; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
HTML 태그 제거 함수의 안전성을 개선하세요.
이 함수는 HTML 문자열에서 태그를 제거하는 용도로 잘 구현되었으나, 다음과 같은 개선사항이 있습니다:
- 입력 유효성 검사가 없습니다.
html매개변수가null이나undefined인 경우 오류가 발생할 수 있습니다. - DOM 조작은 비용이 많이 들 수 있으므로, 간단한 HTML 제거에는 정규식 접근 방식이 더 효율적일 수 있습니다.
다음과 같이 개선할 수 있습니다:
-const stripHtml = (html: string): string => {
+const stripHtml = (html: string | null | undefined): string => {
+ if (html == null) return '';
+
+ // 간단한 HTML에 대해서는 정규식 사용 (더 효율적)
+ // return html.replace(/<[^>]*>?/g, '');
+
const tmp = document.createElement('div');
tmp.innerHTML = html;
return tmp.textContent || tmp.innerText || '';
};DOM 기반 방식은 HTML 엔티티를 올바르게 디코딩하는 이점이 있으므로, 정규식 접근 방식은 선택적으로 적용하세요.
📝 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 stripHtml = (html: string): string => { | |
| const tmp = document.createElement('div'); | |
| tmp.innerHTML = html; | |
| return tmp.textContent || tmp.innerText || ''; | |
| }; | |
| const stripHtml = (html: string | null | undefined): string => { | |
| if (html == null) return ''; | |
| // 간단한 HTML에 대해서는 정규식 사용 (더 효율적) | |
| // return html.replace(/<[^>]*>?/g, ''); | |
| const tmp = document.createElement('div'); | |
| tmp.innerHTML = html; | |
| return tmp.textContent || tmp.innerText || ''; | |
| }; |
🤖 Prompt for AI Agents
In src/features/event/lib/stripHtml.ts lines 1 to 5, improve the stripHtml
function by adding input validation to handle null or undefined html parameters
safely, returning an empty string in such cases. Additionally, consider
providing an alternative implementation using a regular expression to remove
HTML tags for better performance in simple cases, while keeping the DOM-based
approach optional to preserve correct HTML entity decoding.
Summary by CodeRabbit
신규 기능
개선 및 변경
버그 수정
스타일
기타