parent
bd03321cc0
commit
b5d5cd4aeb
@ -0,0 +1,268 @@ |
||||
// |
||||
// PaymentLinkManagerView.swift |
||||
// PadelClub |
||||
// |
||||
// Created by Razmig Sarkissian on 16/10/2025. |
||||
// |
||||
|
||||
|
||||
// |
||||
// PaymentLinkManagerView.swift |
||||
// PadelClub |
||||
// |
||||
// Created by Razmig Sarkissian on 01/10/2025. |
||||
// |
||||
|
||||
import SwiftUI |
||||
import PadelClubData |
||||
|
||||
struct PaymentLinkManagerView: View { |
||||
let teamRegistration: TeamRegistration |
||||
@State private var isLoading = false |
||||
@State private var showAlert = false |
||||
@State private var alertMessage = "" |
||||
@State private var paymentLink: String? |
||||
@State private var showCopiedConfirmation = false |
||||
|
||||
var body: some View { |
||||
VStack(spacing: 20) { |
||||
// Header |
||||
header |
||||
|
||||
// Get Payment Link Button |
||||
getPaymentLinkButton |
||||
|
||||
// Payment Link Display and Actions |
||||
if let link = paymentLink { |
||||
paymentLinkSection(link: link) |
||||
} |
||||
|
||||
Spacer() |
||||
} |
||||
.padding() |
||||
.alert("Erreur", isPresented: $showAlert) { |
||||
Button("OK") { } |
||||
} message: { |
||||
Text(alertMessage) |
||||
} |
||||
} |
||||
|
||||
// MARK: - ViewBuilder Components |
||||
|
||||
@ViewBuilder |
||||
private var header: some View { |
||||
VStack(spacing: 8) { |
||||
Image(systemName: "creditcard.circle.fill") |
||||
.font(.system(size: 50)) |
||||
.foregroundColor(.blue) |
||||
|
||||
Text("Lien de paiement") |
||||
.font(.title2) |
||||
.fontWeight(.bold) |
||||
|
||||
Text("Obtenez un lien de paiement à partager avec l'équipe") |
||||
.font(.subheadline) |
||||
.foregroundColor(.secondary) |
||||
.multilineTextAlignment(.center) |
||||
} |
||||
} |
||||
|
||||
@ViewBuilder |
||||
private var getPaymentLinkButton: some View { |
||||
Button { |
||||
getPaymentLink() |
||||
} label: { |
||||
HStack { |
||||
if isLoading { |
||||
ProgressView() |
||||
.progressViewStyle(CircularProgressViewStyle()) |
||||
.tint(.white) |
||||
} else { |
||||
Image(systemName: "link.circle") |
||||
} |
||||
Text(paymentLink == nil ? "Obtenir le lien de paiement" : "Régénérer le lien") |
||||
} |
||||
.frame(maxWidth: .infinity) |
||||
.padding() |
||||
.background(Color.blue) |
||||
.foregroundColor(.white) |
||||
.cornerRadius(12) |
||||
} |
||||
.disabled(isLoading) |
||||
} |
||||
|
||||
@ViewBuilder |
||||
private func paymentLinkSection(link: String) -> some View { |
||||
VStack(spacing: 16) { |
||||
// Success message |
||||
HStack { |
||||
Image(systemName: "checkmark.circle.fill") |
||||
.foregroundColor(.green) |
||||
Text("Lien copié dans le presse-papiers!") |
||||
.font(.subheadline) |
||||
.foregroundColor(.green) |
||||
} |
||||
.padding(.vertical, 8) |
||||
.padding(.horizontal, 12) |
||||
.background(Color.green.opacity(0.1)) |
||||
.cornerRadius(8) |
||||
|
||||
// Link display |
||||
linkDisplayView(link: link) |
||||
|
||||
// Action buttons |
||||
actionButtons(link: link) |
||||
} |
||||
.transition(.move(edge: .top).combined(with: .opacity)) |
||||
.animation(.spring(response: 0.6, dampingFraction: 0.8), value: paymentLink) |
||||
} |
||||
|
||||
@ViewBuilder |
||||
private func linkDisplayView(link: String) -> some View { |
||||
VStack(alignment: .leading, spacing: 8) { |
||||
Text("Lien de paiement:") |
||||
.font(.caption) |
||||
.fontWeight(.semibold) |
||||
.foregroundColor(.secondary) |
||||
|
||||
ScrollView(.horizontal, showsIndicators: false) { |
||||
Text(link) |
||||
.font(.system(.caption, design: .monospaced)) |
||||
.padding(12) |
||||
.background(Color.gray.opacity(0.1)) |
||||
.cornerRadius(8) |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ViewBuilder |
||||
private func actionButtons(link: String) -> some View { |
||||
VStack(spacing: 12) { |
||||
// Copy button |
||||
copyButton(link: link) |
||||
|
||||
// Share button |
||||
shareButton(link: link) |
||||
|
||||
// Open in browser button |
||||
openInBrowserButton(link: link) |
||||
} |
||||
} |
||||
|
||||
@ViewBuilder |
||||
private func copyButton(link: String) -> some View { |
||||
Button { |
||||
UIPasteboard.general.string = link |
||||
showCopiedConfirmation = true |
||||
|
||||
// Haptic feedback |
||||
let generator = UINotificationFeedbackGenerator() |
||||
generator.notificationOccurred(.success) |
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { |
||||
showCopiedConfirmation = false |
||||
} |
||||
} label: { |
||||
HStack { |
||||
Image(systemName: showCopiedConfirmation ? "checkmark.circle.fill" : "doc.on.doc.fill") |
||||
Text(showCopiedConfirmation ? "Copié !" : "Copier le lien") |
||||
.fontWeight(.semibold) |
||||
} |
||||
.frame(maxWidth: .infinity) |
||||
.padding() |
||||
.background(showCopiedConfirmation ? Color.green : Color.blue.opacity(0.1)) |
||||
.foregroundColor(showCopiedConfirmation ? .white : .blue) |
||||
.cornerRadius(10) |
||||
.overlay( |
||||
RoundedRectangle(cornerRadius: 10) |
||||
.stroke(showCopiedConfirmation ? Color.green : Color.blue, lineWidth: 1) |
||||
) |
||||
} |
||||
.disabled(showCopiedConfirmation) |
||||
.animation(.easeInOut(duration: 0.2), value: showCopiedConfirmation) |
||||
} |
||||
|
||||
@ViewBuilder |
||||
private func shareButton(link: String) -> some View { |
||||
ShareLink(item: link) { |
||||
HStack { |
||||
Image(systemName: "square.and.arrow.up.fill") |
||||
Text("Partager le lien") |
||||
.fontWeight(.semibold) |
||||
} |
||||
.frame(maxWidth: .infinity) |
||||
.padding() |
||||
.background(Color.blue.opacity(0.1)) |
||||
.foregroundColor(.blue) |
||||
.cornerRadius(10) |
||||
.overlay( |
||||
RoundedRectangle(cornerRadius: 10) |
||||
.stroke(Color.blue, lineWidth: 1) |
||||
) |
||||
} |
||||
} |
||||
|
||||
@ViewBuilder |
||||
private func openInBrowserButton(link: String) -> some View { |
||||
Button { |
||||
if let url = URL(string: link) { |
||||
UIApplication.shared.open(url) |
||||
} |
||||
} label: { |
||||
HStack { |
||||
Image(systemName: "safari.fill") |
||||
Text("Ouvrir dans Safari") |
||||
.fontWeight(.semibold) |
||||
} |
||||
.frame(maxWidth: .infinity) |
||||
.padding() |
||||
.background(Color.blue.opacity(0.1)) |
||||
.foregroundColor(.blue) |
||||
.cornerRadius(10) |
||||
.overlay( |
||||
RoundedRectangle(cornerRadius: 10) |
||||
.stroke(Color.blue, lineWidth: 1) |
||||
) |
||||
} |
||||
} |
||||
|
||||
// MARK: - Private Methods |
||||
|
||||
private func getPaymentLink() { |
||||
isLoading = true |
||||
showCopiedConfirmation = false |
||||
|
||||
Task { |
||||
do { |
||||
let response = try await PaymentService.getPaymentLink( |
||||
teamRegistrationId: teamRegistration.id |
||||
) |
||||
await MainActor.run { |
||||
isLoading = false |
||||
if response.success, let link = response.paymentLink { |
||||
paymentLink = link |
||||
// Automatically copy to clipboard |
||||
UIPasteboard.general.string = link |
||||
|
||||
// Haptic feedback |
||||
let generator = UINotificationFeedbackGenerator() |
||||
generator.notificationOccurred(.success) |
||||
} else { |
||||
alertMessage = response.message ?? "Impossible d'obtenir le lien de paiement" |
||||
showAlert = true |
||||
} |
||||
} |
||||
} catch { |
||||
await MainActor.run { |
||||
isLoading = false |
||||
alertMessage = "Erreur lors de la récupération du lien" |
||||
showAlert = true |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
#Preview { |
||||
PaymentLinkManagerView(teamRegistration: TeamRegistration()) |
||||
} |
||||
Loading…
Reference in new issue