Das Backend bool-konvertiert nur is_premium explizit; alle anderen 0/1-Spalten gehen unverändert durch FastAPI. Decode-Fehler vorher still verschluckt → jetzt auch geloggt, damit das nicht nochmal passiert.
114 lines
3.7 KiB
Swift
114 lines
3.7 KiB
Swift
import SwiftUI
|
|
|
|
struct SettingsView: View {
|
|
@Environment(AuthSession.self) private var auth
|
|
|
|
var body: some View {
|
|
NavigationStack {
|
|
Form {
|
|
Section {
|
|
HStack(spacing: 14) {
|
|
avatarView
|
|
.frame(width: 60, height: 60)
|
|
.clipShape(Circle())
|
|
VStack(alignment: .leading, spacing: 2) {
|
|
Text(displayName)
|
|
.font(.headline)
|
|
if let email = auth.profile?.email {
|
|
Text(email)
|
|
.font(.footnote)
|
|
.foregroundStyle(.secondary)
|
|
}
|
|
}
|
|
}
|
|
.padding(.vertical, 4)
|
|
}
|
|
|
|
Section("Account") {
|
|
LabeledContent("Rolle", value: rolleLabel)
|
|
if auth.profile?.isFounderFlag == true {
|
|
LabeledContent("Founder", value: founderLabel)
|
|
}
|
|
if auth.profile?.isPartnerFlag == true {
|
|
LabeledContent("Partner", value: "Ja")
|
|
}
|
|
if let tier = auth.profile?.subscriptionTier, !tier.isEmpty {
|
|
LabeledContent("Abo", value: tier.capitalized)
|
|
}
|
|
LabeledContent("Premium", value: premiumValue ? "Ja" : "Nein")
|
|
}
|
|
|
|
if let wohnort = auth.profile?.wohnort, !wohnort.isEmpty {
|
|
Section("Ort") {
|
|
Text(wohnort)
|
|
}
|
|
}
|
|
|
|
Section {
|
|
Button("Abmelden", role: .destructive) {
|
|
auth.logout()
|
|
}
|
|
}
|
|
|
|
Section("Über") {
|
|
Text("Ban Yaro Go ist die native iOS-Ergänzung zur banyaro.app PWA. Phase 1: deine Touren ansehen.")
|
|
.font(.footnote)
|
|
.foregroundStyle(.secondary)
|
|
}
|
|
}
|
|
.navigationTitle("Mehr")
|
|
.refreshable { await auth.loadProfile() }
|
|
}
|
|
}
|
|
|
|
private var displayName: String {
|
|
auth.profile?.name ?? auth.userName ?? "—"
|
|
}
|
|
|
|
private var premiumValue: Bool {
|
|
auth.profile?.isPremium ?? auth.isPremium
|
|
}
|
|
|
|
private var rolleLabel: String {
|
|
switch auth.profile?.rolle?.lowercased() {
|
|
case "admin": return "Admin"
|
|
case "moderator": return "Moderator"
|
|
case nil: return "—"
|
|
default: return "Mitglied"
|
|
}
|
|
}
|
|
|
|
private var founderLabel: String {
|
|
if let n = auth.profile?.founderNumber { return "#\(n)" }
|
|
return "Ja"
|
|
}
|
|
|
|
@ViewBuilder
|
|
private var avatarView: some View {
|
|
if let path = auth.profile?.avatarUrl, !path.isEmpty,
|
|
let url = avatarURL(path) {
|
|
AsyncImage(url: url) { phase in
|
|
switch phase {
|
|
case .success(let img): img.resizable().scaledToFill()
|
|
default: avatarPlaceholder
|
|
}
|
|
}
|
|
} else {
|
|
avatarPlaceholder
|
|
}
|
|
}
|
|
|
|
private var avatarPlaceholder: some View {
|
|
ZStack {
|
|
Color.accentColor.opacity(0.2)
|
|
Image(systemName: "person.crop.circle.fill")
|
|
.font(.system(size: 36))
|
|
.foregroundStyle(Color.accentColor)
|
|
}
|
|
}
|
|
|
|
private func avatarURL(_ path: String) -> URL? {
|
|
if path.hasPrefix("http") { return URL(string: path) }
|
|
return URL(string: "https://banyaro.app\(path)")
|
|
}
|
|
}
|