Inhalt
Aktueller Ordner:
duesseldorfer-schuelerinventar-swift-client/Duesk/ViewsProfileEditView.swift
import SwiftUI
struct ProfileEditView: View {
@Environment(\.dismiss) private var dismiss
@StateObject private var viewModel: ProfileEditViewModel
@State private var selectedTab = 0
let onSaved: (() -> Void)?
init(profile: Profile? = nil, onSaved: (() -> Void)? = nil) {
_viewModel = StateObject(wrappedValue: ProfileEditViewModel(profile: profile))
self.onSaved = onSaved
}
var body: some View {
NavigationView {
VStack(spacing: 0) {
// Header Form
Form {
Section("Profilinformationen") {
TextField("Name *", text: $viewModel.name)
.textFieldStyle(RoundedBorderTextFieldStyle())
Picker("Gruppe", selection: $viewModel.selectedGroup) {
Text("Keine Gruppe").tag(nil as Group?)
ForEach(viewModel.groups) { group in
Text(group.name).tag(group as Group?)
}
Text("+ Neue Gruppe...").tag(Group(gruppeID: -1, name: ""))
}
if viewModel.selectedGroup?.gruppeID == -1 {
TextField("Neuer Gruppenname", text: $viewModel.newGroupName)
.textFieldStyle(RoundedBorderTextFieldStyle())
}
}
}
.frame(height: 180)
.scrollDisabled(true)
// Tab Selector
Picker("", selection: $selectedTab) {
Text("Selbsteinschätzung (SE)").tag(0)
Text("Fremdeinschätzung (FE)").tag(1)
}
.pickerStyle(.segmented)
.padding()
// Items List
ScrollView {
LazyVStack(spacing: 12) {
ForEach(0..<36, id: \.self) { i in
ItemRatingCard(
index: i,
itemName: Norms.items[i],
selection: selectedTab == 0 ? $viewModel.seItems[i] : $viewModel.feItems[i]
)
}
}
.padding()
}
}
.navigationTitle(viewModel.existingProfile == nil ? "Neues Profil" : "Profil bearbeiten")
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("Abbrechen") { dismiss() }
}
ToolbarItem(placement: .confirmationAction) {
Button("Speichern") {
Task {
if await viewModel.save() {
onSaved?()
dismiss()
}
}
}
.disabled(viewModel.isSaving)
}
}
.overlay {
if viewModel.isLoading || viewModel.isSaving {
Color.black.opacity(0.3)
.ignoresSafeArea()
ProgressView()
}
}
.alert("Fehler", isPresented: .constant(viewModel.errorMessage != nil)) {
Button("OK") { viewModel.errorMessage = nil }
} message: {
Text(viewModel.errorMessage ?? "")
}
}
.task {
await viewModel.loadGroups()
}
}
}
struct ItemRatingCard: View {
let index: Int
let itemName: String
@Binding var selection: Int
let options = [(1, "1 - trifft nicht zu"), (2, "2 - trifft teilweise zu"), (3, "3 - trifft zu"), (4, "4 - trifft voll zu")]
var body: some View {
VStack(alignment: .leading, spacing: 8) {
HStack {
Text("\(index + 1).")
.font(.headline)
.foregroundColor(.secondary)
.frame(width: 30, alignment: .leading)
Text(itemName)
.font(.subheadline)
.fontWeight(.medium)
}
HStack(spacing: 8) {
ForEach(options, id: \.0) { value, label in
Button(action: { selection = value }) {
Text(label)
.font(.caption)
.padding(.horizontal, 8)
.padding(.vertical, 4)
.background(selection == value ? Color.blue : Color.gray.opacity(0.2))
.foregroundColor(selection == value ? .white : .primary)
.cornerRadius(6)
}
.buttonStyle(PlainButtonStyle())
}
}
}
.padding(12)
.background(Color(.textBackgroundColor))
.cornerRadius(10)
}
}