Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PWN-9259] Home screen outgoing transfer #1497

Merged
merged 3 commits into from
Jul 26, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ public class StrigaBankTransferUserActionConsumer: UserActionConsumer {
case let .complete(action, result):
Task { [weak self] in
guard let self = self else { return }
var userAction = Action(
let userAction = Action(
id: action.id,
accountId: action.accountId,
token: action.token,
Expand Down Expand Up @@ -175,3 +175,42 @@ public class BankTransferClaimUserAction: UserAction {
lhs.id == rhs.id
}
}


public class OutgoingBankTransferUserAction: UserAction {
public static func == (lhs: OutgoingBankTransferUserAction, rhs: OutgoingBankTransferUserAction) -> Bool {
lhs.id == rhs.id
}

/// Unique internal id to track.
public var id: String
lisemyon marked this conversation as resolved.
Show resolved Hide resolved
public var accountId: String
public let token: EthereumToken?
public let amount: String?
public let receivingAddress: String
/// Abstract status.
public var status: UserActionStatus
public var createdDate: Date
public var updatedDate: Date
public var result: BankTransferClaimUserActionResult?

public init(
id: String,
accountId: String,
token: EthereumToken?,
amount: String?,
receivingAddress: String,
status: UserActionStatus,
createdDate: Date = Date(),
updatedDate: Date = Date()
) {
self.id = id
self.accountId = accountId
self.token = token
self.amount = amount
self.receivingAddress = receivingAddress
self.status = status
self.createdDate = createdDate
self.updatedDate = updatedDate
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
{
"images" : [
{
"filename" : "Upload.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Upload@2x.png",
"filename" : "Icon@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Upload@3x.png",
"filename" : "Icon@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
Binary file not shown.
1 change: 1 addition & 0 deletions p2p_wallet/Resources/Base.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -1475,3 +1475,4 @@
"Receiver" = "Receiver";
"Your bank account name must match the name registered to your Key App account" = "Your bank account name must match the name registered to your Key App account";
"Your IBAN" = "Your IBAN";
"Outgoing transfer" = "Outgoing transfer";
1 change: 1 addition & 0 deletions p2p_wallet/Resources/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -1474,3 +1474,4 @@
"Receiver" = "Receiver";
"Your bank account name must match the name registered to your Key App account" = "Your bank account name must match the name registered to your Key App account";
"Your IBAN" = "Your IBAN";
"Outgoing transfer" = "Outgoing transfer";
1 change: 1 addition & 0 deletions p2p_wallet/Resources/fr.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -1510,3 +1510,4 @@
"Receiver" = "Destinataire";
"Your bank account name must match the name registered to your Key App account" = "Le nom de votre compte bancaire doit correspondre au nom enregistré sur votre compte Key App";
"Your IBAN" = "Votre IBAN";
"Outgoing transfer" = "Transfert sortant";
1 change: 1 addition & 0 deletions p2p_wallet/Resources/ru.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -1506,3 +1506,4 @@
"Receiver" = "Получатель";
"Your bank account name must match the name registered to your Key App account" = "Имя вашего банковского счета должно совпадать с именем, зарегистрированным в вашей учетной записи Key App.";
"Your IBAN" = "Ваш IBAN";
"Outgoing transfer" = "Исходящий перевод";
1 change: 1 addition & 0 deletions p2p_wallet/Resources/vi.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -1512,3 +1512,4 @@
"Receiver" = "Người nhận";
"Your bank account name must match the name registered to your Key App account" = "Tên tài khoản ngân hàng của bạn phải khớp với tên đã đăng ký với tài khoản Key App của bạn";
"Your IBAN" = "IBAN của bạn";
"Outgoing transfer" = "chuyển đi";
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ final class WithdrawCoordinator: Coordinator<WithdrawCoordinator.Result> {
.map { WithdrawCoordinator.Result.canceled },
viewModel.actionCompletedPublisher
.map { WithdrawCoordinator.Result.verified }
.handleEvents(receiveOutput: { _ in
self.navigationController.popToRootViewController(animated: true)
.handleEvents(receiveOutput: { [weak self] _ in
self?.navigationController.popToRootViewController(animated: true)
})
)
.prefix(1).eraseToAnyPublisher()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class WithdrawViewModel: BaseViewModel, ObservableObject {
@Published var IBAN: String = ""
@Published var BIC: String = ""
@Published var receiver: String = ""
@Published var actionTitle: String = "Withdraw"
@Published var actionTitle: String = L10n.withdraw
@Published var isDataValid = false
@Published var fieldsStatuses = [WithdrawViewField: FieldStatus]()
@Published var isLoading = false
Expand Down Expand Up @@ -50,7 +50,7 @@ class WithdrawViewModel: BaseViewModel, ObservableObject {
isDataValid = fields.values.filter({ status in
status == .valid
}).count == fields.keys.count
actionTitle = isDataValid ? L10n.withdrawal : L10n.checkYourData
actionTitle = isDataValid ? L10n.withdraw : L10n.checkYourData
})
.assignWeak(to: \.fieldsStatuses, on: self)
.store(in: &subscriptions)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ struct HomeAccountsAggregator: DataAggregator {
input: (
solanaAccounts: [RenderableSolanaAccount],
ethereumAccounts: [RenderableEthereumAccount],
bankTransferAccounts: [BankTransferRenderableAccount]
bankTransferAccounts: [any RenderableAccount]
)
)
-> (primary: [any RenderableAccount], secondary: [any RenderableAccount]) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ struct HomeEthereumAccountsAggregator: DataAggregator {
// Compare using fiat.
if balanceInFiat >= CurrencyAmount(usd: 5) {
// Balance is greater than $1, user can claim.
status = .readyToClaim
status = .ready
} else {
// Balance is to low.
status = .balanceToLow
Expand All @@ -40,7 +40,7 @@ struct HomeEthereumAccountsAggregator: DataAggregator {
// Compare using crypto amount.
if account.balance > 0 {
// Balance is not zero
status = .readyToClaim
status = .ready
} else {
// Balance is to low.
status = .balanceToLow
Expand All @@ -49,7 +49,7 @@ struct HomeEthereumAccountsAggregator: DataAggregator {

} else {
// Claiming is running.
status = .isClaimming
status = .isProcessing
}

return RenderableEthereumAccount(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,11 @@ struct HomeAccountsView: View {
.padding(.top, 32)
wrappedList(itemsCount: viewModel.accounts.count) {
ForEach(viewModel.accounts, id: \.id) {
tokenCell(rendableAccount: $0, isVisiable: true)
if $0 is OutgoingBankTransferRenderableAccount {
bankTransferCell(rendableAccount: $0, isVisiable: true)
} else {
tokenCell(rendableAccount: $0, isVisiable: true)
}
}
}
if !viewModel.hiddenAccounts.isEmpty {
Expand Down Expand Up @@ -138,6 +142,19 @@ struct HomeAccountsView: View {
.padding(.horizontal, 16)
}

private func bankTransferCell(
rendableAccount: any RenderableAccount,
isVisiable: Bool
) -> some View {
HomeBankTransferAccountView(
renderable: rendableAccount,
onTap: nil,
onButtonTap: nil
)
.frame(height: 72)
.padding(.horizontal, 16)
}

@ViewBuilder
private func wrappedList<Content: View>(
itemsCount: Int,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,39 +107,15 @@ final class HomeAccountsViewModel: BaseViewModel, ObservableObject {
// bankTransferPublisher
let bankTransferServicePublisher = Publishers.CombineLatest(
bankTransferService.value.state
.compactMap { $0.value.wallet?.accounts.usdc },
userActionService.$actions.map { userActions in
userActions.compactMap { $0 as? BankTransferClaimUserAction }
}
.compactMap { $0.value.wallet?.accounts },
userActionService.$actions

)
.compactMap { (account, actions) -> [BankTransferRenderableAccount]? in
guard
account.availableBalance > 0,
let address = try? EthereumAddress(
hex: EthereumAddresses.ERC20.usdc.rawValue,
eip55: false
) else { return nil }

let token = EthereumToken(
name: SolanaToken.usdc.name,
symbol: SolanaToken.usdc.symbol,
decimals: 6,
logo: URL(string: SolanaToken.usdc.logoURI ?? ""),
contractType: .erc20(contract: address)
.compactMap { (account, actions) -> [any RenderableAccount] in
BankTransferRenderableAccountFactory.renderableAccount(
accounts: account,
actions: actions
)

let action = actions.first(where: { action in
action.id == account.accountID
})
return [
BankTransferRenderableAccount(
accountId: account.accountID,
token: token,
visibleAmount: account.availableBalance,
rawAmount: account.totalBalance,
status: action?.status == .processing ? .isClaimming : .readyToClaim
)
]
}

let homeAccountsAggregator = HomeAccountsAggregator()
Expand All @@ -150,7 +126,8 @@ final class HomeAccountsViewModel: BaseViewModel, ObservableObject {
bankTransferServicePublisher.prepend([])
)
.map { solanaAccounts, ethereumAccounts, bankTransferAccounts in
homeAccountsAggregator.transform(input: (solanaAccounts, ethereumAccounts, bankTransferAccounts))
homeAccountsAggregator
.transform(input: (solanaAccounts, ethereumAccounts, bankTransferAccounts))
}
.receive(on: RunLoop.main)
.sink { primary, secondary in
Expand Down Expand Up @@ -236,7 +213,7 @@ final class HomeAccountsViewModel: BaseViewModel, ObservableObject {
let userActionService: UserActionService = Resolver.resolve()
let userWalletManager: UserWalletManager = Resolver.resolve()
guard
account.status != .isClaimming,
account.status != .isProcessing,
let walletPubKey = userWalletManager.wallet?.account.publicKey
else { return }
let userAction = BankTransferClaimUserAction(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import BankTransfer
import BigInt
import Foundation
import KeyAppBusiness
import KeyAppKitCore
import BigInt
import Web3
import Wormhole

struct BankTransferRenderableAccount: RenderableAccount {
let accountId: String
Expand Down Expand Up @@ -43,9 +46,9 @@ struct BankTransferRenderableAccount: RenderableAccount {

var detail: AccountDetail {
switch status {
case .readyToClaim:
case .ready:
return .button(label: L10n.claim, enabled: true)
case .isClaimming:
case .isProcessing:
return .button(label: L10n.claim, enabled: true)
case .balanceToLow:
return .text("")
Expand All @@ -71,7 +74,7 @@ struct BankTransferRenderableAccount: RenderableAccount {

var isLoading: Bool {
switch status {
case .isClaimming:
case .isProcessing:
return true
default:
return false
Expand All @@ -84,3 +87,102 @@ private extension Int {
Double(self * 10_000)
}
}

struct OutgoingBankTransferRenderableAccount: RenderableAccount {
let accountId: String
let fiat: Fiat
let visibleAmount: Double
var status: RenderableEthereumAccount.Status

var id: String { accountId }

var icon: AccountIcon { .image(.iconUpload) }

var wrapped: Bool { false }

var title: String { L10n.outgoingTransfer }

var subtitle: String {
String(format: "%.2f", visibleAmount) + " \(fiat.code)"
}

var detail: AccountDetail {
switch status {
case .ready, .isProcessing:
return .button(label: L10n.confirm, enabled: true)
case .balanceToLow:
return .text("")
}
}

var extraAction: AccountExtraAction? { nil }

var tags: AccountTags {
var tags: AccountTags = []

if status == .balanceToLow {
if visibleAmount == 0 {
tags.insert(.hidden)
} else {
tags.insert(.ignore)
}
}
return tags
}

var isLoading: Bool {
switch status {
case .isProcessing:
return true
default:
return false
}
}
}

class BankTransferRenderableAccountFactory {
static func renderableAccount(accounts: UserAccounts, actions: [any UserAction]) -> [any RenderableAccount] {
var transactions = [any RenderableAccount]()
if
let usdc = accounts.usdc,
usdc.availableBalance > 0,
let address = try? EthereumAddress(
hex: EthereumAddresses.ERC20.usdc.rawValue,
eip55: false
) {
let token = EthereumToken(
name: SolanaToken.usdc.name,
symbol: SolanaToken.usdc.symbol,
decimals: 6,
logo: URL(string: SolanaToken.usdc.logoURI ?? ""),
contractType: .erc20(contract: address)
)
let action = actions
.compactMap { $0 as? BankTransferClaimUserAction }
.first(where: { action in
action.id == usdc.accountID
})
transactions.append(
BankTransferRenderableAccount(
accountId: usdc.accountID,
token: token,
visibleAmount: usdc.availableBalance,
rawAmount: usdc.totalBalance,
status: action?.status == .processing ? .isProcessing : .ready
)
)
}

if let eur = accounts.eur {
transactions.append(
OutgoingBankTransferRenderableAccount(
accountId: eur.accountID,
fiat: .eur,
visibleAmount: 1,
status: .ready
)
)
}
return transactions
}
}
Loading
Loading