import SwiftUI import Combine // MARK: – Data Models enum SentimentType: String, CaseIterable { case excited, interested, neutral, confused, disinterested var score: Int { switch self { case .excited: return 100 case .interested: return 80 case .neutral: return 50 case .confused: return 30 case .disinterested: return 10 } } var emoji: String { switch self { case .excited: return "😃" case .interested: return "🤔" case .neutral: return "😐" case .confused: return "😕" case .disinterested: return "😴" } } var color: Color { switch self { case .excited: return VelocityTheme.success case .interested: return VelocityTheme.accent case .neutral: return VelocityTheme.mutedFg case .confused: return VelocityTheme.warning case .disinterested: return VelocityTheme.danger } } } struct Visitor: Identifiable { let id: String let faceId: String var sentiment: SentimentType var confidence: Double var dwellTime: Int // seconds var zone: String let timestamp: Date } enum LeadSource: String { case whatsapp = "WhatsApp" case walkin = "Walk-in" case website = "Website" } enum LeadStatus: String { case hot = "Hot" case engaged = "Engaged" case new = "New" case qualified = "Qualified" case closed = "Closed" var color: Color { switch self { case .hot: return VelocityTheme.danger case .engaged: return VelocityTheme.accent case .new: return VelocityTheme.mutedFg case .qualified: return VelocityTheme.success case .closed: return Color(red: 0.60, green: 0.57, blue: 0.99) } } } struct Lead: Identifiable { let id: String let name: String let phone: String let source: LeadSource var status: LeadStatus var lastMessage: String var lastActive: Date var unreadCount: Int let qualification: String let budget: String let interest: String var initials: String { String(name.split(separator: " ").prefix(2).compactMap(\.first)) } } struct ChatMessage: Identifiable { let id: String let sender: String // "user" | "oracle" | "ai" let content: String let timestamp: Date } struct SystemHealth { var cpu: Double // 0–1 var gpu: Double var memory: Double } struct DashboardMetrics { var activeVisitors: Int var revenue: String var aiJobs: Int var dailyVisitors: Int var sentimentScore: Double // 0–100 var systemHealth: SystemHealth } // MARK: – Shared Store @Observable final class AppStore { static let shared = AppStore() private init() { startTimer() } // ── Dashboard ───────────────────────────────────────────────── var metrics = DashboardMetrics( activeVisitors: 17, revenue: "$3.2M", aiJobs: 24, dailyVisitors: 128, sentimentScore: 78, systemHealth: SystemHealth(cpu: 0.42, gpu: 0.61, memory: 0.55) ) var dashboardMessages: [ChatMessage] = [ ChatMessage(id: "d0", sender: "ai", content: "Hello, Ahmed. I've analysed the Q3 pipeline. Would you like a refined strategy for the Apex Innovations deal?", timestamp: Date().addingTimeInterval(-300)) ] var isDashboardThinking = false // ── Visitors ────────────────────────────────────────────────── var visitors: [Visitor] = [ Visitor(id: "v1", faceId: "face_001", sentiment: .excited, confidence: 0.92, dwellTime: 450, zone: "Penthouse Show", timestamp: Date()), Visitor(id: "v2", faceId: "face_002", sentiment: .interested, confidence: 0.87, dwellTime: 320, zone: "Amenity Deck VR", timestamp: Date()), Visitor(id: "v3", faceId: "face_003", sentiment: .neutral, confidence: 0.78, dwellTime: 180, zone: "Reception", timestamp: Date()), Visitor(id: "v4", faceId: "face_004", sentiment: .confused, confidence: 0.74, dwellTime: 95, zone: "Penthouse Show", timestamp: Date()), Visitor(id: "v5", faceId: "face_005", sentiment: .disinterested, confidence: 0.65, dwellTime: 60, zone: "Gallery", timestamp: Date()), ] // ── Alerts ──────────────────────────────────────────────────── var isAlertActive = false var alertMessage = "" func triggerAlert(_ msg: String) { isAlertActive = true alertMessage = msg } func clearAlert() { isAlertActive = false alertMessage = "" } // ── Leads (Oracle) ──────────────────────────────────────────── var leads: [Lead] = [ Lead(id: "1", name: "Mohammed Al-Rashid", phone: "+971 55 123 4567", source: .whatsapp, status: .hot, lastMessage: "Can we schedule a viewing for the penthouse tomorrow?", lastActive: Date().addingTimeInterval(-300), unreadCount: 2, qualification: "whale", budget: "AED 15M+", interest: "Penthouse Suite"), Lead(id: "2", name: "Sarah Chen", phone: "+971 50 987 6543", source: .walkin, status: .engaged, lastMessage: "Thank you for the brochure. I will review with my partner.", lastActive: Date().addingTimeInterval(-1800), unreadCount: 0, qualification: "potential", budget: "AED 5–8M", interest: "2BR Sea View"), Lead(id: "3", name: "James Wilson", phone: "+971 52 456 7890", source: .website, status: .new, lastMessage: "Interested in investment opportunities.", lastActive: Date().addingTimeInterval(-7200), unreadCount: 1, qualification: "potential", budget: "AED 3–5M", interest: "1BR Investment"), Lead(id: "4", name: "Fatima Hassan", phone: "+971 54 321 0987", source: .whatsapp, status: .qualified,lastMessage: "What are the payment plan options?", lastActive: Date().addingTimeInterval(-14400), unreadCount: 0, qualification: "whale", budget: "AED 12M+", interest: "3BR + Maid"), Lead(id: "5", name: "David Kumar", phone: "+971 56 789 0123", source: .walkin, status: .closed, lastMessage: "Contract signed. Thank you!", lastActive: Date().addingTimeInterval(-86400), unreadCount: 0, qualification: "whale", budget: "AED 20M", interest: "Full Floor"), ] var messages: [String: [ChatMessage]] = [ "1": [ ChatMessage(id: "m1", sender: "user", content: "Hi, I am interested in the penthouse units.", timestamp: Date().addingTimeInterval(-7200)), ChatMessage(id: "m2", sender: "oracle", content: "Welcome! Our penthouse collection features 4 exclusive units with panoramic sea views. Prices start at AED 15M.", timestamp: Date().addingTimeInterval(-7200 + 30)), ChatMessage(id: "m3", sender: "user", content: "Can we schedule a viewing tomorrow?", timestamp: Date().addingTimeInterval(-300)), ], "2": [ ChatMessage(id: "m4", sender: "oracle", content: "Hello Sarah! Here is the digital brochure for the 2-bedroom units we discussed.", timestamp: Date().addingTimeInterval(-14400)), ChatMessage(id: "m5", sender: "user", content: "Thank you. I will review with my partner.", timestamp: Date().addingTimeInterval(-1800)), ], ] var activeLeadId: String? = "1" var isOracleThinking = false func addDashboardMessage(sender: String, content: String) { let msg = ChatMessage(id: UUID().uuidString, sender: sender, content: content, timestamp: Date()) dashboardMessages.append(msg) } func addOracleMessage(leadId: String, sender: String, content: String) { let msg = ChatMessage(id: UUID().uuidString, sender: sender, content: content, timestamp: Date()) if messages[leadId] == nil { messages[leadId] = [] } messages[leadId]!.append(msg) } // ── Live ticker ─────────────────────────────────────────────── private var timerTask: AnyCancellable? private var alertTask: DispatchWorkItem? private func startTimer() { timerTask = Timer.publish(every: 5, on: .main, in: .common) .autoconnect() .sink { [weak self] _ in self?.tick() } } private func tick() { // jitter visitor count ±1 let delta = Int.random(in: -1...1) metrics.activeVisitors = max(10, metrics.activeVisitors + delta) // jitter sentiment ±2 let sDelta = Double.random(in: -2...2) metrics.sentimentScore = min(100, max(40, metrics.sentimentScore + sDelta)) // jitter system health metrics.systemHealth.cpu = Double.random(in: 0.30...0.65) metrics.systemHealth.gpu = Double.random(in: 0.45...0.75) metrics.systemHealth.memory = Double.random(in: 0.40...0.70) // Random alert (same 10% chance as WebOS every tick) if !isAlertActive && Double.random(in: 0...1) > 0.85 { triggerAlert("Confusion detected in Zone B – Penthouse Gallery") let work = DispatchWorkItem { [weak self] in self?.clearAlert() } alertTask = work DispatchQueue.main.asyncAfter(deadline: .now() + 5, execute: work) } } } // MARK: – Helpers extension Date { var relativeShort: String { let diff = Int(Date().timeIntervalSince(self)) if diff < 60 { return "now" } if diff < 3600 { return "\(diff / 60)m ago" } if diff < 86400 { return "\(diff / 3600)h ago" } return "\(diff / 86400)d ago" } }