Skip to content
Merged
Original file line number Diff line number Diff line change
@@ -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
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ data class SupportConversation(
val title: String,
val description: String,
val lastMessageSentAt: Date,
val status: String,
val messages: List<SupportMessage>
): Conversation {
override fun getConversationId(): Long = id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ class HESupportRepository @Inject constructor(
title = it.title,
description = it.description,
lastMessageSentAt = it.updatedAt,
status = it.status,
messages = emptyList()
)
}
Expand All @@ -191,6 +192,7 @@ class HESupportRepository @Inject constructor(
title = title,
description = description,
lastMessageSentAt = updatedAt,
status = status,
messages = messages.map { it.toSupportMessage() }
)

Expand Down
Original file line number Diff line number Diff line change
@@ -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)
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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(
Expand All @@ -140,7 +147,7 @@ fun HEConversationDetailScreen(
) {
item {
ConversationHeader(
messageCount = conversation.messages.size,
status = conversation.status,
lastUpdated = formatRelativeTime(conversation.lastMessageSentAt, resources),
isLoading = isLoading
)
Expand Down Expand Up @@ -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)
}
Expand All @@ -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),
Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ fun generateSampleHESupportConversations(): List<SupportConversation> {
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,
Expand Down Expand Up @@ -73,6 +74,7 @@ fun generateSampleHESupportConversations(): List<SupportConversation> {
"store, I've noticed significant slowdowns and occasional timeout errors affecting customer " +
"experience.",
lastMessageSentAt = twoDaysAgo,
status = "closed",
messages = listOf(
SupportMessage(
id = 4,
Expand Down Expand Up @@ -101,6 +103,7 @@ fun generateSampleHESupportConversations(): List<SupportConversation> {
"configuration, SSL certificate setup, and setting up professional email forwarding for my " +
"business site.",
lastMessageSentAt = oneWeekAgo,
status = "solved",
messages = listOf(
SupportMessage(
id = 6,
Expand Down
6 changes: 6 additions & 0 deletions WordPress/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5182,6 +5182,12 @@ translators: %s: Select control option value e.g: "Auto, 25%". -->
<string name="he_support_include_logs_description">Including logs can help our team investigate issues. Logs may contain recent app activity.</string>
<string name="he_support_download_attachment">Download attachment</string>
<string name="he_support_select_attachments">Select attachments</string>
<string name="he_support_status_waiting_for_support">Waiting for Support</string>
<string name="he_support_status_waiting_for_user">Waiting for User</string>
<string name="he_support_status_solved">Solved</string>
<string name="he_support_status_closed">Closed</string>
<string name="he_support_status_unknown">Unknown</string>
<string name="he_support_conversation_closed_message">This conversation is closed. You can no longer reply to it.</string>
<string name="he_support_video_playback_error_title">Unable to play video</string>
<string name="he_support_video_playback_error_message">This video cannot be played inline. Please download it to view.</string>
<string name="he_support_download_video_button">Download Video</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@ class HESupportRepositoryTest : BaseUnitTest() {
title = title,
description = description,
lastMessageSentAt = updatedAt,
status = status,
messages = emptyList()
)

Expand All @@ -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() }
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
)
}
Expand Down