# 06. Dinamik Harakatlar (Actions), Input Formalar va Holat Boshqaruvi (State Management)

> "Dinamik matn va rasmlarni ko'rsatish — bu oson. Ammo serverdan kelgan dinamik formani (kredit arizasi, pasport ma'lumotlari) mijoz kiritishi, uning validatsiyasi va xavfsiz jo'natilishi haqiqiy Senior mahoratini talab qiladi."

---

## 1. Passiv SDUI vs Interaktiv SDUI

Dastlabki SDUI tizimlari (masalan, yangiliklar tasmasi) faqat o'qish (Read-Only) uchun mo'ljallangan edi. Zamonaviy FinTech va E-Commerce ilovalarda esa interaktiv formalar talab qilinadi:
* Foydalanuvchi kiritadigan matn maydonlari (`text_input`, `secure_input`).
* Tanlov elementlari (`dropdown`, `radio_group`, `checkbox`).
* Kommutatorlar (`toggle_switch`).

### Oltin Qoida: Network Latency vs UX
Agar foydalanuvchi har bir harfni yozganda serverga "shu to'g'rimi?" deb so'rov yuborilsa, harflar kechikib (lag) paydo bo'ladi.
**Xulosa:** Validatsiya **qoidalari** serverdan keladi, biroq validatsiya **tekshiruvi** va oraliq holat (State) 100% klient xotirasida (0 ms) bajariladi.

Quyidagi diagrammada ikki tomonlama bog'lanish (Two-Way Binding) zanjiri tasvirlangan:

```mermaid
flowchart LR
    ServerSchema["Server JSON Schema\n(Fields & Validation Rules)"] --> FormStore["Client FormStateStore\n(In-Memory Values & Errors)"]
    FormStore <-->|"Two-Way Binding"| SwiftUIView["SwiftUI Dynamic Form\n(TextField, Toggle, Dropdown)"]
    
    UserAction["Foydalanuvchi 'Yuborish'ni bosdi"] --> LocalValidator["Local Validation Engine\n(Regex, Required, Length)"]
    LocalValidator -->|"Xatolik bo'lsa"| ErrorDisplay["Qizil Ogohlantirishlar (0 ms)"]
    LocalValidator -->|"Hammasi to'g'ri"| NetworkSubmit["POST /api/v1/submit\n(JSON Payload)"]
    NetworkSubmit --> ServerResponse["Server Yangi Ekranni Qaytaradi"]

    style FormStore fill:#131720,stroke:#bef264,stroke-width:2px
    style LocalValidator fill:#181d26,stroke:#7da2ce,stroke-width:1px
    style SwiftUIView fill:#181d26,stroke:#60a5fa,stroke-width:1px
```

---

## 2. Serverdan Keladigan Dinamik Validatsiya Qoidalari

Server maydon bilan birga uning qoidalarini ham JSON da taqdim etadi:

```json
{
  "id": "phone_input_field",
  "type": "text_input",
  "props": {
    "label": "Telefon raqamingiz",
    "placeholder": "+998 90 123 45 67",
    "keyboardType": "phonePad",
    "stateKey": "user_phone"
  },
  "validations": [
    {
      "rule": "required",
      "errorMessage": "Telefon raqami kiritilishi shart"
    },
    {
      "rule": "regex",
      "pattern": "^\\+998[0-9]{9}$",
      "errorMessage": "Format: +998XXXXXXXXX ko'rinishida bo'lsin"
    }
  ]
}
```

---

## 3. Klientdagi Holat Markazi (FormStateStore)

Foydalanuvchi kiritgan barcha maydon qiymatlarini bitta xavfsiz xotirada saqlovchi va validatsiyani nazorat qiluvchi reaktiv sinf:

```swift
import SwiftUI

@MainActor
@Observable
public final class FormStateStore {
    // Har bir maydonning joriy matni: ["user_phone": "+998901234567"]
    public var values: [String: String] = [:]
    
    // Xatoliklar xaritasi: ["user_phone": "Format xato"]
    public var errors: [String: String] = [:]
    
    // Forma yuborilish holati
    public var isSubmitting: Bool = false
    
    public init() {}
    
    public func setValue(_ value: String, for key: String) {
        values[key] = value
        // Qiymat o'zgarganda xatolikni tozalaymiz
        errors.removeValue(forKey: key)
    }
    
    public func validate(key: String, rules: [ValidationRule]) -> Bool {
        let text = values[key] ?? ""
        
        for rule in rules {
            switch rule.type {
            case .required:
                if text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
                    errors[key] = rule.errorMessage
                    return false
                }
            case .regex(let pattern):
                let predicate = NSPredicate(format: "SELF MATCHES %@", pattern)
                if !predicate.evaluate(with: text) {
                    errors[key] = rule.errorMessage
                    return false
                }
            case .minLength(let min):
                if text.count < min {
                    errors[key] = rule.errorMessage
                    return false
                }
            }
        }
        
        errors.removeValue(forKey: key)
        return true
    }
    
    /// PCI-DSS Xavfsizlik talabi: Maxfiy ma'lumotlarni tozalash
    public func clearSensitiveData() {
        values.removeAll()
        errors.removeAll()
        isSubmitting = false
    }
}

public struct ValidationRule: Sendable {
    public enum RuleType: Sendable {
        case required
        case regex(pattern: String)
        case minLength(count: Int)
    }
    
    public let type: RuleType
    public let errorMessage: String
}
```

