import ManaCore import SwiftUI /// Report-Form für ein Marketplace-Deck — Pflicht-Komponente nach /// App-Store-Guideline 5.1.1(v) (Report-Mechanismus für UGC). /// /// Owned-State (Kategorie, Message, Submit-Status). Bei Erfolg schließt /// das Sheet und ruft `onCompleted` mit einer Toast-Message auf. struct ReportDeckSheet: View { let slug: String let onCompleted: (String) -> Void @Environment(AuthClient.self) private var auth @Environment(\.dismiss) private var dismiss @State private var category: ReportCategory = .spam @State private var message: String = "" @State private var isSubmitting = false @State private var errorMessage: String? var body: some View { Form { Section("Grund") { Picker("Grund", selection: $category) { ForEach(ReportCategory.allCases, id: \.self) { cat in Text(cat.label).tag(cat) } } .pickerStyle(.inline) .labelsHidden() } Section { TextField("Optional: Details", text: $message, axis: .vertical) .lineLimit(3 ... 6) .textInputAutocapitalization(.sentences) } header: { Text("Beschreibung") } footer: { Text("Wir prüfen jede Meldung. Hass und Rechtsverletzungen werden bevorzugt behandelt.") } if let errorMessage { Section { Text(errorMessage) .font(.footnote) .foregroundStyle(WordeckTheme.error) } } } .disabled(isSubmitting) .navigationTitle("Deck melden") #if os(iOS) .navigationBarTitleDisplayMode(.inline) #endif .toolbar { ToolbarItem(placement: .cancellationAction) { Button("Abbrechen") { dismiss() } } ToolbarItem(placement: .confirmationAction) { Button("Senden") { Task { await submit() } } .disabled(isSubmitting) } } } private func submit() async { isSubmitting = true errorMessage = nil defer { isSubmitting = false } let api = WordeckAPI(auth: auth) let trimmed = message.trimmingCharacters(in: .whitespacesAndNewlines) do { let response = try await api.reportDeck( slug: slug, body: ReportDeckBody( category: category, body: trimmed.isEmpty ? nil : trimmed, versionId: nil, cardContentHash: nil ) ) let toast = response.alreadyReported ? "Du hast dieses Deck bereits gemeldet." : "Meldung gesendet. Danke fürs Aufpassen." onCompleted(toast) dismiss() } catch { errorMessage = (error as? LocalizedError)?.errorDescription ?? String(describing: error) } } } /// Schlichtes Top-Banner für kurze Bestätigungen. struct ToastBanner: View { let text: String var body: some View { Text(text) .font(.subheadline.weight(.medium)) .foregroundStyle(WordeckTheme.foreground) .padding(.horizontal, 14) .padding(.vertical, 10) .background(.regularMaterial, in: Capsule()) .overlay(Capsule().stroke(WordeckTheme.border, lineWidth: 0.5)) .padding(.horizontal, 16) .transition(.move(edge: .top).combined(with: .opacity)) } }