Files
timetracker/ios/TimeTracker/TimeTracker/Features/Clients/ClientsViewModel.swift
Simon Franken 39d6ea00d9 Fix iOS list response decoding to match plain-array backend responses
GET /clients and GET /projects return bare arrays, not wrapped objects.
Remove ClientListResponse and ProjectListResponse wrapper structs and
update ClientsViewModel, ProjectsViewModel, and TimerViewModel to decode
[Client] and [Project] directly.
2026-02-19 19:05:43 +01:00

87 lines
2.4 KiB
Swift

import Foundation
import SwiftUI
@MainActor
final class ClientsViewModel: ObservableObject {
@Published var clients: [Client] = []
@Published var isLoading = false
@Published var error: String?
private let apiClient = APIClient()
private let database = DatabaseService.shared
func loadClients() async {
isLoading = true
error = nil
do {
clients = try await apiClient.request(
endpoint: APIEndpoint.clients,
authenticated: true
)
try await database.saveClients(clients)
isLoading = false
} catch {
isLoading = false
self.error = error.localizedDescription
// Load from cache
clients = (try? await database.fetchClients()) ?? []
}
}
func createClient(name: String, description: String?) async {
isLoading = true
do {
let input = CreateClientInput(name: name, description: description)
try await apiClient.requestVoid(
endpoint: APIEndpoint.clients,
method: .post,
body: input,
authenticated: true
)
await loadClients()
} catch {
isLoading = false
self.error = error.localizedDescription
}
}
func updateClient(id: String, name: String, description: String?) async {
isLoading = true
do {
let input = UpdateClientInput(name: name, description: description)
try await apiClient.requestVoid(
endpoint: APIEndpoint.client(id: id),
method: .put,
body: input,
authenticated: true
)
await loadClients()
} catch {
isLoading = false
self.error = error.localizedDescription
}
}
func deleteClient(_ client: Client) async {
do {
try await apiClient.requestVoid(
endpoint: APIEndpoint.client(id: client.id),
method: .delete,
authenticated: true
)
clients.removeAll { $0.id == client.id }
} catch {
self.error = error.localizedDescription
}
}
}