import SwiftUI enum LeadDetailStyle { static let blue = LeadOverviewStyle.blue static let background = Color(uiColor: .systemGroupedBackground) static let card = Color(uiColor: .secondarySystemGroupedBackground) } extension LeadDetail { var initials: String { String(lead.displayName.split(separator: " ").prefix(2).compactMap(\.first)).uppercased() } var contactDescription: String? { let value = [contactName, contactRole].compactMap { $0 }.joined(separator: " · ") return value.isEmpty ? nil : value } var phoneURL: URL? { guard let phone = lead.phoneNumber else { return nil } let digits = phone.filter { $0.isNumber || $0 == "+" } return digits.isEmpty ? nil : URL(string: "tel:\(digits)") } var emailURL: URL? { guard let email, !email.isEmpty else { return nil } var url = URLComponents() url.scheme = "mailto" url.path = email return url.url } var routeURL: URL? { var url = URLComponents() url.scheme = "https" url.host = "maps.apple.com" url.queryItems = [URLQueryItem(name: "daddr", value: lead.fullAddress)] return url.url } } extension LeadOffer { var subtitle: String { let kindName: String switch kind { case .purchase: kindName = "Kauf" case .rental: kindName = "Miete" case .service: kindName = "Service" } let price = amount.formatted(.currency(code: "EUR").locale(Locale(identifier: "de_DE"))) let interval: String switch billing { case .once: interval = "netto" case .monthly: interval = "/ Monat" case .annually: interval = "/ Jahr" } let date = acceptedAt ?? validUntil let suffix = date.map { (acceptedAt == nil ? "gültig bis " : "angenommen am ") + $0.formatted(.dateTime.day().month().year().locale(Locale(identifier: "de_DE"))) } return [id, kindName, "\(price) \(interval)", suffix].compactMap { $0 }.joined(separator: " · ") } } struct LeadSectionHeading: View { let title: LocalizedStringKey var body: some View { Text(title).font(.caption).foregroundStyle(.secondary) .padding(.horizontal, 16) } } struct LeadSignatureProgress: View { let signed: Int let total: Int var body: some View { if total > 0 && signed == total { Label("Vollständig", systemImage: "checkmark.circle.fill") .foregroundStyle(.green).font(.subheadline) } else { Text("\(signed) von \(total)").foregroundStyle(.secondary).font(.subheadline) } } } struct LeadSignButton: View { let action: () -> Void var body: some View { Button(action: action) { Label("Unterschreiben", systemImage: "signature") .font(.subheadline.weight(.medium)) } .buttonStyle(.borderedProminent) .buttonBorderShape(.capsule) } } extension Error { var leadFileMessage: LocalizedStringResource { if let error = self as? LeadError { return error.message } switch self as? LeadFileError { case .notFound: return "Diese Datei ist nicht mehr verfügbar." case .invalidFile: return "Die heruntergeladene Datei ist ungültig und kann nicht geöffnet werden." case .storageUnavailable: return "Die Datei konnte nicht auf diesem Gerät gespeichert werden." case nil: return "Die Datei konnte nicht geladen werden. Bitte versuche es erneut." } } }