---

## 4. Dinamik TextField Komponenti

SwiftUI da ushbu holat bilan ikki tomonlama bog'langan (two-way binding) matn kiritish komponenti:

```swift
import SwiftUI

public struct SDUITextFieldView: View {
    public let label: String
    public let placeholder: String
    public let stateKey: String
    public let rules: [ValidationRule]
    @Bindable public var formStore: FormStateStore
    
    public var body: some View {
        VStack(alignment: .leading, spacing: 6) {
            Text(label)
                .font(.caption.bold())
                .foregroundColor(.secondary)
            
            TextField(
                placeholder,
                text: Binding(
                    get: { formStore.values[stateKey] ?? "" },
                    set: { formStore.setValue($0, for: stateKey) }
                )
            )
            .textFieldStyle(.plain)
            .padding(12)
            .background(Color(uiColor: .secondarySystemBackground))
            .cornerRadius(8)
            .overlay(
                RoundedRectangle(cornerRadius: 8)
                    .stroke(formStore.errors[stateKey] != nil ? Color.red : Color.clear, lineWidth: 1)
            )
            
            // Xatolik xabari
            if let error = formStore.errors[stateKey] {
                Text(error)
                    .font(.caption2)
                    .foregroundColor(.red)
                    .transition(.opacity)
            }
        }
        .padding(.horizontal, 16)
        .padding(.vertical, 8)
    }
}
```

---

## 5. Dinamik Submit Oqimi (Form Submission Workflow)

Foydalanuvchi "Arizani topshirish" tugmasini bosganda ketma-ketlik:

```mermaid
sequenceDiagram
    autonumber
    participant User as Foydalanuvchi
    participant UI as Dynamic Form (SwiftUI)
    participant Store as FormStateStore
    participant API as Backend API

    User->>UI: "Ariza topshirish" tugmasini bosadi
    UI->>Store: Barcha maydonlarni tekshirish (Local Validation)
    
    alt Xatolik aniqlansa
        Store-->>UI: errors xaritasi to'ldiriladi
        UI-->>User: Qizil xatoliklar bir zumda chiqadi (0 ms)
    else Barcha maydonlar to'g'ri
        UI->>Store: isSubmitting = true (Spinner yoqiladi)
        UI->>API: POST /api/v1/loan/apply { values }
        API-->>UI: 200 OK + Yangi Muvaffaqiyat Ekrani (SDUI)
        UI->>Store: clearSensitiveData() (Xotira tozalanadi)
        UI-->>User: Muvaffaqiyat ekrani ko'rsatiladi!
    end
```

---

## 6. Interaktiv Savol-Javob (Self-Check Quiz)

<details>
<summary><b>1-Savol: Nega maxfiy ma'lumotlar (masalan, karta CVV kodi yoki pasport seriyasi) kiritilayotganda FormStateStore'ni diskka yozish (persistence) qat'iyan taqiqlanadi?</b> (Yechimni ko'rish uchun bosing)</summary>

**Tahlil va Yechim:**
Xavfsizlik va xalqaro PCI-DSS standartlari talabi tufayli. FormStateStore faqat operativ xotirada (RAM) saqlanishi kerak. Agar ilova backgroundga o'tsa yoki forma muvaffaqiyatli jo'natilsa, maxfiy kalitlar xotiradan butunlay tozalanishi (`formStore.clearSensitiveData()`) shart. Diskka yozilsa, qurilma zaxira nusxasi (iTunes/iCloud Backup) orqali ma'lumotlar oshkor bo'lishi mumkin.
</details>

<details>
<summary><b>2-Savol: Foydalanuvchi forma to'ldirib bo'lgach, internet o'chib qolsa, SDUI qanday harakat qilishi lozim?</b> (Yechimni ko'rish uchun bosing)</summary>

**Tahlil va Yechim:**
Tugma ustidagi yuklanish indikatori (Loading Spinner) to'xtatilib, "Internet aloqasi yo'q. Qaytadan urinib ko'ring" degan alert yoki snackbar ko'rsatilishi kerak. Kiritilgan ma'lumotlar esa yo'qolib ketmasdan maydonlarda saqlanib turishi shart.
</details>

---

## 7. Amaliy Topshiriq (Senior Challenge)

`FormStateStore` ga yangi `dependent_validation` qoidasini qo'shing:
* **Shart:** Agar `delivery_type` dropdown maydoni `"courier"` ga teng bo'lsa, `address_input` maydoni majburiy (`required`) bo'lsin. Agar `"pickup"` (o'zi olib ketish) bo'lsa, manzil maydoni ixtiyoriy bo'lsin.
* Ushbu dinamik bog'liqlikni klientda 0 ms kechikish bilan ishlovchi reaktiv mantiq orqali amalga oshiring!
