NTP-5471 | Abha aadhar fix (#13683)
Co-authored-by: Shivam Goyal <shivam.goyal@navi.com>
This commit is contained in:
committed by
GitHub
parent
70111615d7
commit
7a060f3187
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2024 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.base.utils
|
||||
|
||||
class AadhaarUtils {
|
||||
private val d =
|
||||
arrayOf(
|
||||
intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9),
|
||||
intArrayOf(1, 2, 3, 4, 0, 6, 7, 8, 9, 5),
|
||||
intArrayOf(2, 3, 4, 0, 1, 7, 8, 9, 5, 6),
|
||||
intArrayOf(3, 4, 0, 1, 2, 8, 9, 5, 6, 7),
|
||||
intArrayOf(4, 0, 1, 2, 3, 9, 5, 6, 7, 8),
|
||||
intArrayOf(5, 9, 8, 7, 6, 0, 4, 3, 2, 1),
|
||||
intArrayOf(6, 5, 9, 8, 7, 1, 0, 4, 3, 2),
|
||||
intArrayOf(7, 6, 5, 9, 8, 2, 1, 0, 4, 3),
|
||||
intArrayOf(8, 7, 6, 5, 9, 3, 2, 1, 0, 4),
|
||||
intArrayOf(9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
|
||||
)
|
||||
|
||||
private val p =
|
||||
arrayOf(
|
||||
intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9),
|
||||
intArrayOf(1, 5, 7, 6, 2, 8, 3, 0, 9, 4),
|
||||
intArrayOf(5, 8, 0, 3, 7, 9, 6, 1, 4, 2),
|
||||
intArrayOf(8, 9, 1, 6, 0, 4, 3, 5, 2, 7),
|
||||
intArrayOf(9, 4, 5, 3, 1, 2, 6, 8, 7, 0),
|
||||
intArrayOf(4, 2, 8, 6, 5, 7, 3, 9, 0, 1),
|
||||
intArrayOf(2, 7, 9, 3, 8, 0, 6, 4, 1, 5),
|
||||
intArrayOf(7, 0, 4, 6, 9, 1, 3, 2, 5, 8)
|
||||
)
|
||||
|
||||
private val inv = intArrayOf(0, 4, 3, 2, 1, 5, 6, 7, 8, 9)
|
||||
|
||||
fun validateVerhoeff(num: String): Boolean {
|
||||
var charIndex = 0
|
||||
val myArray = stringToReversedIntArray(num)
|
||||
for (index in myArray.indices) {
|
||||
charIndex = d[charIndex][p[index % 8][myArray[index]]]
|
||||
}
|
||||
return charIndex == 0
|
||||
}
|
||||
|
||||
fun stringToReversedIntArray(num: String): IntArray {
|
||||
val myArray = num.map { it.toString().toInt() }.toIntArray()
|
||||
return myArray.reversedArray()
|
||||
}
|
||||
|
||||
fun isValidAadhaar(aadhaarNumber: String): Boolean {
|
||||
val aadhaarPattern = Regex("\\d{12}")
|
||||
return aadhaarPattern.matches(aadhaarNumber) && validateVerhoeff(aadhaarNumber)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2024 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.base
|
||||
|
||||
import com.navi.base.utils.AadhaarUtils
|
||||
import org.junit.Assert.assertArrayEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
|
||||
class AadhaarUtilsTest {
|
||||
private val aadhaarUtils = AadhaarUtils()
|
||||
|
||||
@Test
|
||||
fun `validateAadhaarNumber returns true for valid Aadhaar number`() {
|
||||
val validAadhaar = "273838226780"
|
||||
assertTrue(aadhaarUtils.isValidAadhaar(validAadhaar))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `validateAadhaarNumber returns false for invalid Aadhaar number`() {
|
||||
val invalidAadhaar = "123456781235"
|
||||
assertFalse(aadhaarUtils.isValidAadhaar(invalidAadhaar))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `validateAadhaarNumber returns false for non-numeric input`() {
|
||||
val invalidAadhaar = "1234A6781234"
|
||||
assertFalse(aadhaarUtils.isValidAadhaar(invalidAadhaar))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `validateAadhaarNumber returns false for input with less than 12 digits`() {
|
||||
val shortAadhaar = "123456"
|
||||
assertFalse(aadhaarUtils.isValidAadhaar(shortAadhaar))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `validateAadhaarNumber returns false for input with more than 12 digits`() {
|
||||
val longAadhaar = "1234567890123"
|
||||
assertFalse(aadhaarUtils.isValidAadhaar(longAadhaar))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `validateVerhoeff returns true for valid Verhoeff number`() {
|
||||
val validVerhoeff = "236"
|
||||
assertTrue(aadhaarUtils.validateVerhoeff(validVerhoeff))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `validateVerhoeff returns false for invalid Verhoeff number`() {
|
||||
val invalidVerhoeff = "123"
|
||||
assertFalse(aadhaarUtils.validateVerhoeff(invalidVerhoeff))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `stringToReversedIntArray correctly reverses string to int array`() {
|
||||
val input = "12345"
|
||||
val expected = intArrayOf(5, 4, 3, 2, 1)
|
||||
assertArrayEquals(expected, aadhaarUtils.stringToReversedIntArray(input))
|
||||
}
|
||||
|
||||
@Test(expected = NumberFormatException::class)
|
||||
fun `stringToReversedIntArray throws exception for non-numeric input`() {
|
||||
val input = "12A45"
|
||||
aadhaarUtils.stringToReversedIntArray(input)
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
package com.navi.insurance.abha
|
||||
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.navi.base.utils.AadhaarUtils
|
||||
import com.navi.base.utils.isNotNull
|
||||
import com.navi.base.utils.isNull
|
||||
import com.navi.base.utils.orZero
|
||||
@@ -54,14 +55,29 @@ constructor(
|
||||
val footerState: StateFlow<String>
|
||||
get() = _footerState.asStateFlow()
|
||||
|
||||
private val _errorState: MutableStateFlow<Int?> = MutableStateFlow(null)
|
||||
val errorState: StateFlow<Int?>
|
||||
get() = _errorState.asStateFlow()
|
||||
|
||||
private var otpPageValidation: Int = 0
|
||||
private var aadharPageValidation: Int = 0
|
||||
var validAadharWidgets: HashMap<String, GenericWidgetDataInfo> = hashMapOf()
|
||||
var validAadharWidgets: HashMap<String, Pair<GenericWidgetDataInfo, Int>> = hashMapOf()
|
||||
var validOtpWidgets: HashMap<String, GenericWidgetDataInfo> = hashMapOf()
|
||||
private var policyId: String? = null
|
||||
private var pageSource: String? = null
|
||||
private var linkAbhaRequest: LinkAbhaRequest = LinkAbhaRequest()
|
||||
|
||||
fun updateErrorIndex(index: Int?) {
|
||||
_errorState.value = index
|
||||
}
|
||||
|
||||
fun isValidAadhar(): Boolean {
|
||||
return (validAadharWidgets[AADHAR_NUMBER_EXTRA]?.first as? EditableTextWidgetData)
|
||||
?.widgetData
|
||||
?.value
|
||||
?.let { AadhaarUtils().isValidAadhaar(it) } ?: false
|
||||
}
|
||||
|
||||
fun setPolicyId(policyId: String?) {
|
||||
this.policyId = policyId
|
||||
}
|
||||
@@ -135,9 +151,13 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun updateAadharValidWidgets(widgetDataInfo: GenericWidgetDataInfo, isValid: Boolean) {
|
||||
fun updateAadharValidWidgets(
|
||||
widgetDataInfo: GenericWidgetDataInfo,
|
||||
isValid: Boolean,
|
||||
index: Int = -1
|
||||
) {
|
||||
when {
|
||||
isValid -> addValidWidget(widgetDataInfo)
|
||||
isValid -> addValidWidget(widgetDataInfo, index)
|
||||
else -> removeValidWidget(widgetDataInfo)
|
||||
}
|
||||
|
||||
@@ -149,16 +169,19 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun addValidWidget(widgetDataInfo: GenericWidgetDataInfo) {
|
||||
private fun addValidWidget(widgetDataInfo: GenericWidgetDataInfo, index: Int) {
|
||||
when (widgetDataInfo) {
|
||||
is EditableTextWidgetData -> {
|
||||
when (widgetDataInfo.widgetData?.id) {
|
||||
AADHAR_NUMBER_EXTRA -> validAadharWidgets[AADHAR_NUMBER_EXTRA] = widgetDataInfo
|
||||
MOBILE_NUMBER_EXTRA -> validAadharWidgets[MOBILE_NUMBER_EXTRA] = widgetDataInfo
|
||||
AADHAR_NUMBER_EXTRA ->
|
||||
validAadharWidgets[AADHAR_NUMBER_EXTRA] = Pair(widgetDataInfo, index)
|
||||
MOBILE_NUMBER_EXTRA ->
|
||||
validAadharWidgets[MOBILE_NUMBER_EXTRA] = Pair(widgetDataInfo, index)
|
||||
}
|
||||
}
|
||||
is SelectableTextWidgetData -> {
|
||||
validAadharWidgets[WidgetTypes.SELECTABLE_TEXT_WIDGET.value] = widgetDataInfo
|
||||
validAadharWidgets[WidgetTypes.SELECTABLE_TEXT_WIDGET.value] =
|
||||
Pair(widgetDataInfo, index)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -167,7 +190,10 @@ constructor(
|
||||
when (widgetDataInfo) {
|
||||
is EditableTextWidgetData -> {
|
||||
when (widgetDataInfo.widgetData?.id) {
|
||||
AADHAR_NUMBER_EXTRA -> validAadharWidgets.remove(AADHAR_NUMBER_EXTRA)
|
||||
AADHAR_NUMBER_EXTRA -> {
|
||||
_errorState.value = null
|
||||
validAadharWidgets.remove(AADHAR_NUMBER_EXTRA)
|
||||
}
|
||||
MOBILE_NUMBER_EXTRA -> validAadharWidgets.remove(MOBILE_NUMBER_EXTRA)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,6 +139,7 @@ class ABHAaadharFragment : BaseFragment(), WidgetCallback {
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun AbhaAadharContentScreen(data: ABHAPageResponse) {
|
||||
val errorIndex = viewModel.errorState.collectAsState()
|
||||
val widgetCallback: WidgetCallback = this
|
||||
Scaffold(
|
||||
modifier = Modifier.fillMaxSize().background(color = Color.White),
|
||||
@@ -163,8 +164,9 @@ class ABHAaadharFragment : BaseFragment(), WidgetCallback {
|
||||
data = genericWidgetData,
|
||||
widgetCallback = widgetCallback,
|
||||
onWidgetUpdate = { data, isValid ->
|
||||
viewModel.updateAadharValidWidgets(data, isValid)
|
||||
}
|
||||
viewModel.updateAadharValidWidgets(data, isValid, index)
|
||||
},
|
||||
showError = errorIndex.value == index
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -189,43 +191,49 @@ class ABHAaadharFragment : BaseFragment(), WidgetCallback {
|
||||
openHelpCenter()
|
||||
}
|
||||
CtaType.NAVIGATE_TO_NEW_SCREEN.value -> {
|
||||
val params = naviClickAction?.parameters?.toMutableList()
|
||||
viewModel.validAadharWidgets.forEach { widgetDataInfo ->
|
||||
if (
|
||||
widgetDataInfo.value is EditableTextWidgetData &&
|
||||
widgetDataInfo?.key == AADHAR_NUMBER_EXTRA
|
||||
) {
|
||||
params?.add(
|
||||
LineItem(
|
||||
AADHAR_NUMBER_EXTRA,
|
||||
(widgetDataInfo.value as EditableTextWidgetData)
|
||||
?.widgetData
|
||||
?.value
|
||||
if (viewModel.isValidAadhar()) {
|
||||
val params = naviClickAction?.parameters?.toMutableList()
|
||||
viewModel.validAadharWidgets.forEach { widgetDataInfo ->
|
||||
if (
|
||||
widgetDataInfo.value.first is EditableTextWidgetData &&
|
||||
widgetDataInfo?.key == AADHAR_NUMBER_EXTRA
|
||||
) {
|
||||
params?.add(
|
||||
LineItem(
|
||||
AADHAR_NUMBER_EXTRA,
|
||||
(widgetDataInfo.value?.first as EditableTextWidgetData)
|
||||
?.widgetData
|
||||
?.value
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
widgetDataInfo.value is EditableTextWidgetData &&
|
||||
widgetDataInfo?.key == MOBILE_NUMBER_EXTRA
|
||||
) {
|
||||
params?.add(
|
||||
LineItem(
|
||||
MOBILE_NUMBER_EXTRA,
|
||||
(widgetDataInfo.value as EditableTextWidgetData)
|
||||
?.widgetData
|
||||
?.value
|
||||
if (
|
||||
widgetDataInfo.value.first is EditableTextWidgetData &&
|
||||
widgetDataInfo?.key == MOBILE_NUMBER_EXTRA
|
||||
) {
|
||||
params?.add(
|
||||
LineItem(
|
||||
MOBILE_NUMBER_EXTRA,
|
||||
(widgetDataInfo.value?.first as EditableTextWidgetData)
|
||||
?.widgetData
|
||||
?.value
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
val redirectionCta = naviClickAction.copy(parameters = params)
|
||||
NaviInsuranceDeeplinkNavigator.navigate(
|
||||
activity,
|
||||
ctaData = redirectionCta,
|
||||
finish = redirectionCta.finish.orFalse(),
|
||||
clearTask = redirectionCta.clearTask.orFalse()
|
||||
)
|
||||
} else {
|
||||
viewModel.updateErrorIndex(
|
||||
viewModel.validAadharWidgets.get(AADHAR_NUMBER_EXTRA)?.second
|
||||
)
|
||||
}
|
||||
val redirectionCta = naviClickAction.copy(parameters = params)
|
||||
NaviInsuranceDeeplinkNavigator.navigate(
|
||||
activity,
|
||||
ctaData = redirectionCta,
|
||||
finish = redirectionCta.finish.orFalse(),
|
||||
clearTask = redirectionCta.clearTask.orFalse()
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
NaviInsuranceDeeplinkNavigator.navigate(
|
||||
|
||||
@@ -94,7 +94,8 @@ fun GenericComposableWidgetFactory(
|
||||
widgetCallback: WidgetCallback? = null,
|
||||
isFirstItemVisible: Boolean = false,
|
||||
onWidgetUpdate: (updatedData: GenericWidgetDataInfo, isValid: Boolean) -> Unit = { _, _ -> },
|
||||
state: String = FooterButtonState.ENABLED.name
|
||||
state: String = FooterButtonState.ENABLED.name,
|
||||
showError: Boolean = false
|
||||
) {
|
||||
LaunchedEffect(key1 = data.toString()) {
|
||||
data?.widgetAnalyticsProperties?.let {
|
||||
@@ -264,7 +265,8 @@ fun GenericComposableWidgetFactory(
|
||||
EditableTextWidgetComposable(
|
||||
data as? EditableTextWidgetData,
|
||||
widgetCallback,
|
||||
onWidgetUpdate
|
||||
onWidgetUpdate,
|
||||
showError
|
||||
)
|
||||
}
|
||||
WidgetTypes.SELECTABLE_TEXT_WIDGET.value -> {
|
||||
|
||||
@@ -30,6 +30,7 @@ data class EditableTextWidgetContentData(
|
||||
@SerializedName("title") val title: TextFieldData? = null,
|
||||
@SerializedName("fixedTitle") val fixedTitle: TextFieldData? = null,
|
||||
@SerializedName("textRules") val textRules: TextRules? = null,
|
||||
@SerializedName("errorText") val errorText: TextFieldData? = null,
|
||||
@SerializedName("value") val value: String? = null,
|
||||
@SerializedName("id") val id: String? = null
|
||||
)
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
package com.navi.naviwidgets.composewidget.widgets
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
@@ -18,7 +18,6 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
@@ -30,6 +29,7 @@ import com.navi.design.theme.ttComposeFontFamily
|
||||
import com.navi.naviwidgets.callbacks.WidgetCallback
|
||||
import com.navi.naviwidgets.composewidget.model.EditableTextWidgetData
|
||||
import com.navi.naviwidgets.composewidget.reusable.colorBorderAlt
|
||||
import com.navi.naviwidgets.composewidget.reusable.colorInputFields
|
||||
import com.navi.naviwidgets.extensions.NaviTextWidgetized
|
||||
import com.navi.naviwidgets.extensions.getKeyBoardType
|
||||
import com.navi.naviwidgets.extensions.hexToColor
|
||||
@@ -39,15 +39,13 @@ import com.navi.naviwidgets.extensions.setWidgetLayoutParams
|
||||
fun EditableTextWidgetComposable(
|
||||
editableTextData: EditableTextWidgetData?,
|
||||
widgetCallback: WidgetCallback? = null,
|
||||
onWidgetUpdate: (updatedData: EditableTextWidgetData, isValid: Boolean) -> Unit
|
||||
onWidgetUpdate: (updatedData: EditableTextWidgetData, isValid: Boolean) -> Unit,
|
||||
isError: Boolean = false
|
||||
) {
|
||||
var textLimit by remember { mutableStateOf(editableTextData?.widgetData?.title?.text ?: "") }
|
||||
editableTextData?.widgetData?.let { data ->
|
||||
setWidgetLayoutParams(widgetLayoutParams = editableTextData?.widgetLayoutParams) {
|
||||
Row(
|
||||
modifier = Modifier.background(Color.White).fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Column(modifier = Modifier.background(Color.White).fillMaxWidth()) {
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
value = textLimit,
|
||||
@@ -73,6 +71,7 @@ fun EditableTextWidgetComposable(
|
||||
}
|
||||
}
|
||||
},
|
||||
isError = isError,
|
||||
placeholder = { NaviTextWidgetized(data?.hintText) },
|
||||
leadingIcon =
|
||||
if (data?.fixedTitle != null) {
|
||||
@@ -85,13 +84,21 @@ fun EditableTextWidgetComposable(
|
||||
),
|
||||
colors =
|
||||
OutlinedTextFieldDefaults.colors(
|
||||
focusedBorderColor = colorBorderAlt,
|
||||
unfocusedBorderColor = colorBorderAlt,
|
||||
focusedBorderColor = if (isError) colorInputFields else colorBorderAlt,
|
||||
unfocusedBorderColor =
|
||||
if (isError) colorInputFields else colorBorderAlt,
|
||||
cursorColor = Color.Black,
|
||||
focusedContainerColor = Color.White,
|
||||
unfocusedContainerColor = Color.White,
|
||||
errorCursorColor = Color.Black
|
||||
errorCursorColor = Color.Black,
|
||||
errorBorderColor = colorInputFields
|
||||
),
|
||||
supportingText =
|
||||
if (isError) {
|
||||
{ NaviTextWidgetized(data.errorText) }
|
||||
} else {
|
||||
null
|
||||
},
|
||||
textStyle =
|
||||
TextStyle(
|
||||
fontFamily = ttComposeFontFamily,
|
||||
|
||||
Reference in New Issue
Block a user