payfrit-works-ios/PayfritWorks/Models/TaskDetails.swift
John Pinkyfloyd c71b9f7dea Add ios-marketing idiom for App Store icon display
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-10 19:37:59 -08:00

159 lines
6.5 KiB
Swift

import SwiftUI
struct TaskDetails {
let taskId: Int
let businessId: Int
let categoryId: Int
let title: String
let createdOn: Date
let statusId: Int
let categoryName: String
let categoryColor: String
let taskTypeName: String
let orderTotal: Double
// Order info
let orderId: Int
let orderRemarks: String
let orderSubmittedOn: Date?
// Location info
let servicePointId: Int
let servicePointName: String
let servicePointTypeId: Int
let deliveryAddress: String
let deliveryLat: Double
let deliveryLng: Double
// Customer info
let customerUserId: Int
let customerFirstName: String
let customerLastName: String
let customerPhone: String
let customerPhotoUrl: String
// Beacon info
let beaconUUID: String
// Line items & table members
let lineItems: [OrderLineItem]
let tableMembers: [TableMember]
/// Decode directly from a [String: Any] dictionary (matches Flutter's fromJson)
init(json: [String: Any]) {
taskId = WorkTask.parseInt(json["TaskID"]) ?? 0
businessId = WorkTask.parseInt(json["BusinessID"] ?? json["TaskBusinessID"]) ?? 0
categoryId = WorkTask.parseInt(json["TaskCategoryID"] ?? json["CategoryID"]) ?? 0
title = (json["Title"] as? String) ?? (json["TaskTitle"] as? String) ?? ""
createdOn = WorkTask.parseDate(json["CreatedOn"] ?? json["TaskCreatedOn"]) ?? Date()
statusId = WorkTask.parseInt(json["StatusID"] ?? json["TaskStatusID"]) ?? 0
categoryName = WorkTask.nonEmpty(json["CategoryName"]) ?? WorkTask.nonEmpty(json["Name"]) ?? WorkTask.nonEmpty(json["TaskCategoryName"]) ?? "General"
categoryColor = WorkTask.nonEmpty(json["CategoryColor"]) ?? WorkTask.nonEmpty(json["Color"]) ?? WorkTask.nonEmpty(json["TaskCategoryColor"]) ?? "#888888"
taskTypeName = (json["TaskTypeName"] as? String) ?? ""
orderTotal = Self.parseDouble(json["OrderTotal"]) ?? 0
orderId = WorkTask.parseInt(json["OrderID"]) ?? 0
orderRemarks = (json["OrderRemarks"] as? String) ?? (json["Remarks"] as? String) ?? ""
if let s = (json["OrderSubmittedOn"] ?? json["SubmittedOn"]) as? String, !s.isEmpty {
orderSubmittedOn = APIService.parseDate(s)
} else {
orderSubmittedOn = nil
}
servicePointId = WorkTask.parseInt(json["ServicePointID"]) ?? 0
servicePointName = (json["ServicePointName"] as? String) ?? ""
servicePointTypeId = WorkTask.parseInt(json["ServicePointTypeID"]) ?? 0
deliveryAddress = (json["DeliveryAddress"] as? String) ?? ""
deliveryLat = Self.parseDouble(json["DeliveryLat"]) ?? 0
deliveryLng = Self.parseDouble(json["DeliveryLng"]) ?? 0
customerUserId = WorkTask.parseInt(json["CustomerUserID"] ?? json["CustomerID"]) ?? 0
customerFirstName = (json["CustomerFirstName"] as? String) ?? (json["FirstName"] as? String) ?? ""
customerLastName = (json["CustomerLastName"] as? String) ?? (json["LastName"] as? String) ?? ""
customerPhone = (json["CustomerPhone"] as? String) ?? (json["Phone"] as? String) ?? ""
// Check multiple key variations for customer photo URL
let photoKeys = ["CustomerPhotoUrl", "CustomerPhotoURL", "CUSTOMERPHOTOURL",
"PhotoUrl", "PhotoURL", "PHOTOURL", "Photo_Url", "PHOTO_URL",
"AvatarUrl", "AvatarURL", "AVATARURL", "Avatar_Url", "AVATAR_URL",
"CustomerAvatar", "CUSTOMERAVATAR", "UserPhotoUrl", "USERPHOTOURL"]
var rawPhoto = ""
for key in photoKeys {
if let url = json[key] as? String, !url.isEmpty {
rawPhoto = url
break
}
}
// If no photo URL but we have customerUserId, construct direct avatar URL
if rawPhoto.isEmpty && customerUserId > 0 {
rawPhoto = "/uploads/avatars/\(customerUserId).jpg"
}
customerPhotoUrl = APIService.resolvePhotoUrl(rawPhoto)
beaconUUID = (json["BeaconUUID"] as? String) ?? ""
// Try multiple key variants for arrays
if let arr = (json["LineItems"] ?? json["LINE_ITEMS"] ?? json["Items"]) as? [[String: Any]] {
lineItems = arr.map { OrderLineItem(json: $0) }
} else {
lineItems = []
}
if let arr = (json["TableMembers"] ?? json["TABLE_MEMBERS"] ?? json["Members"]) as? [[String: Any]] {
tableMembers = arr.map { TableMember(json: $0) }
} else {
tableMembers = []
}
}
private 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
}
var color: Color {
let hex = categoryColor.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 customerFullName: String {
let parts = [customerFirstName, customerLastName].filter { !$0.isEmpty }
return parts.isEmpty ? "Guest" : parts.joined(separator: " ")
}
var locationDisplay: String {
if !deliveryAddress.isEmpty { return deliveryAddress }
if !servicePointName.isEmpty { return servicePointName }
return "No location specified"
}
var isCash: Bool { taskTypeName.lowercased().contains("cash") }
var isDelivery: Bool { !deliveryAddress.isEmpty }
var isTableService: Bool { servicePointId > 0 && !servicePointName.isEmpty }
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"
}
var mainItems: [OrderLineItem] {
lineItems.filter { !$0.isModifier && $0.parentLineItemId == 0 }
}
func modifiers(for parentLineItemId: Int) -> [OrderLineItem] {
lineItems.filter { $0.parentLineItemId == parentLineItemId }
}
}