Updated on 2026-08-14

This commit is contained in:
Tangem 2026-04-15 08:15:22 -07:00
parent ebe84a667e
commit eb2c1d765a
31 changed files with 1034 additions and 123 deletions

View file

@ -85,6 +85,18 @@ interface TangemPayApi {
@Body body: FreezeUnfreezeCardRequest,
): ApiResponse<FreezeUnfreezeCardResponse>
@GET("v1/fees/{type}")
suspend fun getFee(
@Header("Authorization") authHeader: String,
@Path("type") type: String,
): ApiResponse<FeeResponse>
@POST("v1/customer/card/reissue")
suspend fun reissueCard(
@Header("Authorization") authHeader: String,
@Body body: ReissueCardRequest,
): ApiResponse<ReissueCardResponse>
@POST("v1/customer/card/withdraw/data")
suspend fun getWithdrawData(
@Header("Authorization") authHeader: String,

View file

@ -0,0 +1,9 @@
package com.tangem.datasource.api.pay.models.request
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class ReissueCardRequest(
@Json(name = "card_id") val cardId: String,
)

View file

@ -0,0 +1,17 @@
package com.tangem.datasource.api.pay.models.response
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class FeeResponse(
@Json(name = "result") val result: Result,
) {
@JsonClass(generateAdapter = true)
data class Result(
@Json(name = "type") val type: String,
@Json(name = "amount") val amount: String,
@Json(name = "currency") val currency: String,
@Json(name = "description") val description: String,
)
}

View file

@ -0,0 +1,15 @@
package com.tangem.datasource.api.pay.models.response
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class ReissueCardResponse(
@Json(name = "result") val result: Result,
) {
@JsonClass(generateAdapter = true)
data class Result(
@Json(name = "order_id") val orderId: String,
@Json(name = "status") val status: String,
)
}

View file

@ -2,7 +2,9 @@ package com.tangem.datasource.di
import com.tangem.datasource.local.datastore.RuntimeDataStore
import com.tangem.datasource.local.visa.DefaultTangemPayCardFrozenStateStore
import com.tangem.datasource.local.visa.DefaultTangemPayReissueCardStore
import com.tangem.datasource.local.visa.TangemPayCardFrozenStateStore
import com.tangem.datasource.local.visa.TangemPayReissueCardStore
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@ -20,4 +22,12 @@ internal object TangemPayStoresModule {
dataStore = RuntimeDataStore(),
)
}
@Provides
@Singleton
fun provideTangemPayReissueCardStore(): TangemPayReissueCardStore {
return DefaultTangemPayReissueCardStore(
feeStore = RuntimeDataStore(),
)
}
}

View file

@ -0,0 +1,30 @@
package com.tangem.datasource.local.visa
import com.tangem.datasource.local.datastore.RuntimeDataStore
import com.tangem.domain.models.TangemPayReissueCardFee
import com.tangem.domain.models.wallet.UserWalletId
internal class DefaultTangemPayReissueCardStore(
private val feeStore: RuntimeDataStore<TangemPayReissueCardFee>,
) : TangemPayReissueCardStore {
override suspend fun storeReissueFee(
userWalletId: UserWalletId,
tangemPayReissueCardFee: TangemPayReissueCardFee,
) {
feeStore.store(userWalletId.stringValue, tangemPayReissueCardFee)
}
override suspend fun getReissueFee(userWalletId: UserWalletId): TangemPayReissueCardFee? {
return feeStore.getSyncOrNull(userWalletId.stringValue)
}
override suspend fun storeReissueOrderId(cardId: String, orderId: String) {
// TODO v_rodionov: #[REDACTED_TASK_KEY] store orderId in app prefs
}
override suspend fun getOrderId(cardId: String): String? {
// TODO v_rodionov: #[REDACTED_TASK_KEY] store orderId in app prefs
return null
}
}

View file

@ -0,0 +1,15 @@
package com.tangem.datasource.local.visa
import com.tangem.domain.models.TangemPayReissueCardFee
import com.tangem.domain.models.wallet.UserWalletId
interface TangemPayReissueCardStore {
suspend fun storeReissueFee(userWalletId: UserWalletId, tangemPayReissueCardFee: TangemPayReissueCardFee)
suspend fun getReissueFee(userWalletId: UserWalletId): TangemPayReissueCardFee?
suspend fun storeReissueOrderId(cardId: String, orderId: String)
suspend fun getOrderId(cardId: String): String?
}

