- Models: TrainingPlan, Race, FamilyPlan, BeginnerMode, CommunityEvent - Services: 5 service layers with protocol-based architecture - ViewModels: 5 view models with @MainActor ObservableObject pattern - Views: 10 SwiftUI views for all Phase 3 features - Updated README with full Phase 3 documentation Co-Authored-By: Paperclip <noreply@paperclip.ing>
120 lines
3.6 KiB
Swift
120 lines
3.6 KiB
Swift
import Foundation
|
|
import SwiftUI
|
|
|
|
@MainActor
|
|
class CommunityEventViewModel: ObservableObject {
|
|
@Published var events: [CommunityEvent] = []
|
|
@Published var selectedEvent: CommunityEvent?
|
|
@Published var participants: [EventParticipant] = []
|
|
@Published var isLoading: Bool = false
|
|
@Published var error: CommunityEventError?
|
|
@Published var filter: EventFilter = EventFilter()
|
|
|
|
private let service: CommunityEventServiceProtocol
|
|
|
|
init(service: CommunityEventServiceProtocol = CommunityEventService()) {
|
|
self.service = service
|
|
}
|
|
|
|
func fetchEvents() async {
|
|
isLoading = true
|
|
error = nil
|
|
defer { isLoading = false }
|
|
|
|
do {
|
|
events = try await service.listEvents(filter: filter)
|
|
} catch let error as CommunityEventError {
|
|
self.error = error
|
|
} catch {
|
|
print("Failed to fetch events: \(error)")
|
|
}
|
|
}
|
|
|
|
func selectEvent(id: String) async {
|
|
isLoading = true
|
|
error = nil
|
|
defer { isLoading = false }
|
|
|
|
do {
|
|
let result = try await service.getEvent(id: id)
|
|
selectedEvent = result.event
|
|
participants = result.participants
|
|
if let index = events.firstIndex(where: { $0.id == id }) {
|
|
events[index] = result.event
|
|
objectWillChange.send()
|
|
}
|
|
} catch let error as CommunityEventError {
|
|
self.error = error
|
|
} catch {
|
|
print("Failed to get event: \(error)")
|
|
}
|
|
}
|
|
|
|
func createEvent(request: CreateEventRequest) async -> CommunityEvent? {
|
|
isLoading = true
|
|
error = nil
|
|
defer { isLoading = false }
|
|
|
|
do {
|
|
let event = try await service.createEvent(request: request)
|
|
events.insert(event, at: 0)
|
|
objectWillChange.send()
|
|
return event
|
|
} catch let error as CommunityEventError {
|
|
self.error = error
|
|
return nil
|
|
} catch {
|
|
print("Failed to create event: \(error)")
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func updateEvent(id: String, request: UpdateEventRequest) async {
|
|
isLoading = true
|
|
error = nil
|
|
defer { isLoading = false }
|
|
|
|
do {
|
|
let updatedEvent = try await service.updateEvent(id: id, request: request)
|
|
if let index = events.firstIndex(where: { $0.id == id }) {
|
|
events[index] = updatedEvent
|
|
objectWillChange.send()
|
|
}
|
|
if selectedEvent?.id == id {
|
|
selectedEvent = updatedEvent
|
|
}
|
|
} catch let error as CommunityEventError {
|
|
self.error = error
|
|
} catch {
|
|
print("Failed to update event: \(error)")
|
|
}
|
|
}
|
|
|
|
func RSVP(eventId: String, status: RSVPStatus) async {
|
|
do {
|
|
try await service.RSVP(eventId: eventId, status: status)
|
|
if let index = events.firstIndex(where: { $0.id == eventId }) {
|
|
events[index].rsvpStatus = status
|
|
objectWillChange.send()
|
|
}
|
|
} catch {
|
|
print("Failed to RSVP: \(error)")
|
|
}
|
|
}
|
|
|
|
var upcomingEvents: [CommunityEvent] {
|
|
events.filter { $0.isUpcoming }.sorted { $0.startDate < $1.startDate }
|
|
}
|
|
|
|
var ongoingEvents: [CommunityEvent] {
|
|
events.filter { $0.isOngoing }
|
|
}
|
|
|
|
var pastEvents: [CommunityEvent] {
|
|
events.filter { $0.isPast }.sorted { $0.endDate > $1.endDate }
|
|
}
|
|
|
|
var eventTypes: [EventType] { EventType.allCases }
|
|
var rsvpStatuses: [RSVPStatus] { RSVPStatus.allCases }
|
|
}
|