Skip to content

Commit

Permalink
Merge pull request #2214 from HedvigInsurance/feature/conversation-an…
Browse files Browse the repository at this point in the history
…d-new-chat-disambiguation-button-in-help-center

Feature, conversation and new chat disambiguation button in help center
  • Loading branch information
StylianosGakis authored Sep 4, 2024
2 parents 62d7b40 + 06edf64 commit 9a2a232
Show file tree
Hide file tree
Showing 24 changed files with 274 additions and 100 deletions.
1 change: 1 addition & 0 deletions app/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ dependencies {
implementation(projects.dataChatReadTimestampPublic)
implementation(projects.dataClaimFlow)
implementation(projects.dataContractPublic)
implementation(projects.dataConversations)
implementation(projects.dataPayingMember)
implementation(projects.dataSettingsDatastorePublic)
implementation(projects.dataTermination)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import com.hedvig.android.core.fileupload.fileUploadModule
import com.hedvig.android.data.chat.di.dataChatModule
import com.hedvig.android.data.chat.read.timestamp.di.chatReadTimestampModule
import com.hedvig.android.data.claimflow.di.claimFlowDataModule
import com.hedvig.android.data.conversations.di.dataConversationsModule
import com.hedvig.android.data.paying.member.di.dataPayingMemberModule
import com.hedvig.android.data.settings.datastore.di.settingsDatastoreModule
import com.hedvig.android.data.termination.di.terminationDataModule
Expand Down Expand Up @@ -309,6 +310,7 @@ val applicationModule = module {
coreAppReviewModule,
coreCommonModule,
dataChatModule,
dataConversationsModule,
dataPayingMemberModule,
dataStoreModule,
databaseChatAndroidModule,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,9 @@ internal fun HedvigNavHost(
// todo cbm check if we're gonna use chatContext
navigateToNewConversationWithContext(backStackEntry, chatContext)
},
onNavigateToInbox = { backStackEntry ->
navigateToInbox(backStackEntry)
},
openUrl = openUrl,
)
}
Expand Down
21 changes: 21 additions & 0 deletions app/data/data-conversations/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
plugins {
id("hedvig.android.ktlint")
id("hedvig.android.library")
alias(libs.plugins.apollo)
alias(libs.plugins.squareSortDependencies)
}

dependencies {
implementation(libs.apollo.normalizedCache)
implementation(libs.arrow.core)
implementation(libs.koin.core)
implementation(projects.apolloCore)
implementation(projects.apolloOctopusPublic)
}

apollo {
service("octopus") {
packageName = "octopus"
dependsOn(projects.apolloOctopusPublic, true)
}
}
2 changes: 2 additions & 0 deletions app/data/data-conversations/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest />
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.hedvig.android.data.conversations

import arrow.core.Either
import arrow.core.raise.either
import com.apollographql.apollo.ApolloClient
import com.apollographql.apollo.cache.normalized.FetchPolicy
import com.apollographql.apollo.cache.normalized.fetchPolicy
import com.hedvig.android.apollo.ApolloOperationError
import com.hedvig.android.apollo.safeFlow
import com.hedvig.android.logger.LogPriority
import com.hedvig.android.logger.logcat
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import octopus.CbmNumberOfChatMessagesQuery
import octopus.type.ChatMessageSender

class HasAnyActiveConversationUseCase(
private val apolloClient: ApolloClient,
) {
fun invoke(alwaysHitTheNetwork: Boolean = false): Flow<Either<ApolloOperationError, Boolean>> {
return apolloClient
.query(CbmNumberOfChatMessagesQuery())
.fetchPolicy(if (alwaysHitTheNetwork) FetchPolicy.CacheAndNetwork else FetchPolicy.CacheFirst)
.safeFlow()
.map { result ->
either {
val data = result
.onLeft { apolloOperationError ->
logcat(LogPriority.ERROR, apolloOperationError.throwable) {
"isEligibleToShowTheChatIcon cant determine if the chat icon should be shown. $apolloOperationError"
}
}
.bind()
val eligibleFromLegacyConversation = data
.currentMember
.legacyConversation
?.messagePage
?.messages
?.isEligibleToShowTheChatIcon() == true
if (eligibleFromLegacyConversation) {
return@either true
}
val conversations = data.currentMember.conversations
val showChatIcon = conversations.any { conversation ->
val isOpenConversation = conversation.isOpen
val hasAnyMessageSent = conversation.newestMessage != null
isOpenConversation || hasAnyMessageSent
}
showChatIcon
}
}
}
}

