diff --git a/WordPress/src/main/java/org/wordpress/android/support/he/model/ConversationStatus.kt b/WordPress/src/main/java/org/wordpress/android/support/he/model/ConversationStatus.kt new file mode 100644 index 000000000000..4839d24ccc07 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/support/he/model/ConversationStatus.kt @@ -0,0 +1,21 @@ +package org.wordpress.android.support.he.model + +enum class ConversationStatus { + WAITING_FOR_SUPPORT, + WAITING_FOR_USER, + CLOSED, + SOLVED, + UNKNOWN; + + companion object { + fun fromStatus(status: String): ConversationStatus { + return when (status.lowercase()) { + "open", "new", "hold" -> WAITING_FOR_SUPPORT + "closed" -> CLOSED + "pending" -> WAITING_FOR_USER + "solved" -> SOLVED + else -> UNKNOWN + } + } + } +} diff --git a/WordPress/src/main/java/org/wordpress/android/support/he/model/SupportConversation.kt b/WordPress/src/main/java/org/wordpress/android/support/he/model/SupportConversation.kt index dd81da57827e..130e241ade19 100644 --- a/WordPress/src/main/java/org/wordpress/android/support/he/model/SupportConversation.kt +++ b/WordPress/src/main/java/org/wordpress/android/support/he/model/SupportConversation.kt @@ -8,6 +8,7 @@ data class SupportConversation( val title: String, val description: String, val lastMessageSentAt: Date, + val status: String, val messages: List ): Conversation { override fun getConversationId(): Long = id diff --git a/WordPress/src/main/java/org/wordpress/android/support/he/repository/HESupportRepository.kt b/WordPress/src/main/java/org/wordpress/android/support/he/repository/HESupportRepository.kt index e107d19c4300..e1199d998a75 100644 --- a/WordPress/src/main/java/org/wordpress/android/support/he/repository/HESupportRepository.kt +++ b/WordPress/src/main/java/org/wordpress/android/support/he/repository/HESupportRepository.kt @@ -181,6 +181,7 @@ class HESupportRepository @Inject constructor( title = it.title, description = it.description, lastMessageSentAt = it.updatedAt, + status = it.status, messages = emptyList() ) } @@ -191,6 +192,7 @@ class HESupportRepository @Inject constructor( title = title, description = description, lastMessageSentAt = updatedAt, + status = status, messages = messages.map { it.toSupportMessage() } ) diff --git a/WordPress/src/main/java/org/wordpress/android/support/he/ui/ConversationStatusBadge.kt b/WordPress/src/main/java/org/wordpress/android/support/he/ui/ConversationStatusBadge.kt new file mode 100644 index 000000000000..11aa691d9e75 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/support/he/ui/ConversationStatusBadge.kt @@ -0,0 +1,60 @@ +package org.wordpress.android.support.he.ui + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import org.wordpress.android.R +import org.wordpress.android.support.he.model.ConversationStatus + +@Composable +fun ConversationStatusBadge( + status: String, + modifier: Modifier = Modifier +) { + val conversationStatus = ConversationStatus.fromStatus(status) + val (statusText, backgroundColor, textColor) = when (conversationStatus) { + ConversationStatus.WAITING_FOR_SUPPORT -> Triple( + stringResource(R.string.he_support_status_waiting_for_support), + MaterialTheme.colorScheme.primaryContainer, + MaterialTheme.colorScheme.onPrimaryContainer + ) + ConversationStatus.WAITING_FOR_USER -> Triple( + stringResource(R.string.he_support_status_waiting_for_user), + MaterialTheme.colorScheme.secondaryContainer, + MaterialTheme.colorScheme.onSecondaryContainer + ) + ConversationStatus.SOLVED -> Triple( + stringResource(R.string.he_support_status_solved), + MaterialTheme.colorScheme.primary, + MaterialTheme.colorScheme.onPrimary + ) + ConversationStatus.CLOSED -> Triple( + stringResource(R.string.he_support_status_closed), + MaterialTheme.colorScheme.tertiaryContainer, + MaterialTheme.colorScheme.onTertiaryContainer + ) + ConversationStatus.UNKNOWN -> Triple( + stringResource(R.string.he_support_status_unknown), + MaterialTheme.colorScheme.surfaceVariant, + MaterialTheme.colorScheme.onSurfaceVariant + ) + } + + Text( + text = statusText, + style = MaterialTheme.typography.labelSmall, + color = textColor, + modifier = modifier + .background( + color = backgroundColor, + shape = RoundedCornerShape(4.dp) + ) + .padding(horizontal = 6.dp, vertical = 2.dp) + ) +} diff --git a/WordPress/src/main/java/org/wordpress/android/support/he/ui/HEConversationDetailScreen.kt b/WordPress/src/main/java/org/wordpress/android/support/he/ui/HEConversationDetailScreen.kt index 61cbab50d7b6..bf3a8dd4e731 100644 --- a/WordPress/src/main/java/org/wordpress/android/support/he/ui/HEConversationDetailScreen.kt +++ b/WordPress/src/main/java/org/wordpress/android/support/he/ui/HEConversationDetailScreen.kt @@ -61,6 +61,7 @@ import coil.request.videoFrameMillis import org.wordpress.android.R import org.wordpress.android.support.aibot.util.formatRelativeTime import org.wordpress.android.support.he.model.AttachmentState +import org.wordpress.android.support.he.model.ConversationStatus import org.wordpress.android.support.he.model.MessageSendResult import org.wordpress.android.support.he.model.AttachmentType import org.wordpress.android.support.he.model.SupportAttachment @@ -118,12 +119,18 @@ fun HEConversationDetailScreen( ) }, bottomBar = { - ReplyButton( - enabled = !isLoading, - onClick = { - showBottomSheet = true - } - ) + val status = ConversationStatus.fromStatus(conversation.status) + val isClosed = status == ConversationStatus.CLOSED + if (isClosed) { + ClosedConversationBanner() + } else { + ReplyButton( + enabled = !isLoading, + onClick = { + showBottomSheet = true + } + ) + } } ) { contentPadding -> Box( @@ -140,7 +147,7 @@ fun HEConversationDetailScreen( ) { item { ConversationHeader( - messageCount = conversation.messages.size, + status = conversation.status, lastUpdated = formatRelativeTime(conversation.lastMessageSentAt, resources), isLoading = isLoading ) @@ -256,13 +263,24 @@ fun HEConversationDetailScreen( @Composable private fun ConversationHeader( - messageCount: Int, + status: String, lastUpdated: String, isLoading: Boolean = false ) { + val statusText = when (ConversationStatus.fromStatus(status)) { + ConversationStatus.WAITING_FOR_SUPPORT -> + stringResource(R.string.he_support_status_waiting_for_support) + ConversationStatus.WAITING_FOR_USER -> + stringResource(R.string.he_support_status_waiting_for_user) + ConversationStatus.SOLVED -> + stringResource(R.string.he_support_status_solved) + ConversationStatus.CLOSED -> + stringResource(R.string.he_support_status_closed) + ConversationStatus.UNKNOWN -> + stringResource(R.string.he_support_status_unknown) + } val headerDescription = if (!isLoading) { - "${stringResource(R.string.he_support_message_count, messageCount)}. " + - stringResource(R.string.he_support_last_updated, lastUpdated) + "$statusText. ${stringResource(R.string.he_support_last_updated, lastUpdated)}" } else { stringResource(R.string.he_support_last_updated, lastUpdated) } @@ -277,26 +295,7 @@ private fun ConversationHeader( horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { - if (!isLoading) { - Row( - horizontalArrangement = Arrangement.spacedBy(8.dp), - verticalAlignment = Alignment.CenterVertically - ) { - Icon( - painter = painterResource(R.drawable.ic_comment_white_24dp), - contentDescription = null, - tint = MaterialTheme.colorScheme.onSurfaceVariant, - modifier = Modifier.size(20.dp) - ) - Text( - text = stringResource(R.string.he_support_message_count, messageCount), - style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.onSurfaceVariant - ) - } - } else { - Spacer(modifier = Modifier.size(0.dp)) - } + ConversationStatusBadge(status = status) Text( text = stringResource(R.string.he_support_last_updated, lastUpdated), @@ -323,6 +322,36 @@ private fun ConversationTitleCard(title: String) { } } +@Composable +private fun ClosedConversationBanner() { + Box( + modifier = Modifier + .fillMaxWidth() + .background( + color = MaterialTheme.colorScheme.errorContainer, + shape = RoundedCornerShape(8.dp) + ) + .padding(16.dp) + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(12.dp) + ) { + Icon( + painter = painterResource(R.drawable.ic_info_outline_white_24dp), + contentDescription = null, + tint = MaterialTheme.colorScheme.onErrorContainer, + modifier = Modifier.size(24.dp) + ) + Text( + text = stringResource(R.string.he_support_conversation_closed_message), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onErrorContainer + ) + } + } +} + @Composable private fun MessageItem( message: SupportMessage, diff --git a/WordPress/src/main/java/org/wordpress/android/support/he/ui/HEConversationsListScreen.kt b/WordPress/src/main/java/org/wordpress/android/support/he/ui/HEConversationsListScreen.kt index 70f106c36bea..4944bd98b1d1 100644 --- a/WordPress/src/main/java/org/wordpress/android/support/he/ui/HEConversationsListScreen.kt +++ b/WordPress/src/main/java/org/wordpress/android/support/he/ui/HEConversationsListScreen.kt @@ -79,6 +79,12 @@ private fun HEConversationListItem( Column( modifier = Modifier.weight(1f) ) { + // Status badge + ConversationStatusBadge( + status = conversation.status, + modifier = Modifier.padding(bottom = 4.dp) + ) + Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, @@ -95,7 +101,10 @@ private fun HEConversationListItem( ) Text( - text = formatRelativeTime(conversation.lastMessageSentAt, resources), + text = formatRelativeTime( + conversation.lastMessageSentAt, + resources + ), style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(start = 8.dp) diff --git a/WordPress/src/main/java/org/wordpress/android/support/he/util/HEConversationUtils.kt b/WordPress/src/main/java/org/wordpress/android/support/he/util/HEConversationUtils.kt index f662d8c0bf70..88e827c089ff 100644 --- a/WordPress/src/main/java/org/wordpress/android/support/he/util/HEConversationUtils.kt +++ b/WordPress/src/main/java/org/wordpress/android/support/he/util/HEConversationUtils.kt @@ -21,6 +21,7 @@ fun generateSampleHESupportConversations(): List { description = "I'm having trouble logging into my account. The two-factor authentication code " + "doesn't seem to be working properly when I try to access my site from the mobile app.", lastMessageSentAt = oneHourAgo, + status = "Open", messages = listOf( SupportMessage( id = 1, @@ -73,6 +74,7 @@ fun generateSampleHESupportConversations(): List { "store, I've noticed significant slowdowns and occasional timeout errors affecting customer " + "experience.", lastMessageSentAt = twoDaysAgo, + status = "closed", messages = listOf( SupportMessage( id = 4, @@ -101,6 +103,7 @@ fun generateSampleHESupportConversations(): List { "configuration, SSL certificate setup, and setting up professional email forwarding for my " + "business site.", lastMessageSentAt = oneWeekAgo, + status = "solved", messages = listOf( SupportMessage( id = 6, diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index 2e88ae646f6b..76136f8ccb3f 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -5182,6 +5182,12 @@ translators: %s: Select control option value e.g: "Auto, 25%". --> Including logs can help our team investigate issues. Logs may contain recent app activity. Download attachment Select attachments + Waiting for Support + Waiting for User + Solved + Closed + Unknown + This conversation is closed. You can no longer reply to it. Unable to play video This video cannot be played inline. Please download it to view. Download Video diff --git a/WordPress/src/test/java/org/wordpress/android/support/he/repository/HESupportRepositoryTest.kt b/WordPress/src/test/java/org/wordpress/android/support/he/repository/HESupportRepositoryTest.kt index 3b99568e1d1a..e4508fef6276 100644 --- a/WordPress/src/test/java/org/wordpress/android/support/he/repository/HESupportRepositoryTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/support/he/repository/HESupportRepositoryTest.kt @@ -350,6 +350,7 @@ class HESupportRepositoryTest : BaseUnitTest() { title = title, description = description, lastMessageSentAt = updatedAt, + status = status, messages = emptyList() ) @@ -359,6 +360,7 @@ class HESupportRepositoryTest : BaseUnitTest() { title = this.title, description = this.description, lastMessageSentAt = this.updatedAt, + status = this.status, messages = this.messages.map { it.toSupportMessage() } ) diff --git a/WordPress/src/test/java/org/wordpress/android/support/he/ui/HESupportViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/support/he/ui/HESupportViewModelTest.kt index 72181efc3fb1..4e5b3a743f69 100644 --- a/WordPress/src/test/java/org/wordpress/android/support/he/ui/HESupportViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/support/he/ui/HESupportViewModelTest.kt @@ -962,13 +962,15 @@ class HESupportViewModelTest : BaseUnitTest() { private fun createTestConversation( id: Long, title: String = "Test Conversation", - description: String = "Test Description" + description: String = "Test Description", + status: String = "open" ): SupportConversation { return SupportConversation( id = id, title = title, description = description, lastMessageSentAt = Date(), + status = status, messages = emptyList() ) }