Skip to content

Commit

Permalink
[ABW-3743] Show fiat value of Transaction fees (#1292)
Browse files Browse the repository at this point in the history
  • Loading branch information
matiasbzurovski committed Aug 22, 2024
1 parent 379af48 commit e6e0af1
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import SwiftUI

extension TransactionReviewNetworkFee.State {
var displayedTotalFee: String {
"\(reviewedTransaction.transactionFee.totalFee.displayedTotalFee) XRD"
L10n.TransactionReview.xrdAmount(reviewedTransaction.transactionFee.totalFee.displayedTotalFee)
}
}

Expand All @@ -19,8 +19,8 @@ extension TransactionReviewNetworkFee {

public var body: some SwiftUI.View {
WithViewStore(store, observe: { $0 }, send: { .view($0) }) { viewStore in
VStack(alignment: .leading, spacing: .small2) {
HStack {
VStack(alignment: .leading, spacing: .zero) {
HStack(alignment: .top) {
Text(L10n.TransactionReview.NetworkFee.heading)
.sectionHeading
.textCase(.uppercase)
Expand All @@ -32,9 +32,19 @@ extension TransactionReviewNetworkFee {

Spacer(minLength: 0)

Text(viewStore.displayedTotalFee)
.textStyle(.body1HighImportance)
.foregroundColor(.app.gray1)
VStack(alignment: .trailing, spacing: .small3) {
Text(viewStore.displayedTotalFee)
.textStyle(.body1HighImportance)
.foregroundColor(.app.gray1)

loadable(viewStore.fiatValue) {
ProgressView()
} successContent: { value in
Text(value)
.textStyle(.body2HighImportance)
.foregroundColor(.app.gray2)
}
}
}

loadable(viewStore.reviewedTransaction.feePayingValidation) { validation in
Expand All @@ -56,6 +66,9 @@ extension TransactionReviewNetworkFee {
.foregroundColor(.app.blue2)
}
}
.task {
viewStore.send(.task)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import SwiftUI
public struct TransactionReviewNetworkFee: Sendable, FeatureReducer {
public struct State: Sendable, Hashable {
public var reviewedTransaction: ReviewedTransaction
public var fiatValue: Loadable<String> = .idle

public init(
reviewedTransaction: ReviewedTransaction
Expand All @@ -14,22 +15,90 @@ public struct TransactionReviewNetworkFee: Sendable, FeatureReducer {
}

public enum ViewAction: Sendable, Equatable {
case task
case infoTapped
case customizeTapped
}

public enum InternalAction: Sendable, Equatable {
case setTokenPrices(TaskResult<PriceResult>)
}

public enum DelegateAction: Sendable, Equatable {
case showCustomizeFees
}

public struct PriceResult: Sendable, Equatable {
let prices: TokenPricesClient.TokenPrices
let currency: FiatCurrency
}

@Dependency(\.appPreferencesClient) var appPreferencesClient
@Dependency(\.tokenPricesClient) var tokenPricesClient
@Dependency(\.errorQueue) var errorQueue

public init() {}

public func reduce(into state: inout State, viewAction: ViewAction) -> Effect<Action> {
switch viewAction {
case .task:
state.fiatValue = .loading
return .run { send in
let currency = await appPreferencesClient.getPreferences().display.fiatCurrencyPriceTarget
let result = await TaskResult {
let prices = try await tokenPricesClient.getTokenPrices(.init(tokens: [.mainnetXRD], currency: currency), false)
return PriceResult(prices: prices, currency: currency)
}
await send(.internal(.setTokenPrices(result)))
}
case .infoTapped:
.none
return .none
case .customizeTapped:
.send(.delegate(.showCustomizeFees))
return .send(.delegate(.showCustomizeFees))
}
}

public func reduce(into state: inout State, internalAction: InternalAction) -> Effect<Action> {
switch internalAction {
case let .setTokenPrices(.failure(error)):
loggerGlobal.error("TransactionReviewNetworkFee failed to fetch XRD price, error: \(error)")
state.fiatValue = .failure(error)
return .none

case let .setTokenPrices(.success(result)):
guard let price = result.prices[.mainnetXRD] else {
loggerGlobal.error("TransactionReviewNetworkFee didn't get XRD price on response")
state.fiatValue = .failure(MissingXrdPriceError())
return .none
}
state.fiatValue = .success(state.reviewedTransaction.transactionFee.totalFee.fiatValue(xrdPrice: price, currency: result.currency))
return .none
}
}

private struct MissingXrdPriceError: Error {}
}

private extension TransactionFee.TotalFee {
func fiatValue(xrdPrice: Decimal192, currency: FiatCurrency) -> String {
let formatter = Self.feePriceFormatter
formatter.currencyCode = currency.currencyCode

let maxPrice = max * xrdPrice
let maxValue = formatter.string(for: maxPrice.asDouble) ?? maxPrice.formatted()
guard max > min else {
return maxValue
}

let minPrice = min * xrdPrice
let minValue = formatter.string(for: minPrice.asDouble) ?? minPrice.formatted()
return "\(minValue) - \(maxValue)"
}

private static let feePriceFormatter: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.maximumSignificantDigits = 3
return formatter
}()
}

0 comments on commit e6e0af1

Please sign in to comment.