wip
This commit is contained in:
@@ -22,11 +22,6 @@ struct AddTaskView: View {
|
||||
// Validation errors
|
||||
@State private var titleError: String = ""
|
||||
|
||||
// Picker states
|
||||
@State private var showCategoryPicker = false
|
||||
@State private var showFrequencyPicker = false
|
||||
@State private var showPriorityPicker = false
|
||||
@State private var showStatusPicker = false
|
||||
|
||||
enum Field {
|
||||
case title, description, intervalDays, estimatedCost
|
||||
@@ -34,231 +29,110 @@ struct AddTaskView: View {
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
ZStack {
|
||||
Color(.systemGroupedBackground)
|
||||
.ignoresSafeArea()
|
||||
if lookupsManager.isLoading {
|
||||
VStack(spacing: 16) {
|
||||
ProgressView()
|
||||
Text("Loading lookup data...")
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
} else {
|
||||
Form {
|
||||
Section(header: Text("Task Details")) {
|
||||
TextField("Title", text: $title)
|
||||
.focused($focusedField, equals: .title)
|
||||
|
||||
if lookupsManager.isLoading {
|
||||
VStack(spacing: 16) {
|
||||
ProgressView()
|
||||
Text("Loading lookup data...")
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
} else {
|
||||
ScrollView {
|
||||
VStack(spacing: 24) {
|
||||
// Task Information Section
|
||||
VStack(alignment: .leading, spacing: 16) {
|
||||
Text("Task Information")
|
||||
.font(.headline)
|
||||
.foregroundColor(.blue)
|
||||
|
||||
// Title Field
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Text("Task Title *")
|
||||
.font(.subheadline)
|
||||
.foregroundColor(.secondary)
|
||||
|
||||
TextField("e.g., Clean gutters", text: $title)
|
||||
.textFieldStyle(.roundedBorder)
|
||||
.focused($focusedField, equals: .title)
|
||||
|
||||
if !titleError.isEmpty {
|
||||
Text(titleError)
|
||||
.font(.caption)
|
||||
.foregroundColor(.red)
|
||||
}
|
||||
}
|
||||
|
||||
// Description Field
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Text("Description (Optional)")
|
||||
.font(.subheadline)
|
||||
.foregroundColor(.secondary)
|
||||
|
||||
TextEditor(text: $description)
|
||||
.frame(height: 100)
|
||||
.padding(8)
|
||||
.background(Color(.systemBackground))
|
||||
.cornerRadius(8)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 8)
|
||||
.stroke(Color.gray.opacity(0.3), lineWidth: 1)
|
||||
)
|
||||
}
|
||||
|
||||
// Category Picker
|
||||
PickerField(
|
||||
label: "Category *",
|
||||
selectedItem: selectedCategory?.name ?? "Select Category",
|
||||
showPicker: $showCategoryPicker
|
||||
)
|
||||
|
||||
// Frequency Picker
|
||||
PickerField(
|
||||
label: "Frequency *",
|
||||
selectedItem: selectedFrequency?.displayName ?? "Select Frequency",
|
||||
showPicker: $showFrequencyPicker
|
||||
)
|
||||
|
||||
// Interval Days (if applicable)
|
||||
if selectedFrequency?.name != "once" {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Text("Custom Interval (days, optional)")
|
||||
.font(.subheadline)
|
||||
.foregroundColor(.secondary)
|
||||
|
||||
TextField("Leave empty for default", text: $intervalDays)
|
||||
.textFieldStyle(.roundedBorder)
|
||||
.keyboardType(.numberPad)
|
||||
.focused($focusedField, equals: .intervalDays)
|
||||
}
|
||||
}
|
||||
|
||||
// Priority Picker
|
||||
PickerField(
|
||||
label: "Priority *",
|
||||
selectedItem: selectedPriority?.displayName ?? "Select Priority",
|
||||
showPicker: $showPriorityPicker
|
||||
)
|
||||
|
||||
// Status Picker
|
||||
PickerField(
|
||||
label: "Status *",
|
||||
selectedItem: selectedStatus?.displayName ?? "Select Status",
|
||||
showPicker: $showStatusPicker
|
||||
)
|
||||
|
||||
// Due Date Picker
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Text("Due Date *")
|
||||
.font(.subheadline)
|
||||
.foregroundColor(.secondary)
|
||||
|
||||
DatePicker("", selection: $dueDate, displayedComponents: .date)
|
||||
.datePickerStyle(.compact)
|
||||
.labelsHidden()
|
||||
}
|
||||
|
||||
// Estimated Cost Field
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Text("Estimated Cost (Optional)")
|
||||
.font(.subheadline)
|
||||
.foregroundColor(.secondary)
|
||||
|
||||
TextField("e.g., 150.00", text: $estimatedCost)
|
||||
.textFieldStyle(.roundedBorder)
|
||||
.keyboardType(.decimalPad)
|
||||
.focused($focusedField, equals: .estimatedCost)
|
||||
}
|
||||
}
|
||||
|
||||
// Error Message
|
||||
if let errorMessage = viewModel.errorMessage {
|
||||
HStack {
|
||||
Image(systemName: "exclamationmark.triangle.fill")
|
||||
.foregroundColor(.red)
|
||||
|
||||
Text(errorMessage)
|
||||
.font(.caption)
|
||||
.foregroundColor(.red)
|
||||
|
||||
Spacer()
|
||||
|
||||
Button(action: viewModel.clearError) {
|
||||
Image(systemName: "xmark.circle.fill")
|
||||
.foregroundColor(.red)
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
.background(Color.red.opacity(0.1))
|
||||
.cornerRadius(8)
|
||||
}
|
||||
|
||||
// Submit Button
|
||||
Button(action: submitForm) {
|
||||
HStack {
|
||||
if viewModel.isLoading {
|
||||
ProgressView()
|
||||
.progressViewStyle(CircularProgressViewStyle(tint: .white))
|
||||
} else {
|
||||
Text("Create Task")
|
||||
.fontWeight(.semibold)
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding()
|
||||
.background(viewModel.isLoading ? Color.gray : Color.blue)
|
||||
.foregroundColor(.white)
|
||||
.cornerRadius(12)
|
||||
}
|
||||
.disabled(viewModel.isLoading)
|
||||
if !titleError.isEmpty {
|
||||
Text(titleError)
|
||||
.font(.caption)
|
||||
.foregroundColor(.red)
|
||||
}
|
||||
|
||||
TextField("Description (optional)", text: $description, axis: .vertical)
|
||||
.lineLimit(3...6)
|
||||
.focused($focusedField, equals: .description)
|
||||
}
|
||||
|
||||
Section(header: Text("Category")) {
|
||||
Picker("Category", selection: $selectedCategory) {
|
||||
Text("Select Category").tag(nil as TaskCategory?)
|
||||
ForEach(lookupsManager.taskCategories, id: \.id) { category in
|
||||
Text(category.name.capitalized).tag(category as TaskCategory?)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Section(header: Text("Scheduling")) {
|
||||
Picker("Frequency", selection: $selectedFrequency) {
|
||||
Text("Select Frequency").tag(nil as TaskFrequency?)
|
||||
ForEach(lookupsManager.taskFrequencies, id: \.id) { frequency in
|
||||
Text(frequency.displayName).tag(frequency as TaskFrequency?)
|
||||
}
|
||||
}
|
||||
|
||||
if selectedFrequency?.name != "once" {
|
||||
TextField("Custom Interval (days, optional)", text: $intervalDays)
|
||||
.keyboardType(.numberPad)
|
||||
.focused($focusedField, equals: .intervalDays)
|
||||
}
|
||||
|
||||
DatePicker("Due Date", selection: $dueDate, displayedComponents: .date)
|
||||
}
|
||||
|
||||
Section(header: Text("Priority & Status")) {
|
||||
Picker("Priority", selection: $selectedPriority) {
|
||||
Text("Select Priority").tag(nil as TaskPriority?)
|
||||
ForEach(lookupsManager.taskPriorities, id: \.id) { priority in
|
||||
Text(priority.displayName).tag(priority as TaskPriority?)
|
||||
}
|
||||
}
|
||||
|
||||
Picker("Status", selection: $selectedStatus) {
|
||||
Text("Select Status").tag(nil as TaskStatus?)
|
||||
ForEach(lookupsManager.taskStatuses, id: \.id) { status in
|
||||
Text(status.displayName).tag(status as TaskStatus?)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Section(header: Text("Cost")) {
|
||||
TextField("Estimated Cost (optional)", text: $estimatedCost)
|
||||
.keyboardType(.decimalPad)
|
||||
.focused($focusedField, equals: .estimatedCost)
|
||||
}
|
||||
|
||||
if let errorMessage = viewModel.errorMessage {
|
||||
Section {
|
||||
Text(errorMessage)
|
||||
.foregroundColor(.red)
|
||||
.font(.caption)
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationTitle("Add Task")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarLeading) {
|
||||
Button("Cancel") {
|
||||
.navigationTitle("Add Task")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarLeading) {
|
||||
Button("Cancel") {
|
||||
isPresented = false
|
||||
}
|
||||
}
|
||||
|
||||
ToolbarItem(placement: .navigationBarTrailing) {
|
||||
Button("Save") {
|
||||
submitForm()
|
||||
}
|
||||
.disabled(viewModel.isLoading)
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
setDefaults()
|
||||
}
|
||||
.onChange(of: viewModel.taskCreated) { created in
|
||||
if created {
|
||||
isPresented = false
|
||||
}
|
||||
}
|
||||
}
|
||||
.sheet(isPresented: $showCategoryPicker) {
|
||||
LookupPickerView(
|
||||
title: "Select Category",
|
||||
items: lookupsManager.taskCategories.map { LookupItem(id: $0.id, name: $0.name, displayName: $0.name) },
|
||||
selectedId: selectedCategory?.id,
|
||||
isPresented: $showCategoryPicker,
|
||||
onSelect: { id in
|
||||
selectedCategory = lookupsManager.taskCategories.first { $0.id == id }
|
||||
}
|
||||
)
|
||||
}
|
||||
.sheet(isPresented: $showFrequencyPicker) {
|
||||
LookupPickerView(
|
||||
title: "Select Frequency",
|
||||
items: lookupsManager.taskFrequencies.map { LookupItem(id: $0.id, name: $0.name, displayName: $0.displayName) },
|
||||
selectedId: selectedFrequency?.id,
|
||||
isPresented: $showFrequencyPicker,
|
||||
onSelect: { id in
|
||||
selectedFrequency = lookupsManager.taskFrequencies.first { $0.id == id }
|
||||
}
|
||||
)
|
||||
}
|
||||
.sheet(isPresented: $showPriorityPicker) {
|
||||
LookupPickerView(
|
||||
title: "Select Priority",
|
||||
items: lookupsManager.taskPriorities.map { LookupItem(id: $0.id, name: $0.name, displayName: $0.displayName) },
|
||||
selectedId: selectedPriority?.id,
|
||||
isPresented: $showPriorityPicker,
|
||||
onSelect: { id in
|
||||
selectedPriority = lookupsManager.taskPriorities.first { $0.id == id }
|
||||
}
|
||||
)
|
||||
}
|
||||
.sheet(isPresented: $showStatusPicker) {
|
||||
LookupPickerView(
|
||||
title: "Select Status",
|
||||
items: lookupsManager.taskStatuses.map { LookupItem(id: $0.id, name: $0.name, displayName: $0.displayName) },
|
||||
selectedId: selectedStatus?.id,
|
||||
isPresented: $showStatusPicker,
|
||||
onSelect: { id in
|
||||
selectedStatus = lookupsManager.taskStatuses.first { $0.id == id }
|
||||
}
|
||||
)
|
||||
}
|
||||
.onAppear {
|
||||
setDefaults()
|
||||
}
|
||||
.onChange(of: viewModel.taskCreated) { created in
|
||||
if created {
|
||||
isPresented = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,79 +227,6 @@ struct AddTaskView: View {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Supporting Views
|
||||
struct PickerField: View {
|
||||
let label: String
|
||||
let selectedItem: String
|
||||
@Binding var showPicker: Bool
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Text(label)
|
||||
.font(.subheadline)
|
||||
.foregroundColor(.secondary)
|
||||
|
||||
Button(action: {
|
||||
showPicker = true
|
||||
}) {
|
||||
HStack {
|
||||
Text(selectedItem)
|
||||
.foregroundColor(selectedItem.contains("Select") ? .gray : .primary)
|
||||
Spacer()
|
||||
Image(systemName: "chevron.down")
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
.padding()
|
||||
.background(Color(.systemBackground))
|
||||
.cornerRadius(8)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct LookupItem: Identifiable {
|
||||
let id: Int32
|
||||
let name: String
|
||||
let displayName: String
|
||||
}
|
||||
|
||||
struct LookupPickerView: View {
|
||||
let title: String
|
||||
let items: [LookupItem]
|
||||
let selectedId: Int32?
|
||||
@Binding var isPresented: Bool
|
||||
let onSelect: (Int32) -> Void
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
List(items) { item in
|
||||
Button(action: {
|
||||
onSelect(item.id)
|
||||
isPresented = false
|
||||
}) {
|
||||
HStack {
|
||||
Text(item.displayName)
|
||||
.foregroundColor(.primary)
|
||||
Spacer()
|
||||
if selectedId == item.id {
|
||||
Image(systemName: "checkmark")
|
||||
.foregroundColor(.blue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationTitle(title)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarTrailing) {
|
||||
Button("Done") {
|
||||
isPresented = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
AddTaskView(residenceId: 1, isPresented: .constant(true))
|
||||
|
||||
163
iosApp/iosApp/Task/EditTaskView.swift
Normal file
163
iosApp/iosApp/Task/EditTaskView.swift
Normal file
@@ -0,0 +1,163 @@
|
||||
import SwiftUI
|
||||
import ComposeApp
|
||||
|
||||
struct EditTaskView: View {
|
||||
let task: TaskDetail
|
||||
@Binding var isPresented: Bool
|
||||
|
||||
@StateObject private var viewModel = TaskViewModel()
|
||||
@StateObject private var lookupsManager = LookupsManager.shared
|
||||
|
||||
@State private var title: String
|
||||
@State private var description: String
|
||||
@State private var selectedCategory: TaskCategory?
|
||||
@State private var selectedFrequency: TaskFrequency?
|
||||
@State private var selectedPriority: TaskPriority?
|
||||
@State private var selectedStatus: TaskStatus?
|
||||
@State private var dueDate: String
|
||||
@State private var estimatedCost: String
|
||||
|
||||
@State private var showAlert = false
|
||||
@State private var alertMessage = ""
|
||||
|
||||
init(task: TaskDetail, isPresented: Binding<Bool>) {
|
||||
self.task = task
|
||||
self._isPresented = isPresented
|
||||
|
||||
// Initialize state from task
|
||||
_title = State(initialValue: task.title)
|
||||
_description = State(initialValue: task.description ?? "")
|
||||
_selectedCategory = State(initialValue: task.category)
|
||||
_selectedFrequency = State(initialValue: task.frequency)
|
||||
_selectedPriority = State(initialValue: task.priority)
|
||||
_selectedStatus = State(initialValue: task.status)
|
||||
_dueDate = State(initialValue: task.dueDate)
|
||||
_estimatedCost = State(initialValue: task.estimatedCost ?? "")
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
Form {
|
||||
Section(header: Text("Task Details")) {
|
||||
TextField("Title", text: $title)
|
||||
|
||||
TextField("Description", text: $description, axis: .vertical)
|
||||
.lineLimit(3...6)
|
||||
}
|
||||
|
||||
Section(header: Text("Category")) {
|
||||
Picker("Category", selection: $selectedCategory) {
|
||||
ForEach(lookupsManager.taskCategories, id: \.id) { category in
|
||||
Text(category.name.capitalized).tag(category as TaskCategory?)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Section(header: Text("Scheduling")) {
|
||||
Picker("Frequency", selection: $selectedFrequency) {
|
||||
ForEach(lookupsManager.taskFrequencies, id: \.id) { frequency in
|
||||
Text(frequency.name.capitalized).tag(frequency as TaskFrequency?)
|
||||
}
|
||||
}
|
||||
|
||||
TextField("Due Date (YYYY-MM-DD)", text: $dueDate)
|
||||
.keyboardType(.numbersAndPunctuation)
|
||||
}
|
||||
|
||||
Section(header: Text("Priority & Status")) {
|
||||
Picker("Priority", selection: $selectedPriority) {
|
||||
ForEach(lookupsManager.taskPriorities, id: \.id) { priority in
|
||||
Text(priority.name.capitalized).tag(priority as TaskPriority?)
|
||||
}
|
||||
}
|
||||
|
||||
Picker("Status", selection: $selectedStatus) {
|
||||
ForEach(lookupsManager.taskStatuses, id: \.id) { status in
|
||||
Text(status.name.capitalized).tag(status as TaskStatus?)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Section(header: Text("Cost")) {
|
||||
TextField("Estimated Cost", text: $estimatedCost)
|
||||
.keyboardType(.decimalPad)
|
||||
}
|
||||
|
||||
if let errorMessage = viewModel.errorMessage {
|
||||
Section {
|
||||
Text(errorMessage)
|
||||
.foregroundColor(.red)
|
||||
.font(.caption)
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationTitle("Edit Task")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarLeading) {
|
||||
Button("Cancel") {
|
||||
isPresented = false
|
||||
}
|
||||
}
|
||||
|
||||
ToolbarItem(placement: .navigationBarTrailing) {
|
||||
Button("Save") {
|
||||
submitForm()
|
||||
}
|
||||
.disabled(!isFormValid())
|
||||
}
|
||||
}
|
||||
.alert("Success", isPresented: $showAlert) {
|
||||
Button("OK") {
|
||||
isPresented = false
|
||||
}
|
||||
} message: {
|
||||
Text(alertMessage)
|
||||
}
|
||||
.onChange(of: viewModel.taskUpdated) { updated in
|
||||
if updated {
|
||||
alertMessage = "Task updated successfully"
|
||||
showAlert = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func isFormValid() -> Bool {
|
||||
return !title.isEmpty &&
|
||||
selectedCategory != nil &&
|
||||
selectedFrequency != nil &&
|
||||
selectedPriority != nil &&
|
||||
selectedStatus != nil &&
|
||||
!dueDate.isEmpty
|
||||
}
|
||||
|
||||
private func submitForm() {
|
||||
guard isFormValid(),
|
||||
let category = selectedCategory,
|
||||
let frequency = selectedFrequency,
|
||||
let priority = selectedPriority,
|
||||
let status = selectedStatus else {
|
||||
return
|
||||
}
|
||||
|
||||
let request = TaskCreateRequest(
|
||||
residence: task.residence,
|
||||
title: title,
|
||||
description: description.isEmpty ? nil : description,
|
||||
category: category.id,
|
||||
frequency: frequency.id,
|
||||
intervalDays: nil,
|
||||
priority: priority.id,
|
||||
status: status.id,
|
||||
dueDate: dueDate,
|
||||
estimatedCost: estimatedCost.isEmpty ? nil : estimatedCost
|
||||
)
|
||||
|
||||
viewModel.updateTask(id: task.id, request: request) { success in
|
||||
if !success {
|
||||
// Error is already set in viewModel.errorMessage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,9 @@ class TaskViewModel: ObservableObject {
|
||||
@Published var isLoading: Bool = false
|
||||
@Published var errorMessage: String?
|
||||
@Published var taskCreated: Bool = false
|
||||
@Published var taskUpdated: Bool = false
|
||||
@Published var taskCancelled: Bool = false
|
||||
@Published var taskUncancelled: Bool = false
|
||||
|
||||
// MARK: - Private Properties
|
||||
private let taskApi: TaskApi
|
||||
@@ -49,12 +52,99 @@ class TaskViewModel: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
func updateTask(id: Int32, request: TaskCreateRequest, completion: @escaping (Bool) -> Void) {
|
||||
guard let token = tokenStorage.getToken() else {
|
||||
errorMessage = "Not authenticated"
|
||||
completion(false)
|
||||
return
|
||||
}
|
||||
|
||||
isLoading = true
|
||||
errorMessage = nil
|
||||
taskUpdated = false
|
||||
|
||||
taskApi.updateTask(token: token, id: id, request: request) { result, error in
|
||||
if result is ApiResultSuccess<CustomTask> {
|
||||
self.isLoading = false
|
||||
self.taskUpdated = true
|
||||
completion(true)
|
||||
} else if let errorResult = result as? ApiResultError {
|
||||
self.errorMessage = errorResult.message
|
||||
self.isLoading = false
|
||||
completion(false)
|
||||
} else if let error = error {
|
||||
self.errorMessage = error.localizedDescription
|
||||
self.isLoading = false
|
||||
completion(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func cancelTask(id: Int32, completion: @escaping (Bool) -> Void) {
|
||||
guard let token = tokenStorage.getToken() else {
|
||||
errorMessage = "Not authenticated"
|
||||
completion(false)
|
||||
return
|
||||
}
|
||||
|
||||
isLoading = true
|
||||
errorMessage = nil
|
||||
taskCancelled = false
|
||||
|
||||
taskApi.cancelTask(token: token, id: id) { result, error in
|
||||
if result is ApiResultSuccess<TaskCancelResponse> {
|
||||
self.isLoading = false
|
||||
self.taskCancelled = true
|
||||
completion(true)
|
||||
} else if let errorResult = result as? ApiResultError {
|
||||
self.errorMessage = errorResult.message
|
||||
self.isLoading = false
|
||||
completion(false)
|
||||
} else if let error = error {
|
||||
self.errorMessage = error.localizedDescription
|
||||
self.isLoading = false
|
||||
completion(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func uncancelTask(id: Int32, completion: @escaping (Bool) -> Void) {
|
||||
guard let token = tokenStorage.getToken() else {
|
||||
errorMessage = "Not authenticated"
|
||||
completion(false)
|
||||
return
|
||||
}
|
||||
|
||||
isLoading = true
|
||||
errorMessage = nil
|
||||
taskUncancelled = false
|
||||
|
||||
taskApi.uncancelTask(token: token, id: id) { result, error in
|
||||
if result is ApiResultSuccess<TaskCancelResponse> {
|
||||
self.isLoading = false
|
||||
self.taskUncancelled = true
|
||||
completion(true)
|
||||
} else if let errorResult = result as? ApiResultError {
|
||||
self.errorMessage = errorResult.message
|
||||
self.isLoading = false
|
||||
completion(false)
|
||||
} else if let error = error {
|
||||
self.errorMessage = error.localizedDescription
|
||||
self.isLoading = false
|
||||
completion(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func clearError() {
|
||||
errorMessage = nil
|
||||
}
|
||||
|
||||
func resetState() {
|
||||
taskCreated = false
|
||||
taskUpdated = false
|
||||
taskCancelled = false
|
||||
taskUncancelled = false
|
||||
errorMessage = nil
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user