diff options
Diffstat (limited to 'Hutch/Views/Tickets/TrackerListViewModel.swift')
| -rw-r--r-- | Hutch/Views/Tickets/TrackerListViewModel.swift | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/Hutch/Views/Tickets/TrackerListViewModel.swift b/Hutch/Views/Tickets/TrackerListViewModel.swift index 31c07d7..f18bb7b 100644 --- a/Hutch/Views/Tickets/TrackerListViewModel.swift +++ b/Hutch/Views/Tickets/TrackerListViewModel.swift @@ -11,6 +11,18 @@ private struct TrackersPage: Decodable, Sendable { let cursor: String? } +private struct UpdateTrackerResponse: Decodable, Sendable { + let updateTracker: TrackerSummary +} + +private struct DeleteTrackerResponse: Decodable, Sendable { + let deleteTracker: DeletedTracker +} + +private struct DeletedTracker: Decodable, Sendable { + let id: Int +} + // MARK: - View Model @Observable @@ -75,6 +87,28 @@ final class TrackerListViewModel { } """ + private static let updateTrackerMutation = """ + mutation updateTracker($id: Int!, $input: TrackerInput!) { + updateTracker(id: $id, input: $input) { + id + rid + name + description + visibility + updated + owner { canonicalName } + } + } + """ + + private static let deleteTrackerMutation = """ + mutation deleteTracker($id: Int!) { + deleteTracker(id: $id) { + id + } + } + """ + // MARK: - Public API func loadTrackers() async { @@ -155,6 +189,84 @@ final class TrackerListViewModel { } } + func updateTracker( + _ tracker: TrackerSummary, + name: String, + description: String, + visibility: Visibility + ) async -> TrackerSummary? { + guard !isCreatingTracker else { return nil } + + let trimmedName = name.trimmingCharacters(in: .whitespacesAndNewlines) + guard !trimmedName.isEmpty else { + error = "Enter a tracker name." + return nil + } + + isCreatingTracker = true + error = nil + defer { isCreatingTracker = false } + + let trimmedDescription = description.trimmingCharacters(in: .whitespacesAndNewlines) + let input: [String: any Sendable] = [ + "name": trimmedName, + "description": trimmedDescription.isEmpty ? "" : trimmedDescription, + "visibility": visibility.rawValue + ] + + do { + let result = try await client.execute( + service: .todo, + query: Self.updateTrackerMutation, + variables: [ + "id": tracker.id, + "input": input + ], + responseType: UpdateTrackerResponse.self + ) + applyTrackerUpdate(result.updateTracker) + return result.updateTracker + } catch { + self.error = "Couldn’t update the tracker. \(error.userFacingMessage)" + return nil + } + } + + func deleteTracker(_ tracker: TrackerSummary) async -> Bool { + guard !isCreatingTracker else { return false } + + isCreatingTracker = true + error = nil + defer { isCreatingTracker = false } + + do { + _ = try await client.execute( + service: .todo, + query: Self.deleteTrackerMutation, + variables: ["id": tracker.id], + responseType: DeleteTrackerResponse.self + ) + trackers.removeAll { $0.id == tracker.id } + await loadTrackers() + return true + } catch { + self.error = "Couldn’t delete the tracker. \(error.userFacingMessage)" + return false + } + } + + func applyTrackerUpdate(_ tracker: TrackerSummary) { + if let index = trackers.firstIndex(where: { $0.id == tracker.id }) { + trackers[index] = tracker + } else { + trackers.insert(tracker, at: 0) + } + } + + func applyTrackerDeletion(_ tracker: TrackerSummary) { + trackers.removeAll { $0.id == tracker.id } + } + // MARK: - Private private func fetchPage(cursor: String?) async throws -> TrackersPage { |
