Conversation
📝 WalkthroughWalkthrough참여자 상세 화면을 MVVM으로 재구현하고 도메인 모델에 Changes
Sequence Diagram(s)sequenceDiagram
participant User as 사용자
participant Route as ParticipantDetailRoute
participant ViewModel as ParticipantViewModel
participant Repo as Repository
participant Screen as ParticipantDetailScreen
participant UI as UI_컴포넌트
rect rgba(200,200,255,0.5)
User->>Route: 참여 상세 화면 진입
Route->>ViewModel: ViewModel 인스턴스 생성/주입
ViewModel->>Repo: getParticipantDetail(participationId)
Repo-->>ViewModel: ParticipantDetail (domain)
ViewModel->>ViewModel: toUiModel() 변환
ViewModel-->>Screen: uiState(성공) 발행
end
rect rgba(200,255,200,0.5)
User->>Screen: 입금 버튼 클릭
Screen->>ViewModel: OnDepositCompleteClick 인텐트 발행
ViewModel->>Screen: overlayState = DepositBottomSheet (uiState 업데이트)
Screen->>UI: HistoryDepositBottomSheet 렌더링
User->>UI: 입금 정보 제출
UI->>Screen: onSubmitDeposit(depositor, time)
Screen->>ViewModel: SubmitDeposit 인텐트 발행
ViewModel->>ViewModel: overlayState = None, 상태 갱신
ViewModel-->>Screen: uiState 업데이트
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
app/src/main/java/com/poti/android/presentation/history/participant/component/HistoryDeliveryModal.kt (1)
63-64: 버튼 비활성화 상태를 명확하게 관리해야 합니다.현재
currentRating == 0일 때 버튼 클릭이 무시되지만, 버튼이 활성화된 것처럼 보여서 사용자 경험이 좋지 않습니다.PotiModalButton은enabled파라미터를 지원하지만,PotiLargeModal이 이를 노출하고 있지 않아서 직접 전달할 수 없는 상태입니다.다음 중 하나의 방식으로 개선하시기 바랍니다:
PotiLargeModal에btnEnabled: Boolean = true파라미터를 추가하여PotiModalButton에 전달하거나- 현재 조건부 실행 방식에서 사용자에게 시각적 피드백(예: Toast)을 제공하거나
- 별도의 상태 관리 로직으로 버튼 활성화 상태를 더 명확하게 표현해주세요.
app/src/main/java/com/poti/android/presentation/history/participant/component/HistoryDepositBottomSheet.kt (1)
40-49:modifier파라미터 중복 사용 문제가 있습니다.
HistoryDepositBottomSheet의modifier파라미터가PotiBottomSheet에도 전달되고(Line 35),BottomSheetContent에도 전달되고 있습니다(Line 46-47). 동일한 modifier가 두 군데에 적용되면 의도치 않은 레이아웃 동작이 발생할 수 있어요.🐛 수정 제안
content = { BottomSheetContent( depositor = depositor, onDepositorChanged = { depositor = it }, depositTime = depositTime, onDepositTimeChanged = { depositTime = it }, - modifier = modifier - .padding(horizontal = 16.dp), + modifier = Modifier + .padding(horizontal = 16.dp), ) },
🤖 Fix all issues with AI agents
In
`@app/src/main/java/com/poti/android/presentation/history/participant/component/DeliveryStatusContent.kt`:
- Line 3: The import for ParticipantShippingUiModel is missing its package path
causing a compile error; update the import in DeliveryStatusContent.kt to use
the full package-qualified name where ParticipantShippingUiModel is declared
(replace the bare "import ParticipantShippingUiModel" with the full package
import for ParticipantShippingUiModel), then recompile to ensure the symbol in
DeliveryStatusContent (the composable/component referencing
ParticipantShippingUiModel) resolves correctly.
In
`@app/src/main/java/com/poti/android/presentation/history/participant/component/DepositStatusContent.kt`:
- Around line 3-4: The file has unresolved imports for
ParticipantShippingUiModel and PaymentInfoUiModel; locate the Kotlin/Java
declarations of ParticipantShippingUiModel and PaymentInfoUiModel in the project
and replace the two incorrect import lines in DepositStatusContent.kt with their
correct fully-qualified class names (use the exact package + class names as
declared); save and recompile to confirm the compile error is resolved.
In
`@app/src/main/java/com/poti/android/presentation/history/participant/model/Contract.kt`:
- Line 3: The import line "import ParticipantDetailUiModel" is invalid for a
type in the same package; remove that import or replace it with the
fully-qualified class name where used (referencing ParticipantDetailUiModel in
Contract.kt) so the compiler can resolve the symbol—either delete the stray
import statement or reference
com.poti.android.presentation.history.participant.model.ParticipantDetailUiModel
(FQCN) where needed.
In
`@app/src/main/java/com/poti/android/presentation/history/participant/model/ParticipantDetailUiModel.kt`:
- Around line 1-7: This file is missing its package declaration: add "package
com.poti.android.presentation.history.participant.model" at the very top of the
file so the declarations (imports and types like ParticipantDetailUiModel /
ParticipantButtonState references) compile in the correct package; ensure the
package line appears before any imports or other code so other modules can
reference classes from this file.
In
`@app/src/main/java/com/poti/android/presentation/history/participant/ParticipantDetailScreen.kt`:
- Around line 40-48: The UI currently only handles
uiState.participantDetailState.onSuccess and leaves Loading/Error blank; update
the composable to handle all states (Loading -> show a progress indicator, Error
-> show an error message/retry) by switching on uiState.participantDetailState
(e.g., when/collectAsState or onLoading/onError handlers) and render
ParticipantDetailScreen only on success; also wire the action lambdas so
onDetailClick and onActionButtonClick call the ViewModel's processIntent (e.g.,
dispatch appropriate intents from the ViewModel) instead of empty lambdas,
keeping onBackClick as onPopBackStack.
- Line 3: 현재 ParticipantDetailScreen.kt의 import문이 패키지 경로 없이 "import
ParticipantDetailUiModel"로 되어 있어 컴파일 오류가 납니다; ParticipantDetailUiModel이 선언된 실제
패키지(예: com.poti.android.presentation.history.participant.model 또는 프로젝트 내 해당
패키지)를 찾아 해당 전체 경로로 import문을 교체하고 기존 잘못된 import 라인을 제거하세요 (참조 대상:
ParticipantDetailUiModel, 파일: ParticipantDetailScreen.kt).
In
`@app/src/main/java/com/poti/android/presentation/history/participant/ParticipantViewModel.kt`:
- Around line 3-5: Replace the bare imports at the top of
ParticipantViewModel.kt by adding full package-qualified import statements for
ParticipantDetailUiModel, ParticipantShippingUiModel, and PaymentInfoUiModel;
locate the real packages where those classes are declared (e.g., their UI/model
packages) and update the import lines for the symbols ParticipantDetailUiModel,
ParticipantShippingUiModel, and PaymentInfoUiModel so the compiler can resolve
them.
- Around line 34-46: Replace the runtime-crashing TODO() placeholders in
ParticipantViewModel.processIntent with no-op or safe stub implementations: for
each branch handling ParticipantDetailUiIntent (e.g., LoadDetail, OnBackClick,
OnPartyDetailClick, OnDepositCompleteClick, SubmitDeposit, OnDeliveredClick,
ConfirmDelivery, SkipReview, SubmitReview) return Unit and/or log the intent
instead of calling TODO(); ensure processIntent compiles and does not throw by
removing all TODO() invocations and using simple stubs (logging or empty
handlers) until real logic is implemented.
🧹 Nitpick comments (5)
app/src/main/java/com/poti/android/presentation/history/component/HistoryCardItem.kt (1)
60-91: NullableimageUrl처리에 대한 기본 이미지/placeholder 추가 권장
imageUrl가null일 때AsyncImage가 빈 영역으로 남을 수 있어 UX가 떨어질 수 있습니다. Coil 버전에 따라 동작이 달라질 수 있으니, placeholder/error 또는 기본 리소스를 넣는 방식으로 안전하게 처리하는 편이 좋겠습니다.♻️ 제안 변경 예시
AsyncImage( - model = imageUrl, + model = imageUrl, + placeholder = painterResource(R.drawable.img_placeholder), + error = painterResource(R.drawable.img_placeholder), contentDescription = null, modifier = Modifier .fillMaxHeight() .aspectRatio(1f) .clip(RoundedCornerShape(8.dp)), contentScale = ContentScale.Crop, )app/src/main/java/com/poti/android/presentation/history/participant/component/HistoryDeliveryModal.kt (1)
71-77: 하드코딩된 dp 값을 Dimens 리소스로 관리하는 것을 고려해 보세요.현재
16.dp,28.dp,10.dp,12.dp등 여러 값이 하드코딩되어 있습니다. 디자인 시스템의 일관성과 유지보수성을 위해 프로젝트에서 사용하는Dimens객체나 리소스로 관리하시면 추후 디자인 변경 시 한 곳에서 수정할 수 있어 편리합니다.다만 현재 구현도 기능적으로 문제없으므로, 팀 컨벤션에 따라 결정해 주시면 됩니다.
app/src/main/java/com/poti/android/presentation/history/participant/component/HistoryDepositBottomSheet.kt (1)
72-78: 하드코딩된 패딩 값에 대한 설명이 필요합니다.
226.dp는 매직 넘버로 보입니다. 키보드 회피를 위한 값이라면WindowInsets를 활용하거나, 의도를 명확히 하는 상수나 주석을 추가하시는 것이 유지보수에 도움이 될 것 같습니다.app/src/main/java/com/poti/android/presentation/history/participant/component/DeliveryStatusContent.kt (1)
25-75: 전반적인 구현은 잘 되어 있습니다.
Modifier가 첫 번째 선택적 파라미터로 올바르게 위치해 있습니다.screenWidthDp를 사용한 반응형 패딩 처리가 좋습니다.PotiTheme의 색상과 타이포그래피를 일관되게 사용하고 있네요.when표현식으로 상태별 UI 분기가 명확합니다.다만,
when의else브랜치가 빈 블록으로 처리되어 있는데, 향후 새로운ParticipantStatusType이 추가될 경우 누락될 수 있습니다. 가능하다면 exhaustive when을 사용하거나, 의도적으로 무시하는 상태들을 명시적으로 나열하시는 것을 권장드립니다.app/src/main/java/com/poti/android/presentation/history/participant/ParticipantViewModel.kt (1)
48-88: 하드코딩된 Mock 데이터 및 Domain 모델 직접 사용에 대한 검토가 필요합니다.현재 구현에서 몇 가지 개선 포인트가 있어요:
UseCase/Repository 누락: 실제 데이터를 가져오는
UseCase나Repository가 주입되지 않았습니다. UI 확인용 Mock 데이터라면 이해되지만, 추후 연결이 필요해요.Domain 모델 직접 사용:
PartySummary,MemberPayment같은 Domain 모델이 UI Layer에서 직접 사용되고 있습니다. Clean Architecture 원칙에 따라toUiModel()같은 Mapper를 통해 변환하시는 것을 권장드려요.에러 처리 누락:
launchScope사용 시onError콜백이 제공되지 않아 예외 발생 시 무시됩니다.🔧 개선 방향 제안
`@HiltViewModel` class ParticipantViewModel `@Inject` constructor( savedStateHandle: SavedStateHandle, private val getParticipantDetailUseCase: GetParticipantDetailUseCase, // UseCase 주입 ) : BaseViewModel<...>(...) { private fun getParticipantDetail(participantId: Long) = launchScope( onError = { e -> updateState { copy(participantDetailState = ApiState.Error(e)) } } ) { val result = getParticipantDetailUseCase(participantId) updateState { copy(participantDetailState = ApiState.Success(result.toUiModel())) } } }
...in/java/com/poti/android/presentation/history/participant/component/DeliveryStatusContent.kt
Outdated
Show resolved
Hide resolved
...ain/java/com/poti/android/presentation/history/participant/component/DepositStatusContent.kt
Outdated
Show resolved
Hide resolved
app/src/main/java/com/poti/android/presentation/history/participant/model/Contract.kt
Outdated
Show resolved
Hide resolved
...ain/java/com/poti/android/presentation/history/participant/model/ParticipantDetailUiModel.kt
Show resolved
Hide resolved
app/src/main/java/com/poti/android/presentation/history/participant/ParticipantDetailScreen.kt
Outdated
Show resolved
Hide resolved
| uiState.participantDetailState.onSuccess { participantDetail -> | ||
| ParticipantDetailScreen( | ||
| participantDetail = participantDetail, | ||
| onBackClick = onPopBackStack, | ||
| onDetailClick = {}, | ||
| onActionButtonClick = {}, | ||
| modifier = modifier, | ||
| ) | ||
| } |
There was a problem hiding this comment.
Loading 및 Error 상태 처리가 누락되었습니다.
현재 onSuccess만 처리하고 있어 Loading/Error 상태에서는 화면이 빈 상태로 표시됩니다. UX 개선을 위해 각 상태에 대한 처리를 추가하시는 것을 권장드려요.
또한 onDetailClick과 onActionButtonClick이 빈 람다로 전달되어 ViewModel의 Intent와 연결되지 않았습니다. MVI 패턴의 단방향 데이터 흐름을 완성하려면 ViewModel의 processIntent를 호출해야 해요.
🔧 상태 처리 및 Intent 연결 제안
`@Composable`
fun ParticipantDetailRoute(
onPopBackStack: () -> Unit,
modifier: Modifier = Modifier,
viewModel: ParticipantViewModel = hiltViewModel(),
) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
- uiState.participantDetailState.onSuccess { participantDetail ->
+ when (val state = uiState.participantDetailState) {
+ is ApiState.Loading -> {
+ // Loading UI (예: CircularProgressIndicator)
+ }
+ is ApiState.Error -> {
+ // Error UI (예: 에러 메시지 및 재시도 버튼)
+ }
+ is ApiState.Success -> {
+ ParticipantDetailScreen(
+ participantDetail = state.data,
+ onBackClick = { viewModel.processIntent(ParticipantDetailUiIntent.OnBackClick) },
+ onDetailClick = { viewModel.processIntent(ParticipantDetailUiIntent.OnPartyDetailClick) },
+ onActionButtonClick = { buttonState ->
+ when (buttonState) {
+ ParticipantButtonState.DEPOSIT_DONE ->
+ viewModel.processIntent(ParticipantDetailUiIntent.OnDepositCompleteClick)
+ ParticipantButtonState.DELIVERY_RECEIVED ->
+ viewModel.processIntent(ParticipantDetailUiIntent.OnDeliveredClick)
+ ParticipantButtonState.NONE -> {}
+ }
+ },
+ modifier = modifier,
+ )
+ }
+ else -> {}
+ }
- ParticipantDetailScreen(
- participantDetail = participantDetail,
- onBackClick = onPopBackStack,
- onDetailClick = {},
- onActionButtonClick = {},
- modifier = modifier,
- )
- }
}🤖 Prompt for AI Agents
In
`@app/src/main/java/com/poti/android/presentation/history/participant/ParticipantDetailScreen.kt`
around lines 40 - 48, The UI currently only handles
uiState.participantDetailState.onSuccess and leaves Loading/Error blank; update
the composable to handle all states (Loading -> show a progress indicator, Error
-> show an error message/retry) by switching on uiState.participantDetailState
(e.g., when/collectAsState or onLoading/onError handlers) and render
ParticipantDetailScreen only on success; also wire the action lambdas so
onDetailClick and onActionButtonClick call the ViewModel's processIntent (e.g.,
dispatch appropriate intents from the ViewModel) instead of empty lambdas,
keeping onBackClick as onPopBackStack.
app/src/main/java/com/poti/android/presentation/history/participant/ParticipantViewModel.kt
Outdated
Show resolved
Hide resolved
app/src/main/java/com/poti/android/presentation/history/participant/ParticipantViewModel.kt
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In
`@app/src/main/java/com/poti/android/presentation/history/participant/ParticipantDetailScreen.kt`:
- Around line 60-63: The onDetailClick is passing the wrong identifier: change
the argument to ParticipantDetailUiIntent.OnPartyDetailClick from
participantDetail.participationId to participantDetail.partyId in the
onDetailClick lambda inside ParticipantDetailScreen (where
viewModel.processIntent is called) so the partyId from the model is used when
navigating to the party details.
♻️ Duplicate comments (5)
app/src/main/java/com/poti/android/presentation/history/participant/model/Contract.kt (1)
3-3: 패키지 경로 없는 import는 컴파일 오류입니다.동일 패키지 타입은 import 없이 사용하거나 FQCN으로 지정해야 합니다.
🛠️ 수정 제안
-import ParticipantDetailUiModelapp/src/main/java/com/poti/android/presentation/history/participant/model/ParticipantDetailUiModel.kt (1)
1-7: 패키지 선언 누락으로 기본 패키지에 컴파일됩니다.다른 파일에서 참조가 깨질 수 있어 최상단에 패키지 선언을 추가해 주세요.
🛠️ 수정 제안
+package com.poti.android.presentation.history.participant.model + import com.poti.android.domain.model.history.MemberPayment import com.poti.android.domain.model.history.ParticipantDetail import com.poti.android.domain.model.history.PartySummaryapp/src/main/java/com/poti/android/presentation/history/participant/ParticipantViewModel.kt (1)
3-5: 패키지 경로 없는 import는 컴파일 오류입니다.해당 타입들은 UI 모델 패키지의 FQCN으로 import 해야 합니다.
🛠️ 수정 제안
-import ParticipantDetailUiModel -import ParticipantShippingUiModel -import PaymentInfoUiModel +import com.poti.android.presentation.history.participant.model.ParticipantDetailUiModel +import com.poti.android.presentation.history.participant.model.ParticipantShippingUiModel +import com.poti.android.presentation.history.participant.model.PaymentInfoUiModelapp/src/main/java/com/poti/android/presentation/history/participant/ParticipantDetailScreen.kt (2)
3-3: 패키지 경로 없는 import는 컴파일 오류입니다.정확한 패키지 경로로 import 해주세요.
🛠️ 수정 제안
-import ParticipantDetailUiModel +import com.poti.android.presentation.history.participant.model.ParticipantDetailUiModel
55-56: Loading/Error 상태가 표시되지 않아 빈 화면이 됩니다.Success 외 상태를 분기 처리해 로딩/에러 UI를 제공해주세요.
🛠️ 수정 예시
- uiState.participantDetailState.onSuccess { participantDetail -> - ParticipantDetailScreen( - participantDetail = participantDetail, - overlayState = uiState.overlayState, - onBackClick = onPopBackStack, - onDetailClick = { - viewModel.processIntent(ParticipantDetailUiIntent.OnPartyDetailClick(participantDetail.partyId)) - }, - onActionButtonClick = { buttonState -> - if (buttonState == ParticipantButtonState.DEPOSIT_DONE) { - viewModel.processIntent(ParticipantDetailUiIntent.OnDepositCompleteClick) - } else { - viewModel.processIntent(ParticipantDetailUiIntent.OnDeliveredClick) - } - }, - onOverlayClose = { viewModel.processIntent(ParticipantDetailUiIntent.CloseOverlay) }, - onSubmitDeposit = { depositor, depositTime -> - viewModel.processIntent(ParticipantDetailUiIntent.SubmitDeposit(depositor, depositTime)) - }, - onConfirmDelivery = { viewModel.processIntent(ParticipantDetailUiIntent.ConfirmDelivery) }, - onSubmitReview = { rating -> viewModel.processIntent(ParticipantDetailUiIntent.SubmitReview(rating)) }, - onSkipReview = { viewModel.processIntent(ParticipantDetailUiIntent.SkipReview) }, - modifier = modifier, - ) - } + when (val state = uiState.participantDetailState) { + is ApiState.Loading -> { + // TODO: 로딩 UI + } + is ApiState.Error -> { + // TODO: 에러 UI + 재시도 + } + is ApiState.Success -> { + ParticipantDetailScreen( + participantDetail = state.data, + overlayState = uiState.overlayState, + onBackClick = onPopBackStack, + onDetailClick = { + viewModel.processIntent(ParticipantDetailUiIntent.OnPartyDetailClick(state.data.partyId)) + }, + onActionButtonClick = { buttonState -> + if (buttonState == ParticipantButtonState.DEPOSIT_DONE) { + viewModel.processIntent(ParticipantDetailUiIntent.OnDepositCompleteClick) + } else { + viewModel.processIntent(ParticipantDetailUiIntent.OnDeliveredClick) + } + }, + onOverlayClose = { viewModel.processIntent(ParticipantDetailUiIntent.CloseOverlay) }, + onSubmitDeposit = { depositor, depositTime -> + viewModel.processIntent(ParticipantDetailUiIntent.SubmitDeposit(depositor, depositTime)) + }, + onConfirmDelivery = { viewModel.processIntent(ParticipantDetailUiIntent.ConfirmDelivery) }, + onSubmitReview = { rating -> viewModel.processIntent(ParticipantDetailUiIntent.SubmitReview(rating)) }, + onSkipReview = { viewModel.processIntent(ParticipantDetailUiIntent.SkipReview) }, + modifier = modifier, + ) + } + }
🧹 Nitpick comments (1)
app/src/main/java/com/poti/android/presentation/history/participant/model/ParticipantDetailUiModel.kt (1)
8-35: UI 모델에@Immutable적용을 권장합니다.UiState에서 List 포함 모델을 직접 보유하므로 안정성 힌트를 주면 불필요한 리컴포지션을 줄일 수 있습니다.
♻️ 적용 예시
+import androidx.compose.runtime.Immutable import com.poti.android.domain.model.history.MemberPayment import com.poti.android.domain.model.history.ParticipantDetail import com.poti.android.domain.model.history.PartySummary @@ +@Immutable data class ParticipantDetailUiModel( @@ +@Immutable data class PaymentInfoUiModel( @@ +@Immutable data class ParticipantShippingUiModel(코딩 가이드라인 기준입니다.
app/src/main/java/com/poti/android/presentation/history/participant/ParticipantDetailScreen.kt
Show resolved
Hide resolved
ParticipantDetailUiModel 의 package 명 누락
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In
`@app/src/main/java/com/poti/android/presentation/history/participant/model/ParticipantDetailUiModel.kt`:
- Around line 45-53: The accountInfo currently appends shippingInfo.receiver
which can expose the wrong name; update the PaymentInfoUiModel.accountInfo
construction so that when this.paymentInfo.bank and
this.paymentInfo.accountNumber are present you include the actual depositor
field (e.g., this.paymentInfo.depositName or this.paymentInfo.depositor) if
non-null/non-blank, otherwise do NOT append shippingInfo.receiver and just
render "bank accountNumber"; modify the logic in the PaymentInfoUiModel mapping
inside ParticipantDetailUiModel (the paymentInfo -> accountInfo block) to prefer
the depositor field and omit shippingInfo.receiver when depositor is absent.
♻️ Duplicate comments (2)
app/src/main/java/com/poti/android/presentation/history/participant/ParticipantDetailScreen.kt (2)
55-57: Loading/Error 상태 처리가 없어 빈 화면이 될 수 있습니다.
성공 케이스만 처리하고 있어 로딩/에러 시 화면이 비게 됩니다. 상태 분기를 추가해 기본 UI를 노출해 주세요. 코딩 가이드라인에 따라 드리는 의견입니다.🛠️ 수정 제안
+import com.poti.android.core.common.state.ApiState @@ - uiState.participantDetailState.onSuccess { participantDetail -> - ParticipantDetailScreen( - participantDetail = participantDetail, + when (val state = uiState.participantDetailState) { + is ApiState.Success -> { + val participantDetail = state.data + ParticipantDetailScreen( + participantDetail = participantDetail, @@ - ) - } + ) + } + is ApiState.Loading -> { + // TODO: Loading UI + } + is ApiState.Error -> { + // TODO: Error UI / Retry + } + }
60-63: Party 상세 이동에 잘못된 ID가 전달됩니다.
현재 participationId를 넘기고 있어 잘못된 상세로 이동할 수 있습니다. partyId로 교체해 주세요.🛠️ 수정 제안
- viewModel.processIntent(ParticipantDetailUiIntent.OnPartyDetailClick(participantDetail.participationId)) + viewModel.processIntent(ParticipantDetailUiIntent.OnPartyDetailClick(participantDetail.partyId))
🧹 Nitpick comments (1)
app/src/main/java/com/poti/android/presentation/history/participant/ParticipantViewModel.kt (1)
56-77: TODO로 남은 API 연동은 출시 전 이슈로 추적해 주세요.
현재는 더미/빈 처리라 실제 연동 시점이 명확히 관리되어야 합니다. 필요하시면 구현 방향 정리나 템플릿 작성도 도와드릴게요.
| paymentInfo = PaymentInfoUiModel( | ||
| shippingFee = this.paymentInfo.shippingFee, | ||
| totalAmount = this.paymentInfo.totalAmount, | ||
| depositStatus = this.paymentInfo.depositStatus, | ||
| accountInfo = if (this.paymentInfo.bank != null && this.paymentInfo.accountNumber != null) { | ||
| "${this.paymentInfo.bank} ${this.paymentInfo.accountNumber} ${this.shippingInfo.receiver}" | ||
| } else { | ||
| "-" | ||
| }, |
There was a problem hiding this comment.
입금 계좌 표기에 수령인 정보가 섞일 수 있습니다.
shippingInfo.receiver가 예금주명이 아니라면 잘못된 계좌 정보로 노출될 수 있습니다. 예금주 필드가 있다면 그 값을 사용하고, 없다면 수령인 문자열은 제외해 주세요.
🛠️ 수정 제안
- accountInfo = if (this.paymentInfo.bank != null && this.paymentInfo.accountNumber != null) {
- "${this.paymentInfo.bank} ${this.paymentInfo.accountNumber} ${this.shippingInfo.receiver}"
- } else {
- "-"
- },
+ accountInfo = if (this.paymentInfo.bank != null && this.paymentInfo.accountNumber != null) {
+ "${this.paymentInfo.bank} ${this.paymentInfo.accountNumber}"
+ } else {
+ "-"
+ },📝 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.
| paymentInfo = PaymentInfoUiModel( | |
| shippingFee = this.paymentInfo.shippingFee, | |
| totalAmount = this.paymentInfo.totalAmount, | |
| depositStatus = this.paymentInfo.depositStatus, | |
| accountInfo = if (this.paymentInfo.bank != null && this.paymentInfo.accountNumber != null) { | |
| "${this.paymentInfo.bank} ${this.paymentInfo.accountNumber} ${this.shippingInfo.receiver}" | |
| } else { | |
| "-" | |
| }, | |
| paymentInfo = PaymentInfoUiModel( | |
| shippingFee = this.paymentInfo.shippingFee, | |
| totalAmount = this.paymentInfo.totalAmount, | |
| depositStatus = this.paymentInfo.depositStatus, | |
| accountInfo = if (this.paymentInfo.bank != null && this.paymentInfo.accountNumber != null) { | |
| "${this.paymentInfo.bank} ${this.paymentInfo.accountNumber}" | |
| } else { | |
| "-" | |
| }, |
🤖 Prompt for AI Agents
In
`@app/src/main/java/com/poti/android/presentation/history/participant/model/ParticipantDetailUiModel.kt`
around lines 45 - 53, The accountInfo currently appends shippingInfo.receiver
which can expose the wrong name; update the PaymentInfoUiModel.accountInfo
construction so that when this.paymentInfo.bank and
this.paymentInfo.accountNumber are present you include the actual depositor
field (e.g., this.paymentInfo.depositName or this.paymentInfo.depositor) if
non-null/non-blank, otherwise do NOT append shippingInfo.receiver and just
render "bank accountNumber"; modify the logic in the PaymentInfoUiModel mapping
inside ParticipantDetailUiModel (the paymentInfo -> accountInfo block) to prefer
the depositor field and omit shippingInfo.receiver when depositor is absent.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In
`@app/src/main/java/com/poti/android/presentation/history/participant/ParticipantViewModel.kt`:
- Around line 126-133: patchSubmitDeposit currently just sets overlayState to
ParticipantDetailOverlayState.None without calling the API or handling failures;
wrap the API call in launchScope inside a try/catch, set overlayState to a
loading state before the call, call the deposit confirmation API (use the same
function names you already have for network calls), on success updateState to
overlayState = ParticipantDetailOverlayState.None and refresh participant data,
and on failure set overlayState to an error/failed state (or retain the previous
overlayState) and emit a user-facing error (e.g., via a snackbar/toast event or
error field) so failures are surfaced and state is not incorrectly cleared;
ensure you reference patchSubmitDeposit, updateState and
ParticipantDetailOverlayState when implementing this.
- Around line 82-124: getParticipantDetail uses launchScope without providing an
onError handler so failures are swallowed; update launchScope call in
getParticipantDetail to provide an onError callback that updates
participantDetailState to an error state (e.g., ApiState.Error or a suitable
ApiState failure variant) via updateState, passing the exception/message so the
UI can show failure feedback; ensure you reference getParticipantDetail,
launchScope, updateState and participantDetailState when implementing the
change.
🧹 Nitpick comments (4)
app/src/main/java/com/poti/android/presentation/history/participant/model/ParticipantDetailOverlayState.kt (2)
3-15: Sealed interface 패턴이 잘 적용되어 있어요!오버레이 상태를
sealed interface로 정의하여when표현식에서 컴파일 타임 exhaustiveness 검사를 받을 수 있도록 한 점이 좋습니다.data object사용도 Kotlin 1.9+ 권장 사항에 부합해요.다만, Jetpack Compose에서 불필요한 리컴포지션을 방지하기 위해
@Immutable어노테이션 추가를 고려해 주세요.♻️ 리컴포지션 최적화를 위한 제안
package com.poti.android.presentation.history.participant.model +import androidx.compose.runtime.Immutable + +@Immutable sealed interface ParticipantDetailOverlayState { data object None : ParticipantDetailOverlayState data object DepositBottomSheet : ParticipantDetailOverlayState data object DeliveryConfirmModal : ParticipantDetailOverlayState + `@Immutable` data class DeliveryReviewModal( val recruiterName: String, val recruiterProfileUrl: String, val partnerRating: String, ) : ParticipantDetailOverlayState }
10-14:partnerRating타입을Double또는Float로 변경하는 것을 권장드려요.
partnerRating이 평점을 나타내는 값이라면,String대신 숫자 타입을 사용하는 것이 타입 안전성과 연산 측면에서 더 적합해요. UI에서 포맷팅이 필요한 경우 표시 시점에 변환하는 것이 좋습니다.♻️ 타입 변경 제안
data class DeliveryReviewModal( val recruiterName: String, val recruiterProfileUrl: String, - val partnerRating: String, + val partnerRating: Double, ) : ParticipantDetailOverlayStateapp/src/main/java/com/poti/android/presentation/history/participant/ParticipantViewModel.kt (2)
35-80:processIntent가 모든 Intent를 처리하고 있어 좋아요.
when표현식이 exhaustive하게 모든 케이스를 처리하고 있습니다. 이전 리뷰에서 지적된TODO()플레이스홀더 문제도 해결되었네요.다만, TODO 주석이 여러 곳에 남아있는데 (Line 57-58, 71, 76, 130-131), PR 체크리스트에 "바텀시트 연결"과 "모달 연결"이 미완료로 표시되어 있으니 후속 작업에서 구현될 것으로 보여요.
TODO 항목들의 구현을 도와드릴까요? 필요하시면 API 연동 코드 템플릿을 제공해 드릴 수 있어요.
7-8: 일부 필드는 Domain 모델을 직접 사용하고 있어요.
ParticipantDetailUiModel에서partySummary: PartySummary와memberPayments: List<MemberPayment>가 Domain 모델을 직접 사용하고 있는데,paymentInfo와shippingInfo는PaymentInfoUiModel,ParticipantShippingUiModel같은 전용 UI 모델로 변환하고 있어서 일관성이 떨어져요. Domain 모델이 순수 Kotlin이라 기술적 문제는 없지만, 계층 분리를 더 명확하게 하려면PartySummaryUiModel,MemberPaymentUiModel같은 UI 모델로 변환하는 것도 고려해볼 만해요.
| private fun getParticipantDetail(participantId: Long) = launchScope { | ||
| updateState { | ||
| copy( | ||
| participantDetailState = ApiState.Success( | ||
| ParticipantDetailUiModel( | ||
| participationId = 1, | ||
| partyId = 1, | ||
| orderNumber = "참여번호 poti-1", | ||
| partySummary = PartySummary( | ||
| imageUrl = "", | ||
| artist = "아이브(아이브)", | ||
| title = "러브다이브 위드뮤", | ||
| partyStatus = PartyStatusType.CLOSED, | ||
| statusMessage = "다른 참여자를 기다리고 있어요", | ||
| ), | ||
| memberPayments = listOf( | ||
| MemberPayment( | ||
| memberName = "멤버1", | ||
| price = 9000, | ||
| ), | ||
| ), | ||
| paymentInfo = PaymentInfoUiModel( | ||
| shippingFee = 9000, | ||
| totalAmount = 18000, | ||
| depositStatus = ParticipantStatusType.DELIVERED, | ||
| accountInfo = "카카오뱅크 3333-19-1234123 이포티", | ||
| depositDeadline = "2026-01-01 23:50 까지", | ||
| ), | ||
| shippingInfo = ParticipantShippingUiModel( | ||
| shippingMethod = "일반택", | ||
| deliveryTrackingInfo = "우체국 20203344656423232", | ||
| receiver = "이포티", | ||
| addressInfo = "이포티\n(01234) 서울특별시 솝트구 다솝로 456\n010-1234-5678", | ||
| carrier = null, | ||
| trackingNumber = null, | ||
| shippingStatus = ParticipantStatusType.DELIVERED, | ||
| ), | ||
| buttonState = ParticipantButtonState.DELIVERY_RECEIVED, | ||
| ), | ||
| ), | ||
| ) | ||
| } | ||
| } |
There was a problem hiding this comment.
launchScope 호출 시 에러 핸들링이 누락되어 있어요.
현재 launchScope의 onError 콜백을 제공하지 않아, API 호출 실패 시 사용자에게 피드백 없이 실패가 무시됩니다. 실제 API 연동 시에는 에러 상태 처리가 필요해요.
🔧 에러 핸들링 추가 제안
- private fun getParticipantDetail(participantId: Long) = launchScope {
+ private fun getParticipantDetail(participantId: Long) = launchScope(
+ onError = { throwable ->
+ updateState { copy(participantDetailState = ApiState.Error(throwable)) }
+ }
+ ) {
updateState {
copy(
participantDetailState = ApiState.Success(
// ...
),
)
}
}🤖 Prompt for AI Agents
In
`@app/src/main/java/com/poti/android/presentation/history/participant/ParticipantViewModel.kt`
around lines 82 - 124, getParticipantDetail uses launchScope without providing
an onError handler so failures are swallowed; update launchScope call in
getParticipantDetail to provide an onError callback that updates
participantDetailState to an error state (e.g., ApiState.Error or a suitable
ApiState failure variant) via updateState, passing the exception/message so the
UI can show failure feedback; ensure you reference getParticipantDetail,
launchScope, updateState and participantDetailState when implementing the
change.
| private fun patchSubmitDeposit( | ||
| depositor: String, | ||
| depositTime: String, | ||
| ) = launchScope { | ||
| // TODO: 입금 확인 요청 API 호출 | ||
| // 성공 시 overlayState = None 및 데이터 갱신 | ||
| updateState { copy(overlayState = ParticipantDetailOverlayState.None) } | ||
| } |
There was a problem hiding this comment.
patchSubmitDeposit 함수도 에러 핸들링이 필요해요.
API 호출이 추가될 예정이므로, 에러 발생 시 사용자에게 적절한 피드백을 제공하고 overlayState를 유지하거나 에러 상태로 전환하는 로직이 필요합니다.
🔧 에러 핸들링 추가 제안
private fun patchSubmitDeposit(
depositor: String,
depositTime: String,
- ) = launchScope {
+ ) = launchScope(
+ onError = { throwable ->
+ // TODO: 에러 처리 (토스트 또는 에러 상태 표시)
+ }
+ ) {
// TODO: 입금 확인 요청 API 호출
// 성공 시 overlayState = None 및 데이터 갱신
updateState { copy(overlayState = ParticipantDetailOverlayState.None) }
}🤖 Prompt for AI Agents
In
`@app/src/main/java/com/poti/android/presentation/history/participant/ParticipantViewModel.kt`
around lines 126 - 133, patchSubmitDeposit currently just sets overlayState to
ParticipantDetailOverlayState.None without calling the API or handling failures;
wrap the API call in launchScope inside a try/catch, set overlayState to a
loading state before the call, call the deposit confirmation API (use the same
function names you already have for network calls), on success updateState to
overlayState = ParticipantDetailOverlayState.None and refresh participant data,
and on failure set overlayState to an error/failed state (or retain the previous
overlayState) and emit a user-facing error (e.g., via a snackbar/toast event or
error field) so failures are surfaced and state is not incorrectly cleared;
ensure you reference patchSubmitDeposit, updateState and
ParticipantDetailOverlayState when implementing this.
Related issue 🛠️
Work Description ✏️
Screenshot 📸
Uncompleted Tasks 😅
To Reviewers 📢
Summary by CodeRabbit
릴리스 노트
새로운 기능
버그 수정
✏️ Tip: You can customize this high-level summary in your review settings.