// // 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") .accessibilityIdentifier("polls.list") .toolbar { ToolbarItem(placement: .primaryAction) { Button { showJoinPoll = true } label: { Image(systemName: "link.badge.plus") .accessibilityLabel("Join a poll") } } } .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) .contentShape(Rectangle()) } } } .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() } }