Files
Sportstime/SportsTime/Features/Polls/ViewModels/PollDetailViewModel.swift
Trey t d034ee8612 fix: multiple bug fixes and improvements
- Fix suggested trips showing wrong sports for cross-country trips
- Remove quick start sections from home variants (Classic, Spotify)
- Remove dead quickActions code from HomeView
- Fix pace capsule animation in TripCreationView
- Add text wrapping to achievement descriptions
- Improve poll parsing with better error handling
- Various sharing system improvements

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 09:35:18 -06:00

175 lines
4.8 KiB
Swift

//
// PollDetailViewModel.swift
// SportsTime
//
// ViewModel for viewing poll details and results
//
import Foundation
import SwiftUI
@Observable
@MainActor
final class PollDetailViewModel {
var poll: TripPoll?
var votes: [PollVote] = []
var myVote: PollVote?
var isLoading = false
var isRefreshing = false
var error: PollError?
private let pollService = PollService.shared
var results: PollResults? {
guard let poll else { return nil }
return PollResults(poll: poll, votes: votes)
}
func checkIsOwner() async -> Bool {
guard let poll else { return false }
do {
let userId = try await pollService.getCurrentUserRecordID()
return poll.ownerId == userId
} catch {
return false
}
}
var isOwner: Bool {
get async {
await checkIsOwner()
}
}
var hasVoted: Bool {
myVote != nil
}
var shareURL: URL? {
poll?.shareURL
}
func loadPoll(byId pollId: UUID) async {
isLoading = true
error = nil
do {
async let pollTask = pollService.fetchPoll(byId: pollId)
async let votesTask = pollService.fetchVotes(forPollId: pollId)
async let myVoteTask = pollService.fetchMyVote(forPollId: pollId)
let (fetchedPoll, fetchedVotes, fetchedMyVote) = try await (pollTask, votesTask, myVoteTask)
self.poll = fetchedPoll
self.votes = fetchedVotes
self.myVote = fetchedMyVote
// Subscribe to vote updates
try? await pollService.subscribeToVoteUpdates(forPollId: pollId)
} catch let pollError as PollError {
error = pollError
} catch {
self.error = .unknown(error)
}
isLoading = false
}
func loadPoll(byShareCode shareCode: String) async {
isLoading = true
error = nil
do {
let fetchedPoll = try await pollService.fetchPoll(byShareCode: shareCode)
self.poll = fetchedPoll
// Now fetch votes with the poll ID
async let votesTask = pollService.fetchVotes(forPollId: fetchedPoll.id)
async let myVoteTask = pollService.fetchMyVote(forPollId: fetchedPoll.id)
let (fetchedVotes, fetchedMyVote) = try await (votesTask, myVoteTask)
self.votes = fetchedVotes
self.myVote = fetchedMyVote
// Subscribe to vote updates
try? await pollService.subscribeToVoteUpdates(forPollId: fetchedPoll.id)
} catch let pollError as PollError {
error = pollError
} catch {
self.error = .unknown(error)
}
isLoading = false
}
/// Load poll from an existing object (avoids CloudKit fetch delay)
func loadPoll(from existingPoll: TripPoll) async {
isLoading = true
error = nil
self.poll = existingPoll
do {
// Still fetch votes and subscription from CloudKit
async let votesTask = pollService.fetchVotes(forPollId: existingPoll.id)
async let myVoteTask = pollService.fetchMyVote(forPollId: existingPoll.id)
let (fetchedVotes, fetchedMyVote) = try await (votesTask, myVoteTask)
self.votes = fetchedVotes
self.myVote = fetchedMyVote
// Subscribe to vote updates
try? await pollService.subscribeToVoteUpdates(forPollId: existingPoll.id)
} catch {
// Votes fetch failed, but we have the poll - non-critical error
self.votes = []
}
isLoading = false
}
func refresh() async {
guard let poll else { return }
isRefreshing = true
do {
async let votesTask = pollService.fetchVotes(forPollId: poll.id)
async let myVoteTask = pollService.fetchMyVote(forPollId: poll.id)
let (fetchedVotes, fetchedMyVote) = try await (votesTask, myVoteTask)
self.votes = fetchedVotes
self.myVote = fetchedMyVote
} catch {
// Silently fail refresh - user can pull to refresh again
}
isRefreshing = false
}
func deletePoll() async -> Bool {
guard let poll else { return false }
isLoading = true
error = nil
do {
try await pollService.deletePoll(poll.id)
try? await pollService.unsubscribeFromVoteUpdates()
self.poll = nil
return true
} catch let pollError as PollError {
error = pollError
} catch {
self.error = .unknown(error)
}
isLoading = false
return false
}
func cleanup() async {
try? await pollService.unsubscribeFromVoteUpdates()
}
}