refactor: remove legacy trip creation flow, extract shared components
- Delete TripCreationView.swift and TripCreationViewModel.swift (unused) - Extract TripOptionsView to standalone file - Extract DateRangePicker and DayCell to standalone file - Extract LocationSearchSheet and CityInputType to standalone file - Fix TripWizardView to pass games dictionary to TripOptionsView - Remove debug print statements from TripDetailView Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
//
|
||||
// LocationSearchSheet.swift
|
||||
// SportsTime
|
||||
//
|
||||
// Extracted from TripCreationView - location search sheet for adding cities/places.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
// MARK: - City Input Type
|
||||
|
||||
enum CityInputType {
|
||||
case mustStop
|
||||
case preferred
|
||||
case homeLocation
|
||||
case startLocation
|
||||
case endLocation
|
||||
}
|
||||
|
||||
// MARK: - Location Search Sheet
|
||||
|
||||
struct LocationSearchSheet: View {
|
||||
let inputType: CityInputType
|
||||
let onAdd: (LocationInput) -> Void
|
||||
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
@State private var searchText = ""
|
||||
@State private var searchResults: [LocationSearchResult] = []
|
||||
@State private var isSearching = false
|
||||
@State private var searchTask: Task<Void, Never>?
|
||||
|
||||
private let locationService = LocationService.shared
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
VStack(spacing: 0) {
|
||||
// Search field
|
||||
HStack {
|
||||
Image(systemName: "magnifyingglass")
|
||||
.foregroundStyle(.secondary)
|
||||
TextField("Search cities, addresses, places...", text: $searchText)
|
||||
.textFieldStyle(.plain)
|
||||
.autocorrectionDisabled()
|
||||
if isSearching {
|
||||
LoadingSpinner(size: .small)
|
||||
} else if !searchText.isEmpty {
|
||||
Button {
|
||||
searchText = ""
|
||||
searchResults = []
|
||||
} label: {
|
||||
Image(systemName: "xmark.circle.fill")
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
.background(Color(.secondarySystemBackground))
|
||||
.clipShape(RoundedRectangle(cornerRadius: 10))
|
||||
.padding()
|
||||
|
||||
// Results list
|
||||
if searchResults.isEmpty && !searchText.isEmpty && !isSearching {
|
||||
ContentUnavailableView(
|
||||
"No Results",
|
||||
systemImage: "mappin.slash",
|
||||
description: Text("Try a different search term")
|
||||
)
|
||||
} else {
|
||||
List(searchResults) { result in
|
||||
Button {
|
||||
onAdd(result.toLocationInput())
|
||||
dismiss()
|
||||
} label: {
|
||||
HStack {
|
||||
Image(systemName: "mappin.circle.fill")
|
||||
.foregroundStyle(.red)
|
||||
.font(.title2)
|
||||
VStack(alignment: .leading) {
|
||||
Text(result.name)
|
||||
.foregroundStyle(.primary)
|
||||
if !result.address.isEmpty {
|
||||
Text(result.address)
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
Spacer()
|
||||
Image(systemName: "plus.circle")
|
||||
.foregroundStyle(.blue)
|
||||
}
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
}
|
||||
.listStyle(.plain)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.navigationTitle(inputType == .mustStop ? "Add Must-Stop" : "Add Location")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .cancellationAction) {
|
||||
Button("Cancel") {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.presentationDetents([.large])
|
||||
.onChange(of: searchText) { _, newValue in
|
||||
// Debounce search
|
||||
searchTask?.cancel()
|
||||
searchTask = Task {
|
||||
try? await Task.sleep(for: .milliseconds(300))
|
||||
guard !Task.isCancelled else { return }
|
||||
await performSearch(query: newValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func performSearch(query: String) async {
|
||||
guard !query.isEmpty else {
|
||||
searchResults = []
|
||||
return
|
||||
}
|
||||
|
||||
isSearching = true
|
||||
do {
|
||||
searchResults = try await locationService.searchLocations(query)
|
||||
} catch {
|
||||
searchResults = []
|
||||
}
|
||||
isSearching = false
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Preview
|
||||
|
||||
#Preview {
|
||||
LocationSearchSheet(inputType: .mustStop) { _ in }
|
||||
}
|
||||
Reference in New Issue
Block a user