Files
Gas-Tank-AR-App/GasTankAR/Views/Leads/Detail/LeadDetailViewModel.swift

107 lines
3.9 KiB
Swift

import Foundation
import Observation
@MainActor
@Observable
final class LeadDetailViewModel {
private(set) var detail: LeadDetail?
private(set) var error: LeadError?
var expandedOffers: Set<String> = []
var expandedGroups: Set<String> = []
var selectedDocument: LeadDocument?
var signingRequest: LeadSigningRequest?
private(set) var signedDocumentURLs: [String: URL] = [:]
private let leadID: String
private let salesCode: String
private let getDetail: GetLeadDetailUseCase
private var generation = 0
init(leadID: String, salesCode: String, repository: any LeadDetailRepository) {
self.leadID = leadID
self.salesCode = salesCode
self.getDetail = GetLeadDetailUseCase(repository: repository)
}
var lead: Lead? { detail?.lead }
var isAllExpanded: Bool {
guard let detail, !detail.offers.isEmpty else { return false }
return Set(detail.offers.map(\.id)).isSubset(of: expandedOffers)
&& Set(detail.offers.flatMap(\.groups).map(\.id)).isSubset(of: expandedGroups)
}
func load() async {
generation += 1
let request = generation
detail = nil
error = nil
do {
let result = try await getDetail.execute(id: leadID, salesCode: salesCode)
try Task.checkCancellation()
guard request == generation else { return }
detail = result
let documents = result.offers.flatMap(\.documents)
signedDocumentURLs = LeadSignedDocumentStore().savedURLs(
documents: documents, leadID: leadID, salesCode: salesCode
)
for document in documents {
if let url = signedDocumentURLs[document.id] { didSign(document, url: url) }
}
if let first = result.offers.first {
expandedOffers = [first.id]
expandedGroups = Set(first.groups.filter { !$0.isComplete }.map(\.id))
} else {
expandedOffers = []
expandedGroups = []
}
} catch is CancellationError {
} catch {
guard request == generation, !Task.isCancelled else { return }
self.error = error as? LeadError ?? .unexpected
}
}
func startSigning(offer: LeadOffer, group: LeadDocumentGroup? = nil) {
let documents = group?.documents ?? offer.documents
guard documents.contains(where: { $0.status == .pending }) else { return }
signingRequest = LeadSigningRequest(
offerID: offer.id,
signerName: detail?.contactName ?? detail?.lead.displayName ?? "Kunde",
documents: documents
)
}
func didSign(_ document: LeadDocument, url: URL) {
signedDocumentURLs[document.id] = url
guard var detail else { return }
for offerIndex in detail.offers.indices {
for groupIndex in detail.offers[offerIndex].groups.indices {
for documentIndex in detail.offers[offerIndex].groups[groupIndex].documents.indices {
if detail.offers[offerIndex].groups[groupIndex].documents[documentIndex].id == document.id {
detail.offers[offerIndex].groups[groupIndex].documents[documentIndex].status = .signed
}
}
}
}
self.detail = detail
}
func toggleOffer(_ id: String) {
if !expandedOffers.insert(id).inserted { expandedOffers.remove(id) }
}
func toggleGroup(_ id: String) {
if !expandedGroups.insert(id).inserted { expandedGroups.remove(id) }
}
func toggleAll() {
guard let detail else { return }
if isAllExpanded {
expandedOffers = []
expandedGroups = []
} else {
expandedOffers = Set(detail.offers.map(\.id))
expandedGroups = Set(detail.offers.flatMap(\.groups).map(\.id))
}
}
}