Files
Sportstime/SportsTime/Features/Polls/ViewModels/PollCreationViewModel.swift
Trey t 13385b6562 feat(polls): implement group trip polling MVP
Add complete group trip polling feature allowing users to share trips
with friends for voting using Borda count scoring.

New components:
- TripPoll and PollVote domain models with share codes and rankings
- LocalTripPoll and LocalPollVote SwiftData models for persistence
- CKTripPoll and CKPollVote CloudKit record wrappers
- PollService actor for CloudKit CRUD operations and subscriptions
- PollCreation/Detail/Voting views and view models
- Deep link handling for sportstime://poll/{code} URLs
- Debug Pro status override toggle in Settings

Integration:
- HomeView shows polls section in My Trips
- SportsTimeApp registers SwiftData models and handles deep links

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 21:54:42 -06:00

78 lines
1.9 KiB
Swift

//
// PollCreationViewModel.swift
// SportsTime
//
// ViewModel for creating trip polls
//
import Foundation
import SwiftUI
@Observable
@MainActor
final class PollCreationViewModel {
var title: String = ""
var selectedTripIds: Set<UUID> = []
var isLoading = false
var error: PollError?
var createdPoll: TripPoll?
private let pollService = PollService.shared
var canCreate: Bool {
!title.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
&& selectedTripIds.count >= 2
}
var validationMessage: String? {
if title.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
return "Enter a title for your poll"
}
if selectedTripIds.count < 2 {
return "Select at least 2 trips to create a poll"
}
return nil
}
func createPoll(trips: [Trip]) async {
guard canCreate else { return }
isLoading = true
error = nil
do {
let userId = try await pollService.getCurrentUserRecordID()
let selectedTrips = trips.filter { selectedTripIds.contains($0.id) }
let poll = TripPoll(
title: title.trimmingCharacters(in: .whitespacesAndNewlines),
ownerId: userId,
tripSnapshots: selectedTrips
)
createdPoll = try await pollService.createPoll(poll)
} catch let pollError as PollError {
error = pollError
} catch {
self.error = .unknown(error)
}
isLoading = false
}
func toggleTrip(_ tripId: UUID) {
if selectedTripIds.contains(tripId) {
selectedTripIds.remove(tripId)
} else {
selectedTripIds.insert(tripId)
}
}
func reset() {
title = ""
selectedTripIds = []
error = nil
createdPoll = nil
}
}