import SwiftUI struct WorkTask: Identifiable { let taskId: Int let businessId: Int let categoryId: Int let taskTypeId: Int // 1 = Service Request, 2 = Chat let title: String let details: String let createdOn: Date let statusId: Int let sourceType: String let sourceId: Int let categoryName: String let categoryColor: String let taskTypeName: String let taskTypeColor: String let orderTotal: Double // Location (may be included in list responses) let servicePointName: String let deliveryAddress: String var id: Int { taskId } /// Decode directly from a [String: Any] dictionary (matches Flutter's fromJson) init(json: [String: Any]) { taskId = Self.parseInt(json["TaskID"]) ?? 0 businessId = Self.parseInt(json["BusinessID"] ?? json["TaskBusinessID"]) ?? 0 categoryId = Self.parseInt(json["TaskCategoryID"]) ?? 0 taskTypeId = Self.parseInt(json["TaskTypeID"]) ?? 1 title = (json["Title"] as? String) ?? (json["TaskTitle"] as? String) ?? "" details = (json["Details"] as? String) ?? (json["TaskDetails"] as? String) ?? "" createdOn = Self.parseDate(json["CreatedOn"] ?? json["TaskCreatedOn"]) ?? Date() statusId = Self.parseInt(json["StatusID"] ?? json["TaskStatusID"]) ?? 0 sourceType = (json["SourceType"] as? String) ?? (json["TaskSourceType"] as? String) ?? "" sourceId = Self.parseInt(json["SourceID"] ?? json["TaskSourceID"]) ?? 0 // Server key varies: CategoryName, Name, TaskCategoryName — try all // NOTE: Do NOT fallback to TaskTypeName as it's a different field categoryName = Self.nonEmpty(json["CategoryName"]) ?? Self.nonEmpty(json["Name"]) ?? Self.nonEmpty(json["TaskCategoryName"]) ?? "Uncategorized" // Category color as fallback categoryColor = Self.nonEmpty(json["CategoryColor"]) ?? Self.nonEmpty(json["Color"]) ?? Self.nonEmpty(json["TaskCategoryColor"]) ?? "#888888" taskTypeName = (json["TaskTypeName"] as? String) ?? "" // TaskType color is the primary color source taskTypeColor = Self.nonEmpty(json["TaskTypeColor"]) ?? "" orderTotal = Self.parseDouble(json["OrderTotal"]) ?? 0 servicePointName = (json["ServicePointName"] as? String) ?? "" deliveryAddress = (json["DeliveryAddress"] as? String) ?? "" } var locationDisplay: String { if !deliveryAddress.isEmpty { return deliveryAddress } if !servicePointName.isEmpty { return servicePointName } return "" } /// Primary color from TaskType, falls back to category color var color: Color { let hexSource = !taskTypeColor.isEmpty ? taskTypeColor : categoryColor let hex = hexSource.replacingOccurrences(of: "#", with: "") guard hex.count == 6, let val = UInt64(hex, radix: 16) else { return Color(red: 0.53, green: 0.53, blue: 0.53) } return Color( red: Double((val >> 16) & 0xFF) / 255, green: Double((val >> 8) & 0xFF) / 255, blue: Double(val & 0xFF) / 255 ) } var statusName: String { switch statusId { case 0: return "Pending" case 1: return "Accepted" case 2: return "In Progress" case 3: return "Completed" default: return "Unknown" } } var timeAgo: String { let diff = Date().timeIntervalSince(createdOn) let minutes = Int(diff / 60) if minutes < 1 { return "just now" } if minutes < 60 { return "\(minutes)m ago" } let hours = minutes / 60 if hours < 24 { return "\(hours)h ago" } return "\(hours / 24)d ago" } /// Chat or Call Team Member tasks - both involve customer interaction var isChat: Bool { taskTypeId == 2 || taskTypeId == 6 || taskTypeName.lowercased().contains("chat") } var isCash: Bool { taskTypeName.lowercased().contains("cash") } // MARK: - Flexible parsing helpers /// Returns the string value if it's non-nil and non-empty, otherwise nil static func nonEmpty(_ value: Any?) -> String? { guard let s = value as? String, !s.trimmingCharacters(in: .whitespaces).isEmpty else { return nil } return s } static func parseDouble(_ value: Any?) -> Double? { guard let value = value else { return nil } if let d = value as? Double { return d } if let i = value as? Int { return Double(i) } if let s = value as? String, let d = Double(s) { return d } if let n = value as? NSNumber { return n.doubleValue } return nil } static func parseInt(_ value: Any?) -> Int? { guard let value = value else { return nil } if let v = value as? Int { return v } if let v = value as? Double { return Int(v) } if let v = value as? NSNumber { return v.intValue } if let v = value as? String, let i = Int(v) { return i } return nil } static func parseDate(_ value: Any?) -> Date? { guard let value = value else { return nil } if let d = value as? Date { return d } if let s = value as? String { return APIService.parseDate(s) } return nil } }