Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 2 additions & 27 deletions Sunshade/Models/DashboardViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,6 @@ class DashboardViewModel: ObservableObject {

// MARK: - User Name State Management

/// Stores the authenticated user's display name from Apple Sign-In or similar auth providers.
/// This takes precedence over userProfile.name when available.
///
/// Priority order for display names:
/// 1. authenticatedUserName (from sign-in providers like Apple)
/// 2. userProfile.name (user's manually set profile name)
/// 3. Default greeting without name
private var authenticatedUserName: String?

// Cached weekly session data to prevent O(n) filtering on every access
private var cachedWeeklyData: (startOfWeek: Date, sessions: [ExposureSession], cacheDate: Date)?
Expand Down Expand Up @@ -228,10 +220,10 @@ class DashboardViewModel: ObservableObject {

// MARK: - User Name & Greeting Management

/// Returns the current display name following the established priority order.
/// Returns the current display name from the user profile.
/// This provides a single source of truth for which name to display.
private var currentDisplayName: String {
return authenticatedUserName ?? userProfile.name
return userProfile.name
}

/// Updates the greeting using the current display name.
Expand All @@ -240,23 +232,6 @@ class DashboardViewModel: ObservableObject {
greeting = TimeUtils.getPersonalizedGreeting(name: currentDisplayName)
}

/// Sets the authenticated user's name and immediately updates the greeting.
/// This is called when a user successfully authenticates via Apple Sign-In or similar providers.
/// The authenticated name takes precedence over the profile name.
///
/// - Parameter userName: The display name from the authentication provider
func updateGreetingForUser(_ userName: String) {
authenticatedUserName = userName
updateGreeting()
}

/// Clears the authenticated user state and reverts to using the profile name.
/// This is called when the user signs out of their authenticated session.
func clearAuthenticatedUser() {
authenticatedUserName = nil
updateGreeting()
}

private func fetchWeatherData(for location: CLLocation) async {
isLoading = true
weatherError = nil
Expand Down
37 changes: 27 additions & 10 deletions Sunshade/Models/UserProfile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,50 +45,67 @@ enum TemperatureUnit: String, CaseIterable {
class UserProfile: ObservableObject {
@Published var name: String {
didSet {
UserDefaults.standard.set(name, forKey: "userName")
DispatchQueue.main.async {
UserDefaults.standard.set(self.name, forKey: "userName")
}
}
}

@Published var skinType: SkinType {
didSet {
UserDefaults.standard.set(skinType.rawValue, forKey: "userSkinType")
hasCompletedSkinTypeOnboarding = true
DispatchQueue.main.async {
UserDefaults.standard.set(self.skinType.rawValue, forKey: "userSkinType")
// Update onboarding flag directly without triggering didSet
if !self.hasCompletedSkinTypeOnboarding {
self.hasCompletedSkinTypeOnboarding = true
}
}
}
}

@Published var ageRange: AgeRange {
didSet {
UserDefaults.standard.set(ageRange.rawValue, forKey: "userAgeRange")
DispatchQueue.main.async {
UserDefaults.standard.set(self.ageRange.rawValue, forKey: "userAgeRange")
}
}
}

@Published var photosensitiveMedications: Bool {
didSet {
UserDefaults.standard.set(photosensitiveMedications, forKey: "userPhotosensitiveMedications")
DispatchQueue.main.async {
UserDefaults.standard.set(self.photosensitiveMedications, forKey: "userPhotosensitiveMedications")
}
}
}

@Published var preferredActivities: [OutdoorActivity] {
didSet {
let activityStrings = preferredActivities.map { $0.rawValue }
UserDefaults.standard.set(activityStrings, forKey: "userPreferredActivities")
DispatchQueue.main.async {
let activityStrings = self.preferredActivities.map { $0.rawValue }
UserDefaults.standard.set(activityStrings, forKey: "userPreferredActivities")
}
}
}

@Published var temperatureUnit: TemperatureUnit {
didSet {
UserDefaults.standard.set(temperatureUnit.rawValue, forKey: "temperatureUnit")
DispatchQueue.main.async {
UserDefaults.standard.set(self.temperatureUnit.rawValue, forKey: "temperatureUnit")
}
}
}

@Published var hasCompletedSkinTypeOnboarding: Bool {
didSet {
UserDefaults.standard.set(hasCompletedSkinTypeOnboarding, forKey: "hasCompletedSkinTypeOnboarding")
DispatchQueue.main.async {
UserDefaults.standard.set(self.hasCompletedSkinTypeOnboarding, forKey: "hasCompletedSkinTypeOnboarding")
}
}
}

init() {
self.name = UserDefaults.standard.string(forKey: "userName") ?? "User"
self.name = UserDefaults.standard.string(forKey: "userName") ?? ""

// Load skin type with safe default
let savedSkinType = UserDefaults.standard.integer(forKey: "userSkinType")
Expand Down
Loading