// // CanPaymentTempView.swift // SodaLive // // Created by klaus on 5/20/24. // import SwiftUI import Bootpay import BootpayUI struct CanPaymentTempView: View { @StateObject var viewModel = CanPaymentTempViewModel() let orderType: OrderType let contentId: Int let title: String let can: Int init(orderType: OrderType, contentId: Int, title: String, can: Int) { self.orderType = orderType self.contentId = contentId self.title = title self.can = can } var body: some View { ZStack { Color.black.ignoresSafeArea() if viewModel.isShowPaymentView { BootpayUI(payload: viewModel.payload, requestType: BootpayRequest.TYPE_PAYMENT) .onConfirm { DEBUG_LOG("onConfirm: \($0)") return true } .onCancel { DEBUG_LOG("onCancel: \($0)") } .onError { DEBUG_LOG("onError: \($0)") viewModel.isShowPaymentView = false viewModel.errorMessage = "결제 중 오류가 발생했습니다." viewModel.isShowPopup = true } .onDone { DEBUG_LOG("onDone: \($0)") viewModel.verifyPayment($0) { let can = UserDefaults.int(forKey: .can) UserDefaults.set(can + self.can, forKey: .can) AppState.shared.purchasedContentId = contentId AppState.shared.purchasedContentOrderType = orderType DispatchQueue.main.async { AppState.shared.back() } } } .onClose { DEBUG_LOG("onClose") viewModel.isShowPaymentView = false } } else { GeometryReader { proxy in VStack(spacing: 0) { DetailNavigationBar(title: "결제하기") ScrollView(.vertical, showsIndicators: false) { VStack(spacing: 0) { HStack(spacing: 0) { Text(self.title) .font(.custom(Font.bold.rawValue, size: 15.3)) .foregroundColor(Color(hex: "eeeeee")) .padding(.leading, 13.3) Spacer() Text("\(self.can * 110) 원") .font(.custom(Font.bold.rawValue, size: 15.3)) .foregroundColor(Color.grayee) } .padding(.horizontal, 13.3) .padding(.vertical, 23.3) .background(Color.gray22) .cornerRadius(16.7) .padding(.horizontal, 13.3) .frame(width: screenSize().width) .padding(.top, 13.3) Text("결제 수단 선택") .font(.custom(Font.bold.rawValue, size: 16.7)) .foregroundColor(Color.grayee) .frame(width: screenSize().width - 26.7, alignment: .leading) .padding(.top, 26.7) HStack(spacing: 13.3) { Text("카드") .font(.custom( viewModel.paymentMethod == .card ? Font.bold.rawValue : Font.medium.rawValue, size: 16.7)) .foregroundColor(viewModel.paymentMethod == .card ? Color.button : Color.grayee) .frame(width: (screenSize().width - 40) / 2) .padding(.vertical, 16.7) .background( viewModel.paymentMethod == .card ? Color.button.opacity(0.3) : Color.gray23 ) .cornerRadius(10) .overlay( RoundedRectangle(cornerRadius: 10) .stroke(lineWidth: 1) .foregroundColor(viewModel.paymentMethod == .card ? Color.button : Color.gray77) ) .onTapGesture { if viewModel.paymentMethod != .card { viewModel.paymentMethod = .card } } Text("계좌이체") .font(.custom( viewModel.paymentMethod == .bank ? Font.bold.rawValue : Font.medium.rawValue, size: 16.7)) .foregroundColor(viewModel.paymentMethod == .bank ? Color.button : Color.grayee) .frame(width: (screenSize().width - 40) / 2) .padding(.vertical, 16.7) .background( viewModel.paymentMethod == .bank ? Color.button.opacity(0.3) : Color.gray23 ) .cornerRadius(10) .overlay( RoundedRectangle(cornerRadius: 10) .stroke(lineWidth: 1) .foregroundColor(viewModel.paymentMethod == .bank ? Color.button : Color.gray77) ) .onTapGesture { if viewModel.paymentMethod != .bank { viewModel.paymentMethod = .bank } } } .frame(width: screenSize().width - 26.7) .padding(.top, 16.7) HStack(spacing: 13.3) { Text("휴대폰 결제") .font(.custom( viewModel.paymentMethod == .phone ? Font.bold.rawValue : Font.medium.rawValue, size: 16.7)) .foregroundColor(viewModel.paymentMethod == .phone ? Color.button : Color.grayee) .frame(width: (screenSize().width - 40) / 2) .padding(.vertical, 16.7) .background( viewModel.paymentMethod == .phone ? Color.button.opacity(0.3) : Color.gray23 ) .cornerRadius(10) .overlay( RoundedRectangle(cornerRadius: 10) .stroke(lineWidth: 1) .foregroundColor(viewModel.paymentMethod == .phone ? Color.button : Color.gray77) ) .onTapGesture { if viewModel.paymentMethod != .phone { viewModel.paymentMethod = .phone } } Spacer() } .frame(width: screenSize().width - 26.7) .padding(.top, 16.7) HStack(spacing: 6.7) { Image(viewModel.isTermsAgree ? "btn_select_checked" : "btn_select_normal") .resizable() .frame(width: 20, height: 20) Text("구매조건 확인 및 결제 진행 동의") .font(.custom(Font.medium.rawValue, size: 14.7)) .foregroundColor(Color.grayee) } .frame(width: screenSize().width - 53.4, alignment: .leading) .padding(.top, 16.7) .onTapGesture { viewModel.isTermsAgree.toggle() } } } Spacer() HStack(spacing: 0) { VStack(alignment: .leading, spacing: 5) { Text("결제금액") .font(.custom(Font.medium.rawValue, size: 13.3)) .foregroundColor(Color.grayee) HStack(spacing: 0) { Text("\(self.can * 110) 원") .font(.custom(Font.bold.rawValue, size: 23.3)) .foregroundColor(Color.grayee) } } Spacer() Text("결제하기") .font(.custom(Font.bold.rawValue, size: 18.3)) .foregroundColor(.white) .padding(.vertical, 16) .frame(minWidth: 200) .background(Color.button) .cornerRadius(10) .onTapGesture { if viewModel.paymentMethod == nil { viewModel.errorMessage = "결제수단을 선택해 주세요." viewModel.isShowPopup = true } else if !viewModel.isTermsAgree { viewModel.errorMessage = "결제진행에 동의하셔야 결제가 가능합니다." viewModel.isShowPopup = true } else { viewModel.chargeCan(can: can, paymentGateway: .PG){ viewModel.payload.orderName = self.title viewModel.payload.price = Double(self.can * 110) viewModel.payload.taxFree = 0 viewModel.isShowPaymentView = true } } } } .padding(.leading, 22) .padding(.trailing, 13.3) .padding(.vertical, 13.3) .background(Color.gray22) .cornerRadius(16.7, corners: [.topLeft, .topRight]) if proxy.safeAreaInsets.bottom > 0 { Rectangle() .foregroundColor(Color.gray22) .frame(width: proxy.size.width, height: 15.3) } } .popup(isPresented: $viewModel.isShowPopup, type: .toast, position: .top, autohideIn: 2) { GeometryReader { geo in HStack { Spacer() Text(viewModel.errorMessage) .padding(.vertical, 13.3) .padding(.horizontal, 6.7) .frame(width: geo.size.width - 66.7, alignment: .center) .font(.custom(Font.medium.rawValue, size: 12)) .background(Color.button) .foregroundColor(Color.white) .multilineTextAlignment(.leading) .fixedSize(horizontal: false, vertical: true) .cornerRadius(20) .padding(.top, 66.7) Spacer() } } } .edgesIgnoringSafeArea(.bottom) } } if viewModel.isLoading { LoadingView() } } } } #Preview { CanPaymentTempView(orderType: .KEEP, contentId: 0, title: "콘텐츠 제목", can: 1000) }