Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,8 @@ internal fun MapScreen(
onSelectedFilterChange(next)
},
modifier = Modifier.padding(top = 12.dp),
departmentName = departmentName.toString()
departmentName = departmentName.toString(),
filters = mapState.availableFilters,
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ data class MapState(
val restaurantInfoList: List<RestaurantInfo> = emptyList(),
val storeType: StoreType? = null,
val selectedFilter: FilterType = FilterType.Mine,
val availableFilters: List<FilterType> = FilterType.entries,
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.

medium

MapState의 초기값으로 availableFiltersFilterType.entries로 설정되어 있습니다. fetchUserCollegeDepartment가 완료되기 전(UiState.Init 또는 Loading 상태)에도 UI가 렌더링될 경우, 모든 필터가 잠시 노출되었다가 사라지는 현상이 발생할 수 있습니다. 초기값을 빈 리스트로 설정하거나, 항상 노출되는 기본 필터만 포함하는 것이 사용자 경험 측면에서 더 좋습니다.

Suggested change
val availableFilters: List<FilterType> = FilterType.entries,
val availableFilters: List<FilterType> = emptyList(),

val filterChangeResult: FilterChangeResult? = null,
) {
sealed class FilterChangeResult {
Expand Down Expand Up @@ -83,14 +84,24 @@ class MapViewModel @Inject constructor(
_departmentId.value = newDepartmentId
_collegeId.value = newCollegeId

val hasFestival = allPartnerships.hasFestivalPartnership()
val availableFilters = if (hasFestival) {
FilterType.entries
} else {
listOf(FilterType.All, FilterType.Mine)
}
Comment on lines +88 to +92
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.

medium

availableFilters를 정의할 때 특정 필터를 제외한 나머지를 직접 리스트로 나열하기보다, FilterType.entries를 필터링하는 방식이 추후 새로운 필터 타입이 추가될 때 유지보수 측면에서 더 유리합니다.

Suggested change
val availableFilters = if (hasFestival) {
FilterType.entries
} else {
listOf(FilterType.All, FilterType.Mine)
}
val availableFilters = if (hasFestival) {
FilterType.entries
} else {
FilterType.entries.filter { it != FilterType.Festival }
}


// Festival 제휴가 하나라도 있으면 Festival을 우선하고, 없으면 기존 기본 필터 규칙을 따른다.
val initialFilter = when {
allPartnerships.hasFestivalPartnership() -> FilterType.Festival
hasFestival -> FilterType.Festival
newDepartmentId == -1L -> FilterType.All
else -> FilterType.Mine
}
_uiState.value = UiState.Success(
MapState(selectedFilter = initialFilter),
MapState(
selectedFilter = initialFilter,
availableFilters = availableFilters,
),
)

when (initialFilter) {
Expand Down Expand Up @@ -181,15 +192,9 @@ class MapViewModel @Inject constructor(
if (prefetchedPartnerships == null)
_uiState.value = UiState.Loading

val partnerships = partnershipRepository.getAllPartnerships().mapNotNull {
val festivalInfos =
it.partnershipInfos.filter { info -> info.periodType == PeriodType.FESTIVAL }
if (festivalInfos.isEmpty()) return@mapNotNull null

it.copy(
partnershipInfos = festivalInfos
)
}
val partnerships =
(prefetchedPartnerships ?: partnershipRepository.getAllPartnerships())
.festivalPartnerships()

_uiState.value = UiState.Success(
currentData.copy(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,11 @@ fun PartnershipFilterToggle(
selected: FilterType,
onSelectedChange: (FilterType) -> Unit,
departmentName: String,
filters: List<FilterType> = FilterType.entries,
modifier: Modifier = Modifier,
) {
Timber.d("departmentName = $departmentName")
val items = FilterType.entries.map {
val items = filters.map {
it to it.getLabel(departmentName)
}
Row(
Expand Down Expand Up @@ -112,4 +113,4 @@ fun PartnershipToggleItem(
style = EatssuTheme.typography.body2
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,76 @@ class MapViewModelBehaviorSpec : AppBehaviorSpec({
eventually(2.seconds) {
val state = viewModel.uiState.value as UiState.Success
state.data.selectedFilter shouldBe FilterType.All
state.data.availableFilters shouldBe listOf(FilterType.All, FilterType.Mine)
state.data.partnerships shouldBe allPartnerships
}
coVerify(atLeast = 1) { partnershipRepository.getAllPartnerships() }
}
}
}

`when`("Festival 제휴가 있으면") {
val festivalInfo = Partnership.PartnershipInfo(
id = 1,
partnershipType = "DISCOUNT",
collegeName = "IT",
departmentName = "CS",
likeCount = 1,
isLiked = false,
description = "축제 할인",
startDate = "2025-05-01",
endDate = "2025-05-03",
periodType = PeriodType.FESTIVAL,
)
val normalInfo = Partnership.PartnershipInfo(
id = 2,
partnershipType = "DISCOUNT",
collegeName = "IT",
departmentName = "CS",
likeCount = 1,
isLiked = false,
description = "상시 할인",
startDate = "2025-01-01",
endDate = "2025-12-31",
periodType = PeriodType.NORMAL,
)
val allPartnerships = listOf(
samplePartnership(
storeName = "Festival Cafe",
infos = listOf(festivalInfo, normalInfo),
)
)
coEvery {
getUserCollegeDepartmentUseCase()
} returns sampleUserInfo(
nickname = "eatssu",
college = College(collegeId = 1, collegeName = "IT"),
department = Department(departmentId = 11, departmentName = "컴퓨터학부"),
)
coEvery { partnershipRepository.getAllPartnerships() } returns allPartnerships
coEvery { partnershipRepository.getUserCollegePartnerships() } returns emptyList()

val viewModel = MapViewModel(
partnershipRepository = partnershipRepository,
getPartnershipDetailUseCase = getPartnershipDetailUseCase,
getUserCollegeDepartmentUseCase = getUserCollegeDepartmentUseCase,
analyticsTracker = analyticsTracker,
)

then("Festival 필터로 시작하고 Festival 필터 버튼을 표시한다") {
runTest {
eventually(2.seconds) {
val state = viewModel.uiState.value as UiState.Success
state.data.selectedFilter shouldBe FilterType.Festival
state.data.availableFilters shouldBe FilterType.entries.toList()
state.data.partnerships.first().partnershipInfos shouldBe listOf(
festivalInfo
)
}
}
}
}

`when`("학과 정보가 없는 사용자가 Mine 필터를 선택하면") {
coEvery {
getUserCollegeDepartmentUseCase()
Expand All @@ -90,7 +153,9 @@ class MapViewModelBehaviorSpec : AppBehaviorSpec({
then("RequiresDepartment 결과를 상태에 반영하고 Mine 데이터를 로드하지 않는다") {
runTest {
eventually(2.seconds) {
viewModel.uiState.value shouldBe UiState.Success(MapState(selectedFilter = FilterType.All))
val state = viewModel.uiState.value as UiState.Success
state.data.selectedFilter shouldBe FilterType.All
state.data.availableFilters shouldBe listOf(FilterType.All, FilterType.Mine)
}

clearMocks(partnershipRepository, answers = false, recordedCalls = true)
Expand Down
Loading