payfrit-beacon-ios/_backup/Views/BusinessSelectionScreen.swift
John Pinkyfloyd 8c2320da44 Add ios-marketing idiom, iPad orientations, launch screen
- 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>
2026-02-10 19:38:11 -08:00

196 lines
7.3 KiB
Swift

import SwiftUI
struct BusinessSelectionScreen: View {
@EnvironmentObject var appState: AppState
@State private var businesses: [Employment] = []
@State private var isLoading = true
@State private var error: String?
var body: some View {
NavigationStack {
Group {
if isLoading {
ProgressView("Loading businesses...")
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else if let error = error {
VStack(spacing: 16) {
Image(systemName: "exclamationmark.triangle")
.font(.largeTitle)
.foregroundColor(.orange)
Text(error)
.foregroundColor(.secondary)
.multilineTextAlignment(.center)
Button("Retry") { loadBusinesses() }
.buttonStyle(.borderedProminent)
.tint(.payfritGreen)
}
.padding()
} else if businesses.isEmpty {
VStack(spacing: 16) {
Image(systemName: "building.2")
.font(.largeTitle)
.foregroundColor(.secondary)
Text("No businesses found")
.foregroundColor(.secondary)
}
} else {
ScrollView {
LazyVStack(spacing: 12) {
ForEach(businesses) { biz in
NavigationLink(value: biz) {
VStack(spacing: 0) {
BusinessHeaderImage(businessId: biz.businessId)
HStack {
VStack(alignment: .leading, spacing: 2) {
Text(biz.businessName)
.font(.subheadline.weight(.semibold))
.foregroundColor(.primary)
if !biz.businessCity.isEmpty {
Text(biz.businessCity)
.font(.caption)
.foregroundColor(.secondary)
}
}
Spacer()
Image(systemName: "chevron.right")
.font(.caption)
.foregroundColor(.secondary)
}
.padding(.horizontal, 12)
.padding(.vertical, 8)
}
.background(Color(.systemBackground))
.clipShape(RoundedRectangle(cornerRadius: 12, style: .continuous))
.overlay(
RoundedRectangle(cornerRadius: 12, style: .continuous)
.stroke(Color(.systemGray4), lineWidth: 0.5)
)
.shadow(color: .black.opacity(0.06), radius: 4, x: 0, y: 2)
}
.buttonStyle(.plain)
}
}
.padding(.horizontal, 16)
.padding(.top, 8)
.padding(.bottom, 20)
}
}
}
.navigationTitle("Select Business")
.navigationDestination(for: Employment.self) { biz in
BeaconDashboard(business: biz)
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button {
logout()
} label: {
Image(systemName: "rectangle.portrait.and.arrow.right")
}
}
}
}
.task { loadBusinesses() }
}
private func loadBusinesses() {
isLoading = true
error = nil
Task {
do {
businesses = try await APIService.shared.getMyBusinesses()
isLoading = false
} catch let apiError as APIError where apiError == .unauthorized {
await appState.handleUnauthorized()
} catch {
self.error = error.localizedDescription
isLoading = false
}
}
}
private func logout() {
Task {
await AuthStorage.shared.clearAuth()
await APIService.shared.logout()
appState.clearAuth()
}
}
}
// Make Employment Hashable for NavigationLink
extension Employment: Hashable {
static func == (lhs: Employment, rhs: Employment) -> Bool {
lhs.employeeId == rhs.employeeId && lhs.businessId == rhs.businessId
}
func hash(into hasher: inout Hasher) {
hasher.combine(employeeId)
hasher.combine(businessId)
}
}
// MARK: - Business Header Image
struct BusinessHeaderImage: View {
let businessId: Int
@State private var loadedImage: UIImage?
@State private var isLoading = true
private var imageURLs: [URL] {
[
"https://dev.payfrit.com/uploads/headers/\(businessId).png",
"https://dev.payfrit.com/uploads/headers/\(businessId).jpg",
].compactMap { URL(string: $0) }
}
var body: some View {
ZStack {
Color(.systemGray6)
if let image = loadedImage {
Image(uiImage: image)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(maxWidth: .infinity)
} else if isLoading {
ProgressView()
.tint(.payfritGreen)
.frame(maxWidth: .infinity)
.frame(height: 100)
} else {
Image(systemName: "building.2")
.font(.system(size: 30))
.foregroundColor(.secondary)
.frame(maxWidth: .infinity)
.frame(height: 100)
}
}
.task {
await loadImage()
}
}
private func loadImage() async {
for url in imageURLs {
do {
let (data, response) = try await URLSession.shared.data(from: url)
if let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200,
let image = UIImage(data: data) {
await MainActor.run {
loadedImage = image
isLoading = false
}
return
}
} catch {
continue
}
}
await MainActor.run {
isLoading = false
}
}
}