More UI Changes? Not sure why they didn't go previously
This commit is contained in:
144
LabWise/ProfileView.swift
Normal file
144
LabWise/ProfileView.swift
Normal file
@@ -0,0 +1,144 @@
|
||||
import SwiftUI
|
||||
import LabWiseKit
|
||||
|
||||
@Observable
|
||||
final class ProfileViewModel {
|
||||
var profile: UserProfile?
|
||||
var isLoading = false
|
||||
var isSaving = false
|
||||
var isEditing = false
|
||||
var errorMessage: String?
|
||||
|
||||
// Editable fields
|
||||
var piFirstName = ""
|
||||
var bldgCode = ""
|
||||
var lab = ""
|
||||
var contact = ""
|
||||
|
||||
private let profileClient = ProfileClient()
|
||||
private let authClient = AuthClient()
|
||||
|
||||
func load() async {
|
||||
isLoading = true
|
||||
defer { isLoading = false }
|
||||
do {
|
||||
let p = try await profileClient.get()
|
||||
profile = p
|
||||
populateFields(from: p)
|
||||
} catch {
|
||||
// Profile may not exist yet — that's OK
|
||||
}
|
||||
}
|
||||
|
||||
func save() async {
|
||||
isSaving = true
|
||||
defer { isSaving = false }
|
||||
do {
|
||||
let body = UserProfileUpsertBody(
|
||||
piFirstName: piFirstName,
|
||||
bldgCode: bldgCode,
|
||||
lab: lab,
|
||||
contact: contact.isEmpty ? nil : contact
|
||||
)
|
||||
let updated = try await profileClient.upsert(body)
|
||||
profile = updated
|
||||
populateFields(from: updated)
|
||||
isEditing = false
|
||||
} catch {
|
||||
errorMessage = "Failed to save profile."
|
||||
}
|
||||
}
|
||||
|
||||
func signOut() async {
|
||||
try? await authClient.signOut()
|
||||
await MainActor.run {
|
||||
AppState.shared.signedOut()
|
||||
}
|
||||
}
|
||||
|
||||
private func populateFields(from p: UserProfile) {
|
||||
piFirstName = p.piFirstName
|
||||
bldgCode = p.bldgCode
|
||||
lab = p.lab
|
||||
contact = p.contact ?? ""
|
||||
}
|
||||
}
|
||||
|
||||
struct ProfileView: View {
|
||||
@Environment(AppState.self) private var appState
|
||||
@State private var viewModel = ProfileViewModel()
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
Form {
|
||||
if let user = appState.currentUser {
|
||||
Section("Account") {
|
||||
LabeledContent("Email", value: user.email)
|
||||
}
|
||||
}
|
||||
|
||||
Section("Lab Info") {
|
||||
if viewModel.isEditing {
|
||||
TextField("PI First Name", text: $viewModel.piFirstName)
|
||||
TextField("Building Code", text: $viewModel.bldgCode)
|
||||
TextField("Lab", text: $viewModel.lab)
|
||||
TextField("Contact", text: $viewModel.contact)
|
||||
} else {
|
||||
LabeledContent("PI First Name", value: viewModel.piFirstName.isEmpty ? "—" : viewModel.piFirstName)
|
||||
LabeledContent("Building Code", value: viewModel.bldgCode.isEmpty ? "—" : viewModel.bldgCode)
|
||||
LabeledContent("Lab", value: viewModel.lab.isEmpty ? "—" : viewModel.lab)
|
||||
LabeledContent("Contact", value: viewModel.contact.isEmpty ? "—" : viewModel.contact)
|
||||
}
|
||||
}
|
||||
|
||||
Section {
|
||||
Button(role: .destructive) {
|
||||
Task { await viewModel.signOut() }
|
||||
} label: {
|
||||
HStack {
|
||||
Spacer()
|
||||
Text("Sign Out")
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationTitle("Profile")
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .topBarTrailing) {
|
||||
if viewModel.isEditing {
|
||||
Button("Save") {
|
||||
Task { await viewModel.save() }
|
||||
}
|
||||
.disabled(viewModel.isSaving)
|
||||
} else {
|
||||
Button("Edit") {
|
||||
viewModel.isEditing = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if viewModel.isEditing {
|
||||
ToolbarItem(placement: .topBarLeading) {
|
||||
Button("Cancel") {
|
||||
viewModel.isEditing = false
|
||||
if let p = viewModel.profile {
|
||||
viewModel.piFirstName = p.piFirstName
|
||||
viewModel.bldgCode = p.bldgCode
|
||||
viewModel.lab = p.lab
|
||||
viewModel.contact = p.contact ?? ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.alert("Error", isPresented: .constant(viewModel.errorMessage != nil)) {
|
||||
Button("OK") { viewModel.errorMessage = nil }
|
||||
} message: {
|
||||
Text(viewModel.errorMessage ?? "")
|
||||
}
|
||||
}
|
||||
.task {
|
||||
await viewModel.load()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user