View file

@ -1556,6 +1556,17 @@
<string name="tangem_pay_explore_transaction">Explore transaction</string>
<string name="tangem_pay_fee_subtitle">Service fees</string>
<string name="tangem_pay_fee_title">Fee</string>
<string name="tangempay_card_details_reissue_card">Replace card</string>
<string name="tangempay_reissue_card_title">Replace your card?</string>
<string name="tangempay_reissue_card_description">This generates a new set of card details. Your old details will stop working. You can\'t undo this.</string>
<string name="tangempay_reissue_card_fee_label">Replacement fee</string>
<string name="tangempay_reissue_card_confirm">Replace card</string>
<string name="tangempay_reissue_card_in_progress">Replacing your digital card</string>
<string name="tangempay_reissue_card_in_progress_description">Usually takes up to 5 minutes. In rare cases, up to 48 hours.</string>
<string name="tangempay_reissue_card_insufficient_funds">Insufficient funds to replace the card</string>
<string name="tangempay_reissue_card_insufficient_funds_title">Unable to cover fee</string>
<string name="tangempay_reissue_card_insufficient_funds_subtitle">Deposit USDC to payment account to cover the issuing fee</string>
<string name="tangempay_reissue_card_fee_unreachable_error_title">Replacement fee info unreachable</string>
<string name="tangem_pay_freeze_card_alert_body">Keep your money safe. You can unfreeze anytime.</string>
<string name="tangem_pay_freeze_card_alert_title">Freeze your card?</string>
<string name="tangem_pay_freeze_card_failed">Failed to freeze the card. Try again later.</string>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="32"
android:viewportHeight="32">
<path
android:pathData="M11.888,8.087C11.238,7.437 11.382,6.343 12.241,6.015C12.558,5.894 12.878,5.789 13.201,5.7C14.09,5.456 15.001,5.333 15.934,5.333C18.912,5.333 21.445,6.367 23.534,8.433C25.623,10.5 26.667,13.022 26.667,16V16.233L27.868,15.033C28.383,14.518 29.219,14.518 29.734,15.033C30.25,15.549 30.25,16.385 29.734,16.9L26.401,20.233C25.812,20.823 24.857,20.823 24.267,20.233L20.934,16.9C20.419,16.385 20.419,15.549 20.934,15.033C21.45,14.518 22.285,14.518 22.801,15.033L24.001,16.233V16C24.001,13.778 23.218,11.889 21.651,10.333C20.084,8.778 18.179,8 15.934,8C15.356,8 14.79,8.067 14.234,8.2C13.997,8.257 13.762,8.326 13.528,8.407C12.96,8.605 12.314,8.513 11.888,8.087ZM2.267,16.967C1.752,16.451 1.752,15.616 2.267,15.1L6.075,11.293C6.402,10.965 6.933,10.965 7.26,11.293L11.068,15.1C11.583,15.616 11.583,16.451 11.068,16.967C10.552,17.482 9.716,17.482 9.201,16.967L8.001,15.767V16C8.001,18.222 8.784,20.111 10.351,21.667C11.917,23.222 13.823,24 16.067,24C16.645,24 17.212,23.933 17.767,23.8C18.005,23.743 18.24,23.674 18.473,23.593C19.042,23.395 19.688,23.487 20.114,23.913C20.763,24.563 20.619,25.657 19.761,25.985C19.444,26.106 19.124,26.211 18.801,26.3C17.912,26.545 17.001,26.667 16.067,26.667C13.09,26.667 10.556,25.633 8.467,23.567C6.379,21.5 5.334,18.978 5.334,16V15.767L4.134,16.967C3.619,17.482 2.783,17.482 2.267,16.967Z"
android:fillColor="#000000"/>
</vector>

View file

