From f55d386ddd113c47fa67579e3d86d6ee0cda178b Mon Sep 17 00:00:00 2001 From: Aman tonk Date: Mon, 21 Oct 2024 09:29:39 +0900 Subject: [PATCH] Added Support of Bank and PayEasy (#53) --- .editorconfig | 2 +- .../navigation/PaymentResultScreenModel.kt | 4 +- .../InlinedPaymentPrimaryButton.kt | 37 ++++- .../sdk/ui/composables/InlinedWebView.kt | 11 +- .../awating/KonbiniAwaitingPaymentScreen.kt | 17 ++- .../payment/InlinedPaymentProcessor.kt | 6 +- .../payment/KomojuPaymentScreenModel.kt | 94 +++++++++++-- .../screens/payment/KomojuPaymentUIState.kt | 7 + .../screens/payment/composables/BankForm.kt | 46 ++++++- .../payment/composables/CompatTextField.kt | 105 +++++++++++++++ .../payment/composables/CreditCardForm.kt | 6 +- .../payment/composables/KonbiniBrandsRow.kt | 6 +- .../screens/payment/composables/PaidyForm.kt | 13 +- .../payment/composables/PayEasyForm.kt | 126 ++++++++++++++++++ .../payment/composables/PaymentMethodForm.kt | 10 +- .../payment/composables/PaymentMethodsRow.kt | 12 +- .../com/komoju/android/sdk/utils/StringExt.kt | 7 +- .../ui/remote/dtos/CreateSessionRequest.kt | 6 +- .../ui/screens/store/FakeStoreScreen.kt | 9 +- .../com/komoju/mobile/sdk/entities/Payment.kt | 23 +++- .../mobile/sdk/entities/PaymentRequest.kt | 21 ++- .../sdk/remote/dtos/PaymentRequestDto.kt | 28 ++++ .../sdk/remote/mappers/PaymentMapper.kt | 13 ++ 23 files changed, 564 insertions(+), 45 deletions(-) create mode 100644 android/src/main/java/com/komoju/android/sdk/ui/screens/payment/composables/CompatTextField.kt create mode 100644 android/src/main/java/com/komoju/android/sdk/ui/screens/payment/composables/PayEasyForm.kt diff --git a/.editorconfig b/.editorconfig index cf8ace6..580b6ec 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,7 +8,7 @@ ktlint_standard = disabled [*.{java,kt,kts,xml}] indent_size = 4 -max_line_length = 180 +max_line_length = 140 [**/test/**] ktlint_standard_class-naming = disabled diff --git a/android/src/main/java/com/komoju/android/sdk/navigation/PaymentResultScreenModel.kt b/android/src/main/java/com/komoju/android/sdk/navigation/PaymentResultScreenModel.kt index 2191c4b..ce993da 100644 --- a/android/src/main/java/com/komoju/android/sdk/navigation/PaymentResultScreenModel.kt +++ b/android/src/main/java/com/komoju/android/sdk/navigation/PaymentResultScreenModel.kt @@ -16,4 +16,6 @@ internal class PaymentResultScreenModel : ScreenModel { } @Composable -internal fun Navigator.paymentResultScreenModel() = rememberNavigatorScreenModel(PaymentResultScreenModel::class.simpleName) { PaymentResultScreenModel() } +internal fun Navigator.paymentResultScreenModel() = rememberNavigatorScreenModel(PaymentResultScreenModel::class.simpleName) { + PaymentResultScreenModel() +} diff --git a/android/src/main/java/com/komoju/android/sdk/ui/composables/InlinedPaymentPrimaryButton.kt b/android/src/main/java/com/komoju/android/sdk/ui/composables/InlinedPaymentPrimaryButton.kt index d49322e..448213e 100644 --- a/android/src/main/java/com/komoju/android/sdk/ui/composables/InlinedPaymentPrimaryButton.kt +++ b/android/src/main/java/com/komoju/android/sdk/ui/composables/InlinedPaymentPrimaryButton.kt @@ -36,7 +36,12 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.launch @Composable -internal fun InlinedPaymentPrimaryButton(text: String, state: InlinedPaymentPrimaryButtonState, modifier: Modifier = Modifier, onClick: () -> Unit) { +internal fun InlinedPaymentPrimaryButton( + text: String, + state: InlinedPaymentPrimaryButtonState, + modifier: Modifier = Modifier, + onClick: () -> Unit, +) { val configurableTheme = LocalConfigurableTheme.current Button( modifier = modifier, @@ -54,10 +59,27 @@ internal fun InlinedPaymentPrimaryButton(text: String, state: InlinedPaymentPrim contentAlignment = Alignment.Center, ) { when (state) { - InlinedPaymentPrimaryButtonState.LOADING -> CircularProgressIndicator(strokeWidth = 2.dp, color = LocalContentColor.current, modifier = Modifier.size(24.dp)) - InlinedPaymentPrimaryButtonState.IDLE -> Text(modifier = Modifier.padding(8.dp), text = text, style = TextStyle(fontWeight = FontWeight.Bold), maxLines = 1) - InlinedPaymentPrimaryButtonState.SUCCESS -> Icon(Icons.Rounded.CheckCircle, contentDescription = null, modifier = Modifier.size(24.dp)) - InlinedPaymentPrimaryButtonState.ERROR -> Icon(Icons.Rounded.Close, contentDescription = null, modifier = Modifier.size(24.dp)) + InlinedPaymentPrimaryButtonState.LOADING -> CircularProgressIndicator( + strokeWidth = 2.dp, + color = LocalContentColor.current, + modifier = Modifier.size(24.dp), + ) + InlinedPaymentPrimaryButtonState.IDLE -> Text( + modifier = Modifier.padding(8.dp), + text = text, + style = TextStyle(fontWeight = FontWeight.Bold), + maxLines = 1, + ) + InlinedPaymentPrimaryButtonState.SUCCESS -> Icon( + Icons.Rounded.CheckCircle, + contentDescription = null, + modifier = Modifier.size(24.dp), + ) + InlinedPaymentPrimaryButtonState.ERROR -> Icon( + Icons.Rounded.Close, + contentDescription = null, + modifier = Modifier.size(24.dp), + ) } } } @@ -71,8 +93,9 @@ enum class InlinedPaymentPrimaryButtonState { } @Composable -fun rememberInlinedPaymentPrimaryButtonState(default: InlinedPaymentPrimaryButtonState = InlinedPaymentPrimaryButtonState.IDLE): MutableState = - rememberSaveable { mutableStateOf(default) } +fun rememberInlinedPaymentPrimaryButtonState( + default: InlinedPaymentPrimaryButtonState = InlinedPaymentPrimaryButtonState.IDLE, +): MutableState = rememberSaveable { mutableStateOf(default) } @Composable @Preview(showBackground = true, showSystemUi = true) diff --git a/android/src/main/java/com/komoju/android/sdk/ui/composables/InlinedWebView.kt b/android/src/main/java/com/komoju/android/sdk/ui/composables/InlinedWebView.kt index 2230c37..d95d442 100644 --- a/android/src/main/java/com/komoju/android/sdk/ui/composables/InlinedWebView.kt +++ b/android/src/main/java/com/komoju/android/sdk/ui/composables/InlinedWebView.kt @@ -32,7 +32,13 @@ import com.komoju.android.sdk.R @SuppressLint("SetJavaScriptEnabled") @Composable -internal fun InlinedWebView(modifier: Modifier, url: String, onDone: (String) -> Unit, onChallengePresented: () -> Unit, onCloseButtonClicked: () -> Unit) { +internal fun InlinedWebView( + modifier: Modifier, + url: String, + onDone: (String) -> Unit, + onChallengePresented: () -> Unit, + onCloseButtonClicked: () -> Unit, +) { val state = rememberWebViewState(url) Column(modifier = modifier) { Row( @@ -81,7 +87,8 @@ internal fun InlinedWebView(modifier: Modifier, url: String, onDone: (String) -> } } -private class InlinedWebViewClient(private val onDeeplinkCaptured: (String) -> Unit, private val onChallengePresented: () -> Unit) : AccompanistWebViewClient() { +private class InlinedWebViewClient(private val onDeeplinkCaptured: (String) -> Unit, private val onChallengePresented: () -> Unit) : + AccompanistWebViewClient() { @Deprecated("Deprecated in Java") override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean = view.checkAndOpen(url) override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean = view.checkAndOpen(request.url.toString()) diff --git a/android/src/main/java/com/komoju/android/sdk/ui/screens/awating/KonbiniAwaitingPaymentScreen.kt b/android/src/main/java/com/komoju/android/sdk/ui/screens/awating/KonbiniAwaitingPaymentScreen.kt index 40efafa..b3738c2 100644 --- a/android/src/main/java/com/komoju/android/sdk/ui/screens/awating/KonbiniAwaitingPaymentScreen.kt +++ b/android/src/main/java/com/komoju/android/sdk/ui/screens/awating/KonbiniAwaitingPaymentScreen.kt @@ -55,7 +55,11 @@ internal data class KonbiniAwaitingPaymentScreen(val route: KomojuPaymentRoute.K val uiState by screenModel.state.collectAsStateWithLifecycle() RouterEffect(screenModel.router.collectAsStateWithLifecycle(), screenModel::onRouteConsumed) uiState.payment?.let { - PaymentStatus(it, onPrimaryButtonClicked = screenModel::onPrimaryButtonClicked, onSecondaryButtonClicked = screenModel::onSecondaryButtonClicked) + PaymentStatus( + payment = it, + onPrimaryButtonClicked = screenModel::onPrimaryButtonClicked, + onSecondaryButtonClicked = screenModel::onSecondaryButtonClicked, + ) } if (uiState.isLoading) { Box( @@ -88,7 +92,12 @@ private fun PaymentStatus(payment: Payment, onPrimaryButtonClicked: () -> Unit, Spacer(modifier = Modifier.padding(16.dp)) Text(payment.title, fontSize = 32.sp, style = TextStyle(fontWeight = FontWeight.Medium)) Spacer(modifier = Modifier.padding(8.dp)) - Text(payment.description, fontSize = 16.sp, color = Gray700, style = TextStyle(fontWeight = FontWeight.Normal, textAlign = TextAlign.Center)) + Text( + text = payment.description, + fontSize = 16.sp, + color = Gray700, + style = TextStyle(fontWeight = FontWeight.Normal, textAlign = TextAlign.Center), + ) Box( modifier = Modifier .weight(1f) @@ -179,7 +188,9 @@ private val Payment.description get() = when { status == PaymentStatus.COMPLETED -> "Your payment has been processed successfully." status == PaymentStatus.FAILED -> "Your payment has failed." - this is Payment.Konbini && status == PaymentStatus.AUTHORIZED -> "You need to go to your local ${this.konbiniStoreKey} and make the payment to proceed." + this is Payment.Konbini && status == PaymentStatus.AUTHORIZED -> + "You need to go to your local ${this.konbiniStoreKey}" + + " and make the payment to proceed." else -> "Your payment is awaiting processing." } diff --git a/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/InlinedPaymentProcessor.kt b/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/InlinedPaymentProcessor.kt index bcc8ecf..0547079 100644 --- a/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/InlinedPaymentProcessor.kt +++ b/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/InlinedPaymentProcessor.kt @@ -42,7 +42,11 @@ private suspend fun KomojuRemoteApi.payByToken( } } -private suspend fun KomojuRemoteApi.processBySession(sessionId: String, onSuccess: suspend (PaymentStatus) -> Unit, onError: (Reason) -> Unit) { +private suspend fun KomojuRemoteApi.processBySession( + sessionId: String, + onSuccess: suspend (PaymentStatus) -> Unit, + onError: (Reason) -> Unit, +) { sessions.verifyPaymentBySessionID(sessionId).onSuccess { paymentDetails -> onSuccess(paymentDetails.status) }.onFailure { diff --git a/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/KomojuPaymentScreenModel.kt b/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/KomojuPaymentScreenModel.kt index 8763f2a..f9f9697 100644 --- a/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/KomojuPaymentScreenModel.kt +++ b/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/KomojuPaymentScreenModel.kt @@ -13,6 +13,7 @@ import com.komoju.android.sdk.utils.CreditCardUtils.isValidCardHolderNameChar import com.komoju.android.sdk.utils.CreditCardUtils.isValidCardNumber import com.komoju.android.sdk.utils.CreditCardUtils.isValidExpiryDate import com.komoju.android.sdk.utils.DeeplinkEntity +import com.komoju.android.sdk.utils.isKatakanaOnly import com.komoju.android.sdk.utils.isValidEmail import com.komoju.mobile.sdk.entities.Payment import com.komoju.mobile.sdk.entities.PaymentMethod @@ -33,7 +34,8 @@ import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -internal class KomojuPaymentScreenModel(private val config: KomojuSDK.Configuration) : RouterStateScreenModel(KomojuPaymentUIState()) { +internal class KomojuPaymentScreenModel(private val config: KomojuSDK.Configuration) : + RouterStateScreenModel(KomojuPaymentUIState()) { private val komojuApi: KomojuRemoteApi = KomojuRemoteApi(config.publishableKey, config.language.languageCode) private val _offSitePaymentURL = MutableStateFlow(null) val offSitePaymentURL = _offSitePaymentURL.asStateFlow() @@ -141,7 +143,11 @@ internal class KomojuPaymentScreenModel(private val config: KomojuSDK.Configurat mutableRouter.value = Router.ReplaceAll( KomojuPaymentRoute.ProcessPayment( configuration = config, - processType = KomojuPaymentRoute.ProcessPayment.ProcessType.PayByToken(tokens.id, request.amount, request.currency), + processType = KomojuPaymentRoute.ProcessPayment.ProcessType.PayByToken( + tokens.id, + request.amount, + request.currency, + ), ), ) } @@ -151,9 +157,11 @@ internal class KomojuPaymentScreenModel(private val config: KomojuSDK.Configurat if (config.inlinedProcessing) { mutableState.update { it.copy(inlinedCreditCardProcessingURL = tokens.authURL) } } else { - mutableRouter.value = Router.ReplaceAll(KomojuPaymentRoute.WebView(url = tokens.authURL, isJavaScriptEnabled = true)) + mutableRouter.value = + Router.ReplaceAll(KomojuPaymentRoute.WebView(url = tokens.authURL, isJavaScriptEnabled = true)) } } + ERRORED, UNKNOWN -> mutableRouter.value = Router.ReplaceAll(KomojuPaymentRoute.PaymentFailed(Reason.CREDIT_CARD_ERROR)) } }.onFailure { @@ -205,7 +213,11 @@ internal class KomojuPaymentScreenModel(private val config: KomojuSDK.Configurat when (this) { is Payment.Konbini -> mutableRouter.value = Router.Replace(KomojuPaymentRoute.KonbiniAwaitingPayment(config, payment = this)) is Payment.OffSitePayment -> _offSitePaymentURL.value = redirectURL - is Payment.Completed -> mutableRouter.value = Router.SetPaymentResultAndPop(KomojuSDK.PaymentResult(isSuccessFul = status == PaymentStatus.CAPTURED)) + is Payment.Completed -> + mutableRouter.value = + Router.SetPaymentResultAndPop(KomojuSDK.PaymentResult(isSuccessFul = status == PaymentStatus.CAPTURED)) + is Payment.BankTransfer -> mutableRouter.value = Router.ReplaceAll(KomojuPaymentRoute.WebView(url = instructionURL)) + is Payment.PayEasy -> mutableRouter.value = Router.ReplaceAll(KomojuPaymentRoute.WebView(url = instructionURL)) else -> Unit } } @@ -217,10 +229,54 @@ internal class KomojuPaymentScreenModel(private val config: KomojuSDK.Configurat is PaymentMethod.NetCash -> state.value.netCashDisplayData.validate() is PaymentMethod.BitCash -> state.value.bitCashDisplayData.validate() is PaymentMethod.WebMoney -> state.value.webMoneyDisplayData.validate() + is PaymentMethod.BankTransfer, + is PaymentMethod.PayEasy, + -> state.value.commonDisplayData.validate() + is PaymentMethod.OffSitePayment -> true // No input required for Offsite payment else -> false } + private fun CommonDisplayData.validate(): Boolean { + val lastNameError = if (lastName.isBlank()) "The entered last name cannot be empty" else null + val firstNameError = if (firstName.isBlank()) "The entered first name cannot be empty" else null + val firstNamePhoneticError = when { + firstNamePhonetic.isBlank() -> "The entered first name phonetic cannot be empty" + firstNamePhonetic.isKatakanaOnly.not() -> "The entered first name phonetic must be a kana" + else -> null + } + val lastNamePhoneticError = when { + lastNamePhonetic.isBlank() -> "The entered last name phonetic cannot be empty" + lastNamePhonetic.isKatakanaOnly.not() -> "The entered last name phonetic must be a kana" + else -> null + } + val emailError = if (email.isValidEmail.not()) "The entered email is not valid" else null + val phoneNumberError = when { + phoneNumber.isBlank() -> "The entered phone number cannot be empty" + phoneNumber.length < 7 -> "The entered phone number is not valid" + phoneNumber.isDigitsOnly().not() -> "The entered phone number is not valid" + else -> null + } + mutableState.update { + it.copy( + commonDisplayData = it.commonDisplayData.copy( + lastNameError = lastNameError, + firstNameError = firstNameError, + firstNamePhoneticError = firstNamePhoneticError, + lastNamePhoneticError = lastNamePhoneticError, + emailError = emailError, + phoneNumberError = phoneNumberError, + ), + ) + } + return lastNameError == null && + firstNameError == null && + firstNamePhoneticError == null && + lastNamePhoneticError == null && + emailError == null && + phoneNumberError == null + } + private fun WebMoneyDisplayData.validate(): Boolean { val prepaidNumberError = when { prepaidNumber.isBlank() -> "The entered prepaid number cannot be empty" @@ -252,6 +308,7 @@ internal class KomojuPaymentScreenModel(private val config: KomojuSDK.Configurat } return idError == null } + private fun NetCashDisplayData.validate(): Boolean { val idError = when { netCashId.isBlank() -> "The entered net cash id cannot be empty" @@ -347,7 +404,7 @@ internal class KomojuPaymentScreenModel(private val config: KomojuSDK.Configurat paymentMethod = this, bitCashId = state.value.bitCashDisplayData.bitCashId, ) - is PaymentMethod.CreditCard -> error("Credit Card needs to generate tokens first!") + is PaymentMethod.Konbini -> PaymentRequest.Konbini( paymentMethod = this, konbiniBrand = state.value.konbiniDisplayData.selectedKonbiniBrand!!, @@ -358,19 +415,40 @@ internal class KomojuPaymentScreenModel(private val config: KomojuSDK.Configurat paymentMethod = this, netCashId = state.value.netCashDisplayData.netCashId, ) - is PaymentMethod.Other -> error("payment method is not supported!") + is PaymentMethod.Paidy -> PaymentRequest.Paidy( paymentMethod = this, fullName = state.value.paidyDisplayData.fullName, phoneNumber = state.value.paidyDisplayData.phoneNumber, ) - is PaymentMethod.BankTransfer -> TODO() - is PaymentMethod.PayEasy -> TODO() + + is PaymentMethod.BankTransfer -> PaymentRequest.BankTransfer( + paymentMethod = this, + lastName = state.value.commonDisplayData.lastName, + firstName = state.value.commonDisplayData.firstName, + lastNamePhonetic = state.value.commonDisplayData.lastNamePhonetic, + firstNamePhonetic = state.value.commonDisplayData.firstNamePhonetic, + email = state.value.commonDisplayData.email, + phoneNumber = state.value.commonDisplayData.phoneNumber, + ) + + is PaymentMethod.PayEasy -> PaymentRequest.PayEasy( + paymentMethod = this, + lastName = state.value.commonDisplayData.lastName, + firstName = state.value.commonDisplayData.firstName, + lastNamePhonetic = state.value.commonDisplayData.lastNamePhonetic, + firstNamePhonetic = state.value.commonDisplayData.firstNamePhonetic, + email = state.value.commonDisplayData.email, + phoneNumber = state.value.commonDisplayData.phoneNumber, + ) is PaymentMethod.WebMoney -> PaymentRequest.WebMoney( paymentMethod = this, prepaidNumber = state.value.webMoneyDisplayData.prepaidNumber, ) + is PaymentMethod.OffSitePayment -> PaymentRequest.OffSitePaymentRequest(this) + is PaymentMethod.CreditCard -> error("Credit Card needs to generate tokens first!") + is PaymentMethod.Other -> error("payment method is not supported!") } fun onCloseClicked() { diff --git a/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/KomojuPaymentUIState.kt b/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/KomojuPaymentUIState.kt index ba53c56..09714ee 100644 --- a/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/KomojuPaymentUIState.kt +++ b/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/KomojuPaymentUIState.kt @@ -28,6 +28,13 @@ internal data class CommonDisplayData( val firstNamePhonetic: String = String.empty, val email: String = String.empty, val phoneNumber: String = String.empty, + val fullNameError: String? = null, + val lastNameError: String? = null, + val firstNameError: String? = null, + val lastNamePhoneticError: String? = null, + val firstNamePhoneticError: String? = null, + val emailError: String? = null, + val phoneNumberError: String? = null, ) internal data class CreditCardDisplayData( diff --git a/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/composables/BankForm.kt b/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/composables/BankForm.kt index b55874f..7453f9d 100644 --- a/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/composables/BankForm.kt +++ b/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/composables/BankForm.kt @@ -12,7 +12,9 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.intl.Locale import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.komoju.android.sdk.types.Currency @@ -23,6 +25,8 @@ import com.komoju.android.sdk.ui.theme.LocalI18nTexts import com.komoju.android.sdk.utils.AmountUtils import com.komoju.mobile.sdk.entities.PaymentMethod +internal val JAPANESE_LOCALE = Locale("ja") + @Composable internal fun BankForm( bankTransfer: PaymentMethod.BankTransfer, @@ -36,39 +40,62 @@ internal fun BankForm( } } Column { - TextField( + CompatTextField( + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), value = commonDisplayData.lastName, titleKey = "LAST_NAME", placeholderKey = "LAST_NAME", onValueChange = { onCommonDisplayDataChange(commonDisplayData.copy(lastName = it)) }, + keyboardType = KeyboardType.Text, + imeActions = ImeAction.Next, + singleLine = true, + error = commonDisplayData.lastNameError, ) - TextField( + CompatTextField( + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), value = commonDisplayData.firstName, titleKey = "FIRST_NAME", placeholderKey = "FIRST_NAME", onValueChange = { onCommonDisplayDataChange(commonDisplayData.copy(firstName = it)) }, + keyboardType = KeyboardType.Text, + imeActions = ImeAction.Next, + singleLine = true, + error = commonDisplayData.firstNameError, ) - TextField( + CompatTextField( + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), value = commonDisplayData.lastNamePhonetic, titleKey = "LAST_NAME_PHONETIC", placeholderKey = "LAST_NAME_PHONETIC", onValueChange = { onCommonDisplayDataChange(commonDisplayData.copy(lastNamePhonetic = it)) }, + keyboardType = KeyboardType.Text, + keyBoardLocale = JAPANESE_LOCALE, + imeActions = ImeAction.Next, + singleLine = true, + error = commonDisplayData.lastNamePhoneticError, ) - TextField( + CompatTextField( + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), value = commonDisplayData.firstNamePhonetic, titleKey = "FIRST_NAME_PHONETIC", placeholderKey = "FIRST_NAME_PHONETIC", onValueChange = { onCommonDisplayDataChange(commonDisplayData.copy(firstNamePhonetic = it)) }, + keyboardType = KeyboardType.Text, + keyBoardLocale = JAPANESE_LOCALE, + imeActions = ImeAction.Next, + singleLine = true, + error = commonDisplayData.firstNamePhoneticError, ) - TextField( + CompatTextField( + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), value = commonDisplayData.email, titleKey = "EMAIL", placeholderKey = "EXAMPLE_EMAIL", @@ -76,8 +103,12 @@ internal fun BankForm( onCommonDisplayDataChange(commonDisplayData.copy(email = it)) }, keyboardType = KeyboardType.Email, + imeActions = ImeAction.Next, + singleLine = true, + error = commonDisplayData.emailError, ) - TextField( + CompatTextField( + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), value = commonDisplayData.phoneNumber, titleKey = "TELEPHONE_NUMBER", placeholderKey = "TELEPHONE_NUMBER_PLACEHOLDER", @@ -85,6 +116,9 @@ internal fun BankForm( onCommonDisplayDataChange(commonDisplayData.copy(phoneNumber = it)) }, keyboardType = KeyboardType.Number, + imeActions = ImeAction.Done, + singleLine = true, + error = commonDisplayData.phoneNumberError, ) Spacer(modifier = Modifier.height(16.dp)) PrimaryButton( diff --git a/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/composables/CompatTextField.kt b/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/composables/CompatTextField.kt new file mode 100644 index 0000000..e2ef477 --- /dev/null +++ b/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/composables/CompatTextField.kt @@ -0,0 +1,105 @@ +package com.komoju.android.sdk.ui.screens.payment.composables + +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.OutlinedTextFieldDefaults +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardCapitalization +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.intl.Locale +import androidx.compose.ui.text.intl.LocaleList +import androidx.compose.ui.unit.dp +import com.komoju.android.sdk.ui.theme.Gray200 +import com.komoju.android.sdk.ui.theme.LocalConfigurableTheme +import com.komoju.android.sdk.ui.theme.LocalI18nTexts +import com.komoju.android.sdk.ui.theme.Red600 + +@Composable +internal fun CompatTextField( + modifier: Modifier = Modifier, + value: String, + titleKey: String, + placeholderKey: String, + onValueChange: (String) -> Unit, + error: String? = null, + keyboardType: KeyboardType = KeyboardType.Unspecified, + capitalization: KeyboardCapitalization = KeyboardCapitalization.Unspecified, + keyBoardLocale: Locale = Locale.current, + imeActions: ImeAction = ImeAction.Unspecified, + singleLine: Boolean = false, +) { + val configurableTheme = LocalConfigurableTheme.current + OutlinedTextField( + modifier = modifier, + value = value, + onValueChange = onValueChange, + shape = RoundedCornerShape(8.dp), + label = { + Text(text = LocalI18nTexts.current[titleKey]) + }, + placeholder = { + Text(text = LocalI18nTexts.current[placeholderKey]) + }, + isError = error != null, + singleLine = singleLine, + supportingText = { + if (error != null) { + Text(text = error, color = Red600) + } + }, + keyboardOptions = KeyboardOptions( + keyboardType = keyboardType, + capitalization = capitalization, + hintLocales = LocaleList(keyBoardLocale), + imeAction = imeActions, + ), + colors = OutlinedTextFieldDefaults.colors() + .copy( + focusedLabelColor = Color(configurableTheme.primaryButtonColor), + focusedIndicatorColor = Color(configurableTheme.primaryButtonColor), + unfocusedIndicatorColor = Gray200, + ), + ) +// Column { +// Text( +// modifier = Modifier +// .fillMaxWidth() +// .padding(horizontal = 16.dp), +// text = LocalI18nTexts.current[titleKey], +// ) +// Box( +// modifier = Modifier +// .fillMaxWidth() +// .padding(horizontal = 16.dp, vertical = 8.dp) +// .border(1.dp, if (error != null) Red600 else Gray200, shape = RoundedCornerShape(8.dp)) +// .padding(16.dp), +// ) { +// BasicTextField( +// modifier = Modifier.fillMaxWidth(), +// value = value, +// onValueChange = onValueChange, +// textStyle = TextStyle(fontSize = 16.sp, color = Color.Black), +// singleLine = true, +// keyboardOptions = KeyboardOptions(keyboardType = keyboardType, capitalization = capitalization), +// ) +// if (value.isEmpty()) { +// Text( +// text = LocalI18nTexts.current[placeholderKey], +// style = TextStyle(fontSize = 16.sp, color = Gray500), +// ) +// } +// } +// Text( +// modifier = Modifier +// .fillMaxWidth() +// .padding(horizontal = 16.dp), +// text = LocalI18nTexts.current[error.orEmpty()], +// style = TextStyle(fontSize = 16.sp, color = Red600), +// ) +// } +} diff --git a/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/composables/CreditCardForm.kt b/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/composables/CreditCardForm.kt index 21a7959..89883d3 100644 --- a/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/composables/CreditCardForm.kt +++ b/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/composables/CreditCardForm.kt @@ -191,7 +191,11 @@ internal fun CreditCardForm( } } - Image(painter = painterResource(R.drawable.komoju_ic_cvv), contentDescription = null, modifier = Modifier.padding(start = 16.dp)) + Image( + painter = painterResource(R.drawable.komoju_ic_cvv), + contentDescription = null, + modifier = Modifier.padding(start = 16.dp), + ) } } } diff --git a/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/composables/KonbiniBrandsRow.kt b/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/composables/KonbiniBrandsRow.kt index 09da09d..d0b8e22 100644 --- a/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/composables/KonbiniBrandsRow.kt +++ b/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/composables/KonbiniBrandsRow.kt @@ -54,7 +54,11 @@ private fun KonbiniBrand(konbiniBrand: KonbiniBrand, isSelected: Boolean, onSele .clickable(onClick = onSelected) .padding(8.dp), ) { - Image(painter = painterResource(konbiniBrand.displayIcon), contentDescription = "${konbiniBrand.key} icon", modifier = Modifier.size(32.dp)) + Image( + painter = painterResource(konbiniBrand.displayIcon), + contentDescription = "${konbiniBrand.key} icon", + modifier = Modifier.size(32.dp), + ) Spacer(modifier = Modifier.height(4.dp)) Text(LocalI18nTexts.current[konbiniBrand.key], fontSize = 14.sp) } diff --git a/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/composables/PaidyForm.kt b/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/composables/PaidyForm.kt index c9eeb8e..d37ce64 100644 --- a/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/composables/PaidyForm.kt +++ b/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/composables/PaidyForm.kt @@ -19,7 +19,12 @@ import com.komoju.android.sdk.ui.theme.LocalI18nTexts import com.komoju.mobile.sdk.entities.PaymentMethod @Composable -internal fun PaidyForm(paidy: PaymentMethod.Paidy, paidyDisplayData: PaidyDisplayData, onPaidyDisplayDataChange: (PaidyDisplayData) -> Unit, onPayButtonClicked: () -> Unit) { +internal fun PaidyForm( + paidy: PaymentMethod.Paidy, + paidyDisplayData: PaidyDisplayData, + onPaidyDisplayDataChange: (PaidyDisplayData) -> Unit, + onPayButtonClicked: () -> Unit, +) { Column { TextField( value = paidyDisplayData.fullName, @@ -40,7 +45,11 @@ internal fun PaidyForm(paidy: PaymentMethod.Paidy, paidyDisplayData: PaidyDispla }, error = paidyDisplayData.phoneNumberError, ) - PrimaryButton(LocalI18nTexts.current["CONTINUE_TO_PAIDY"], modifier = Modifier.fillMaxWidth().padding(all = 16.dp), onPayButtonClicked) + PrimaryButton( + LocalI18nTexts.current["CONTINUE_TO_PAIDY"], + modifier = Modifier.fillMaxWidth().padding(all = 16.dp), + onPayButtonClicked, + ) } } diff --git a/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/composables/PayEasyForm.kt b/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/composables/PayEasyForm.kt new file mode 100644 index 0000000..239779a --- /dev/null +++ b/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/composables/PayEasyForm.kt @@ -0,0 +1,126 @@ +package com.komoju.android.sdk.ui.screens.payment.composables + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.unit.dp +import com.komoju.android.sdk.types.Currency +import com.komoju.android.sdk.ui.composables.PrimaryButton +import com.komoju.android.sdk.ui.screens.payment.CommonDisplayData +import com.komoju.android.sdk.ui.theme.LocalI18nTexts +import com.komoju.android.sdk.utils.AmountUtils +import com.komoju.mobile.sdk.entities.PaymentMethod + +@Composable +internal fun PayEasyForm( + payEasy: PaymentMethod.PayEasy, + commonDisplayData: CommonDisplayData, + onCommonDisplayDataChange: (CommonDisplayData) -> Unit, + onPayButtonClicked: () -> Unit, +) { + val displayPayableAmount by remember(payEasy.amount) { + derivedStateOf { + AmountUtils.formatToDecimal(Currency.parse(payEasy.currency), payEasy.amount) + } + } + Column { + CompatTextField( + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), + value = commonDisplayData.lastName, + titleKey = "LAST_NAME", + placeholderKey = "LAST_NAME", + onValueChange = { + onCommonDisplayDataChange(commonDisplayData.copy(lastName = it)) + }, + keyboardType = KeyboardType.Text, + imeActions = ImeAction.Next, + singleLine = true, + error = commonDisplayData.lastNameError, + ) + CompatTextField( + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), + value = commonDisplayData.firstName, + titleKey = "FIRST_NAME", + placeholderKey = "FIRST_NAME", + onValueChange = { + onCommonDisplayDataChange(commonDisplayData.copy(firstName = it)) + }, + keyboardType = KeyboardType.Text, + imeActions = ImeAction.Next, + singleLine = true, + error = commonDisplayData.firstNameError, + ) + CompatTextField( + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), + value = commonDisplayData.lastNamePhonetic, + titleKey = "LAST_NAME_PHONETIC", + placeholderKey = "LAST_NAME_PHONETIC", + onValueChange = { + onCommonDisplayDataChange(commonDisplayData.copy(lastNamePhonetic = it)) + }, + keyboardType = KeyboardType.Text, + keyBoardLocale = JAPANESE_LOCALE, + imeActions = ImeAction.Next, + singleLine = true, + error = commonDisplayData.lastNamePhoneticError, + ) + CompatTextField( + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), + value = commonDisplayData.firstNamePhonetic, + titleKey = "FIRST_NAME_PHONETIC", + placeholderKey = "FIRST_NAME_PHONETIC", + onValueChange = { + onCommonDisplayDataChange(commonDisplayData.copy(firstNamePhonetic = it)) + }, + keyboardType = KeyboardType.Text, + keyBoardLocale = JAPANESE_LOCALE, + imeActions = ImeAction.Next, + singleLine = true, + error = commonDisplayData.firstNamePhoneticError, + ) + CompatTextField( + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), + value = commonDisplayData.email, + titleKey = "EMAIL", + placeholderKey = "EXAMPLE_EMAIL", + onValueChange = { + onCommonDisplayDataChange(commonDisplayData.copy(email = it)) + }, + keyboardType = KeyboardType.Email, + imeActions = ImeAction.Next, + singleLine = true, + error = commonDisplayData.emailError, + ) + CompatTextField( + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), + value = commonDisplayData.phoneNumber, + titleKey = "TELEPHONE_NUMBER", + placeholderKey = "TELEPHONE_NUMBER_PLACEHOLDER", + onValueChange = { + onCommonDisplayDataChange(commonDisplayData.copy(phoneNumber = it)) + }, + keyboardType = KeyboardType.Number, + imeActions = ImeAction.Done, + singleLine = true, + error = commonDisplayData.phoneNumberError, + ) + Spacer(modifier = Modifier.height(16.dp)) + PrimaryButton( + modifier = Modifier + .padding(16.dp) + .fillMaxWidth(), + text = "${LocalI18nTexts.current["PAY"]} $displayPayableAmount", + onClick = onPayButtonClicked, + ) + } +} diff --git a/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/composables/PaymentMethodForm.kt b/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/composables/PaymentMethodForm.kt index e7ba97f..5dfea37 100644 --- a/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/composables/PaymentMethodForm.kt +++ b/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/composables/PaymentMethodForm.kt @@ -101,7 +101,15 @@ internal fun PaymentMethodForm( onPaymentRequested(paymentMethod) }, ) - is PaymentMethod.PayEasy -> Unit + + is PaymentMethod.PayEasy -> PayEasyForm( + payEasy = paymentMethod, + commonDisplayData = commonDisplayData, + onCommonDisplayDataChange = onCommonDisplayDataChange, + onPayButtonClicked = { + onPaymentRequested(paymentMethod) + }, + ) is PaymentMethod.Other -> Unit } diff --git a/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/composables/PaymentMethodsRow.kt b/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/composables/PaymentMethodsRow.kt index 9654233..b1e978a 100644 --- a/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/composables/PaymentMethodsRow.kt +++ b/android/src/main/java/com/komoju/android/sdk/ui/screens/payment/composables/PaymentMethodsRow.kt @@ -29,7 +29,11 @@ import com.komoju.mobile.sdk.entities.PaymentMethod import com.komoju.mobile.sdk.types.OffSitePaymentType @Composable -internal fun PaymentMethodsRow(paymentMethods: List, selectedPaymentMethod: PaymentMethod?, onSelected: (PaymentMethod) -> Unit) { +internal fun PaymentMethodsRow( + paymentMethods: List, + selectedPaymentMethod: PaymentMethod?, + onSelected: (PaymentMethod) -> Unit, +) { LazyRow(contentPadding = PaddingValues(horizontal = 8.dp)) { items(paymentMethods) { paymentMethod -> PaymentMethodComposable( @@ -54,7 +58,11 @@ private fun PaymentMethodComposable(paymentMethod: PaymentMethod, isSelected: Bo .clickable(onClick = onSelected) .padding(start = 12.dp, end = 12.dp, top = 12.dp, bottom = 8.dp), ) { - Image(painter = painterResource(paymentMethod.displayIcon), contentDescription = "${paymentMethod.displayName} icon", modifier = Modifier.height(32.dp)) + Image( + painter = painterResource(paymentMethod.displayIcon), + contentDescription = "${paymentMethod.displayName} icon", + modifier = Modifier.height(32.dp), + ) Spacer(modifier = Modifier.height(4.dp)) Text(paymentMethod.displayName, color = Color.Black, fontWeight = FontWeight.SemiBold, fontSize = 14.sp) } diff --git a/android/src/main/java/com/komoju/android/sdk/utils/StringExt.kt b/android/src/main/java/com/komoju/android/sdk/utils/StringExt.kt index 1677ce6..b431528 100644 --- a/android/src/main/java/com/komoju/android/sdk/utils/StringExt.kt +++ b/android/src/main/java/com/komoju/android/sdk/utils/StringExt.kt @@ -6,7 +6,6 @@ internal inline val String.Companion.empty get() = "" internal inline val String.isValidEmail: Boolean get() = matches(EMAIL_REGEX) -internal inline val String.hostName get() = replace("https://", "") - .replace("http://", "").run { - substring(0.. Unit = {}, onItemClicked: () -> Un ) } Text("¥" + item.price, fontSize = 18.sp, color = Color.Black, fontWeight = FontWeight.Bold, modifier = Modifier.padding(4.dp)) - Text(stringResource(item.name), fontSize = 14.sp, color = Color.Black, fontWeight = FontWeight.Medium, lineHeight = 16.sp, modifier = Modifier.padding(horizontal = 4.dp)) + Text( + stringResource(item.name), + fontSize = 14.sp, + color = Color.Black, + fontWeight = FontWeight.Medium, + lineHeight = 16.sp, + modifier = Modifier.padding(horizontal = 4.dp), + ) Text( stringResource(R.string.model) + ": " + item.model + ", " + stringResource(item.color), fontSize = 12.sp, diff --git a/shared/src/commonMain/kotlin/com/komoju/mobile/sdk/entities/Payment.kt b/shared/src/commonMain/kotlin/com/komoju/mobile/sdk/entities/Payment.kt index a4ea57f..7036b4a 100644 --- a/shared/src/commonMain/kotlin/com/komoju/mobile/sdk/entities/Payment.kt +++ b/shared/src/commonMain/kotlin/com/komoju/mobile/sdk/entities/Payment.kt @@ -18,8 +18,26 @@ sealed interface Payment { ) : Payment data class CreditCard(override val status: PaymentStatus, override val amount: String, override val currency: String) : Payment - data class OffSitePayment(override val status: PaymentStatus, override val amount: String, override val currency: String, val type: String, val redirectURL: String) : Payment + data class OffSitePayment( + override val status: PaymentStatus, + override val amount: String, + override val currency: String, + val type: String, + val redirectURL: String, + ) : Payment data class Completed(override val status: PaymentStatus, override val amount: String, override val currency: String) : Payment + data class BankTransfer( + override val status: PaymentStatus, + override val amount: String, + override val currency: String, + val instructionURL: String, + ) : Payment + data class PayEasy( + override val status: PaymentStatus, + override val amount: String, + override val currency: String, + val instructionURL: String, + ) : Payment data class Error(val code: String, val message: String, override val amount: String, override val currency: String) : Payment { override val status: PaymentStatus = PaymentStatus.EXPIRED @@ -38,7 +56,8 @@ enum class PaymentStatus { ; companion object { - fun fromString(status: String): PaymentStatus = entries.find { it.name == status.uppercase() } ?: throw IllegalArgumentException("Invalid payment status: $status") + fun fromString(status: String): PaymentStatus = + entries.find { it.name == status.uppercase() } ?: throw IllegalArgumentException("Invalid payment status: $status") fun PaymentStatus.isSuccessful(): Boolean = this in listOf(COMPLETED, CAPTURED) } diff --git a/shared/src/commonMain/kotlin/com/komoju/mobile/sdk/entities/PaymentRequest.kt b/shared/src/commonMain/kotlin/com/komoju/mobile/sdk/entities/PaymentRequest.kt index 23f3459..646ff3c 100644 --- a/shared/src/commonMain/kotlin/com/komoju/mobile/sdk/entities/PaymentRequest.kt +++ b/shared/src/commonMain/kotlin/com/komoju/mobile/sdk/entities/PaymentRequest.kt @@ -5,10 +5,29 @@ import com.komoju.mobile.sdk.entities.PaymentMethod.Konbini.KonbiniBrand sealed interface PaymentRequest { val paymentMethod: PaymentMethod - data class Konbini(override val paymentMethod: PaymentMethod.Konbini, val konbiniBrand: KonbiniBrand, val email: String) : PaymentRequest + data class Konbini(override val paymentMethod: PaymentMethod.Konbini, val konbiniBrand: KonbiniBrand, val email: String) : + PaymentRequest data class Paidy(override val paymentMethod: PaymentMethod.Paidy, val fullName: String, val phoneNumber: String) : PaymentRequest data class OffSitePaymentRequest(override val paymentMethod: PaymentMethod.OffSitePayment) : PaymentRequest data class NetCash(override val paymentMethod: PaymentMethod.NetCash, val netCashId: String) : PaymentRequest data class BitCash(override val paymentMethod: PaymentMethod.BitCash, val bitCashId: String) : PaymentRequest data class WebMoney(override val paymentMethod: PaymentMethod.WebMoney, val prepaidNumber: String) : PaymentRequest + data class BankTransfer( + override val paymentMethod: PaymentMethod.BankTransfer, + val lastName: String, + val firstName: String, + val lastNamePhonetic: String, + val firstNamePhonetic: String, + val email: String, + val phoneNumber: String, + ) : PaymentRequest + data class PayEasy( + override val paymentMethod: PaymentMethod.PayEasy, + val lastName: String, + val firstName: String, + val lastNamePhonetic: String, + val firstNamePhonetic: String, + val email: String, + val phoneNumber: String, + ) : PaymentRequest } diff --git a/shared/src/commonMain/kotlin/com/komoju/mobile/sdk/remote/dtos/PaymentRequestDto.kt b/shared/src/commonMain/kotlin/com/komoju/mobile/sdk/remote/dtos/PaymentRequestDto.kt index 68f357e..d18901e 100644 --- a/shared/src/commonMain/kotlin/com/komoju/mobile/sdk/remote/dtos/PaymentRequestDto.kt +++ b/shared/src/commonMain/kotlin/com/komoju/mobile/sdk/remote/dtos/PaymentRequestDto.kt @@ -49,6 +49,30 @@ internal data class PaymentRequestDto(@SerialName("payment_details") val payment prepaidNumber = paymentRequest.prepaidNumber, ), ) + + is PaymentRequest.BankTransfer -> PaymentRequestDto( + paymentDetails = PaymentDetails( + type = "bank_transfer", + phoneNumber = paymentRequest.phoneNumber, + email = paymentRequest.email, + givenName = paymentRequest.firstName, + givenNameKana = paymentRequest.firstNamePhonetic, + familyName = paymentRequest.lastName, + familyNameKana = paymentRequest.lastNamePhonetic, + ), + ) + + is PaymentRequest.PayEasy -> PaymentRequestDto( + paymentDetails = PaymentDetails( + type = "pay_easy", + phoneNumber = paymentRequest.phoneNumber, + email = paymentRequest.email, + givenName = paymentRequest.firstName, + givenNameKana = paymentRequest.firstNamePhonetic, + familyName = paymentRequest.lastName, + familyNameKana = paymentRequest.lastNamePhonetic, + ), + ) } } @@ -60,5 +84,9 @@ internal data class PaymentRequestDto(@SerialName("payment_details") val payment @SerialName("customer_name") val fullName: String? = null, @SerialName("phone") val phoneNumber: String? = null, @SerialName("prepaid_number") val prepaidNumber: String? = null, + @SerialName("given_name") val givenName: String? = null, + @SerialName("given_name_kana") val givenNameKana: String? = null, + @SerialName("family_name") val familyName: String? = null, + @SerialName("family_name_kana") val familyNameKana: String? = null, ) } diff --git a/shared/src/commonMain/kotlin/com/komoju/mobile/sdk/remote/mappers/PaymentMapper.kt b/shared/src/commonMain/kotlin/com/komoju/mobile/sdk/remote/mappers/PaymentMapper.kt index f9f14ca..acde911 100644 --- a/shared/src/commonMain/kotlin/com/komoju/mobile/sdk/remote/mappers/PaymentMapper.kt +++ b/shared/src/commonMain/kotlin/com/komoju/mobile/sdk/remote/mappers/PaymentMapper.kt @@ -44,6 +44,19 @@ internal object PaymentMapper { status = PaymentStatus.fromString(payment.status.orEmpty()), ) + "bank_transfer" -> Payment.BankTransfer( + amount = payment.amount.orEmpty(), + currency = payment.currency.orEmpty(), + status = PaymentStatus.fromString(payment.status.orEmpty()), + instructionURL = payment.paymentDetails.instructionsUrl.orEmpty(), + ) + "pay_easy" -> Payment.PayEasy( + amount = payment.amount.orEmpty(), + currency = payment.currency.orEmpty(), + status = PaymentStatus.fromString(payment.status.orEmpty()), + instructionURL = payment.paymentDetails.instructionsUrl.orEmpty(), + ) + else -> error("Invalid payment type") } }