- 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>
116 lines
4 KiB
Swift
116 lines
4 KiB
Swift
import SwiftUI
|
|
|
|
struct BeaconDetailScreen: View {
|
|
let beacon: Beacon
|
|
var onSaved: () -> Void
|
|
|
|
@State private var name: String = ""
|
|
@State private var uuid: String = ""
|
|
@State private var isActive: Bool = true
|
|
@State private var isSaving = false
|
|
@State private var isDeleting = false
|
|
@State private var error: String?
|
|
@State private var showDeleteConfirm = false
|
|
@EnvironmentObject var appState: AppState
|
|
@Environment(\.dismiss) private var dismiss
|
|
|
|
var body: some View {
|
|
Form {
|
|
Section("Beacon Info") {
|
|
TextField("Name", text: $name)
|
|
TextField("UUID (32 hex characters)", text: $uuid)
|
|
.textInputAutocapitalization(.characters)
|
|
.autocorrectionDisabled()
|
|
.font(.system(.body, design: .monospaced))
|
|
Toggle("Active", isOn: $isActive)
|
|
}
|
|
|
|
Section("Details") {
|
|
LabeledContent("ID", value: "\(beacon.id)")
|
|
LabeledContent("Business ID", value: "\(beacon.businessId)")
|
|
if let date = beacon.createdAt {
|
|
LabeledContent("Created", value: date.formatted(date: .abbreviated, time: .shortened))
|
|
}
|
|
if let date = beacon.updatedAt {
|
|
LabeledContent("Updated", value: date.formatted(date: .abbreviated, time: .shortened))
|
|
}
|
|
}
|
|
|
|
if let error = error {
|
|
Section {
|
|
HStack {
|
|
Image(systemName: "exclamationmark.circle.fill")
|
|
.foregroundColor(.red)
|
|
Text(error)
|
|
.foregroundColor(.red)
|
|
}
|
|
}
|
|
}
|
|
|
|
Section {
|
|
Button("Save Changes") { save() }
|
|
.frame(maxWidth: .infinity)
|
|
.disabled(isSaving || isDeleting || name.isEmpty || uuid.isEmpty)
|
|
}
|
|
|
|
Section {
|
|
Button(isDeleting ? "Deleting..." : "Delete Beacon", role: .destructive) {
|
|
showDeleteConfirm = true
|
|
}
|
|
.frame(maxWidth: .infinity)
|
|
.disabled(isSaving || isDeleting)
|
|
}
|
|
}
|
|
.navigationTitle(beacon.name)
|
|
.onAppear {
|
|
name = beacon.name
|
|
uuid = beacon.uuid
|
|
isActive = beacon.isActive
|
|
}
|
|
.alert("Delete Beacon?", isPresented: $showDeleteConfirm) {
|
|
Button("Delete", role: .destructive) { deleteBeacon() }
|
|
Button("Cancel", role: .cancel) {}
|
|
} message: {
|
|
Text("This will permanently remove \"\(beacon.name)\". Service points using this beacon will be unassigned.")
|
|
}
|
|
}
|
|
|
|
private func save() {
|
|
isSaving = true
|
|
error = nil
|
|
Task {
|
|
do {
|
|
try await APIService.shared.updateBeacon(
|
|
beaconId: beacon.id,
|
|
name: name.trimmingCharacters(in: .whitespaces),
|
|
uuid: uuid.trimmingCharacters(in: .whitespaces),
|
|
isActive: isActive
|
|
)
|
|
onSaved()
|
|
dismiss()
|
|
} catch let apiError as APIError where apiError == .unauthorized {
|
|
await appState.handleUnauthorized()
|
|
} catch {
|
|
self.error = error.localizedDescription
|
|
}
|
|
isSaving = false
|
|
}
|
|
}
|
|
|
|
private func deleteBeacon() {
|
|
isDeleting = true
|
|
error = nil
|
|
Task {
|
|
do {
|
|
try await APIService.shared.deleteBeacon(beaconId: beacon.id)
|
|
onSaved()
|
|
dismiss()
|
|
} catch let apiError as APIError where apiError == .unauthorized {
|
|
await appState.handleUnauthorized()
|
|
} catch {
|
|
self.error = error.localizedDescription
|
|
}
|
|
isDeleting = false
|
|
}
|
|
}
|
|
}
|