Add lead workflows, PDF signing, AR projects and photo gallery integration

This commit is contained in:
Dennis Nemec
2026-11-08 17:49:39 +01:00
parent a343bde741
commit 8d18873412
82 changed files with 6401 additions and 34 deletions

View File

@ -0,0 +1,68 @@
import Foundation
struct DefaultLeadRepository: LeadRepository {
let remoteService: any LeadRemoteService
func leads(for salesCode: String, query: LeadQuery) async throws -> [Lead] {
do {
let values = try await remoteService.fetchLeads(salesCode: salesCode, query: query)
let leads = try values.map { try $0.toDomain() }
guard Set(leads.map(\.id)).count == leads.count else {
throw LeadError.invalidResponse
}
return leads
} catch {
throw Self.map(error)
}
}
func lead(id: String, salesCode: String) async throws -> Lead {
do {
let value = try await remoteService.fetchLead(id: id, salesCode: salesCode)
guard value.id == id else { throw LeadError.invalidResponse }
return try value.toDomain()
} catch {
throw Self.map(error, leadID: id)
}
}
func setBookmark(_ bookmarked: Bool, leadID: String, salesCode: String) async throws -> Lead {
do {
let value = try await remoteService.setBookmark(bookmarked, id: leadID, salesCode: salesCode)
guard value.id == leadID, value.isBookmarked == bookmarked else {
throw LeadError.invalidResponse
}
return try value.toDomain()
} catch {
throw Self.map(error, leadID: leadID)
}
}
static func map(_ error: Error, leadID: String? = nil) -> Error {
if error is CancellationError { return CancellationError() }
if let error = error as? LeadError { return error }
if let error = error as? URLError {
switch error.code {
case .cancelled: return CancellationError()
case .notConnectedToInternet, .networkConnectionLost: return LeadError.offline
case .timedOut: return LeadError.timeout
case .cannotFindHost, .cannotConnectToHost, .dnsLookupFailed:
return LeadError.serviceUnavailable
default: return LeadError.unexpected
}
}
if let error = error as? LeadRemoteError {
switch error {
case .http(401): return LeadError.unauthorized
case .http(403): return LeadError.forbidden
case .http(404):
return leadID.map { LeadError.notFound(leadID: $0) } ?? .serviceUnavailable
case .http(let status) where status >= 500: return LeadError.serviceUnavailable
case .malformedResponse: return LeadError.invalidResponse
default: return LeadError.unexpected
}
}
if error is DecodingError { return LeadError.invalidResponse }
return LeadError.unexpected
}
}