// // GoalTabView.swift // HaruDanim // // Lists all `Goal`s and hosts a sheet for creating new ones. // import SwiftUI import SwiftData struct GoalTabView: View { @Environment(\.modelContext) private var modelContext @Query(sort: \Goal.createdAt, order: .reverse) private var goals: [Goal] @State private var isAddSheetPresented = false private var dateRangeFormatter: Date.FormatStyle { .dateTime.year().month().day() } var body: some View { NavigationStack { List { ForEach(goals) { goal in NavigationLink { GoalDetailView(goal: goal) } label: { HStack(spacing: 12) { Circle() .fill(Color(hex: goal.colorHex)) .frame(width: 20, height: 20) VStack(alignment: .leading, spacing: 4) { Text(goal.title) Text("\(goal.startDate.formatted(dateRangeFormatter)) ~ \(goal.endDate.formatted(dateRangeFormatter))") .font(.caption) .foregroundStyle(.secondary) } Spacer() Text("다짐 \(goal.quests.count)") .font(.caption) .foregroundStyle(.secondary) } } } .onDelete(perform: deleteGoals) } .navigationTitle("목표") .overlay { if goals.isEmpty { ContentUnavailableView( "목표가 없어요", systemImage: "flag", description: Text("오른쪽 위 + 버튼으로 목표를 추가하세요.") ) } } .toolbar { ToolbarItem(placement: .topBarTrailing) { Button { isAddSheetPresented = true } label: { Label("목표 추가", systemImage: "plus") } } } .sheet(isPresented: $isAddSheetPresented) { AddGoalSheet() } } } private func deleteGoals(at offsets: IndexSet) { for index in offsets { modelContext.delete(goals[index]) } } } // MARK: - Add Goal Sheet private struct AddGoalSheet: View { @Environment(\.modelContext) private var modelContext @Environment(\.dismiss) private var dismiss @State private var title = "" @State private var color = Color(hex: "#2F6B4F") @State private var startDate = Date.now @State private var endDate = Date.now private var trimmedTitle: String { title.trimmingCharacters(in: .whitespacesAndNewlines) } private var isValid: Bool { !trimmedTitle.isEmpty && endDate >= startDate } var body: some View { NavigationStack { Form { Section("이름") { TextField("목표 이름", text: $title) } Section("색상") { ColorPicker("색상 선택", selection: $color, supportsOpacity: false) } Section("기간") { DatePicker("시작일", selection: $startDate, displayedComponents: .date) DatePicker("종료일", selection: $endDate, in: startDate..., displayedComponents: .date) } } .navigationTitle("새 목표") .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .cancellationAction) { Button("취소") { dismiss() } } ToolbarItem(placement: .confirmationAction) { Button("저장") { save() } .disabled(!isValid) } } } } private func save() { let goal = Goal( title: trimmedTitle, colorHex: color.toHex(), startDate: startDate, endDate: endDate ) modelContext.insert(goal) dismiss() } } #Preview { GoalTabView() .modelContainer(for: [Goal.self, Quest.self, Action.self, Tag.self], inMemory: true) }