@Suppress("ktlint:standard:max-line-length")
private fun List<CbmNumberOfChatMessagesQuery.Data.CurrentMember.LegacyConversation.MessagePage.Message>.isEligibleToShowTheChatIcon(): Boolean {
// If there are *any* messages from the member, then we should show the chat icon
if (this.any { it.sender == ChatMessageSender.MEMBER }) return true
// There is always an automatic message sent by Hedvig, therefore we need to check for > 1
return this.filter { it.sender == ChatMessageSender.HEDVIG }.size > 1
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.hedvig.android.data.conversations.di

import com.apollographql.apollo.ApolloClient
import com.hedvig.android.data.conversations.HasAnyActiveConversationUseCase
import org.koin.dsl.module

val dataConversationsModule = module {
single<HasAnyActiveConversationUseCase> { HasAnyActiveConversationUseCase(get<ApolloClient>()) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ fun Surface(
CompositionLocalProvider(LocalContentColor provides contentColor) {
Box(
modifier = modifier
.minimumInteractiveComponentSize()
.surface(
shape = shape,
backgroundColor = color,
Expand Down
2 changes: 2 additions & 0 deletions app/feature/feature-help-center/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ dependencies {
implementation(projects.coreResources)
implementation(projects.coreUi)
implementation(projects.dataContractPublic)
implementation(projects.dataConversations)
implementation(projects.dataTermination)
implementation(projects.designSystemHedvig)
implementation(projects.featureFlagsPublic)
implementation(projects.moleculeAndroid)
implementation(projects.moleculePublic)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ fun NavGraphBuilder.helpCenterGraph(
hedvigDeepLinkContainer: HedvigDeepLinkContainer,
navigator: Navigator,
onNavigateToQuickLink: (NavBackStackEntry, QuickLinkDestination.OuterDestination) -> Unit,
onNavigateToInbox: (NavBackStackEntry) -> Unit,
onNavigateToNewConversation: (NavBackStackEntry, AppDestination.Chat.ChatContext?) -> Unit,
openUrl: (String) -> Unit,
) {
Expand All @@ -52,13 +53,15 @@ fun NavGraphBuilder.helpCenterGraph(
is QuickLinkDestination.OuterDestination -> {
onNavigateToQuickLink(backStackEntry, destination)
}

is QuickLinkDestination.InnerHelpCenterDestination -> {
when (destination) {
is QuickLinkDestination.InnerHelpCenterDestination.FirstVet -> {
with(navigator) {
backStackEntry.navigate(HelpCenterDestinations.FirstVet(destination.sections))
}
}

is QuickLinkDestination.InnerHelpCenterDestination.QuickLinkSickAbroad -> {
with(navigator) {
backStackEntry.navigate(
Expand All @@ -73,7 +76,10 @@ fun NavGraphBuilder.helpCenterGraph(
}
}
},
openChat = {
onNavigateToInbox = {
onNavigateToInbox(backStackEntry)
},
onNavigateToNewConversation = {
onNavigateToNewConversation(backStackEntry, null)
},
onNavigateUp = navigator::navigateUp,
Expand All @@ -83,32 +89,34 @@ fun NavGraphBuilder.helpCenterGraph(
HelpCenterDestinations.Topic,
) { backStackEntry ->
val resources = LocalContext.current.resources
val viewModel = koinViewModel<ShowNavigateToInboxViewModel>()
HelpCenterTopicDestination(
showNavigateToInboxViewModel = viewModel,
topic = topic,
onNavigateToQuestion = { question ->
navigateToQuestion(resources, question, navigator, backStackEntry)
},
onNavigateUp = navigator::navigateUp,
onNavigateBack = navigator::popBackStack,
openChat = {
onNavigateToNewConversation(backStackEntry, topic.chatContext)
},
onNavigateToInbox = { onNavigateToInbox(backStackEntry) },
onNavigateToNewConversation = { onNavigateToNewConversation(backStackEntry, topic.chatContext) },
)
}
navdestination<HelpCenterDestinations.Question>(
HelpCenterDestinations.Question,
) { backStackEntry ->
val viewModel = koinViewModel<ShowNavigateToInboxViewModel>()
val resources = LocalContext.current.resources
HelpCenterQuestionDestination(
showNavigateToInboxViewModel = viewModel,
questionId = question,
onNavigateToQuestion = { question ->
navigateToQuestion(resources, question, navigator, backStackEntry)
},
onNavigateToInbox = { onNavigateToInbox(backStackEntry) },
onNavigateToNewConversation = { onNavigateToNewConversation(backStackEntry, question.chatContext) },
onNavigateUp = navigator::navigateUp,
onNavigateBack = navigator::popBackStack,
openChat = {
onNavigateToNewConversation(backStackEntry, question.chatContext)
},
)
}
navdestination<HelpCenterDestinations.FirstVet>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,21 @@ package com.hedvig.android.feature.help.center

import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import arrow.core.NonEmptyList
import arrow.core.merge
import com.hedvig.android.data.conversations.HasAnyActiveConversationUseCase
import com.hedvig.android.feature.help.center.data.GetQuickLinksUseCase
import com.hedvig.android.feature.help.center.model.Question
import com.hedvig.android.feature.help.center.model.QuickAction
import com.hedvig.android.feature.help.center.model.Topic
import com.hedvig.android.molecule.public.MoleculePresenter
import com.hedvig.android.molecule.public.MoleculePresenterScope
import kotlinx.coroutines.flow.map

internal sealed interface HelpCenterEvent {
data class OnQuickActionSelected(val quickAction: QuickAction) : HelpCenterEvent
Expand All @@ -33,6 +37,7 @@ internal data class HelpCenterUiState(
val quickLinksUiState: QuickLinkUiState,
val selectedQuickAction: QuickAction?,
val search: Search?,
val showNavigateToInboxButton: Boolean,
) {
data class QuickLink(val quickAction: QuickAction)

Expand Down Expand Up @@ -63,6 +68,7 @@ internal data class HelpCenterUiState(

internal class HelpCenterPresenter(
private val getQuickLinksUseCase: GetQuickLinksUseCase,
private val hasAnyActiveConversationUseCase: HasAnyActiveConversationUseCase,
) : MoleculePresenter<HelpCenterEvent, HelpCenterUiState> {
@Composable
override fun MoleculePresenterScope<HelpCenterEvent>.present(lastState: HelpCenterUiState): HelpCenterUiState {
Expand All @@ -71,6 +77,9 @@ internal class HelpCenterPresenter(
var currentState by remember {
mutableStateOf(lastState)
}
val hasAnyActiveConversation by remember(hasAnyActiveConversationUseCase) {
hasAnyActiveConversationUseCase.invoke().map { it.mapLeft { false }.merge() }
}.collectAsState(false)

CollectEvents { event ->
when (event) {
Expand Down Expand Up @@ -120,6 +129,7 @@ internal class HelpCenterPresenter(
return currentState.copy(
quickLinksUiState = quickLinksUiState,
selectedQuickAction = selectedQuickAction,
showNavigateToInboxButton = hasAnyActiveConversation,
)
}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
package com.hedvig.android.feature.help.center

import com.hedvig.android.data.conversations.HasAnyActiveConversationUseCase
import com.hedvig.android.feature.help.center.data.GetQuickLinksUseCase
import com.hedvig.android.feature.help.center.model.commonQuestions
import com.hedvig.android.feature.help.center.model.commonTopics
import com.hedvig.android.molecule.android.MoleculeViewModel

internal class HelpCenterViewModel(
getQuickLinksUseCase: GetQuickLinksUseCase,
hasAnyActiveConversationUseCase: HasAnyActiveConversationUseCase,
) : MoleculeViewModel<HelpCenterEvent, HelpCenterUiState>(
initialState = HelpCenterUiState(
topics = commonTopics,
questions = commonQuestions,
selectedQuickAction = null,
quickLinksUiState = HelpCenterUiState.QuickLinkUiState.Loading,
search = null,
showNavigateToInboxButton = false,
),
presenter = HelpCenterPresenter(
getQuickLinksUseCase = getQuickLinksUseCase,
hasAnyActiveConversationUseCase = hasAnyActiveConversationUseCase,
),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.hedvig.android.feature.help.center

import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import arrow.core.merge
import com.hedvig.android.data.conversations.HasAnyActiveConversationUseCase
import com.hedvig.android.molecule.android.MoleculeViewModel
import com.hedvig.android.molecule.public.MoleculePresenter
import com.hedvig.android.molecule.public.MoleculePresenterScope
import kotlinx.coroutines.flow.map

internal class ShowNavigateToInboxViewModel(
hasAnyActiveConversationUseCase: HasAnyActiveConversationUseCase,
) : MoleculeViewModel<Unit, Boolean>(
false,
ShowNavigateToInboxPresenter(hasAnyActiveConversationUseCase),
)

internal class ShowNavigateToInboxPresenter(
private val hasAnyActiveConversationUseCase: HasAnyActiveConversationUseCase,
) : MoleculePresenter<Unit, Boolean> {
@Composable
override fun MoleculePresenterScope<Unit>.present(lastState: Boolean): Boolean {
return remember(hasAnyActiveConversationUseCase) {
hasAnyActiveConversationUseCase.invoke().map { it.mapLeft { false }.merge() }
}.collectAsState(lastState).value
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.hedvig.android.feature.help.center.di

import com.apollographql.apollo.ApolloClient
import com.hedvig.android.data.conversations.HasAnyActiveConversationUseCase
import com.hedvig.android.feature.help.center.HelpCenterViewModel
import com.hedvig.android.feature.help.center.ShowNavigateToInboxViewModel
import com.hedvig.android.feature.help.center.data.GetMemberActionsUseCase
import com.hedvig.android.feature.help.center.data.GetMemberActionsUseCaseImpl
import com.hedvig.android.feature.help.center.data.GetQuickLinksUseCase
Expand All @@ -28,6 +30,12 @@ val helpCenterModule = module {
viewModel<HelpCenterViewModel> {
HelpCenterViewModel(
getQuickLinksUseCase = get<GetQuickLinksUseCase>(),
hasAnyActiveConversationUseCase = get<HasAnyActiveConversationUseCase>(),
)
}
viewModel<ShowNavigateToInboxViewModel> {
ShowNavigateToInboxViewModel(
hasAnyActiveConversationUseCase = get<HasAnyActiveConversationUseCase>(),
)
}
}
Loading

0 comments on commit 9a2a232

Please sign in to comment.