-
Notifications
You must be signed in to change notification settings - Fork 4
[FEAT] 동아리 추가 기능 구현 #30
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동아리 코드 확인 및 추가 기능을 위한 end-to-end 흐름을 추가했다. 새 DTO 3종을 도입하고, RemoteClubDataSource/Repository에 확인·추가 API를 구현했다. AddClubViewModel을 신설하고 DI에 등록했으며, ClubCodeInputScreen을 ViewModel 기반 상태 구동 방식으로 리팩터링했다. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant UI as ClubCodeInputScreen
participant VM as AddClubViewModel
participant Repo as ClubRepository
participant DS as RemoteClubDataSource
participant API as Server (clubs API)
User->>UI: 동아리 코드 입력/확인
UI->>VM: confirmClubCode(code)
VM->>Repo: confirmClubCode(code)
Repo->>DS: GET /clubs?clubNumber=code
DS->>API: HTTP GET
API-->>DS: 200 OK (ClubCodeConfirmResponseDto) / 4xx (ErrorResponseDto/텍스트)
DS-->>Repo: ApiResult.Success / ApiResult.Error
Repo-->>VM: 결과 전달
VM-->>UI: uiState 업데이트(성공: clubId/clubName, 실패: errorMessage)
rect rgba(200, 245, 200, 0.25)
Note over UI,VM: 확인 성공 시
UI->>VM: addClub(clubId)
VM->>Repo: addClub(clubId)
Repo->>DS: POST /clubs/{clubId}
DS->>API: HTTP POST
API-->>DS: 200 OK (AddClubResponseDto) / 4xx (ErrorResponseDto/텍스트)
DS-->>Repo: ApiResult.Success / Error
Repo-->>VM: 결과 전달
VM-->>UI: uiState.isAddClubSuccess=true or errorMessage
UI-->>User: 성공 시 홈으로 이동
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (6)
composeApp/src/commonMain/kotlin/org/whosin/client/data/remote/RemoteClubDataSource.kt (2)
102-133: 동아리 코드 확인 로직이 잘 구현되었습니다.에러 응답 파싱 패턴이 적절합니다.
ErrorResponseDto파싱 실패 시 기본 메시지로 폴백하는 구조가 안정적입니다.다만, 디버깅을 위해 파싱 실패 시 예외를 로깅하는 것을 고려해보세요:
} catch (e: Exception) { + println("ErrorResponseDto 파싱 실패: ${e.message}") // 파싱 실패 시 기본 에러 메시지 ApiResult.Error(
135-164: 동아리 추가 로직이 잘 구현되었습니다.
confirmClubCode와 동일한 에러 핸들링 패턴을 사용하여 일관성이 유지됩니다.동일하게, 디버깅을 위해 파싱 실패 시 예외를 로깅하는 것을 고려해보세요:
} catch (e: Exception) { + println("ErrorResponseDto 파싱 실패: ${e.message}") // 파싱 실패 시 기본 에러 메시지 ApiResult.Error(composeApp/src/commonMain/kotlin/org/whosin/client/presentation/auth/clubcode/ClubCodeInputScreen.kt (2)
221-224: 중복된 키보드 숨김 로직을 제거하세요.
LaunchedEffect(currentState)블록(Lines 87-90)에서 이미 SUCCESS 상태일 때 키보드를 숨기고 있습니다. 여기서의 추가 호출은 불필요합니다.if (isComplete) { viewModel.confirmClubCode(clubCode = fullCode) - if (currentState == ClubCodeState.SUCCESS){ - keyboardController?.hide() - } }
284-289: println 디버그 코드를 제거하거나 로깅으로 개선하세요.프로덕션 코드에 println을 남기는 것보다는 제거하거나, 필요하다면 적절한 로깅 프레임워크를 사용하는 것이 좋습니다.
} else { - println("ClubCodeInputScreen : 확인 버튼 오류") }composeApp/src/commonMain/kotlin/org/whosin/client/presentation/auth/clubcode/AddClubViewModel.kt (2)
28-57: 동아리 코드 확인 로직이 잘 구현되었습니다.API 결과에 따른 상태 업데이트가 적절하며, 에러 메시지 폴백 처리도 좋습니다. 중첩된
result.data.data접근은 DTO 구조(ClubCodeConfirmResponseDto.data: ClubCodeConfirmData)를 고려하면 올바릅니다.다만, Lines 43과 53의 println 디버그 코드는 제거하거나 적절한 로깅으로 교체하는 것이 좋습니다:
- println("AddClubViewModel : 조회 성공")- println("AddClubViewModel : 조회 실패")
71-95: 동아리 추가 로직이 잘 구현되었습니다.에러 처리와 로딩 상태 관리가 적절합니다.
다만,
isAddClubSuccess가 한번 true로 설정되면 리셋되지 않습니다. 사용자가 다시 시도할 경우를 대비해resetErrorState()나 별도 메서드에서 이를 초기화하는 것을 고려해보세요:fun resetErrorState() { _uiState.update { it.copy( verificationState = ClubCodeState.INPUT, errorMessage = null, clubName = null, - clubId = null + clubId = null, + isAddClubSuccess = false ) } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
composeApp/src/commonMain/kotlin/org/whosin/client/data/dto/response/AddClubResponseDto.kt(1 hunks)composeApp/src/commonMain/kotlin/org/whosin/client/data/dto/response/ClubCodeConfirmResponseDto.kt(1 hunks)composeApp/src/commonMain/kotlin/org/whosin/client/data/dto/response/ErrorResponseDto.kt(1 hunks)composeApp/src/commonMain/kotlin/org/whosin/client/data/remote/RemoteClubDataSource.kt(2 hunks)composeApp/src/commonMain/kotlin/org/whosin/client/data/repository/ClubRepository.kt(2 hunks)composeApp/src/commonMain/kotlin/org/whosin/client/di/DIModules.kt(2 hunks)composeApp/src/commonMain/kotlin/org/whosin/client/presentation/auth/clubcode/AddClubViewModel.kt(1 hunks)composeApp/src/commonMain/kotlin/org/whosin/client/presentation/auth/clubcode/ClubCodeInputScreen.kt(9 hunks)
🧰 Additional context used
🪛 detekt (1.23.8)
composeApp/src/commonMain/kotlin/org/whosin/client/data/remote/RemoteClubDataSource.kt
[warning] 122-122: The caught exception is swallowed. The original exception could be lost.
(detekt.exceptions.SwallowedException)
[warning] 153-153: The caught exception is swallowed. The original exception could be lost.
(detekt.exceptions.SwallowedException)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: ios-build
🔇 Additional comments (11)
composeApp/src/commonMain/kotlin/org/whosin/client/di/DIModules.kt (1)
13-13: LGTM!AddClubViewModel이 DI 모듈에 올바르게 등록되었습니다. 다른 ViewModel들과 동일한 패턴을 따르고 있어 일관성이 유지됩니다.
Also applies to: 53-53
composeApp/src/commonMain/kotlin/org/whosin/client/data/dto/response/AddClubResponseDto.kt (1)
6-16: LGTM!표준 API 응답 구조를 잘 따르고 있습니다.
@Serializable과@SerialName어노테이션이 올바르게 사용되었고,data필드의 nullable 처리도 적절합니다.composeApp/src/commonMain/kotlin/org/whosin/client/data/repository/ClubRepository.kt (1)
25-29: LGTM!Repository 레이어가 DataSource에 적절히 위임하고 있습니다. 단일 책임 원칙을 잘 따르고 있으며, 반환 타입도 올바릅니다.
composeApp/src/commonMain/kotlin/org/whosin/client/data/dto/response/ClubCodeConfirmResponseDto.kt (1)
6-24: LGTM!중첩된 DTO 구조가 API 응답 형태에 적합하게 설계되었습니다. 모든 필드의 직렬화 어노테이션이 올바르게 적용되어 있습니다.
composeApp/src/commonMain/kotlin/org/whosin/client/data/dto/response/ErrorResponseDto.kt (1)
6-16: LGTM!구조화된 에러 응답 처리를 위한 DTO가 잘 설계되었습니다. 이를 통해 일관된 에러 핸들링이 가능해집니다.
composeApp/src/commonMain/kotlin/org/whosin/client/presentation/auth/clubcode/ClubCodeInputScreen.kt (3)
52-58: ViewModel 기반 상태 관리로의 리팩토링이 잘 되었습니다.콜백 기반에서
uiState기반으로 전환하여 단방향 데이터 흐름을 구현했습니다.collectAsStateWithLifecycle을 사용하여 생명주기를 고려한 상태 수집도 적절합니다.
79-97: 상태 변경에 따른 사이드 이펙트 처리가 적절합니다.에러 상태 리셋 및 키보드 숨김 로직이
LaunchedEffect를 통해 올바르게 처리되고 있습니다.
264-275: 동아리 추가 실패 시 에러 메시지가 적절히 표시됩니다.에러 상태에 따라 조건부로 메시지를 렌더링하는 로직이 명확합니다.
composeApp/src/commonMain/kotlin/org/whosin/client/presentation/auth/clubcode/AddClubViewModel.kt (3)
13-20: LGTM!
AddClubUiState가 필요한 모든 상태를 잘 정의하고 있습니다. 불변 데이터 클래스로 설계되어 안전한 상태 관리가 가능합니다.
22-27: LGTM!StateFlow 패턴이 올바르게 구현되었습니다. private MutableStateFlow와 public StateFlow의 분리가 캡슐화를 잘 보장합니다.
59-69: LGTM!에러 상태를 깔끔하게 리셋하고 있습니다. 모든 관련 필드를 초기화하여 일관된 상태를 유지합니다.
🚀 이슈번호
✏️ 변경사항
📷 스크린샷
안드로이드
Screen_Recording_20251004_000039_WhosInClient.mp4
iOS
2025-10-03.23.47.23.mov
✍️ 사용법
🎸 기타
Summary by CodeRabbit