diff --git a/app/ios-combined/src/iosTest/kotlin/club/nito/ios/combined/EntryPointTest.kt b/app/ios-combined/src/iosTest/kotlin/club/nito/ios/combined/EntryPointTest.kt index 0b061772..32ed2a6e 100644 --- a/app/ios-combined/src/iosTest/kotlin/club/nito/ios/combined/EntryPointTest.kt +++ b/app/ios-combined/src/iosTest/kotlin/club/nito/ios/combined/EntryPointTest.kt @@ -2,6 +2,7 @@ package club.nito.ios.combined import club.nito.core.data.AuthRepository import club.nito.core.data.ScheduleRepository +import club.nito.core.domain.GetParticipantScheduleListUseCase import club.nito.core.domain.GetRecentScheduleUseCase import club.nito.core.domain.ObserveAuthStatusUseCase import club.nito.core.domain.ParticipateUseCase @@ -37,6 +38,7 @@ class EntryPointTest { assertNotNull(kmpEntryPoint.get()) assertNotNull(kmpEntryPoint.get()) assertNotNull(kmpEntryPoint.get()) + assertNotNull(kmpEntryPoint.get()) assertNotNull(kmpEntryPoint.get()) } } diff --git a/core/data/src/commonMain/kotlin/club/nito/core/data/DefaultParticipantRepository.kt b/core/data/src/commonMain/kotlin/club/nito/core/data/DefaultParticipantRepository.kt index 8aa59e3c..73d09af8 100644 --- a/core/data/src/commonMain/kotlin/club/nito/core/data/DefaultParticipantRepository.kt +++ b/core/data/src/commonMain/kotlin/club/nito/core/data/DefaultParticipantRepository.kt @@ -10,6 +10,9 @@ class DefaultParticipantRepository( override suspend fun getParticipants(scheduleId: String): List = remoteDataSource.getParticipants(scheduleId = scheduleId) + override suspend fun getParticipants(scheduleIds: List): List = + remoteDataSource.getParticipants(scheduleIds = scheduleIds) + override suspend fun participate(declaration: ParticipantDeclaration): Long = remoteDataSource.participate(declaration = declaration) } diff --git a/core/data/src/commonMain/kotlin/club/nito/core/data/ParticipantRepository.kt b/core/data/src/commonMain/kotlin/club/nito/core/data/ParticipantRepository.kt index 90e66ca9..29522379 100644 --- a/core/data/src/commonMain/kotlin/club/nito/core/data/ParticipantRepository.kt +++ b/core/data/src/commonMain/kotlin/club/nito/core/data/ParticipantRepository.kt @@ -14,6 +14,13 @@ sealed interface ParticipantRepository { */ suspend fun getParticipants(scheduleId: String): List + /** + * 該当の予定の参加情報を取得する + * + * @param scheduleIds 参加情報を取得するスケジュールID配列 + */ + suspend fun getParticipants(scheduleIds: List): List + /** * 該当のスケジュールに参加する * diff --git a/core/domain/src/androidMain/kotlin/club/nito/core/domain/di/UseCaseModule.kt b/core/domain/src/androidMain/kotlin/club/nito/core/domain/di/UseCaseModule.kt index 7a573ee5..41dc5a43 100644 --- a/core/domain/src/androidMain/kotlin/club/nito/core/domain/di/UseCaseModule.kt +++ b/core/domain/src/androidMain/kotlin/club/nito/core/domain/di/UseCaseModule.kt @@ -4,6 +4,8 @@ import club.nito.core.data.AuthRepository import club.nito.core.data.ParticipantRepository import club.nito.core.data.ScheduleRepository import club.nito.core.data.UserRepository +import club.nito.core.domain.GetParticipantScheduleListExecutor +import club.nito.core.domain.GetParticipantScheduleListUseCase import club.nito.core.domain.GetRecentScheduleExecutor import club.nito.core.domain.GetRecentScheduleUseCase import club.nito.core.domain.ObserveAuthStatusExecutor @@ -54,6 +56,17 @@ class UseCaseModule { userRepository = userRepository, ) + @Provides + fun provideGetParticipantScheduleListUseCase( + scheduleRepository: ScheduleRepository, + participantRepository: ParticipantRepository, + userRepository: UserRepository, + ): GetParticipantScheduleListUseCase = GetParticipantScheduleListExecutor( + scheduleRepository = scheduleRepository, + participantRepository = participantRepository, + userRepository = userRepository, + ) + @Provides fun provideParticipateUseCase( participantRepository: ParticipantRepository, diff --git a/core/domain/src/commonMain/kotlin/club/nito/core/domain/GetParticipantScheduleListUseCase.kt b/core/domain/src/commonMain/kotlin/club/nito/core/domain/GetParticipantScheduleListUseCase.kt new file mode 100644 index 00000000..c3c7c378 --- /dev/null +++ b/core/domain/src/commonMain/kotlin/club/nito/core/domain/GetParticipantScheduleListUseCase.kt @@ -0,0 +1,72 @@ +package club.nito.core.domain + +import club.nito.core.data.ParticipantRepository +import club.nito.core.data.ScheduleRepository +import club.nito.core.data.UserRepository +import club.nito.core.domain.model.ParticipantSchedule +import club.nito.core.model.FetchMultipleContentResult +import club.nito.core.model.Schedule +import club.nito.core.model.UserProfile +import club.nito.core.model.participant.Participant +import club.nito.core.model.toNitoError +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow + +/** + * スケジュール一覧を取得するユースケース + */ +sealed interface GetParticipantScheduleListUseCase { + operator fun invoke(): Flow> +} + +class GetParticipantScheduleListExecutor( + private val scheduleRepository: ScheduleRepository, + private val participantRepository: ParticipantRepository, + private val userRepository: UserRepository, +) : GetParticipantScheduleListUseCase { + override fun invoke(): Flow> = flow { + val schedules = try { + scheduleRepository.getScheduleList(limit = 10) + } catch (e: Throwable) { + emit(FetchMultipleContentResult.Failure(error = e.toNitoError())) + return@flow + } + + if (schedules.isEmpty()) { + emit(FetchMultipleContentResult.NoContent) + return@flow + } + + val participants = participantRepository.getParticipants(scheduleIds = schedules.map { it.id }) + val profiles = userRepository.getProfiles(userIds = participants.distinctBy { it.userId }.map { it.userId }) + + val participantScheduleList = transformToParticipantScheduleList( + schedules = schedules, + participants = participants, + userProfiles = profiles, + ) + + emit(FetchMultipleContentResult.Success(participantScheduleList)) + } + + private fun transformToParticipantScheduleList( + schedules: List, + participants: List, + userProfiles: List, + ): List = schedules.map { schedule -> + val scheduleParticipants = participants.filter { it.scheduleId == schedule.id } + val scheduleParticipantProfiles = userProfiles.filter { profile -> + scheduleParticipants.any { it.userId == profile.id } + } + + ParticipantSchedule( + id = schedule.id, + scheduledAt = schedule.scheduledAt, + metAt = schedule.metAt, + venueId = schedule.venueId, + meetId = schedule.meetId, + description = schedule.description, + participants = scheduleParticipantProfiles, + ) + } +} diff --git a/core/domain/src/iosMain/kotlin/club/nito/core/domain/useCaseModule.kt b/core/domain/src/iosMain/kotlin/club/nito/core/domain/useCaseModule.kt index 3fb2ebe1..75cf1bc7 100644 --- a/core/domain/src/iosMain/kotlin/club/nito/core/domain/useCaseModule.kt +++ b/core/domain/src/iosMain/kotlin/club/nito/core/domain/useCaseModule.kt @@ -10,5 +10,6 @@ val useCaseModule: Module = module { singleOf(::SignInExecutor) bind SignInUseCase::class singleOf(::SignOutExecutor) bind SignOutUseCase::class singleOf(::GetRecentScheduleExecutor) bind GetRecentScheduleUseCase::class + singleOf(::GetParticipantScheduleListExecutor) bind GetParticipantScheduleListUseCase::class singleOf(::ParticipateExecutor) bind ParticipateUseCase::class } diff --git a/core/model/src/commonMain/kotlin/club/nito/core/model/FetchMultipleContentResult.kt b/core/model/src/commonMain/kotlin/club/nito/core/model/FetchMultipleContentResult.kt new file mode 100644 index 00000000..f6f40933 --- /dev/null +++ b/core/model/src/commonMain/kotlin/club/nito/core/model/FetchMultipleContentResult.kt @@ -0,0 +1,26 @@ +package club.nito.core.model + +/** + * 複数のコンテンツデータを取得する結果 + */ +sealed interface FetchMultipleContentResult { + /** + * 取得中 + */ + data object Loading : FetchMultipleContentResult + + /** + * 該当データなし + */ + data object NoContent : FetchMultipleContentResult + + /** + * 取得成功 + */ + data class Success(val data: List) : FetchMultipleContentResult + + /** + * 取得失敗 + */ + data class Failure(val error: NitoError?) : FetchMultipleContentResult +} diff --git a/core/network/src/commonMain/kotlin/club/nito/core/network/participation/ParticipantRemoteDataSource.kt b/core/network/src/commonMain/kotlin/club/nito/core/network/participation/ParticipantRemoteDataSource.kt index abdc2749..7ab4719a 100644 --- a/core/network/src/commonMain/kotlin/club/nito/core/network/participation/ParticipantRemoteDataSource.kt +++ b/core/network/src/commonMain/kotlin/club/nito/core/network/participation/ParticipantRemoteDataSource.kt @@ -14,6 +14,13 @@ sealed interface ParticipantRemoteDataSource { */ suspend fun getParticipants(scheduleId: String): List + /** + * 該当の予定の参加情報を取得する + * + * @param scheduleIds 参加情報を取得するスケジュールID配列 + */ + suspend fun getParticipants(scheduleIds: List): List + /** * 該当のスケジュールに参加する * diff --git a/core/network/src/commonMain/kotlin/club/nito/core/network/participation/SupabaseParticipantRemoteDataSource.kt b/core/network/src/commonMain/kotlin/club/nito/core/network/participation/SupabaseParticipantRemoteDataSource.kt index fe9a124f..a865aed8 100644 --- a/core/network/src/commonMain/kotlin/club/nito/core/network/participation/SupabaseParticipantRemoteDataSource.kt +++ b/core/network/src/commonMain/kotlin/club/nito/core/network/participation/SupabaseParticipantRemoteDataSource.kt @@ -25,6 +25,18 @@ class SupabaseParticipantRemoteDataSource( .decodeList() .map(NetworkParticipant::toParticipant) + override suspend fun getParticipants(scheduleIds: List): List = postgrest + .select( + filter = { + and { + isIn("schedule_id", scheduleIds) + exact("deleted_at", null) + } + }, + ) + .decodeList() + .map(NetworkParticipant::toParticipant) + override suspend fun participate(declaration: ParticipantDeclaration): Long { val result = postgrest.insert( value = declaration.toNetworkModel(),