Files
pulse-mobile/PulseHealth/Views/Savings/EditSavingsCategoryView.swift

139 lines
7.3 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import SwiftUI
struct EditSavingsCategoryView: View {
@Binding var isPresented: Bool
@EnvironmentObject var authManager: AuthManager
let category: SavingsCategory
let onSaved: () async -> Void
@State private var name: String
@State private var isDeposit: Bool
@State private var isRecurring: Bool
@State private var isAccount: Bool
@State private var recurringAmount: String
@State private var interestRate: String
@State private var isLoading = false
@State private var showCloseConfirm = false
init(isPresented: Binding<Bool>, category: SavingsCategory, onSaved: @escaping () async -> Void) {
self._isPresented = isPresented
self.category = category
self.onSaved = onSaved
self._name = State(initialValue: category.name)
self._isDeposit = State(initialValue: category.isDeposit == true)
self._isRecurring = State(initialValue: category.isRecurring == true)
self._isAccount = State(initialValue: category.isAccount == true)
let ra = category.recurringAmount
self._recurringAmount = State(initialValue: ra != nil ? String(format: "%.0f", ra!) : "")
let ir = category.interestRate
self._interestRate = State(initialValue: ir != nil ? String(format: "%.1f", ir!) : "")
}
var body: some View {
ZStack {
Color(hex: "0a0a1a").ignoresSafeArea()
VStack(spacing: 0) {
RoundedRectangle(cornerRadius: 3).fill(Color.white.opacity(0.2)).frame(width: 40, height: 4).padding(.top, 12)
HStack {
Button("Отмена") { isPresented = false }.foregroundColor(Color(hex: "8888aa"))
Spacer()
Text("Редактировать категорию").font(.headline).foregroundColor(.white)
Spacer()
Button(action: save) {
if isLoading { ProgressView().tint(Color(hex: "0D9488")).scaleEffect(0.8) }
else { Text("Сохранить").foregroundColor(name.isEmpty ? Color(hex: "8888aa") : Color(hex: "0D9488")).fontWeight(.semibold) }
}.disabled(name.isEmpty || isLoading)
}
.padding(.horizontal, 20).padding(.vertical, 16)
Divider().background(Color.white.opacity(0.1))
ScrollView {
VStack(spacing: 16) {
fieldLabel("Название") {
TextField("Например: На машину", text: $name)
.foregroundColor(.white).padding(14)
.background(RoundedRectangle(cornerRadius: 12).fill(Color.white.opacity(0.07)))
}
VStack(alignment: .leading, spacing: 8) {
Label("Тип", systemImage: "tag.fill").font(.caption).foregroundColor(Color(hex: "8888aa"))
HStack(spacing: 8) {
TypeButton(label: "💰 Накопление", selected: !isDeposit && !isRecurring && !isAccount) { isDeposit = false; isRecurring = false; isAccount = false }
TypeButton(label: "🏦 Вклад", selected: isDeposit) { isDeposit = true; isRecurring = false; isAccount = false }
}
HStack(spacing: 8) {
TypeButton(label: "🔄 Регулярные", selected: isRecurring) { isDeposit = false; isRecurring = true; isAccount = false }
TypeButton(label: "🏧 Счёт", selected: isAccount) { isDeposit = false; isRecurring = false; isAccount = true }
}
}
if isRecurring {
fieldLabel("Сумма / мес. (₽)") {
TextField("0", text: $recurringAmount).keyboardType(.decimalPad)
.foregroundColor(.white).padding(14)
.background(RoundedRectangle(cornerRadius: 12).fill(Color.white.opacity(0.07)))
}
}
if isDeposit {
fieldLabel("Ставка (%)") {
TextField("0.0", text: $interestRate).keyboardType(.decimalPad)
.foregroundColor(.white).padding(14)
.background(RoundedRectangle(cornerRadius: 12).fill(Color.white.opacity(0.07)))
}
}
// Close / Restore
Button(action: { showCloseConfirm = true }) {
HStack {
Image(systemName: category.isClosed == true ? "arrow.uturn.backward" : "checkmark.seal")
Text(category.isClosed == true ? "Восстановить" : "Закрыть категорию")
}
.foregroundColor(category.isClosed == true ? Color(hex: "0D9488") : Color(hex: "ff4757"))
.frame(maxWidth: .infinity).padding(14)
.background(RoundedRectangle(cornerRadius: 12).fill(Color.white.opacity(0.05)))
}
}.padding(20)
}
}
}
.confirmationDialog(
category.isClosed == true ? "Восстановить категорию?" : "Закрыть категорию?",
isPresented: $showCloseConfirm,
titleVisibility: .visible
) {
Button(category.isClosed == true ? "Восстановить" : "Закрыть",
role: category.isClosed == true ? .none : .destructive) {
Task { await toggleClose() }
}
Button("Отмена", role: .cancel) {}
}
}
@ViewBuilder func fieldLabel<Content: View>(_ label: String, @ViewBuilder content: () -> Content) -> some View {
VStack(alignment: .leading, spacing: 8) {
Label(label, systemImage: "pencil").font(.caption).foregroundColor(Color(hex: "8888aa"))
content()
}
}
func save() {
isLoading = true
Task {
var params: [String: Any] = ["name": name, "is_deposit": isDeposit, "is_recurring": isRecurring, "is_account": isAccount]
if isRecurring, let a = Double(recurringAmount) { params["recurring_amount"] = a }
if isDeposit, let r = Double(interestRate) { params["interest_rate"] = r }
if let body = try? JSONSerialization.data(withJSONObject: params) {
try? await APIService.shared.updateSavingsCategory(token: authManager.token, id: category.id, body: body)
}
await onSaved()
await MainActor.run { isPresented = false }
}
}
func toggleClose() async {
let params: [String: Any] = ["is_closed": !(category.isClosed == true)]
if let body = try? JSONSerialization.data(withJSONObject: params) {
try? await APIService.shared.updateSavingsCategory(token: authManager.token, id: category.id, body: body)
}
await onSaved()
await MainActor.run { isPresented = false }
}
}