PaidTransactionDetailV.swift (5336B)
1 /* 2 * This file is part of GNU Taler, ©2022-26 Taler Systems S.A. 3 * See LICENSE.md 4 */ 5 /** 6 * Overview when there's more than 1 currency/exchange 7 * 8 * @author Marc Stibane 9 */ 10 import SwiftUI 11 12 struct PaidTransactionDetailV: View { 13 let stack: CallStack 14 let paymentTx: PaymentTransaction 15 16 #if DEBUG 17 @AppStorage("developerMode") var developerMode: Bool = true 18 #else 19 @AppStorage("developerMode") var developerMode: Bool = false 20 #endif 21 22 var body: some View { 23 let common = paymentTx.common 24 let details = paymentTx.details 25 let terms = details.contractTerms 26 let info = details.info 27 Section { 28 if let posConfirmation = details.posConfirmation { 29 Text("Confirmation:", comment: "purchase may have a pos validation / confirmation") 30 .talerFont(.title3) 31 .listRowSeparator(.hidden) 32 let totp = Text(posConfirmation) 33 .talerFont(.title1) 34 let posConfirmationViaNfc = details.posConfirmationViaNfc 35 let isPaying = common.isDialog // We are ALWAYS already finished with the tx 36 if #available(iOS 17.7, *) { 37 BorderWithNFC(totpString: posConfirmation, nfcHint: true, 38 automaticNfc: isPaying ? posConfirmationViaNfc : false, 39 size: 250, scanHints: nil 40 ) { totp } 41 } else { 42 totp 43 } 44 } 45 if let info { 46 // Text(info.merchant.name) TODO: show name & logo here? 47 if common.isDone { 48 VStack(alignment: .leading) { 49 Text("Order-ID:") 50 .talerFont(.title3) 51 HStack { 52 Spacer() 53 Text(info.orderId) 54 .talerFont(.body) 55 } 56 } 57 } 58 } 59 VStack(alignment: .leading) { 60 if let info { 61 Text(info.summary) 62 .talerFont(.title3) 63 } 64 if let choiceIndex = details.choiceIndex { 65 if let contractTerms = details.contractTerms { 66 if let choices = contractTerms.choices, 67 choices.indices.contains(choiceIndex) { 68 let choice = choices[choiceIndex] 69 HStack { 70 if let info { 71 Spacer() 72 } 73 Text(choice.locDescription ?? "Index: \(choiceIndex)") // fallback should never happen 74 .talerFont(.body) 75 } 76 } 77 } 78 } 79 } 80 if let info { 81 if let fulfillmentUrl = info.fulfillmentUrl, common.isDone { 82 // per api-common.rst's WebURL definition, fulfillment_url must be http(s) - 83 // reject any other scheme (tel:, sms:, a third-party app's custom scheme, ...) 84 if let destination = URL(string: fulfillmentUrl), 85 let scheme = destination.scheme?.lowercased(), scheme == "http" || scheme == "https" { 86 let buttonTitle = info.fulfillmentMessage ?? String(localized: "Open merchant website") 87 Link(buttonTitle, destination: destination) 88 .buttonStyle(TalerButtonStyle(type: .prominent)) 89 .accessibilityHint(String(localized: "Will go to the merchant website.", comment: "a11y")) 90 } 91 } else if let fulfillmentMessage = info.fulfillmentMessage { 92 Text(fulfillmentMessage) 93 .talerFont(.body) 94 } 95 } 96 if let failReason = common.failReason { 97 if let hint = failReason.hint { 98 Text(hint) 99 .talerFont(.title3) 100 } 101 } 102 if let abortReason = details.abortReason { 103 if let exchangeResponse = abortReason.exchangeResponse, 104 let hint2 = exchangeResponse.hint { 105 Text(hint2) 106 .talerFont(.body) 107 } 108 if developerMode { 109 if let hint3 = abortReason.hint { 110 Text(hint3) 111 .talerFont(.body) 112 } 113 } 114 } 115 } 116 if let products = terms?.products { 117 if !products.isEmpty { 118 Section { 119 ForEach(products) { product in 120 // if let productId = product.productId { 121 if let productName = product.productName { 122 Text(productName) 123 .talerFont(.body) 124 } 125 } 126 } 127 } 128 } 129 } 130 } 131 132 // MARK: - 133 //#Preview { 134 // TransactionDetailV() 135 //}