This commit is contained in:
Trey t
2025-11-08 16:02:01 -06:00
parent 97eed0eee9
commit 7dce211681
17 changed files with 1757 additions and 56 deletions

View File

@@ -11,21 +11,21 @@ struct AllTasksView: View {
@State private var showEditTask = false
@State private var selectedTaskForEdit: TaskDetail?
@State private var selectedTaskForComplete: TaskDetail?
private var hasNoTasks: Bool {
guard let response = tasksResponse else { return true }
return response.columns.allSatisfy { $0.tasks.isEmpty }
}
private var hasTasks: Bool {
!hasNoTasks
}
var body: some View {
ZStack {
Color(.systemGroupedBackground)
.ignoresSafeArea()
if isLoadingTasks {
ProgressView()
} else if let error = tasksError {
@@ -37,20 +37,20 @@ struct AllTasksView: View {
// Empty state with big button
VStack(spacing: 24) {
Spacer()
Image(systemName: "checklist")
.font(.system(size: 64))
.foregroundStyle(.blue.opacity(0.6))
Text("No tasks yet")
.font(.title2)
.fontWeight(.semibold)
Text("Create your first task to get started")
.font(.body)
.foregroundColor(.secondary)
.multilineTextAlignment(.center)
Button(action: {
showAddTask = true
}) {
@@ -66,13 +66,13 @@ struct AllTasksView: View {
.controlSize(.large)
.padding(.horizontal, 48)
.disabled(residenceViewModel.myResidences?.residences.isEmpty ?? true)
if residenceViewModel.myResidences?.residences.isEmpty ?? true {
Text("Add a property first from the Residences tab")
.font(.caption)
.foregroundColor(.red)
}
Spacer()
}
.padding()
@@ -175,13 +175,13 @@ struct AllTasksView: View {
residenceViewModel.loadMyResidences()
}
}
private func loadAllTasks() {
guard let token = TokenStorage.shared.getToken() else { return }
isLoadingTasks = true
tasksError = nil
let taskApi = TaskApi(client: ApiClient_iosKt.createHttpClient())
taskApi.getTasks(token: token, days: 30) { result, error in
if let successResult = result as? ApiResultSuccess<TaskColumnsResponse> {
@@ -208,16 +208,16 @@ struct DynamicTaskColumnView: View {
let onCompleteTask: (TaskDetail) -> Void
let onArchiveTask: (Int32) -> Void
let onUnarchiveTask: (Int32) -> Void
// Get icon from API response, with fallback
private var columnIcon: String {
column.icons["ios"] ?? "list.bullet"
}
private var columnColor: Color {
Color(hex: column.color) ?? .primary
}
var body: some View {
VStack(spacing: 0) {
ScrollView {
@@ -227,13 +227,13 @@ struct DynamicTaskColumnView: View {
Image(systemName: columnIcon)
.font(.headline)
.foregroundColor(columnColor)
Text(column.displayName)
.font(.headline)
.foregroundColor(columnColor)
Spacer()
Text("\(column.count)")
.font(.caption)
.fontWeight(.semibold)
@@ -243,13 +243,13 @@ struct DynamicTaskColumnView: View {
.background(columnColor)
.cornerRadius(12)
}
if column.tasks.isEmpty {
VStack(spacing: 8) {
Image(systemName: columnIcon)
.font(.system(size: 40))
.foregroundColor(columnColor.opacity(0.3))
Text("No tasks")
.font(.caption)
.foregroundColor(.secondary)
@@ -288,7 +288,7 @@ struct DynamicTaskCard: View {
let onComplete: () -> Void
let onArchive: () -> Void
let onUnarchive: () -> Void
var body: some View {
VStack(alignment: .leading, spacing: 12) {
HStack {
@@ -296,39 +296,41 @@ struct DynamicTaskCard: View {
Text(task.title)
.font(.headline)
.foregroundColor(.primary)
if let status = task.status {
StatusBadge(status: status.name)
}
}
Spacer()
PriorityBadge(priority: task.priority.name)
}
if let description = task.description_, !description.isEmpty {
Text(description)
.font(.subheadline)
.foregroundColor(.secondary)
.lineLimit(2)
}
HStack {
Label(task.frequency.displayName, systemImage: "repeat")
.font(.caption)
.foregroundColor(.secondary)
Spacer()
Label(formatDate(task.dueDate), systemImage: "calendar")
.font(.caption)
.foregroundColor(.secondary)
if let due_date = task.dueDate {
Label(formatDate(due_date), systemImage: "calendar")
.font(.caption)
.foregroundColor(.secondary)
}
}
if task.completions.count > 0 {
Divider()
HStack {
Image(systemName: "checkmark.circle")
.foregroundColor(.green)
@@ -337,7 +339,7 @@ struct DynamicTaskCard: View {
.foregroundColor(.secondary)
}
}
// Render buttons based on buttonTypes array
VStack(spacing: 8) {
ForEach(Array(buttonTypes.enumerated()), id: \.offset) { index, buttonType in
@@ -350,7 +352,7 @@ struct DynamicTaskCard: View {
.cornerRadius(12)
.shadow(color: Color.black.opacity(0.05), radius: 3, x: 0, y: 2)
}
private func formatDate(_ dateString: String) -> String {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
@@ -360,7 +362,7 @@ struct DynamicTaskCard: View {
}
return dateString
}
@ViewBuilder
private func renderButton(for buttonType: String) -> some View {
switch buttonType {
@@ -436,7 +438,7 @@ extension View {
struct RoundedCorner: Shape {
var radius: CGFloat = .infinity
var corners: UIRectCorner = .allCorners
func path(in rect: CGRect) -> Path {
let path = UIBezierPath(
roundedRect: rect,
@@ -505,7 +507,7 @@ extension Color {
default:
return nil
}
self.init(
.sRGB,
red: Double(r) / 255,

View File

@@ -31,7 +31,7 @@ struct EditTaskView: View {
_selectedFrequency = State(initialValue: task.frequency)
_selectedPriority = State(initialValue: task.priority)
_selectedStatus = State(initialValue: task.status)
_dueDate = State(initialValue: task.dueDate)
_dueDate = State(initialValue: task.dueDate ?? "")
_estimatedCost = State(initialValue: task.estimatedCost ?? "")
}