- Fixed App Store icon display with ios-marketing idiom - Added iPad orientation support for multitasking - Added UILaunchScreen for iPad requirements - Removed unused BLE permissions and files from build Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
144 lines
4.7 KiB
Swift
144 lines
4.7 KiB
Swift
import SwiftUI
|
|
import Kingfisher
|
|
|
|
struct BusinessListView: View {
|
|
@Binding var hasAutoSelected: Bool
|
|
var onBusinessSelected: (Business) -> Void
|
|
var onLogout: () -> Void
|
|
|
|
@State private var businesses: [Business] = []
|
|
@State private var isLoading = false
|
|
@State private var errorMessage: String?
|
|
|
|
var body: some View {
|
|
NavigationStack {
|
|
VStack {
|
|
if isLoading {
|
|
Spacer()
|
|
ProgressView("Loading businesses...")
|
|
Spacer()
|
|
} else if let error = errorMessage {
|
|
Spacer()
|
|
Text(error)
|
|
.foregroundColor(.errorRed)
|
|
.multilineTextAlignment(.center)
|
|
.padding()
|
|
addBusinessButton
|
|
Spacer()
|
|
} else if businesses.isEmpty {
|
|
Spacer()
|
|
Text("No businesses found")
|
|
.foregroundColor(.secondary)
|
|
addBusinessButton
|
|
Spacer()
|
|
} else {
|
|
List(businesses) { business in
|
|
Button {
|
|
onBusinessSelected(business)
|
|
} label: {
|
|
businessRow(business)
|
|
}
|
|
.buttonStyle(.plain)
|
|
}
|
|
.listStyle(.plain)
|
|
|
|
addBusinessButton
|
|
}
|
|
}
|
|
.navigationTitle("Select Business")
|
|
.toolbar {
|
|
ToolbarItem(placement: .topBarTrailing) {
|
|
Button("Log Out") {
|
|
logout()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.onAppear {
|
|
loadBusinesses()
|
|
}
|
|
}
|
|
|
|
private func businessRow(_ business: Business) -> some View {
|
|
HStack(spacing: 12) {
|
|
if let ext = business.headerImageExtension, !ext.isEmpty {
|
|
let baseDomain = Api.IS_DEV ? "https://dev.payfrit.com" : "https://biz.payfrit.com"
|
|
let imageUrl = URL(string: "\(baseDomain)/uploads/businesses/\(business.businessId)/header.\(ext)")
|
|
KFImage(imageUrl)
|
|
.resizable()
|
|
.placeholder {
|
|
Image(systemName: "building.2")
|
|
.font(.title2)
|
|
.foregroundColor(.secondary)
|
|
}
|
|
.scaledToFill()
|
|
.frame(width: 48, height: 48)
|
|
.clipShape(Circle())
|
|
} else {
|
|
Image(systemName: "building.2")
|
|
.font(.title2)
|
|
.foregroundColor(.secondary)
|
|
.frame(width: 48, height: 48)
|
|
}
|
|
|
|
VStack(alignment: .leading, spacing: 2) {
|
|
Text(business.name)
|
|
.font(.body.weight(.medium))
|
|
.foregroundColor(.primary)
|
|
Text("Tap to configure beacons")
|
|
.font(.caption)
|
|
.foregroundColor(.secondary)
|
|
}
|
|
|
|
Spacer()
|
|
|
|
Image(systemName: "chevron.right")
|
|
.foregroundColor(.secondary)
|
|
.font(.caption)
|
|
}
|
|
.padding(.vertical, 4)
|
|
}
|
|
|
|
private var addBusinessButton: some View {
|
|
Button {
|
|
let baseDomain = Api.IS_DEV ? "https://dev.payfrit.com" : "https://biz.payfrit.com"
|
|
if let url = URL(string: "\(baseDomain)/portal/index.html") {
|
|
UIApplication.shared.open(url)
|
|
}
|
|
} label: {
|
|
Text("Add Business via Portal")
|
|
.font(.callout)
|
|
.foregroundColor(.payfritGreen)
|
|
}
|
|
.padding()
|
|
}
|
|
|
|
private func loadBusinesses() {
|
|
isLoading = true
|
|
errorMessage = nil
|
|
|
|
Task {
|
|
do {
|
|
let result = try await Api.shared.listBusinesses()
|
|
businesses = result
|
|
isLoading = false
|
|
|
|
if businesses.count == 1 && !hasAutoSelected {
|
|
hasAutoSelected = true
|
|
onBusinessSelected(businesses[0])
|
|
}
|
|
} catch {
|
|
isLoading = false
|
|
errorMessage = error.localizedDescription
|
|
}
|
|
}
|
|
}
|
|
|
|
private func logout() {
|
|
UserDefaults.standard.removeObject(forKey: "token")
|
|
UserDefaults.standard.removeObject(forKey: "userId")
|
|
UserDefaults.standard.removeObject(forKey: "firstName")
|
|
Api.shared.setAuthToken(nil)
|
|
onLogout()
|
|
}
|
|
}
|