Skip to content

[Feat/#94] 굿즈별 페이지 API 연동#101

Merged
jyvnee merged 24 commits intodevelopfrom
feat/#94-party-list-api
Jan 22, 2026
Merged

[Feat/#94] 굿즈별 페이지 API 연동#101
jyvnee merged 24 commits intodevelopfrom
feat/#94-party-list-api

Conversation

@sonyerim
Copy link
Copy Markdown
Contributor

@sonyerim sonyerim commented Jan 21, 2026

Related issue 🛠️

Work Description ✏️

  • 굿즈별 페이지 API 연동

Screenshot 📸

Uncompleted Tasks 😅

  • 바텀시트
  • home, goodsCategory 에서 title 넘겨주기

To Reviewers 📢

Summary by CodeRabbit

  • 새로운 기능

    • 상품 파티 목록 조회 추가 — 페이지네이션, 제목/아티스트/멤버 필터, 정렬 옵션 지원
    • 굿즈 필터 화면에 멤버 선택 바텀시트·정렬 바텀시트 UI 추가 및 정렬 선택 컴포넌트 추가
  • 개선

    • 다중 멤버 선택·저장 및 선택 시 목록 자동 갱신
    • 홈/카테고리/카드 클릭 시 제목을 포함한 탐색 페이로드로 이동 흐름 강화
    • 원활한 DTO→도메인 변환으로 UI 데이터 표현 개선
  • 문구

    • 생성 관련 안내 문구 추가 및 중복 정리

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jan 21, 2026

📝 Walkthrough

Walkthrough

굿즈별 페이지 API 연동을 위해 원격 엔드포인트·DTO·매퍼·레포지토리 메서드를 추가하고, 네비게이션·뷰모델·UI 콜백에 title과 artistId 페이로드를 전달하도록 시그니처와 상태를 확장했습니다. (50단어 이내)

Changes

Cohort / File(s) 변경 사항
원격 서비스 / 데이터소스
app/src/main/java/com/poti/android/data/remote/service/PartyService.kt, app/src/main/java/com/poti/android/data/remote/datasource/PartyRemoteDataSource.kt
GET /api/v1/posts/pots 연동용 getProductPartyList(...) API 메서드 추가
원격 DTO / 매퍼
app/src/main/java/com/poti/android/data/remote/dto/response/party/ProductPartyListResponseDto.kt, app/src/main/java/com/poti/android/data/mapper/party/ProductPartyListMapper.kt
응답 DTO(ProductPartyListResponseDto, PartyDto, PartyUploaderDto) 추가 및 DTO→도메인 매핑 toDomain() 구현
도메인 / 레포지토리
app/src/main/java/com/poti/android/domain/repository/PartyRepository.kt, app/src/main/java/com/poti/android/data/repository/PartyRepositoryImpl.kt, app/src/main/java/com/poti/android/domain/model/party/ProductPartyList.kt
리포지토리에 getProductPartyList(...) 추가, PartyListProductPartyList 명칭 변경, PartySummary.availableMembers 타입을 List<Member>List<String>으로 변경
UI 상태·계약
app/src/main/java/com/poti/android/presentation/party/goodsfilter/model/Contract.kt, app/src/main/java/com/poti/android/presentation/party/goodsfilter/model/GoodsFilteredContracts.kt, app/src/main/java/com/poti/android/presentation/party/goodsfilter/model/GoodsCategoryUiState.kt
FilterMember, PartySortType 도입 및 UiState/Intent/Effect 시그니처·필드(selectedMembers, goodsPartySortType 등) 변경
뷰모델 / 비즈니스 로직
app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsFilterViewModel.kt, app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsCategoryViewModel.kt, app/src/main/java/com/poti/android/presentation/party/home/HomeViewModel.kt
ArtistRepository/PartyRepository 주입, 멤버 조회 및 loadPartyList() 구현, 인텐트 처리·네비게이션에 title 포함 페이로드 전파
네비게이션 / 라우트
app/src/main/java/com/poti/android/presentation/party/goodsfilter/navigation/GoodsNavigation.kt
GoodsRoute.GoodsPartyListtitle: String 추가 및 navigateToGoodsPartyList(artistId, title) 시그니처 변경
화면·컴포넌트
app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsFilteredPartyListScreen.kt, app/src/main/java/com/poti/android/presentation/party/home/component/GoodsLargeCard.kt, app/src/main/java/com/poti/android/presentation/party/home/component/GoodsSmallCard.kt, app/src/main/java/com/poti/android/presentation/party/home/component/HomeGoodsSection.kt, app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsCategoryScreen.kt, app/src/main/java/com/poti/android/presentation/party/home/HomeScreen.kt
카드 클릭 콜백 시그니처를 (Long, String) -> Unit으로 변경하고 artistId/title 페이로드 전달; 화면 파라미터·바인딩 업데이트
더미데이터 / 확장 헬퍼
app/src/main/java/com/poti/android/presentation/party/goodsfilter/DummyPotsDate.kt, app/src/main/java/com/poti/android/presentation/party/goodsfilter/model/Extension.kt
더미 데이터 타입을 ProductPartyList/List<String>으로 변경, membersText join 동작 수정
리소스
app/src/main/res/values/strings.xml
중복된 create_* 문자열 리소스 정리 및 일부 문자열 추가
UI 컴포넌트 추가
app/src/main/java/com/poti/android/presentation/party/goodsfilter/component/FilteredSortBottomSheet.kt
정렬 선택용 BottomSheet 컴포저블 추가
기타
app/src/main/java/com/poti/android/presentation/user/mypage/MyPageScreen.kt
BadgeButton 클릭 콜백을 빈 람다로 변경(미사용 제거)

Sequence Diagram(s)

sequenceDiagram
    participant Screen as GoodsFilteredPartyListScreen
    participant VM as GoodsFilterViewModel
    participant Repo as PartyRepository
    participant DS as PartyRemoteDataSource
    participant Svc as PartyService
    participant API as BackendAPI

    Screen->>VM: LoadGoodsPots / OnMembersSelect / OnSortSelect
    VM->>VM: update selectedMembers / goodsPartySortType
    VM->>Repo: getProductPartyList(page,size,title,artistId,sort,memberIds)
    Repo->>DS: getProductPartyList(...)
    DS->>Svc: getProductPartyList(...) (Retrofit)
    Svc->>API: GET /api/v1/posts/pots?page=&size=&title=&artistId=&sort=&memberIds=
    API-->>Svc: ProductPartyListResponseDto
    Svc-->>DS: BaseResponse<ProductPartyListResponseDto>
    DS-->>Repo: BaseResponse<ProductPartyListResponseDto>
    Repo->>Repo: handleApiResponse -> toDomain()
    Repo-->>VM: Result<ProductPartyList>
    VM->>Screen: update UiState(productPartyListInfo)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45분

Possibly related PRs

Suggested reviewers

  • jyvnee
  • cmj7271
🚥 Pre-merge checks | ✅ 3 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning 일부 변경사항이 PR의 주요 범위를 벗어나 있습니다. MyPageScreen.kt의 수정, 문자열 리소스 정렬, 그리고 불필요한 구조 변경들이 포함되어 있습니다. 불필요한 변경사항(MyPageScreen의 onClick 무효화, 문자열 리소스 중복 처리)을 제거하고, #94 범위로 명확히 제한된 변경만 포함시켜주세요.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 주요 변경사항을 명확하게 설명하고 있습니다. 굿즈별 페이지 API 연동이라는 핵심 목표를 간결하게 표현했습니다.
Description check ✅ Passed PR 설명이 필수 항목을 충족하나 상세도가 부족합니다. 스크린샷이 없고 작업 설명이 한 줄로 축약되어 있으며, 미완료 작업이 명시되어 있습니다.
Linked Issues check ✅ Passed PR의 코드 변경사항이 #94의 주요 요구사항들을 충족합니다. API 엔드포인트 통합(/api/v1/posts/pots, /api/v1/artists/{artistId}/members)이 구현되었고, 바텀시트 UI 컴포넌트가 추가되었으며, 필터링 및 정렬 기능이 완성되었습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a 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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsFilteredPartyListScreen.kt (1)

138-154: LazyColumnitemskey 파라미터가 누락되었습니다.

아이템의 고유 키가 없으면 목록 변경 시 불필요한 리컴포지션이 발생할 수 있습니다. partyId를 키로 사용하는 것을 권장드립니다.

♻️ 제안하는 개선안
-items(partyListInfo.partySummaries) { party ->
+items(
+    items = partyListInfo.partySummaries,
+    key = { it.partyId }
+) { party ->

Based on learnings, LazyColumn에서 key 파라미터를 사용하면 아이템 추가/삭제/재정렬 시 Compose가 효율적으로 리컴포지션을 수행할 수 있습니다.

🤖 Fix all issues with AI agents
In
`@app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsFilterViewModel.kt`:
- Around line 37-45: In GoodsFilterViewModel update the handlers for
GoodsFilterUiIntent.OnMembersSelect and GoodsFilterUiIntent.OnSortSelect so that
after calling updateState (copying selectedMembers or goodsPartySortType) you
also trigger a refresh by calling loadPartyList(); locate the intent handling
block where these cases are processed and add a call to the existing
loadPartyList() method immediately after updateState to ensure the party list
reloads when filters change.
🧹 Nitpick comments (8)
app/src/main/java/com/poti/android/data/remote/dto/response/party/PartyListResponseDto.kt (1)

6-20: LGTM! DTO 구조가 잘 정의되어 있습니다.

kotlinx.serialization을 사용한 DTO 구조가 올바르게 작성되어 있습니다. 다만, @SerialName 어노테이션은 JSON 필드명과 프로퍼티명이 다를 때만 필요합니다. 현재는 모든 필드명이 동일하므로 @SerialName 어노테이션을 제거해도 동작에는 문제가 없습니다. 명시적으로 남겨두는 것도 좋은 선택이니 참고만 해주세요.

app/src/main/java/com/poti/android/presentation/party/goodsfilter/model/Extension.kt (1)

21-25: 불필요한 identity lambda를 제거할 수 있습니다.

availableMembers가 이제 List<String>이므로 { it } 람다는 불필요합니다. joinToString의 기본 동작이 각 요소의 toString()을 호출하므로, String 리스트에서는 람다 없이도 동일하게 동작합니다.

♻️ 제안하는 리팩토링
 `@Composable`
 fun PartySummary.membersText(): String =
     availableMembers.joinToString(
         separator = stringResource(R.string.goods_filter_members_separator),
-    ) { it }
+    )
app/src/main/java/com/poti/android/domain/repository/PartyRepository.kt (1)

41-48: API 설계에 대한 몇 가지 제안 사항이 있습니다.

  1. title 파라미터가 non-nullable String으로 선언되어 있는데, 빈 문자열("")을 전달하는 것보다 String?으로 선언하여 의도를 명확히 하는 것이 좋을 수 있습니다.

  2. sort 파라미터가 String 타입으로 되어 있는데, Domain 레이어에서는 타입 안전성을 위해 enum이나 sealed class를 사용하는 것이 권장됩니다. 현재 Presentation 레이어에 PartySortType이 정의되어 있는데, 이를 Domain 레이어로 이동하거나 Domain 전용 enum을 만드는 것을 고려해 주세요.

♻️ 제안하는 개선안
 suspend fun getPartyList(
     page: Int?,
     size: Int?,
-    title: String,
+    title: String?,
     artistId: Long,
-    sort: String,
+    sort: PartySortType, // Domain 레이어에 정의된 enum 사용
     memberIds: List<Long>?,
 ): Result<PartyList>
app/src/main/java/com/poti/android/presentation/party/goodsfilter/DummyPotsDate.kt (1)

1-5: 파일명 오타가 있습니다.

DummyPotsDate.kt에서 Date가 아닌 Data가 맞는 것 같습니다. DummyPotsData.kt로 변경하는 것을 권장드립니다.

app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsFilterViewModel.kt (1)

21-21: checkNotNull 사용 시 크래시 가능성이 있습니다.

artistId가 Navigation arguments에서 누락되면 앱이 크래시될 수 있습니다. requireNotNull과 명확한 에러 메시지를 사용하거나, 에러 상태로 전환하는 방식을 고려해 주세요.

♻️ 제안하는 개선안
-private val artistId: Long = checkNotNull(savedStateHandle["artistId"])
+private val artistId: Long = requireNotNull(savedStateHandle["artistId"]) {
+    "artistId is required for GoodsFilterViewModel"
+}
app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsFilteredPartyListScreen.kt (2)

40-46: 사용되지 않는 artistId 파라미터가 있습니다.

GoodsFilteredPartyListRouteartistId 파라미터가 함수 내에서 사용되지 않습니다. ViewModel이 SavedStateHandle에서 직접 가져오므로 이 파라미터가 필요한지 확인해 주세요.


164-165: Preview 함수명에 오타가 있습니다.

GoodsFilteredPartyListScreenPreveiw에서 PreviewPreveiw로 잘못 작성되어 있습니다.

♻️ 제안하는 개선안
-private fun GoodsFilteredPartyListScreenPreveiw() {
+private fun GoodsFilteredPartyListScreenPreview() {
app/src/main/java/com/poti/android/presentation/party/goodsfilter/model/Contract.kt (1)

22-25: FilterMember@Immutable 또는 @Stable 어노테이션 추가를 고려해 주세요.

FilterMember가 Compose UI 상태에서 사용되므로, @Immutable 어노테이션을 추가하면 불필요한 리컴포지션을 방지할 수 있습니다.

♻️ 제안하는 개선안
+import androidx.compose.runtime.Immutable
+
+@Immutable
 data class FilterMember(
     val id: Long,
     val name: String,
 )

As per coding guidelines, List나 일반 클래스를 State로 사용할 때 @Immutable이나 @Stable 어노테이션 사용이 권장됩니다.

Copy link
Copy Markdown
Contributor

@doyeon0307 doyeon0307 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

악 title 받아오려면 좀 뒤집어야하네 수고햇어욤

@sonyerim sonyerim added 🌟 Feat 새로운 기능 구현 💻 API 서버 통신 작업 💕 예림 labels Jan 21, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a 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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsFilteredPartyListScreen.kt (1)

3-50: Composable 내 Log.d()는 릴리스 및 개인정보 노출 위험이 있습니다.

line 50에서 uiState.partyListInfo를 매 recomposition마다 로깅하고 있어 사용자 닉네임 등 민감한 정보 노출 및 로그 노이즈 위험이 큽니다. 디버그 환경 전용으로 보호하거나 제거해야 합니다.

또한 LazyColumn의 items() 호출 시 key 파라미터가 누락되었습니다(line 140). 안정적인 item 재식별을 위해 items(partyListInfo.partySummaries, key = { it.partyId }) { party -> 형태로 수정하세요.

🧹 제안 수정
-import android.util.Log
 ...
-    Log.d("GoodsFilterUI", "recompose: ${uiState.partyListInfo}")
 
 ...
-            items(partyListInfo.partySummaries) { party ->
+            items(partyListInfo.partySummaries, key = { it.partyId }) { party ->
♻️ Duplicate comments (1)
app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsFilterViewModel.kt (1)

39-47: 필터 변경 시 파티 목록 재로드가 필요합니다.

OnMembersSelectOnSortSelect에서 상태만 업데이트하고 loadPartyList()를 호출하지 않고 있습니다. 필터 변경 후 목록이 갱신되지 않으면 사용자 경험에 문제가 발생할 수 있습니다.

♻️ 제안하는 수정안
 is GoodsFilterUiIntent.OnMembersSelect -> {
     updateState { copy(selectedMembers = intent.members) }
+    loadPartyList()
 }
 // ...
 is GoodsFilterUiIntent.OnSortSelect -> {
     updateState { copy(goodsPartySortType = intent.sort) }
+    loadPartyList()
 }
🧹 Nitpick comments (4)
app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsFilterViewModel.kt (1)

51-83: loadPartyList() 구현이 전반적으로 잘 되어 있습니다.

launchScope를 활용한 코루틴 실행, onSuccess/onFailure를 통한 Result 처리, 상태 업데이트 로직이 MVI 패턴에 맞게 구현되어 있습니다.

몇 가지 개선 제안사항이 있습니다:

  1. 페이지네이션: page = 0, size = 10이 하드코딩되어 있는데, 향후 페이지네이션 지원 시 상태로 관리하는 것이 좋겠습니다.
  2. 로깅: android.util.Log 대신 Timber나 프로젝트의 로깅 유틸리티 사용을 권장드립니다.
- Log.e("GoodsFilterVM", "loadPartyList failed", throwable)
+ Timber.e(throwable, "loadPartyList failed")
app/src/main/java/com/poti/android/presentation/party/home/component/HomeGoodsSection.kt (1)

67-77: LazyRowitemskey 파라미터가 누락되었습니다.

코딩 가이드라인에 따르면 LazyColumn/LazyRow 등 리스트에서 key 파라미터를 사용하여 불필요한 리컴포지션을 방지해야 합니다. GroupItem에 고유 식별자가 있다면 key로 지정해주세요.

♻️ 제안하는 수정안
 items(
     items = groupItems,
+    key = { it.artistId } // 또는 고유한 식별자 사용
 ) { item ->
     GoodsSmallCard(
         imageUrl = item.postImage,
         artist = item.artist,
         artistId = item.artistId,
         title = item.postTitle,
         partyCount = item.postCount,
         tag = item.tag,
         onClick = onCardClick,
     )
 }

Based on coding guidelines, LazyColumn 등 리스트에서 key 파라미터가 누락되었는지 확인해야 합니다.

app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsFilteredPartyListScreen.kt (1)

133-151: LazyColumn items에 안정적인 key를 지정해 주세요.
partyId가 식별자라면 key로 지정해 스크롤 위치/리컴포지션 안정성을 확보하는 편이 좋습니다. 코딩 가이드라인에 따라 확인했습니다.

♻️ 제안 수정
-            items(partyListInfo.partySummaries) { party ->
+            items(
+                items = partyListInfo.partySummaries,
+                key = { it.partyId },
+            ) { party ->
app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsCategoryScreen.kt (1)

135-147: Goods 카테고리 목록도 key 지정 권장드립니다.
groupItems에 고유 ID가 없다면 artistId + postTitle 등 조합으로 key를 지정해 리컴포지션 안정성을 확보해 주세요. 코딩 가이드라인에 따라 확인했습니다.

♻️ 제안 수정
-            items(goodsCategory.groupItems) { groupItem ->
+            items(
+                items = goodsCategory.groupItems,
+                key = { it.artistId to it.postTitle },
+            ) { groupItem ->

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a 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

🤖 Fix all issues with AI agents
In `@app/src/main/java/com/poti/android/presentation/user/mypage/MyPageScreen.kt`:
- Around line 118-122: BadgeButton currently uses an empty lambda for onClick so
the passed-in onArtistClick is never invoked; update the BadgeButton call in
MyPageScreen to use the onArtistClick parameter (e.g., onClick = onArtistClick)
and apply the TODO conditional ("// TODO: [예림] 선택 최애 없을 때만 이동") around that call
so navigation only happens when the favorite selection condition is met; if the
click should be intentionally disabled instead, remove the onArtistClick
parameter from MyPageScreen or mark it with `@Suppress`("UnusedParameter") and/or
render BadgeButton conditionally.

Comment on lines 118 to 122
BadgeButton(
bias = biasText,
onClick = onArtistClick,
onClick = { },
modifier = Modifier,
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

onArtistClick 콜백이 사용되지 않고 빈 람다로 대체되어 버튼이 동작하지 않습니다.

현재 BadgeButtononClick이 빈 람다 { }로 설정되어 있어, 버튼을 클릭해도 아무런 동작이 발생하지 않습니다. onArtistClick 파라미터가 MyPageScreen에 전달되지만 실제로 사용되지 않아 dead code가 되었습니다.

Line 61의 TODO 주석(// TODO: [예림] 선택 최애 없을 때만 이동)을 고려하면, 조건부 네비게이션 로직이 필요해 보입니다.

🛠️ TODO 로직을 반영한 수정 제안
 BadgeButton(
     bias = biasText,
-    onClick = { },
+    onClick = {
+        if (userMyPage.favoriteArtistName == null) {
+            onArtistClick()
+        }
+    },
     modifier = Modifier,
 )

또는 의도적으로 비활성화하는 것이라면, 파라미터에서 onArtistClick을 제거하고 @Suppress("UnusedParameter")를 사용하거나, 버튼 자체를 조건부로 렌더링하는 것을 고려해 주세요.

🤖 Prompt for AI Agents
In `@app/src/main/java/com/poti/android/presentation/user/mypage/MyPageScreen.kt`
around lines 118 - 122, BadgeButton currently uses an empty lambda for onClick
so the passed-in onArtistClick is never invoked; update the BadgeButton call in
MyPageScreen to use the onArtistClick parameter (e.g., onClick = onArtistClick)
and apply the TODO conditional ("// TODO: [예림] 선택 최애 없을 때만 이동") around that call
so navigation only happens when the favorite selection condition is met; if the
click should be intentionally disabled instead, remove the onArtistClick
parameter from MyPageScreen or mark it with `@Suppress`("UnusedParameter") and/or
render BadgeButton conditionally.

…t-api

# Conflicts:
#	app/src/main/java/com/poti/android/data/remote/datasource/PartyRemoteDataSource.kt
#	app/src/main/java/com/poti/android/data/remote/service/PartyService.kt
#	app/src/main/java/com/poti/android/data/repository/PartyRepositoryImpl.kt
#	app/src/main/java/com/poti/android/domain/repository/PartyRepository.kt
#94-party-list-api

# Conflicts:
#	app/src/main/java/com/poti/android/data/remote/dto/response/party/ProductPartyListResponseDto.kt
#	app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsCategoryScreen.kt
#	app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsCategoryViewModel.kt
#	app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsFilterViewModel.kt
#	app/src/main/java/com/poti/android/presentation/party/goodsfilter/model/GoodsCategoryUiState.kt
#	app/src/main/java/com/poti/android/presentation/party/goodsfilter/navigation/GoodsNavigation.kt
#	app/src/main/java/com/poti/android/presentation/party/home/HomeScreen.kt
#	app/src/main/java/com/poti/android/presentation/party/home/HomeViewModel.kt
#	app/src/main/java/com/poti/android/presentation/party/home/component/HomeGoodsSection.kt
#	app/src/main/java/com/poti/android/presentation/party/home/model/Contracts.kt
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a 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

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/party/home/HomeViewModel.kt (1)

18-26: 파라미터 순서가 일치하지 않습니다.

NavigateToGoodsPartyListOnCardClick의 파라미터 순서를 확인해 주세요.

  • HomeUiEffect.NavigateToGoodsPartyList 정의: (val title: String, val artistId: Long)
  • 호출 코드: HomeUiEffect.NavigateToGoodsPartyList(intent.artistId, intent.title) ← 순서 반대

라인 23에서 인자를 순서대로 전달해야 합니다:

sendEffect(HomeUiEffect.NavigateToGoodsPartyList(intent.title, intent.artistId))

마찬가지로 HomeScreen.ktOnCardClick 호출도 확인이 필요합니다.

app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsFilteredPartyListScreen.kt (1)

140-156: LazyColumn itemskey 파라미터를 추가해 주세요.

코딩 가이드라인에 따르면, LazyColumn에서 key 파라미터가 누락되면 불필요한 리컴포지션이 발생할 수 있습니다. partyId를 key로 사용하시면 아이템 변경 시 효율적인 업데이트가 가능합니다.

♻️ 제안하는 수정 사항
-            items(productPartyListInfo.partySummaries) { party ->
+            items(
+                items = productPartyListInfo.partySummaries,
+                key = { it.partyId }
+            ) { party ->
🤖 Fix all issues with AI agents
In
`@app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsCategoryScreen.kt`:
- Around line 75-76: The onCardClick lambda is only passing title but
GoodsCategoryUiIntent.OnCardClick requires both artistId: Long and title:
String; update GoodsCategoryRoute to forward the received artistId into
GoodsCategoryScreen and change the onCardClick handlers (both the higher-order
lambda in GoodsCategoryScreen and the call site using groupItem.postTitle) to
pass both parameters (title and the artistId) matching the (String, Long) ->
Unit signature, then invoke
viewModel.processIntent(GoodsCategoryUiIntent.OnCardClick(artistId, title)) (or
equivalent ordering used by the intent) so both required fields are provided.

In
`@app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsFilteredPartyListScreen.kt`:
- Line 3: 파일 GoodsFilteredPartyListScreen.kt에 남아있는 디버그 로그를 제거하세요: 모든 Log.d 호출을
삭제하고 사용하지 않게 된 import android.util.Log 문도 함께 제거하며, 관련된 함수나 컴포저블(예:
GoodsFilteredPartyListScreen) 내부에서 디버그 출력 대신 필요하면 적절한 로깅(프로덕션 로그 또는 analytics)으로
대체하세요.

In
`@app/src/main/java/com/poti/android/presentation/party/goodsfilter/model/Contracts.kt`:
- Around line 61-73: The loadState property currently masks original errors by
returning ApiState.Failure(""); update the failure branch to propagate the real
error(s) from productPartyListInfo and/or membersLoadState instead of an empty
string — e.g., if productPartyListInfo is ApiState.Failure return that failure,
else if membersLoadState is ApiState.Failure return that failure, or combine
both messages when both are failures; change the failure branch in the loadState
getter so ApiState.Failure carries the original error details from
productPartyListInfo and membersLoadState.
♻️ Duplicate comments (1)
app/src/main/java/com/poti/android/presentation/user/mypage/MyPageScreen.kt (1)

118-122: onArtistClick 콜백이 사용되지 않아 버튼 클릭 시 동작하지 않습니다.

현재 BadgeButtononClick이 빈 람다로 설정되어 있어요. Line 61의 TODO 주석에 따르면 "선택 최애 없을 때만 이동"하는 조건부 로직이 필요해 보입니다. PR 설명에도 바텀시트 작업이 미완료라고 되어 있으니, 해당 작업과 함께 처리해 주시면 될 것 같습니다.

🧹 Nitpick comments (7)
app/src/main/java/com/poti/android/presentation/party/home/component/HomeGoodsSection.kt (1)

62-77: LazyRow 항목에 key 지정 권장

리스트 변경 시 아이템 상태가 뒤섞이거나 불필요한 리컴포지션이 발생할 수 있어요. items(groupItems, key = { /* 안정적 유니크 키 */ }) 형태로 키를 지정해 주세요. (예: postId가 있다면 그 값을 사용) 코딩 가이드라인에 따라, ...

app/src/main/java/com/poti/android/domain/model/party/ProductPartyList.kt (1)

3-7: Compose 안정성을 위해 @Immutable 어노테이션 추가를 고려해 주세요.

List는 Compose에서 불안정한(unstable) 타입으로 취급되어 불필요한 리컴포지션을 유발할 수 있습니다. 이 도메인 모델이 UI State에서 직접 사용된다면 @Immutable 어노테이션을 추가하시는 것을 권장드려요.

♻️ 제안 코드
+import androidx.compose.runtime.Immutable
+
+@Immutable
 data class ProductPartyList(
     val partyTitle: String,
     val artistName: String,
     val partySummaries: List<PartySummary>,
 )

+@Immutable
 data class PartySummary(
     ...
 )

단, Domain 레이어의 순수성을 유지하려면 Presentation 레이어에 별도 UI 모델을 만들어 @Immutable을 적용하는 방법도 있습니다.

app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsCategoryScreen.kt (1)

135-142: LazyColumn items에 key 지정이 권장됩니다.

groupItems가 변경/갱신될 때 재사용 및 리컴포지션 안정성을 위해 안정적인 key(예: 고유 ID)를 지정해 주세요.

app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsFilterViewModel.kt (1)

36-47: 바텀시트 TODO는 릴리즈 전에 트래킹이 필요합니다.

두 인텐트 모두 TODO만 있고 동작이 없어서 UX 상 반응이 없습니다. 최소한 이슈/후속 PR로 추적 부탁드립니다. 필요하시면 연결 로직 초안도 도와드릴게요.

app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsFilteredPartyListScreen.kt (1)

20-20: Hilt ViewModel import가 deprecated 되었습니다.

androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel은 deprecated 되었습니다. Modern Android Development 권장 사항에 따라 androidx.hilt.navigation.compose.hiltViewModel을 사용해 주세요.

♻️ 제안하는 수정 사항
-import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
+import androidx.hilt.navigation.compose.hiltViewModel
app/src/main/java/com/poti/android/presentation/party/goodsfilter/model/Contracts.kt (2)

37-59: @Composable getter를 UiState에서 분리하는 것을 권장드립니다.

memberFilterText@Composable get()으로 선언되어 있어 UiState가 Compose 런타임에 의존하게 됩니다. 이로 인해:

  • Domain 순수성 원칙에 위배될 수 있습니다
  • 단위 테스트 작성이 어려워집니다
  • State 클래스의 재사용성이 제한됩니다

Screen Composable에서 직접 처리하거나 별도의 @Composable 확장 함수로 분리하시는 것을 권장드립니다.

♻️ 제안하는 수정 사항

UiState에서는 순수 데이터만 유지하고, 텍스트 생성 로직은 Composable 확장 함수로 분리해 주세요:

// Contracts.kt - UiState에서 memberFilterText 제거
data class GoodsFilterUiState(
    val productPartyListInfo: ApiState<ProductPartyList> = ApiState.Loading,
    val membersLoadState: ApiState<List<FilterMember>> = ApiState.Loading,
    val displayMembers: List<FilterMember> = emptyList(),
    val selectedMembers: List<FilterMember> = emptyList(),
    val goodsPartySortType: PartySortType = PartySortType.LATEST,
) : UiState {
    val selectedMemberIds: List<Long>
        get() = selectedMembers.map { it.id }

    val loadState: ApiState<Unit>
        get() = // ... 기존 로직
}

// Extension.kt 또는 Screen 파일에 추가
`@Composable`
fun GoodsFilterUiState.memberFilterText(): String = when {
    selectedMembers.isEmpty() ->
        stringResource(R.string.goods_filter_member_select)
    selectedMembers.size == 1 ->
        selectedMembers[0].name
    selectedMembers.size == 2 ->
        stringResource(
            R.string.goods_filter_member_two_format,
            selectedMembers[0].name,
            selectedMembers[1].name,
        )
    else ->
        stringResource(
            R.string.goods_filter_member_more_format,
            selectedMembers[0].name,
            selectedMembers[1].name,
            selectedMembers.size - 2,
        )
}

22-25: FilterMember@Stable 어노테이션 추가를 고려해 주세요.

FilterMemberList로 사용되고 있으므로, Compose 컴파일러가 안정성을 올바르게 추론하지 못해 불필요한 리컴포지션이 발생할 수 있습니다. 코딩 가이드라인에 따라 @Stable 또는 @Immutable 어노테이션을 추가하시면 성능 최적화에 도움이 됩니다.

♻️ 제안하는 수정 사항
+import androidx.compose.runtime.Immutable

+@Immutable
 data class FilterMember(
     val id: Long,
     val name: String,
 )

Comment on lines +61 to +73
val loadState: ApiState<Unit>
get() = when {
productPartyListInfo is ApiState.Loading &&
membersLoadState is ApiState.Loading -> ApiState.Loading

productPartyListInfo is ApiState.Failure ||
membersLoadState is ApiState.Failure -> ApiState.Failure("")

productPartyListInfo is ApiState.Success &&
membersLoadState is ApiState.Success -> ApiState.Success(Unit)

else -> ApiState.Loading
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

에러 정보가 소실되고 있습니다.

ApiState.Failure("")로 처리하면 원래의 에러 메시지가 소실됩니다. 디버깅이나 사용자에게 적절한 에러 메시지를 표시하기 어려워질 수 있으니, 원본 에러 정보를 유지하거나 적절한 에러 메시지를 전달하시는 것을 권장드립니다.

🐛 제안하는 수정 사항
             productPartyListInfo is ApiState.Failure ||
-                membersLoadState is ApiState.Failure -> ApiState.Failure("")
+                membersLoadState is ApiState.Failure -> {
+                    val errorMessage = when {
+                        productPartyListInfo is ApiState.Failure -> productPartyListInfo.message
+                        membersLoadState is ApiState.Failure -> membersLoadState.message
+                        else -> ""
+                    }
+                    ApiState.Failure(errorMessage)
+                }
🤖 Prompt for AI Agents
In
`@app/src/main/java/com/poti/android/presentation/party/goodsfilter/model/Contracts.kt`
around lines 61 - 73, The loadState property currently masks original errors by
returning ApiState.Failure(""); update the failure branch to propagate the real
error(s) from productPartyListInfo and/or membersLoadState instead of an empty
string — e.g., if productPartyListInfo is ApiState.Failure return that failure,
else if membersLoadState is ApiState.Failure return that failure, or combine
both messages when both are failures; change the failure branch in the loadState
getter so ApiState.Failure carries the original error details from
productPartyListInfo and membersLoadState.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a 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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsFilteredPartyListScreen.kt (2)

140-156: LazyColumn itemskey 파라미터를 추가해 주세요.

items() 함수에 key 파라미터가 누락되어 있습니다. key가 없으면 리스트 항목이 변경될 때 불필요한 리컴포지션이 발생하고, 항목 순서가 바뀔 때 잘못된 상태가 유지될 수 있습니다. PartySummarypartyId를 key로 사용하시는 것을 권장드립니다.

🔧 제안하는 수정 사항
-            items(productPartyListInfo.partySummaries) { party ->
+            items(
+                items = productPartyListInfo.partySummaries,
+                key = { it.partyId }
+            ) { party ->

165-167: Preview 함수명에 오타가 있습니다.

GoodsFilteredPartyListScreenPreveiw에서 PreveiwPreview로 수정이 필요합니다. 작은 오타이지만 코드 검색이나 일관성 측면에서 수정해 주시면 좋겠습니다.

✏️ 제안하는 수정 사항
-private fun GoodsFilteredPartyListScreenPreveiw() {
+private fun GoodsFilteredPartyListScreenPreview() {
app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsCategoryScreen.kt (1)

47-52: NavigateToGoodsPartyList에서 effect의 artistId를 무시하고 있어요.

카드 클릭으로 전달된 effect.artistId를 사용해야 하는데, 현재는 라우트 파라미터의 artistId를 고정으로 사용하고 있습니다. 클릭한 아티스트와 라우트의 아티스트가 다른 경우 잘못된 목록으로 이동하게 돼요. ViewModel에서 GoodsCategoryUiEffect.NavigateToGoodsPartyList(intent.artistId, intent.title)로 제대로 전달하고 있으니, 이를 활용해 주세요.

수정 제안
-            is GoodsCategoryUiEffect.NavigateToGoodsPartyList -> onNavigateToGoodsPartyList(artistId, effect.title)
+            is GoodsCategoryUiEffect.NavigateToGoodsPartyList -> onNavigateToGoodsPartyList(effect.artistId, effect.title)
♻️ Duplicate comments (1)
app/src/main/java/com/poti/android/presentation/party/goodsfilter/model/GoodsFilteredContracts.kt (1)

63-70: 에러 메시지가 소실됩니다.
현재 ApiState.Failure("")로 처리되어 원본 에러 정보가 사라집니다. 디버깅/UX를 위해 원본 메시지를 전달하는 편이 안전합니다.

🐛 제안 수정
-            productPartyListInfo is ApiState.Failure ||
-                membersLoadState is ApiState.Failure -> ApiState.Failure("")
+            productPartyListInfo is ApiState.Failure ||
+                membersLoadState is ApiState.Failure -> {
+                val errorMessage = when {
+                    productPartyListInfo is ApiState.Failure -> productPartyListInfo.message
+                    membersLoadState is ApiState.Failure -> membersLoadState.message
+                    else -> ""
+                }
+                ApiState.Failure(errorMessage)
+            }
🧹 Nitpick comments (2)
app/src/main/java/com/poti/android/presentation/party/goodsfilter/model/GoodsFilteredContracts.kt (1)

22-35: 필터 상태 클래스의 안정성을 개선하세요.

FilterMember는 단순한 불변 데이터 클래스이므로 @Immutable 적용을 권장합니다. 다만 GoodsFilterUiState의 경우, ApiState<T>가 안정성 어노테이션으로 표시되지 않았고, memberFilterText@Composable 게터는 상태 클래스 내에서 Composable 로직을 수행하는 구조이므로, 다음과 같이 개선하는 것을 권장합니다:

  1. FilterMember에 @Immutable 적용 (좋은 관행)
  2. GoodsFilterUiState의 @Composable 게터 리팩토링: 상태 클래스는 순수한 데이터만 보유하고, memberFilterText 같은 UI 텍스트 생성 로직은 Composable 함수 또는 remember + derivedStateOf 내에서 처리하도록 분리

이렇게 하면 Compose 안정성이 명확해지고, 불필요한 리컴포지션을 더 효과적으로 방지할 수 있습니다.

app/src/main/java/com/poti/android/presentation/party/home/component/HomeGoodsSection.kt (1)

62-67: LazyRow 아이템에 안정적인 key를 추가하는 것을 권장드립니다.

리스트 아이템 재배치/상태 보존을 위해 items(..., key = { ... }) 형태로 안정적인 식별자를 지정해 주세요. 코딩 가이드라인에 따라.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a 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

🤖 Fix all issues with AI agents
In
`@app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsFilterViewModel.kt`:
- Around line 89-91: There's a typo: the state property is named cacheedSubTitle
but should be cachedSubTitle; update the property name in the assignment in
GoodsFilterViewModel (where productPartyListInfo, cachedTitle, cacheedSubTitle
are set from partyList.partyTitle and partyList.artistName) and also rename the
corresponding declaration/usage in GoodsFilteredContracts (fix the state
definition and any references to cacheedSubTitle to cachedSubTitle) to keep
names consistent and avoid compile errors.

In
`@app/src/main/java/com/poti/android/presentation/party/goodsfilter/model/GoodsFilteredContracts.kt`:
- Around line 26-34: There are typos in the properties of GoodsFilteredContracts
(cacheedSubTitle, bottomSheetSelectedMembersIdices, isMemberBottomSheetToucehd);
rename them to cachedSubTitle, bottomSheetSelectedMembersIndices, and
isMemberBottomSheetTouched respectively in the data class (or contract) and
update all usages/references (call sites, tests, serialization/mapping,
parcelization) to match the new identifiers to avoid compile errors and
mismatches.
🧹 Nitpick comments (6)
app/src/main/res/values/strings.xml (2)

17-21: 중복된 문자열 값이 존재합니다.

action_button_reset (Line 17)과 action_button_refresh (Line 21)가 모두 동일한 값 "초기화"를 가지고 있습니다.

의도적인 분리라면 무시하셔도 되지만, 동일한 UI 텍스트를 여러 곳에서 사용하는 경우 하나의 string resource를 재사용하시는 것이 Modern Android Development에서 권장하는 방식입니다. 이렇게 하면 향후 번역 작업이나 텍스트 수정 시 유지보수가 용이해집니다.


239-245: 중복된 문자열 리소스가 존재합니다.

goods_filter_member_select (Line 239)와 goods_filter_member_select_label (Line 245)가 동일한 값 "멤버 선택"을 가지고 있습니다.

두 리소스가 UI에서 다른 용도로 사용되는지 확인해 주세요. 만약 동일한 텍스트를 표시하는 용도라면, 하나의 리소스로 통합하시는 것이 리소스 관리 및 다국어 지원(i18n) 측면에서 효율적입니다.

#!/bin/bash
# Description: 두 문자열 리소스의 실제 사용처를 확인합니다.

echo "=== goods_filter_member_select 사용처 ==="
rg -n "goods_filter_member_select[^_]" --type=xml --type=kotlin

echo ""
echo "=== goods_filter_member_select_label 사용처 ==="
rg -n "goods_filter_member_select_label" --type=xml --type=kotlin
app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsFilterViewModel.kt (1)

24-25: savedStateHandle.toRoute<GoodsPartyList>()가 두 번 호출되고 있습니다.

동일한 호출이 두 번 수행되어 약간의 비효율이 발생합니다. 한 번만 호출하여 결과를 재사용하시는 것을 권장드립니다.

♻️ 제안하는 개선안
 `@HiltViewModel`
 class GoodsFilterViewModel `@Inject` constructor(
     private val artistRepository: ArtistRepository,
     private val partyRepository: PartyRepository,
     savedStateHandle: SavedStateHandle,
 ) : BaseViewModel<GoodsFilterUiState, GoodsFilterUiIntent, GoodsFilterUiEffect>(
         initialState = GoodsFilterUiState(),
     ) {
-    private val artistId: Long = savedStateHandle.toRoute<GoodsPartyList>().artistId
-    private val title: String = savedStateHandle.toRoute<GoodsPartyList>().title
+    private val route: GoodsPartyList = savedStateHandle.toRoute<GoodsPartyList>()
+    private val artistId: Long = route.artistId
+    private val title: String = route.title
app/src/main/java/com/poti/android/presentation/party/goodsfilter/model/GoodsFilteredContracts.kt (1)

39-61: @Composable getter가 UiState 내부에 있습니다.

memberFilterText 프로퍼티가 @Composable getter를 사용하고 있어, UiState가 Compose 런타임에 의존하게 됩니다. MVI 패턴에서 UiState는 순수한 데이터 클래스로 유지하고, 문자열 포맷팅 로직은 UI 레이어(Composable 함수 내부)에서 처리하시는 것이 Clean Architecture 원칙에 더 부합합니다.

대안으로 selectedMembers만 UiState에 유지하고, 화면에서 stringResource를 사용하여 텍스트를 생성하시는 방법을 고려해 주세요.

♻️ 제안하는 개선안

UiState에서 memberFilterText를 제거하고, UI 레이어에서 직접 포맷팅:

// GoodsFilteredPartyListScreen.kt 내부
val memberFilterText = when {
    uiState.selectedMembers.isEmpty() ->
        stringResource(R.string.goods_filter_member_select)
    uiState.selectedMembers.size == 1 ->
        uiState.selectedMembers[0].name
    uiState.selectedMembers.size == 2 ->
        stringResource(
            R.string.goods_filter_member_two_format,
            uiState.selectedMembers[0].name,
            uiState.selectedMembers[1].name,
        )
    else ->
        stringResource(
            R.string.goods_filter_member_more_format,
            uiState.selectedMembers[0].name,
            uiState.selectedMembers[1].name,
            uiState.selectedMembers.size - 2,
        )
}
app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsFilteredPartyListScreen.kt (2)

43-49: artistId 파라미터가 사용되지 않고 있습니다.

GoodsFilteredPartyListRouteartistId 파라미터가 함수 내부에서 사용되지 않습니다. ViewModel이 SavedStateHandle에서 직접 artistId를 추출하므로 이 파라미터는 불필요해 보입니다. 제거하시거나, 네비게이션 그래프와의 일관성을 위해 유지해야 하는 경우 @Suppress("UNUSED_PARAMETER")를 추가하시는 것을 고려해 주세요.


165-181: LazyColumnitemskey 파라미터가 누락되었습니다.

items 함수에 key 파라미터를 지정하지 않으면, 리스트 아이템이 변경될 때 불필요한 리컴포지션이 발생할 수 있습니다. partyId를 key로 사용하시면 성능 최적화에 도움이 됩니다. 코딩 가이드라인에서 언급된 Recomposition 방지 원칙에 해당합니다.

♻️ 제안하는 개선안
-            items(productPartyListInfo.partySummaries) { party ->
+            items(
+                items = productPartyListInfo.partySummaries,
+                key = { it.partyId },
+            ) { party ->
                 PartyCard(
                     potId = party.partyId,

Comment on lines +89 to +91
productPartyListInfo = ApiState.Success(partyList),
cachedTitle = partyList.partyTitle,
cacheedSubTitle = partyList.artistName,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

오타 발견: cacheedSubTitle

cacheedSubTitle에 오타가 있습니다. cachedSubTitle로 수정하시는 것이 좋겠습니다. 이 오타는 GoodsFilteredContracts.kt의 상태 정의에도 동일하게 존재하므로 함께 수정이 필요합니다.

🐛 제안하는 수정 사항
-                    cacheedSubTitle = partyList.artistName,
+                    cachedSubTitle = partyList.artistName,
🤖 Prompt for AI Agents
In
`@app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsFilterViewModel.kt`
around lines 89 - 91, There's a typo: the state property is named
cacheedSubTitle but should be cachedSubTitle; update the property name in the
assignment in GoodsFilterViewModel (where productPartyListInfo, cachedTitle,
cacheedSubTitle are set from partyList.partyTitle and partyList.artistName) and
also rename the corresponding declaration/usage in GoodsFilteredContracts (fix
the state definition and any references to cacheedSubTitle to cachedSubTitle) to
keep names consistent and avoid compile errors.

Comment on lines +26 to +34
val cacheedSubTitle: String = "",
val membersLoadState: ApiState<List<Member>> = ApiState.Loading,
val displayMembers: List<Member> = emptyList(),
val selectedMembers: List<Member> = emptyList(),
val goodsPartySortType: PartySortType = PartySortType.HOT,
val isMemberFilterBottomSheetVisible: Boolean = false,
val isSortFilterBottomSheetVisible: Boolean = false,
val bottomSheetSelectedMembersIdices: Set<Int> = setOf(),
val isMemberBottomSheetToucehd: Boolean = false,
Copy link
Copy Markdown

@coderabbitai coderabbitai bot Jan 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

여러 프로퍼티에 오타가 있습니다.

다음 프로퍼티들에 오타가 발견되었습니다:

  • Line 26: cacheedSubTitlecachedSubTitle
  • Line 33: bottomSheetSelectedMembersIdicesbottomSheetSelectedMembersIndices
  • Line 34: isMemberBottomSheetToucehdisMemberBottomSheetTouched
🐛 제안하는 수정 사항
 data class GoodsFilterUiState(
     val productPartyListInfo: ApiState<ProductPartyList> = ApiState.Loading,
     val cachedTitle: String = "",
-    val cacheedSubTitle: String = "",
+    val cachedSubTitle: String = "",
     val membersLoadState: ApiState<List<Member>> = ApiState.Loading,
     val displayMembers: List<Member> = emptyList(),
     val selectedMembers: List<Member> = emptyList(),
     val goodsPartySortType: PartySortType = PartySortType.HOT,
     val isMemberFilterBottomSheetVisible: Boolean = false,
     val isSortFilterBottomSheetVisible: Boolean = false,
-    val bottomSheetSelectedMembersIdices: Set<Int> = setOf(),
-    val isMemberBottomSheetToucehd: Boolean = false,
+    val bottomSheetSelectedMembersIndices: Set<Int> = setOf(),
+    val isMemberBottomSheetTouched: Boolean = false,
 ) : UiState {
📝 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.

Suggested change
val cacheedSubTitle: String = "",
val membersLoadState: ApiState<List<Member>> = ApiState.Loading,
val displayMembers: List<Member> = emptyList(),
val selectedMembers: List<Member> = emptyList(),
val goodsPartySortType: PartySortType = PartySortType.HOT,
val isMemberFilterBottomSheetVisible: Boolean = false,
val isSortFilterBottomSheetVisible: Boolean = false,
val bottomSheetSelectedMembersIdices: Set<Int> = setOf(),
val isMemberBottomSheetToucehd: Boolean = false,
val cachedSubTitle: String = "",
val membersLoadState: ApiState<List<Member>> = ApiState.Loading,
val displayMembers: List<Member> = emptyList(),
val selectedMembers: List<Member> = emptyList(),
val goodsPartySortType: PartySortType = PartySortType.HOT,
val isMemberFilterBottomSheetVisible: Boolean = false,
val isSortFilterBottomSheetVisible: Boolean = false,
val bottomSheetSelectedMembersIndices: Set<Int> = setOf(),
val isMemberBottomSheetTouched: Boolean = false,
🤖 Prompt for AI Agents
In
`@app/src/main/java/com/poti/android/presentation/party/goodsfilter/model/GoodsFilteredContracts.kt`
around lines 26 - 34, There are typos in the properties of
GoodsFilteredContracts (cacheedSubTitle, bottomSheetSelectedMembersIdices,
isMemberBottomSheetToucehd); rename them to cachedSubTitle,
bottomSheetSelectedMembersIndices, and isMemberBottomSheetTouched respectively
in the data class (or contract) and update all usages/references (call sites,
tests, serialization/mapping, parcelization) to match the new identifiers to
avoid compile errors and mismatches.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

영어 잘하네

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@doyeon0307 감사합니다! 😊 코드 리뷰에서 이런 오타를 잡아내는 것도 제 역할이에요. 프로퍼티명의 오타는 나중에 다른 개발자분들이 사용하실 때 혼란을 줄 수 있어서 미리 수정하시는 게 좋습니다!

(੭˃ᴗ˂)੭

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a 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

🤖 Fix all issues with AI agents
In
`@app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsFilterViewModel.kt`:
- Around line 24-107: loadPartyList() can run concurrently and an
earlier-response may overwrite a later one; fix by making only the latest
request able to update state: add a scoped cancellable Job (e.g., a property
currentLoadJob: Job?) or a monotonically increasing requestId (e.g.,
loadRequestCounter: Long) on the ViewModel, cancel the previous Job or increment
and capture the current requestId at the start of loadPartyList(), then before
applying updates in the onSuccess/onFailure handlers check that the captured
requestId matches the latest counter (or that the Job is still active); update
launchScope usage in loadPartyList() to assign to currentLoadJob (or use the
requestId) so duplicated calls will cancel/ignore older responses and only the
latest result from loadPartyList() updates the UI state.
🧹 Nitpick comments (1)
app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsFilterViewModel.kt (1)

126-138: 선택 매핑이 O(n²)이고 객체 동등성에 의존합니다.
멤버 수가 늘어나면 비용이 커지고, 객체 인스턴스가 달라지면 선택 복원이 실패할 수 있습니다. memberId 기반으로 조회하는 방식이 더 안전합니다.

♻️ 제안 수정
     private fun refreshMemberSelectBottomSheet() {
-        val newSelectedIndices = uiState.value.displayMembers.mapIndexed { index, member ->
-            if (member in uiState.value.selectedMembers) index else null
-        }
+        val selectedMemberIds = uiState.value.selectedMembers.map { it.memberId }.toSet()
+        val newSelectedIndices = uiState.value.displayMembers.mapIndexed { index, member ->
+            if (member.memberId in selectedMemberIds) index else null
+        }
             .filterNotNull()
             .toSet()

         updateState {
             copy(
                 bottomSheetSelectedMembersIdices = newSelectedIndices,
                 isMemberBottomSheetToucehd = false,
             )
         }
     }

Comment on lines +24 to 107
private val artistId: Long = savedStateHandle.toRoute<GoodsPartyList>().artistId
private val title: String = savedStateHandle.toRoute<GoodsPartyList>().title

override fun processIntent(intent: GoodsFilterUiIntent) {
when (intent) {
GoodsFilterUiIntent.LoadGoodsPots -> loadGoodsPots()
GoodsFilterUiIntent.OnBackClick -> sendEffect(GoodsFilterUiEffect.NavigateBack)
GoodsFilterUiIntent.OnFloatingClick -> sendEffect(GoodsFilterUiEffect.NavigateToPartyCreate)
is GoodsFilterUiIntent.OnPartyClick ->
sendEffect(GoodsFilterUiEffect.NavigateToPartyDetail(intent.partyId))
GoodsFilterUiIntent.OnMemberFilterClick -> {
// TODO: [예림] 바텀시트 open
}
is GoodsFilterUiIntent.OnMembersSelect -> {
updateState { copy(selectedMember = intent.members) }
}
GoodsFilterUiIntent.OnSortFilterClick -> {
// TODO: [예림] 바텀시트 open
}
is GoodsFilterUiIntent.OnSortSelect -> {
updateState { copy(goodsSortFilter = intent.sort) }
init {
fetchArtistMembers()
loadPartyList()
}

override fun processIntent(intent: GoodsFilterUiIntent) {
when (intent) {
GoodsFilterUiIntent.LoadGoodsPots -> loadPartyList()
GoodsFilterUiIntent.OnBackClick -> sendEffect(GoodsFilterUiEffect.NavigateBack)
GoodsFilterUiIntent.OnFloatingClick -> sendEffect(GoodsFilterUiEffect.NavigateToPartyCreate)
is GoodsFilterUiIntent.OnPartyClick -> sendEffect(GoodsFilterUiEffect.NavigateToPartyDetail(intent.partyId))
GoodsFilterUiIntent.OnMemberFilterClick -> {
refreshMemberSelectBottomSheet()
updateState { copy(isMemberFilterBottomSheetVisible = true) }
}

is GoodsFilterUiIntent.OnMemberSelect -> {
onBottomSheetMemberChanged(intent.index)
}

GoodsFilterUiIntent.OnSortFilterClick -> {
updateState { copy(isSortFilterBottomSheetVisible = true) }
}

GoodsFilterUiIntent.CloseSortFilterBottomSheet -> {
updateState { copy(isSortFilterBottomSheetVisible = false) }
}

is GoodsFilterUiIntent.OnSortSelect -> {
updateState { copy(goodsPartySortType = intent.sort, isSortFilterBottomSheetVisible = false) }
loadPartyList()
}

GoodsFilterUiIntent.CloseMemberFilterBottomSheet -> updateState { copy(isMemberFilterBottomSheetVisible = false) }

GoodsFilterUiIntent.OnMemberFilterDone -> saveSelectedMember()

GoodsFilterUiIntent.OnMemberFilterRefresh -> {
if (uiState.value.bottomSheetSelectedMembersIdices.isNotEmpty()) {
clearSelectedMembers()
}
}
}
}

private fun loadPartyList() = launchScope {
val currentState = uiState.value
val sort = currentState.goodsPartySortType.request
val memberIds = if (currentState.selectedMembers.isNotEmpty()) {
currentState.selectedMembers.map { it.memberId }
} else {
null
}

private fun loadGoodsPots() = launchScope {
updateState { copy(productPartyListInfo = ApiState.Loading) }

partyRepository.getProductPartyList(
page = 0,
size = 10,
title = title,
artistId = artistId,
sort = sort,
memberIds = memberIds,
).onSuccess { partyList ->
updateState {
copy(
productPartyListInfo = ApiState.Success(partyList),
cachedTitle = partyList.partyTitle,
cachedSubTitle = partyList.artistName,
)
}
}.onFailure { throwable ->
updateState {
copy(
partyListInfo = ApiState.Success(dummyPartyList),
membersLoadState = ApiState.Success(emptyList()),
productPartyListInfo = ApiState.Failure(
throwable.message ?: "Failed",
),
)
}
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

연속 요청 시 오래된 응답이 최신 상태를 덮을 수 있습니다.
필터를 빠르게 변경하면 loadPartyList()가 중복 호출되고, 먼저 시작한 요청이 더 늦게 끝나면서 최신 필터 결과를 덮을 위험이 있습니다. 요청 버전 체크(또는 Job 취소)로 최신 요청만 반영되게 해주세요.

✅ 제안 수정 (요청 버전 체크)
     private val artistId: Long = savedStateHandle.toRoute<GoodsPartyList>().artistId
     private val title: String = savedStateHandle.toRoute<GoodsPartyList>().title
+    private var loadPartyListRequestId = 0

     private fun loadPartyList() = launchScope {
+        val requestId = ++loadPartyListRequestId
         val currentState = uiState.value
         val sort = currentState.goodsPartySortType.request
         val memberIds = if (currentState.selectedMembers.isNotEmpty()) {
             currentState.selectedMembers.map { it.memberId }
         } else {
             null
         }

         updateState { copy(productPartyListInfo = ApiState.Loading) }

         partyRepository.getProductPartyList(
             page = 0,
             size = 10,
             title = title,
             artistId = artistId,
             sort = sort,
             memberIds = memberIds,
         ).onSuccess { partyList ->
+            if (requestId != loadPartyListRequestId) return@onSuccess
             updateState {
                 copy(
                     productPartyListInfo = ApiState.Success(partyList),
                     cachedTitle = partyList.partyTitle,
                     cachedSubTitle = partyList.artistName,
                 )
             }
         }.onFailure { throwable ->
+            if (requestId != loadPartyListRequestId) return@onFailure
             updateState {
                 copy(
                     productPartyListInfo = ApiState.Failure(
                         throwable.message ?: "Failed",
                     ),
                 )
             }
         }
     }
🤖 Prompt for AI Agents
In
`@app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsFilterViewModel.kt`
around lines 24 - 107, loadPartyList() can run concurrently and an
earlier-response may overwrite a later one; fix by making only the latest
request able to update state: add a scoped cancellable Job (e.g., a property
currentLoadJob: Job?) or a monotonically increasing requestId (e.g.,
loadRequestCounter: Long) on the ViewModel, cancel the previous Job or increment
and capture the current requestId at the start of loadPartyList(), then before
applying updates in the onSuccess/onFailure handlers check that the captured
requestId matches the latest counter (or that the Job is still active); update
launchScope usage in loadPartyList() to assign to currentLoadJob (or use the
requestId) so duplicated calls will cancel/ignore older responses and only the
latest result from loadPartyList() updates the UI state.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Jan 22, 2026

Ktlint check passed.

Run: https://github.com/team-poti/POTI-ANDROID/actions/runs/21247696095

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a 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

🤖 Fix all issues with AI agents
In
`@app/src/main/java/com/poti/android/presentation/party/goodsfilter/component/FilteredSortBottomSheet.kt`:
- Around line 46-51: onClick 핸들러가 sheetState.hide()를 비동기 호출만 하고 숨김 완료 후 부모에 알리는
onDismissRequest()를 호출하지 않아 상태 불일치가 발생합니다; 수정은 FilteredSortBottomSheet의 onClick
람다에서 scope.launch { sheetState.hide() }를 그냥 호출하는 대신 launch의 반환 Job을 받아 내부에서
sheetState.hide()를 실행하고 그 Job에 대해 invokeOnCompletion { onDismissRequest() }를 등록해
시트가 완전히 숨겨진 뒤 onDismissRequest()가 호출되도록 하세요 (onSelect 호출 순서는 유지).

In
`@app/src/main/java/com/poti/android/presentation/party/goodsfilter/component/GoodsSortBottomSheet.kt`:
- Line 3: Remove the unused imports in GoodsSortBottomSheet.kt that are causing
ktlint failures: specifically delete the import androidx.annotation.StringRes
and the other unused import on line 17; ensure the class GoodsSortBottomSheet
compiles and no references to those annotations remain (if used, replace usages
appropriately), then re-run ktlint/CI to confirm the lint error is resolved.

In
`@app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsCategoryScreen.kt`:
- Line 51: Change the navigation call to use the clicked card's artistId from
the effect by replacing the current artistId argument with effect.artistId in
the GoodsCategoryUiEffect.NavigateToGoodsPartyList handling (so
onNavigateToGoodsPartyList receives effect.artistId, effect.title); also add a
stable key to the LazyColumn items call by passing key = { it.id } when
iterating goodsCategory.groupItems to improve recomposition stability (refer to
items(goodsCategory.groupItems) and groupItem.id).
♻️ Duplicate comments (1)
app/src/main/java/com/poti/android/presentation/party/goodsfilter/model/GoodsFilteredContracts.kt (1)

33-34: 프로퍼티명에 오타가 있습니다.

이전 리뷰에서 지적된 오타가 아직 수정되지 않았습니다:

  • bottomSheetSelectedMembersIdicesbottomSheetSelectedMembersIndices
  • isMemberBottomSheetToucehdisMemberBottomSheetTouched

이 오타들이 다른 파일(GoodsFilteredPartyListScreen.kt)에서도 참조되고 있으므로, 일괄 수정이 필요합니다.

♻️ 제안하는 수정 사항
-    val bottomSheetSelectedMembersIdices: Set<Int> = setOf(),
-    val isMemberBottomSheetToucehd: Boolean = false,
+    val bottomSheetSelectedMembersIndices: Set<Int> = setOf(),
+    val isMemberBottomSheetTouched: Boolean = false,
🧹 Nitpick comments (5)
app/src/main/java/com/poti/android/presentation/party/goodsfilter/component/FilteredSortBottomSheet.kt (2)

41-41: 불필요한 .padding() 호출이에요.

인자 없이 호출된 .padding()은 아무런 효과가 없으므로 제거하시는 것이 좋을 것 같아요.

♻️ 수정 제안
     PotiBottomSheet(
         onDismissRequest = onDismissRequest,
         sheetState = sheetState,
-        modifier = modifier.padding(),
+        modifier = modifier,
     ) {

44-44: 매 리컴포지션마다 새로운 ImmutableList가 생성되고 있어요.

options.map { stringResource(it) }.toImmutableList()가 리컴포지션될 때마다 새 리스트를 생성하고 있어요. stringResource는 Composable 함수라서 remember 블록 안에서 호출할 수 없지만, 현재 구조에서는 options (line 29-31)를 resource ID로 remember하고, 여기서 다시 매핑하는 방식이 비효율적이에요.

♻️ 수정 제안

options를 아예 제거하고, sortTypes만 사용하여 직접 매핑하는 방식으로 단순화할 수 있어요:

     val sortTypes = remember { FilteredSortType.entries.toList() }
 
-    val options = remember {
-        sortTypes.map { it.displayRes }.toImmutableList()
-    }
-
     val selectedIndex = sortTypes.indexOf(selectedSortType)
     val sheetState = rememberModalBottomSheetState()
 
@@ ... @@
         PotiListRadio(
-            options = options.map { stringResource(it) }.toImmutableList(),
+            options = sortTypes.map { stringResource(it.displayRes) }.toImmutableList(),
             selectedOptionIndex = selectedIndex,

중간 options 변수를 제거하면 코드가 더 간결해지고 의도가 명확해져요.

app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsCategoryScreen.kt (1)

135-148: LazyColumnitemskey 파라미터가 누락되었습니다.

리스트 아이템에 고유한 key를 지정하지 않으면 불필요한 리컴포지션이 발생할 수 있습니다. groupItem에 고유 식별자가 있다면 key 파라미터를 추가해 주세요.

♻️ 제안하는 수정 사항
-            items(goodsCategory.groupItems) { groupItem ->
+            items(
+                items = goodsCategory.groupItems,
+                key = { it.artistId } // 또는 다른 고유 식별자
+            ) { groupItem ->
app/src/main/java/com/poti/android/presentation/party/goodsfilter/model/GoodsFilteredContracts.kt (1)

39-61: @Composable getter를 data class 내부에서 사용하는 것은 권장되지 않습니다.

memberFilterText 프로퍼티가 @Composable getter로 정의되어 있습니다. Data class는 순수한 데이터 컨테이너로 유지하는 것이 좋습니다. 이 로직은 UI 레이어(Screen 또는 별도의 Composable 함수)로 이동시키거나, 리소스 ID를 반환하는 방식으로 변경하는 것을 권장드립니다.

♻️ 제안하는 수정 사항

Extension function으로 분리하거나, sealed class로 필터 상태를 표현하는 방법을 고려해 주세요:

// Extension.kt 또는 별도 파일에 정의
`@Composable`
fun GoodsFilterUiState.memberFilterText(): String = when {
    selectedMembers.isEmpty() ->
        stringResource(R.string.goods_filter_member_select)
    selectedMembers.size == 1 ->
        selectedMembers[0].name
    selectedMembers.size == 2 ->
        stringResource(
            R.string.goods_filter_member_two_format,
            selectedMembers[0].name,
            selectedMembers[1].name,
        )
    else ->
        stringResource(
            R.string.goods_filter_member_more_format,
            selectedMembers[0].name,
            selectedMembers[1].name,
            selectedMembers.size - 2,
        )
}
app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsFilteredPartyListScreen.kt (1)

165-181: LazyColumnitemskey 파라미터가 누락되었습니다.

partySummaries 리스트를 렌더링할 때 고유한 key를 지정하지 않으면, 리스트 변경 시 불필요한 리컴포지션이 발생하고 애니메이션이 올바르게 동작하지 않을 수 있습니다.

♻️ 제안하는 수정 사항
-            items(productPartyListInfo.partySummaries) { party ->
+            items(
+                items = productPartyListInfo.partySummaries,
+                key = { it.partyId }
+            ) { party ->

Comment on lines +46 to +51
onClick = { index ->
onSelect(sortTypes[index])
scope.launch {
sheetState.hide()
}
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

sheetState.hide() 이후 onDismissRequest()가 호출되지 않아요.

PotiBottomSheet 내부 패턴(relevant snippet 참조)에서는 sheetState.hide()invokeOnCompletion을 사용하여 onDismissRequest()를 호출하고 있어요. 현재 코드에서는 시트가 숨겨진 후에도 부모 컴포넌트가 이를 인지하지 못해 상태 불일치가 발생할 수 있어요.

🐛 수정 제안
             onClick = { index ->
                 onSelect(sortTypes[index])
                 scope.launch {
                     sheetState.hide()
+                }.invokeOnCompletion {
+                    if (!sheetState.isVisible) {
+                        onDismissRequest()
+                    }
                 }
             },
🤖 Prompt for AI Agents
In
`@app/src/main/java/com/poti/android/presentation/party/goodsfilter/component/FilteredSortBottomSheet.kt`
around lines 46 - 51, onClick 핸들러가 sheetState.hide()를 비동기 호출만 하고 숨김 완료 후 부모에 알리는
onDismissRequest()를 호출하지 않아 상태 불일치가 발생합니다; 수정은 FilteredSortBottomSheet의 onClick
람다에서 scope.launch { sheetState.hide() }를 그냥 호출하는 대신 launch의 반환 Job을 받아 내부에서
sheetState.hide()를 실행하고 그 Job에 대해 invokeOnCompletion { onDismissRequest() }를 등록해
시트가 완전히 숨겨진 뒤 onDismissRequest()가 호출되도록 하세요 (onSelect 호출 순서는 유지).

GoodsCategoryUiEffect.NavigateBack -> onPopBackStack()
GoodsCategoryUiEffect.NavigateToPartyCreate -> onNavigateToPartyCreate()
GoodsCategoryUiEffect.NavigateToGoodsFilter -> onNavigateToGoodsPartyList(artistId)
is GoodsCategoryUiEffect.NavigateToGoodsPartyList -> onNavigateToGoodsPartyList(artistId, effect.title)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

cat -n app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsCategoryScreen.kt

Repository: team-poti/POTI-ANDROID

Length of output: 7859


🏁 Script executed:

# GoodsCategoryUiEffect 정의 확인
fd "GoodsCategoryUiEffect" --type kt -exec cat -n {} +

Repository: team-poti/POTI-ANDROID

Length of output: 235


🏁 Script executed:

# GoodsLargeCard 컴포넌트 확인
fd "GoodsLargeCard" --type kt -exec cat -n {} +

Repository: team-poti/POTI-ANDROID

Length of output: 235


🏁 Script executed:

# Search for GoodsCategoryUiEffect definition
find . -name "*.kt" -type f | xargs grep -l "GoodsCategoryUiEffect" | head -5

Repository: team-poti/POTI-ANDROID

Length of output: 348


🏁 Script executed:

# Search for GoodsLargeCard definition
find . -name "*.kt" -type f | xargs grep -l "fun GoodsLargeCard"

Repository: team-poti/POTI-ANDROID

Length of output: 154


🏁 Script executed:

cat -n ./app/src/main/java/com/poti/android/presentation/party/goodsfilter/model/GoodsCategoryUiState.kt

Repository: team-poti/POTI-ANDROID

Length of output: 2040


🏁 Script executed:

cat -n ./app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsCategoryViewModel.kt

Repository: team-poti/POTI-ANDROID

Length of output: 3823


🏁 Script executed:

cat -n ./app/src/main/java/com/poti/android/presentation/party/home/component/GoodsLargeCard.kt

Repository: team-poti/POTI-ANDROID

Length of output: 6761


effect.artistId를 사용해야 하며, LazyColumn에서 key 파라미터를 추가하세요.

현재 51번 줄에서 route의 artistId를 사용하고 있지만, NavigateToGoodsPartyList effect에는 클릭된 카드의 artistId가 포함되어 있습니다. 각 카드마다 다른 groupItem.artistId를 가질 수 있으므로 effect.artistId를 사용해야 합니다.

수정 예시
is GoodsCategoryUiEffect.NavigateToGoodsPartyList -> onNavigateToGoodsPartyList(effect.artistId, effect.title)

추가로 135번 줄의 items() 호출에서 key 파라미터가 누락되어 있습니다. 리컴포지션 최적화를 위해 다음과 같이 수정하세요:

items(goodsCategory.groupItems, key = { it.id }) { groupItem ->
🤖 Prompt for AI Agents
In
`@app/src/main/java/com/poti/android/presentation/party/goodsfilter/GoodsCategoryScreen.kt`
at line 51, Change the navigation call to use the clicked card's artistId from
the effect by replacing the current artistId argument with effect.artistId in
the GoodsCategoryUiEffect.NavigateToGoodsPartyList handling (so
onNavigateToGoodsPartyList receives effect.artistId, effect.title); also add a
stable key to the LazyColumn items call by passing key = { it.id } when
iterating goodsCategory.groupItems to improve recomposition stability (refer to
items(goodsCategory.groupItems) and groupItem.id).

@jyvnee jyvnee merged commit c8f7f14 into develop Jan 22, 2026
2 checks passed
@github-project-automation github-project-automation bot moved this from To-do to Done in POTI-ANDROID Jan 22, 2026
@jyvnee jyvnee deleted the feat/#94-party-list-api branch January 22, 2026 12:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🌟 Feat 새로운 기능 구현 💕 예림 💻 API 서버 통신 작업

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[Feat] 굿즈별 페이지 API 연동

3 participants