medmap-ios/medmap/ViewModels/DashboardViewModel.swift
2026-09-16 14:43:57 +01:00

109 lines
3.1 KiB
Swift

import Foundation
import SwiftUI
import Combine
@MainActor
final class DashboardViewModel: ViewModel {
@Published private(set) var patient: PatientDTO?
@Published private(set) var prescriptions: [PrescriptionWithSchedulesResponse] = []
@Published private(set) var medications: [String: MedicationDTO] = [:]
@Published private(set) var errorMessage: String?
@Published private(set) var logoutErrorMessage: String?
private let api: MedMapAPI = DIContainer.shared.resolve()
var patientAge: Int? {
guard let dateOfBirth = patient?.dateOfBirth else { return nil }
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd"
guard let birthDate = formatter.date(from: dateOfBirth) else { return nil }
return Calendar.current.dateComponents([.year], from: birthDate, to: .now).year
}
var totalDosesToday: Int {
medicationCards.reduce(0) { $0 + $1.doseTimes.count }
}
var medicationCards: [MedicationCard] {
prescriptions.map { response in
let times = response.schedules
.flatMap(\.timesOfDay)
.sorted()
let medication = medications[response.medicationId]
return MedicationCard(
id: response.prescription.id,
medicationId: response.medicationId,
name: medication?.name ?? "Medicacao prescrita",
tag: medication?.activeIngredient ?? medication?.dosageForm ?? "Ativo",
photoBase64: medication?.medicationPhoto,
doseTimes: times,
nextDoseTime: times.first(where: { $0 >= currentTime }) ?? times.first
)
}
}
func loadDashboard() async {
guard !isLoading else { return }
isLoading = true
errorMessage = nil
defer { isLoading = false }
do {
async let myPatient = api.getMyPatientProfile()
async let activePrescriptions = api.listMyActivePrescriptions()
async let medicationsResponse = api.listMedications()
let (patient, prescriptions, medicationsResponseValue) = try await (myPatient, activePrescriptions, medicationsResponse)
self.patient = patient
self.prescriptions = prescriptions
medications = Dictionary(
uniqueKeysWithValues: medicationsResponseValue.medications.map { ($0.medicationId, $0) }
)
} catch {
errorMessage = "Nao foi possivel carregar a sua medicacao."
fluxlog("Patient dashboard load failed: \(error.localizedDescription)")
}
}
func logout() async {
guard !isLoading else { return }
isLoading = true
logoutErrorMessage = nil
defer { isLoading = false }
do {
try await api.logout()
appStateManager.resetNavigation()
appStateManager.navigateTo(state: .login)
} catch {
logoutErrorMessage = "Nao foi possivel terminar a sessao. Tente novamente."
fluxlog("Patient logout failed: \(error.localizedDescription)")
}
}
private var currentTime: String {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "HH:mm"
return formatter.string(from: .now)
}
}
struct MedicationCard: Identifiable {
let id: String
let medicationId: String
let name: String
let tag: String
let photoBase64: String?
let doseTimes: [String]
let nextDoseTime: String?
}
// Created by RSA on 28/08/2026.
//