-
Notifications
You must be signed in to change notification settings - Fork 0
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
[WEAV-154] 프로필 이미지 Reset 기능 #57
Conversation
Walkthrough이 변경 사항은 Changes
Possibly related PRs
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
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: 3
🧹 Outside diff range and nitpick comments (3)
Projects/Core/NetworkKit/Sources/ProfileService/ProfileService.swift (1)
153-153
: PNG 확장자 하드코딩 개선 필요이미지 확장자가 하드코딩되어 있어, 향후 다른 이미지 형식 지원 시 유연성이 떨어질 수 있습니다.
다음과 같은 개선을 제안드립니다:
- let result = try await client.completeProfileImageUpload(body: .json(.init(imageId: imageId, _extension: .PNG))) + let result = try await client.completeProfileImageUpload(body: .json(.init(imageId: imageId, _extension: imageExtension)))이미지 확장자를 파라미터로 받거나, 이미지 데이터로부터 확장자를 추출하는 방식으로 개선하는 것을 고려해보세요.
Projects/Model/Model/Sources/Auth/Domain/UserInfo.swift (1)
53-56
: 옵셔널 체이닝을 사용하여 코드를 개선하세요현재 구현은 작동하지만, 옵셔널 체이닝을 사용하면 더 간결하고 안전하게 작성할 수 있습니다.
-if let profileImage = dto.profileImages?.first { - self.profile.profileImageUrl = URL(string: profileImage.url) - self.profile.profileImageId = profileImage.id -} +dto.profileImages?.first.map { profileImage in + self.profile.profileImageUrl = URL(string: profileImage.url) + self.profile.profileImageId = profileImage.id +}Projects/Features/Home/Sources/Profile/ProfileView.swift (1)
66-70
: 리프레시 핸들러 구현을 단순화하세요현재 구현도 작동하지만, 더 간단하게 작성할 수 있습니다.
-) { - Task { - await intent.refreshUserInfo() - } -} +) { Task { await intent.refreshUserInfo() } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (9)
OpenApiGenerator/Sources/OpenapiGenerated/Client.swift
(1 hunks)OpenApiGenerator/Sources/OpenapiGenerated/Types.swift
(8 hunks)OpenApiGenerator/Sources/openapi-generator-cli/3days-oas
(1 hunks)Projects/Core/NetworkKit/Sources/ProfileService/ProfileService.swift
(3 hunks)Projects/Core/NetworkKit/Sources/ProfileService/ProfileServiceMock.swift
(1 hunks)Projects/Features/Home/Sources/Profile/ProfileView.swift
(1 hunks)Projects/Features/Home/Sources/ProfilePannel/ProfilePanelView.swift
(2 hunks)Projects/Model/Model/Sources/Auth/Domain/UserInfo.swift
(4 hunks)Tuist/ProjectDescriptionHelpers/Dependency+extensions.swift
(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- OpenApiGenerator/Sources/openapi-generator-cli/3days-oas
🔇 Additional comments (9)
Tuist/ProjectDescriptionHelpers/Dependency+extensions.swift (1)
11-11
: Nuke에서 NukeUI로의 마이그레이션 검증 필요
Nuke에서 NukeUI로의 변경이 감지되었습니다. 이는 SwiftUI 통합을 위한 적절한 변경으로 보이나, 다음 사항들의 검증이 필요합니다:
- 기존 Nuke 관련 import 문의 업데이트
- NukeUI 관련 새로운 기능의 올바른 사용
✅ Verification successful
Nuke에서 NukeUI로의 마이그레이션이 올바르게 이루어짐
코드베이스 검토 결과, 다음과 같은 사항들이 확인되었습니다:
- 기존
Nuke
import 문이 없으며,NukeUI
만 사용 중 ProfilePanelView.swift
에서LazyImage
컴포넌트를 통해 NukeUI의 기능을 적절히 활용- Package.swift에서 Nuke 패키지를 정상적으로 참조
마이그레이션이 정상적으로 완료되어 추가 검증이 필요하지 않습니다.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Nuke 관련 import 문 검색
echo "기존 Nuke import 문 검색:"
rg "import Nuke$"
echo "\nNukeUI import 문 검색:"
rg "import NukeUI"
Length of output: 226
Script:
#!/bin/bash
# Nuke 관련 코드 사용 패턴 검색
echo "Nuke 관련 코드 사용:"
rg "Nuke\." -A 2
echo "\nNukeUI 관련 코드 사용:"
rg "NukeUI\." -A 2
echo "\nProfilePanelView.swift 파일 내용 확인:"
cat "Projects/Features/Home/Sources/ProfilePannel/ProfilePanelView.swift"
Length of output: 13225
Projects/Core/NetworkKit/Sources/ProfileService/ProfileServiceMock.swift (1)
42-45
: Mock 구현이 적절히 완료되었습니다
프로토콜 요구사항에 맞게 구현되었으며, 성공 메시지가 한글로 적절히 출력되도록 처리되었습니다.
Projects/Core/NetworkKit/Sources/ProfileService/ProfileService.swift (1)
28-29
: 프로토콜 확장이 명확하게 정의되었습니다
비동기 처리와 에러 핸들링이 포함된 프로토콜 정의가 적절합니다.
Projects/Model/Model/Sources/Auth/Domain/UserInfo.swift (2)
94-95
: 구현이 적절합니다
프로필 이미지 URL과 ID를 옵셔널로 선언한 것이 적절합니다. 이는 프로필 이미지가 필수가 아닌 상황을 잘 반영합니다.
118-119
: 초기화 구현이 적절합니다
새로운 프로필 이미지 관련 매개변수들이 기본값을 nil로 가지도록 구현된 것이 적절합니다.
Also applies to: 129-129
OpenApiGenerator/Sources/OpenapiGenerated/Types.swift (3)
70-76
: 프로토콜 메서드가 올바르게 정의되었습니다.
프로필 이미지 삭제를 위한 프로토콜 메서드가 명확한 문서화와 함께 잘 정의되어 있습니다.
1394-1426
: 프로필 이미지 모델이 적절하게 정의되었습니다.
ProfileImage 구조체가 필요한 모든 속성과 프로토콜을 포함하여 잘 정의되어 있습니다.
629-632
: 응답 모델 업데이트가 완벽하게 구현되었습니다.
GetMyUserInfoResponse에 프로필 이미지 배열이 옵셔널 타입으로 적절하게 추가되었습니다.
OpenApiGenerator/Sources/OpenapiGenerated/Client.swift (1)
1038-1144
: 클라이언트 구현이 완벽하게 작성되었습니다.
deleteProfileImage 메서드가 다음 사항들을 포함하여 적절하게 구현되었습니다:
- 올바른 HTTP DELETE 메서드 사용
- 모든 상태 코드에 대한 체계적인 에러 처리
- 적절한 시리얼라이제이션/디시리얼라이제이션
public func requestResetProfileImage(imageId: String) async throws { | ||
let result = try await client.deleteProfileImage(path: .init(imageId: imageId)) | ||
_ = try result.noContent | ||
} | ||
|
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
에러 처리 개선 필요
이미지 삭제 요청 시 발생할 수 있는 구체적인 에러 케이스들에 대한 처리가 필요합니다.
다음과 같은 개선을 제안드립니다:
public func requestResetProfileImage(imageId: String) async throws {
+ guard !imageId.isEmpty else {
+ throw ProfileServiceError.invalidImageId
+ }
let result = try await client.deleteProfileImage(path: .init(imageId: imageId))
- _ = try result.noContent
+ do {
+ _ = try result.noContent
+ } catch {
+ throw ProfileServiceError.deletionFailed(error)
+ }
}
Committable suggestion skipped: line range outside the PR's diff.
Button("기본 이미지 적용") { | ||
Task { | ||
if let profileImageId = profile.profileImageId { | ||
try await ProfileService.shared.requestResetProfileImage( | ||
imageId: profileImageId | ||
) | ||
_ = try await AppCoordinator.shared.refreshMyUserInfo() | ||
refreshHandler() | ||
} |
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
로딩 상태와 에러 처리를 추가하세요
프로필 이미지 초기화 기능이 구현되어 있지만, 사용자 피드백이 부족합니다.
Button("기본 이미지 적용") {
+ @State private var isResetting = false
Task {
do {
+ isResetting = true
if let profileImageId = profile.profileImageId {
try await ProfileService.shared.requestResetProfileImage(
imageId: profileImageId
)
_ = try await AppCoordinator.shared.refreshMyUserInfo()
refreshHandler()
}
+ } catch {
+ ToastHelper.showErrorMessage(
+ "프로필 이미지 초기화에 실패했습니다."
+ )
+ } finally {
+ isResetting = false
}
}
}
+.disabled(isResetting)
Committable suggestion skipped: line range outside the PR's diff.
ZStack(alignment: .center) { | ||
if let profileImageUrl = profile.profileImageUrl { | ||
LazyImage(url: profileImageUrl) { state in | ||
if let image = state.image { | ||
image | ||
.resizable() | ||
.aspectRatio(contentMode: .fill) | ||
.frame(width: 96, height: 96, alignment: .center) | ||
.clipped() | ||
.cornerRadius(20, corners: .allCorners) | ||
.cornerRadius(48, corners: .bottomRight) | ||
} else { | ||
ProgressView() | ||
} | ||
} | ||
} else { | ||
DesignCore.Images.profileDefault.image | ||
.frame(width: 102, height: 102) | ||
.cornerRadius(20, corners: .allCorners) | ||
} | ||
DesignCore.Images.cameraCircleFill.image | ||
DesignCore.Images.profileBorder.image | ||
.resizable() | ||
.frame(width: 36, height: 36) | ||
.offset(x: 6, y: -6) | ||
.onTapGesture { | ||
isShowPhotoSheet = true | ||
} | ||
.confirmationDialog( | ||
"프로필 사진 설정", | ||
isPresented: $isShowPhotoSheet, | ||
actions: { | ||
Button("앨범에서 사진 선택") { | ||
isShowPhotoPicker = true | ||
} | ||
Button("기본 이미지 적용") { | ||
// default image | ||
} | ||
Button("취소", role: .cancel) {} | ||
}, | ||
message: { | ||
Text("프로필 사진 설정") | ||
.frame(width: 102, height: 102) | ||
|
||
ZStack(alignment: .topTrailing) { | ||
Color.clear | ||
DesignCore.Images.cameraCircleFill.image | ||
.resizable() | ||
.frame(width: 36, height: 36) | ||
.offset(x: 6, y: -6) | ||
.onTapGesture { |
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
이미지 로딩 실패 처리를 추가하세요
LazyImage를 사용한 비동기 이미지 로딩 구현은 좋습니다만, 이미지 로딩 실패 시의 처리가 누락되어 있습니다.
LazyImage(url: profileImageUrl) { state in
if let image = state.image {
image
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 96, height: 96, alignment: .center)
.clipped()
.cornerRadius(20, corners: .allCorners)
.cornerRadius(48, corners: .bottomRight)
+ } else if state.error != nil {
+ DesignCore.Images.profileDefault.image
+ .frame(width: 102, height: 102)
+ .cornerRadius(20, corners: .allCorners)
} else {
ProgressView()
}
}
📝 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.
ZStack(alignment: .center) { | |
if let profileImageUrl = profile.profileImageUrl { | |
LazyImage(url: profileImageUrl) { state in | |
if let image = state.image { | |
image | |
.resizable() | |
.aspectRatio(contentMode: .fill) | |
.frame(width: 96, height: 96, alignment: .center) | |
.clipped() | |
.cornerRadius(20, corners: .allCorners) | |
.cornerRadius(48, corners: .bottomRight) | |
} else { | |
ProgressView() | |
} | |
} | |
} else { | |
DesignCore.Images.profileDefault.image | |
.frame(width: 102, height: 102) | |
.cornerRadius(20, corners: .allCorners) | |
} | |
DesignCore.Images.cameraCircleFill.image | |
DesignCore.Images.profileBorder.image | |
.resizable() | |
.frame(width: 36, height: 36) | |
.offset(x: 6, y: -6) | |
.onTapGesture { | |
isShowPhotoSheet = true | |
} | |
.confirmationDialog( | |
"프로필 사진 설정", | |
isPresented: $isShowPhotoSheet, | |
actions: { | |
Button("앨범에서 사진 선택") { | |
isShowPhotoPicker = true | |
} | |
Button("기본 이미지 적용") { | |
// default image | |
} | |
Button("취소", role: .cancel) {} | |
}, | |
message: { | |
Text("프로필 사진 설정") | |
.frame(width: 102, height: 102) | |
ZStack(alignment: .topTrailing) { | |
Color.clear | |
DesignCore.Images.cameraCircleFill.image | |
.resizable() | |
.frame(width: 36, height: 36) | |
.offset(x: 6, y: -6) | |
.onTapGesture { | |
ZStack(alignment: .center) { | |
if let profileImageUrl = profile.profileImageUrl { | |
LazyImage(url: profileImageUrl) { state in | |
if let image = state.image { | |
image | |
.resizable() | |
.aspectRatio(contentMode: .fill) | |
.frame(width: 96, height: 96, alignment: .center) | |
.clipped() | |
.cornerRadius(20, corners: .allCorners) | |
.cornerRadius(48, corners: .bottomRight) | |
} else if state.error != nil { | |
DesignCore.Images.profileDefault.image | |
.frame(width: 102, height: 102) | |
.cornerRadius(20, corners: .allCorners) | |
} else { | |
ProgressView() | |
} | |
} | |
} else { | |
DesignCore.Images.profileDefault.image | |
.frame(width: 102, height: 102) | |
.cornerRadius(20, corners: .allCorners) | |
} | |
DesignCore.Images.profileBorder.image | |
.resizable() | |
.frame(width: 102, height: 102) | |
ZStack(alignment: .topTrailing) { | |
Color.clear | |
DesignCore.Images.cameraCircleFill.image | |
.resizable() | |
.frame(width: 36, height: 36) | |
.offset(x: 6, y: -6) | |
.onTapGesture { |
구현사항
Summary by CodeRabbit
릴리스 노트
신규 기능
버그 수정
문서화