@ -0,0 +1,18 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:pathData="M8,16c4.418,0 8,-3.582 8,-8 0,-4.418 -3.582,-8 -8,-8C3.582,0 0,3.582 0,8c0,4.418 3.582,8 8,8Z"
android:strokeWidth="0.5"
android:fillColor="#3e73c4"/>
<path
android:pathData="M10.011,9.062c0,-1.062 -0.64,-1.426 -1.92,-1.578 -0.914,-0.122 -1.097,-0.364 -1.097,-0.789 0,-0.425 0.305,-0.698 0.914,-0.698 0.549,0 0.854,0.182 1.005,0.637 0.016,0.044 0.045,0.082 0.083,0.109 0.038,0.027 0.084,0.042 0.131,0.042h0.488c0.028,0.001 0.056,-0.004 0.082,-0.015 0.026,-0.01 0.05,-0.026 0.07,-0.046 0.02,-0.02 0.036,-0.044 0.046,-0.07 0.011,-0.026 0.016,-0.054 0.015,-0.082v-0.03c-0.06,-0.33 -0.226,-0.63 -0.474,-0.855 -0.248,-0.225 -0.563,-0.362 -0.897,-0.389V4.571c0,-0.122 -0.091,-0.213 -0.243,-0.243h-0.458c-0.122,0 -0.213,0.091 -0.243,0.243V5.269c-0.914,0.121 -1.493,0.728 -1.493,1.487 0,1.001 0.609,1.395 1.889,1.548 0.854,0.152 1.128,0.334 1.128,0.82 0,0.485 -0.426,0.819 -1.005,0.819 -0.793,0 -1.066,-0.333 -1.158,-0.789 -0.03,-0.121 -0.122,-0.182 -0.213,-0.182h-0.518c-0.028,-0.001 -0.056,0.004 -0.082,0.015 -0.026,0.01 -0.05,0.026 -0.07,0.046 -0.02,0.02 -0.036,0.044 -0.046,0.07 -0.01,0.026 -0.016,0.054 -0.015,0.082v0.03c0.122,0.759 0.609,1.305 1.615,1.457v0.729c0,0.121 0.091,0.213 0.243,0.243h0.458c0.122,0 0.213,-0.091 0.243,-0.243V10.67c0.914,-0.152 1.523,-0.789 1.523,-1.609v0.001Z"
android:strokeWidth="0.5"
android:fillColor="#ffffff"/>
<path
android:pathData="M6.446,12.248c-2.377,-0.85 -3.596,-3.49 -2.712,-5.826 0.457,-1.275 1.462,-2.246 2.712,-2.701 0.122,-0.06 0.183,-0.152 0.183,-0.303v-0.425c0,-0.121 -0.06,-0.212 -0.183,-0.243 -0.031,0 -0.091,0 -0.122,0.03 -0.686,0.214 -1.322,0.562 -1.873,1.023 -0.551,0.461 -1.005,1.027 -1.336,1.664 -0.331,0.637 -0.533,1.334 -0.594,2.05 -0.061,0.716 0.02,1.437 0.239,2.121 0.548,1.7 1.859,3.005 3.565,3.551 0.122,0.06 0.244,0 0.274,-0.122 0.031,-0.03 0.031,-0.061 0.031,-0.122v-0.425c0,-0.091 -0.091,-0.212 -0.183,-0.273ZM9.676,2.78c-0.122,-0.061 -0.244,0 -0.274,0.121 -0.031,0.031 -0.031,0.061 -0.031,0.122v0.425c0,0.122 0.091,0.243 0.183,0.303 2.377,0.85 3.596,3.49 2.712,5.826 -0.457,1.275 -1.462,2.246 -2.712,2.701 -0.122,0.06 -0.183,0.152 -0.183,0.303v0.425c0,0.121 0.06,0.212 0.183,0.243 0.031,0 0.091,0 0.122,-0.03 0.686,-0.214 1.322,-0.562 1.873,-1.023 0.551,-0.461 1.005,-1.027 1.336,-1.664 0.331,-0.637 0.533,-1.334 0.594,-2.05 0.061,-0.716 -0.02,-1.437 -0.239,-2.121 -0.548,-1.73 -1.889,-3.035 -3.565,-3.581Z"
android:strokeWidth="0.5"
android:fillColor="#ffffff"/>
</vector>