Files
Sportstime/SportsTime/Features/Polls/Views/PollsListView.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

156 lines
4.1 KiB
Swift

//
// PollsListView.swift
// SportsTime
//
// View for listing user's polls
//
import SwiftUI
struct PollsListView: View {
@Environment(\.colorScheme) private var colorScheme
@State private var polls: [TripPoll] = []
@State private var isLoading = false
@State private var hasLoadedInitially = false
@State private var error: PollError?
@State private var showJoinPoll = false
@State private var joinCode = ""
var body: some View {
Group {
if isLoading && polls.isEmpty {
ProgressView("Loading polls...")
} else if polls.isEmpty {
emptyState
} else {
pollsList
}
}
.navigationTitle("Group Polls")
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button {
showJoinPoll = true
} label: {
Image(systemName: "link.badge.plus")
}
}
}
.refreshable {
await loadPolls()
}
.task {
guard !hasLoadedInitially else { return }
hasLoadedInitially = true
await loadPolls()
}
.alert("Join Poll", isPresented: $showJoinPoll) {
TextField("Enter code", text: $joinCode)
.textInputAutocapitalization(.characters)
Button("Join") {
// Navigation will be handled by deep link
if !joinCode.isEmpty {
// TODO: Navigate to poll detail
}
}
Button("Cancel", role: .cancel) {
joinCode = ""
}
} message: {
Text("Enter the 6-character poll code")
}
.alert("Error", isPresented: .constant(error != nil)) {
Button("OK") {
error = nil
}
} message: {
if let error {
Text(error.localizedDescription)
}
}
}
@ViewBuilder
private var emptyState: some View {
ContentUnavailableView {
Label("No Polls", systemImage: "chart.bar.doc.horizontal")
} description: {
Text("Create a poll from your saved trips to let friends vote on which trip to take.")
}
}
@ViewBuilder
private var pollsList: some View {
List {
ForEach(polls) { poll in
NavigationLink(value: poll) {
PollRowView(poll: poll)
}
}
}
.listStyle(.plain)
.navigationDestination(for: TripPoll.self) { poll in
PollDetailView(poll: poll)
}
}
private func loadPolls() async {
isLoading = true
error = nil
do {
polls = try await PollService.shared.fetchMyPolls()
} catch let pollError as PollError {
error = pollError
} catch {
self.error = .unknown(error)
}
isLoading = false
}
}
// MARK: - Poll Row View
private struct PollRowView: View {
@Environment(\.colorScheme) private var colorScheme
let poll: TripPoll
var body: some View {
VStack(alignment: .leading, spacing: 8) {
HStack {
Text(poll.title)
.font(.headline)
Spacer()
Text(poll.shareCode)
.font(.caption)
.fontWeight(.semibold)
.foregroundStyle(Theme.warmOrange)
.padding(.horizontal, 8)
.padding(.vertical, 4)
.background(Theme.warmOrange.opacity(0.15))
.clipShape(Capsule())
}
HStack {
Label("\(poll.tripSnapshots.count) trips", systemImage: "map")
Spacer()
Text(poll.createdAt, style: .date)
}
.font(.caption)
.foregroundStyle(.secondary)
}
.padding(.vertical, 4)
}
}
#Preview {
NavigationStack {
PollsListView()
}
}