diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/WooShippingLabelCreationFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/WooShippingLabelCreationFragment.kt
index 4a5a8518a36..1f5a293b553 100644
--- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/WooShippingLabelCreationFragment.kt
+++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/WooShippingLabelCreationFragment.kt
@@ -17,6 +17,7 @@ import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground
import com.woocommerce.android.ui.main.AppBarStatus
import com.woocommerce.android.ui.main.MainActivity.Companion.BackPressListener
import com.woocommerce.android.ui.orders.wooshippinglabels.WooShippingLabelCreationViewModel.StartCustomsFormEdit
+import com.woocommerce.android.ui.orders.wooshippinglabels.WooShippingLabelCreationViewModel.StartHazmatFormEdit
import com.woocommerce.android.ui.orders.wooshippinglabels.WooShippingLabelCreationViewModel.StartPackageSelection
import com.woocommerce.android.ui.orders.wooshippinglabels.address.EditAddressFlow
import com.woocommerce.android.ui.orders.wooshippinglabels.address.WooShippingEditAddressFragment.Companion.DESTINATION_ADDRESS_UPDATE_RESULT
@@ -109,6 +110,12 @@ class WooShippingLabelCreationFragment : BaseFragment(), BackPressListener {
findNavController().navigateSafely(it)
}
}
+
+ is StartHazmatFormEdit -> {
+ WooShippingLabelCreationFragmentDirections
+ .actionWooShippingLabelCreationFragmentToWooShippingLabelHazmatFormFragment()
+ .let { findNavController().navigateSafely(it) }
+ }
}
}
}
diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/WooShippingLabelCreationScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/WooShippingLabelCreationScreen.kt
index 0c96710e678..ba0d58a40bc 100644
--- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/WooShippingLabelCreationScreen.kt
+++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/WooShippingLabelCreationScreen.kt
@@ -124,6 +124,7 @@ fun WooShippingLabelCreationScreen(viewModel: WooShippingLabelCreationViewModel)
destinationStatus = viewState.destinationStatus,
actionSnackbar = viewModel.actionSnackbar,
onSplitShipment = viewModel::onSplitShipment,
+ onHazmatNoticeClick = viewModel::onHazmatNoticeClick,
)
}
@@ -166,7 +167,8 @@ fun WooShippingLabelCreationScreen(
destinationStatus: AddressStatus,
modifier: Modifier = Modifier,
actionSnackbar: ActionSnackbar? = null,
- onSplitShipment: () -> Unit = {}
+ onSplitShipment: () -> Unit = {},
+ onHazmatNoticeClick: () -> Unit = {}
) {
val shipmentDetailsValue = if (uiState.isShipmentDetailsExpanded) {
BottomSheetValue.Expanded
@@ -230,7 +232,8 @@ fun WooShippingLabelCreationScreen(
onEditDestinationAddress = onEditDestinationAddress,
destinationStatus = destinationStatus,
actionSnackbar = actionSnackbar,
- onSplitShipment = onSplitShipment
+ onSplitShipment = onSplitShipment,
+ onHazmatNoticeClick = onHazmatNoticeClick
)
val isDarkTheme = isSystemInDarkTheme()
val isCollapsed = scaffoldState.bottomSheetState.isCollapsed
@@ -309,7 +312,8 @@ private fun LabelCreationScreenWithBottomSheet(
destinationStatus: AddressStatus,
modifier: Modifier = Modifier,
actionSnackbar: ActionSnackbar? = null,
- onSplitShipment: () -> Unit = {}
+ onSplitShipment: () -> Unit = {},
+ onHazmatNoticeClick: () -> Unit = {}
) {
val snackbarHostState = remember { SnackbarHostState() }
@@ -418,6 +422,7 @@ private fun LabelCreationScreenWithBottomSheet(
onExpand = { isExpanded.value = it }
)
HazmatCard(
+ onClick = onHazmatNoticeClick,
modifier = Modifier
.fillMaxWidth()
.padding(start = 4.dp, end = 8.dp)
diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/WooShippingLabelCreationViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/WooShippingLabelCreationViewModel.kt
index f7dc4eff82b..548b97eed16 100644
--- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/WooShippingLabelCreationViewModel.kt
+++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/WooShippingLabelCreationViewModel.kt
@@ -631,6 +631,10 @@ class WooShippingLabelCreationViewModel @Inject constructor(
triggerEvent(event)
}
+ fun onHazmatNoticeClick() {
+ triggerEvent(StartHazmatFormEdit)
+ }
+
fun allowBackNavigation(): Boolean {
val state = uiState.value
return when {
@@ -699,6 +703,8 @@ class WooShippingLabelCreationViewModel @Inject constructor(
val customData: CustomsData?
) : Event()
+ data object StartHazmatFormEdit : Event()
+
sealed class WooShippingViewState {
data object Error : WooShippingViewState()
data object Loading : WooShippingViewState()
diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/hazmat/WooShippingLabelHazmatFormFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/hazmat/WooShippingLabelHazmatFormFragment.kt
new file mode 100644
index 00000000000..d7f3e30bced
--- /dev/null
+++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/hazmat/WooShippingLabelHazmatFormFragment.kt
@@ -0,0 +1,31 @@
+package com.woocommerce.android.ui.orders.wooshippinglabels.hazmat
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.compose.material.Surface
+import androidx.compose.ui.platform.ComposeView
+import androidx.compose.ui.platform.ViewCompositionStrategy
+import androidx.fragment.app.viewModels
+import com.woocommerce.android.ui.base.BaseFragment
+import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground
+import dagger.hilt.android.AndroidEntryPoint
+
+@AndroidEntryPoint
+class WooShippingLabelHazmatFormFragment : BaseFragment() {
+ private val viewModel: WooShippingLabelHazmatFormViewModel by viewModels()
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ return ComposeView(requireContext()).apply {
+ setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
+ setContent {
+ WooThemeWithBackground {
+ Surface {
+ WooShippingLabelHazmatFormScreen(viewModel)
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/hazmat/WooShippingLabelHazmatFormScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/hazmat/WooShippingLabelHazmatFormScreen.kt
new file mode 100644
index 00000000000..7d534cc31f4
--- /dev/null
+++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/hazmat/WooShippingLabelHazmatFormScreen.kt
@@ -0,0 +1,112 @@
+package com.woocommerce.android.ui.orders.wooshippinglabels.hazmat
+
+import android.content.res.Configuration
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material3.Checkbox
+import androidx.compose.material3.CheckboxDefaults
+import androidx.compose.material3.HorizontalDivider
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.colorResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.woocommerce.android.R
+import com.woocommerce.android.ui.compose.component.WCColoredButton
+import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground
+
+@Composable
+fun WooShippingLabelHazmatFormScreen(viewModel: WooShippingLabelHazmatFormViewModel) {
+ val viewState by viewModel.viewState.observeAsState()
+ WooShippingLabelHazmatFormScreen(
+ containsHazmatChecked = viewState?.containsHazmatChecked == true,
+ onContainsHazmatChanged = viewModel::onContainsHazmatChanged,
+ onSelectCategoryClick = viewModel::onSelectCategoryClick
+ )
+}
+
+@Composable
+fun WooShippingLabelHazmatFormScreen(
+ containsHazmatChecked: Boolean,
+ onContainsHazmatChanged: (Boolean) -> Unit,
+ onSelectCategoryClick: () -> Unit,
+ modifier: Modifier = Modifier
+) {
+ Column(
+ verticalArrangement = Arrangement.spacedBy(8.dp),
+ modifier = modifier
+ .fillMaxSize()
+ .padding(16.dp)
+ .verticalScroll(rememberScrollState())
+ ) {
+ Text(
+ text = stringResource(R.string.woo_shipping_labels_hazmat_info_title),
+ style = MaterialTheme.typography.titleLarge,
+ fontWeight = FontWeight.Bold,
+ color = colorResource(id = R.color.color_on_surface)
+ )
+ Row(
+ horizontalArrangement = Arrangement.Absolute.SpaceBetween,
+ modifier = modifier
+ .fillMaxWidth()
+ .padding(vertical = 8.dp)
+ ) {
+ Text(
+ text = stringResource(R.string.woo_shipping_labels_hazmat_info_contains_hazmat),
+ style = MaterialTheme.typography.bodyLarge,
+ color = colorResource(id = R.color.color_on_surface),
+ modifier = modifier
+ .align(Alignment.CenterVertically)
+ .weight(1f)
+ )
+ Checkbox(
+ checked = containsHazmatChecked,
+ onCheckedChange = onContainsHazmatChanged,
+ colors = CheckboxDefaults.colors(
+ checkedColor = MaterialTheme.colorScheme.primary,
+ uncheckedColor = colorResource(id = R.color.color_on_surface_disabled),
+ )
+ )
+ }
+ WCColoredButton(
+ text = stringResource(R.string.woo_shipping_labels_hazmat_info_select_category),
+ onClick = onSelectCategoryClick,
+ enabled = containsHazmatChecked,
+ modifier = modifier.fillMaxWidth()
+ )
+
+ HorizontalDivider(modifier = modifier.padding(vertical = 8.dp))
+
+ Text(
+ text = stringResource(R.string.woo_shipping_labels_hazmat_info_full_description),
+ style = MaterialTheme.typography.bodyMedium,
+ color = colorResource(id = R.color.color_on_surface),
+ )
+ }
+}
+
+@Preview
+@Preview("Dark Theme", uiMode = Configuration.UI_MODE_NIGHT_YES)
+@Composable
+fun WooShippingLabelHazmatFormScreenPreview() {
+ WooThemeWithBackground {
+ WooShippingLabelHazmatFormScreen(
+ containsHazmatChecked = false,
+ onContainsHazmatChanged = {},
+ onSelectCategoryClick = {}
+ )
+ }
+}
diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/hazmat/WooShippingLabelHazmatFormViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/hazmat/WooShippingLabelHazmatFormViewModel.kt
new file mode 100644
index 00000000000..a47b7615dc9
--- /dev/null
+++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/hazmat/WooShippingLabelHazmatFormViewModel.kt
@@ -0,0 +1,42 @@
+package com.woocommerce.android.ui.orders.wooshippinglabels.hazmat
+
+import android.os.Parcelable
+import androidx.lifecycle.SavedStateHandle
+import androidx.lifecycle.asLiveData
+import androidx.lifecycle.viewModelScope
+import com.woocommerce.android.viewmodel.MultiLiveEvent.Event
+import com.woocommerce.android.viewmodel.ScopedViewModel
+import com.woocommerce.android.viewmodel.getStateFlow
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.flow.update
+import kotlinx.parcelize.Parcelize
+import javax.inject.Inject
+
+@HiltViewModel
+class WooShippingLabelHazmatFormViewModel @Inject constructor(
+ savedState: SavedStateHandle
+) : ScopedViewModel(savedState) {
+
+ private val _viewState = savedState.getStateFlow(
+ scope = viewModelScope,
+ initialValue = ViewState()
+ )
+ val viewState = _viewState.asLiveData()
+
+ fun onContainsHazmatChanged(containsHazmatChecked: Boolean) {
+ _viewState.update {
+ _viewState.value.copy(containsHazmatChecked = containsHazmatChecked)
+ }
+ }
+
+ fun onSelectCategoryClick() {
+ triggerEvent(OnSelectCategoryClicked)
+ }
+
+ @Parcelize
+ data class ViewState(
+ val containsHazmatChecked: Boolean = false
+ ) : Parcelable
+
+ data object OnSelectCategoryClicked : Event()
+}
diff --git a/WooCommerce/src/main/res/navigation/nav_graph_orders.xml b/WooCommerce/src/main/res/navigation/nav_graph_orders.xml
index 932cdbd31a2..3922ca62692 100644
--- a/WooCommerce/src/main/res/navigation/nav_graph_orders.xml
+++ b/WooCommerce/src/main/res/navigation/nav_graph_orders.xml
@@ -716,6 +716,9 @@
+
+
diff --git a/WooCommerce/src/main/res/values/strings.xml b/WooCommerce/src/main/res/values/strings.xml
index 0225c3afb2c..cb94b7bbdd7 100644
--- a/WooCommerce/src/main/res/values/strings.xml
+++ b/WooCommerce/src/main/res/values/strings.xml
@@ -4516,6 +4516,10 @@
Origin country
Missing country
Select a country
+ Are you shipping dangerous goods or hazardous materials?
+ Contains hazardous materials
+ Potentially hazardous material includes items such as batteries, dry ice, flammable liquids, aerosols, ammunition, fireworks, nail polish, perfume, paint, solvents, and more. Hazardous items must ship in separate packages.
+ Select Category
Hmm, we can\'t find a WordPress.com account connected to this email address.
diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/hazmat/WooShippingLabelHazmatFormViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/hazmat/WooShippingLabelHazmatFormViewModelTest.kt
new file mode 100644
index 00000000000..0c93ac20b33
--- /dev/null
+++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/hazmat/WooShippingLabelHazmatFormViewModelTest.kt
@@ -0,0 +1,92 @@
+package com.woocommerce.android.ui.orders.wooshippinglabels.hazmat
+
+import androidx.lifecycle.SavedStateHandle
+import com.woocommerce.android.viewmodel.BaseUnitTest
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.Before
+import org.junit.Test
+
+@OptIn(ExperimentalCoroutinesApi::class)
+class WooShippingLabelHazmatFormViewModelTest : BaseUnitTest() {
+ private lateinit var viewModel: WooShippingLabelHazmatFormViewModel
+
+ @Before
+ fun setup() {
+ viewModel = WooShippingLabelHazmatFormViewModel(SavedStateHandle())
+ }
+
+ @Test
+ fun `when initialized, then containsHazmatChecked is false by default`() = testBlocking {
+ // Given/When
+ var capturedViewState: WooShippingLabelHazmatFormViewModel.ViewState? = null
+ viewModel.viewState.observeForever {
+ capturedViewState = it
+ }
+
+ // Then
+ assertThat(capturedViewState?.containsHazmatChecked).isFalse()
+ }
+
+ @Test
+ fun `when onContainsHazmatChanged is called with true, then viewState is updated accordingly`() = testBlocking {
+ // Given
+ var capturedViewState: WooShippingLabelHazmatFormViewModel.ViewState? = null
+ viewModel.viewState.observeForever {
+ capturedViewState = it
+ }
+
+ // When
+ viewModel.onContainsHazmatChanged(true)
+
+ // Then
+ assertThat(capturedViewState?.containsHazmatChecked).isTrue()
+ }
+
+ @Test
+ fun `when onContainsHazmatChanged is called with false, then viewState is updated accordingly`() = testBlocking {
+ // Given
+ var capturedViewState: WooShippingLabelHazmatFormViewModel.ViewState? = null
+ viewModel.viewState.observeForever {
+ capturedViewState = it
+ }
+
+ // When
+ viewModel.onContainsHazmatChanged(false)
+
+ // Then
+ assertThat(capturedViewState?.containsHazmatChecked).isFalse()
+ }
+
+ @Test
+ fun `when onSelectCategoryClick is called, then OnSelectCategoryClicked event is triggered`() = testBlocking {
+ // Given
+ var capturedEvent: WooShippingLabelHazmatFormViewModel.OnSelectCategoryClicked? = null
+ viewModel.event.observeForever {
+ capturedEvent = it as? WooShippingLabelHazmatFormViewModel.OnSelectCategoryClicked
+ }
+
+ // When
+ viewModel.onSelectCategoryClick()
+
+ // Then
+ assertThat(capturedEvent).isInstanceOf(WooShippingLabelHazmatFormViewModel.OnSelectCategoryClicked::class.java)
+ }
+
+ @Test
+ fun `when multiple calls to onContainsHazmatChanged, then viewState reflects latest value`() = testBlocking {
+ // Given
+ var capturedViewState: WooShippingLabelHazmatFormViewModel.ViewState? = null
+ viewModel.viewState.observeForever {
+ capturedViewState = it
+ }
+
+ // When
+ viewModel.onContainsHazmatChanged(true)
+ viewModel.onContainsHazmatChanged(false)
+ viewModel.onContainsHazmatChanged(true)
+
+ // Then
+ assertThat(capturedViewState?.containsHazmatChecked).isTrue()
+ }
+}