From f4b69770ebe23ae9909f3eeb98bbe430b36a33e3 Mon Sep 17 00:00:00 2001 From: opficdev Date: Mon, 2 Mar 2026 19:18:43 +0900 Subject: [PATCH 1/8] =?UTF-8?q?feat:=20=EC=8A=A4=EC=99=80=EC=9D=B4?= =?UTF-8?q?=ED=94=84=20=EC=95=A1=EC=85=98=EC=9C=BC=EB=A1=9C=20=EC=99=84?= =?UTF-8?q?=EB=A3=8C=20=ED=86=A0=EA=B8=80=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/settings.local.json | 8 ++++++ .../Presentation/Structure/TodoListItem.swift | 2 ++ .../ViewModel/TodoListViewModel.swift | 26 +++++++++++++++++-- DevLog/UI/Home/TodoListView.swift | 7 ++++- 4 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 .claude/settings.local.json diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..bcea7dd --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,8 @@ +{ + "permissions": { + "allow": [ + "mcp__xcode__XcodeListWindows", + "mcp__xcode__BuildProject" + ] + } +} diff --git a/DevLog/Presentation/Structure/TodoListItem.swift b/DevLog/Presentation/Structure/TodoListItem.swift index ac00d9f..9bfc1eb 100644 --- a/DevLog/Presentation/Structure/TodoListItem.swift +++ b/DevLog/Presentation/Structure/TodoListItem.swift @@ -12,11 +12,13 @@ struct TodoListItem: Identifiable, Hashable { let title: String let tags: [String] let isPinned: Bool + let isCompleted: Bool init(from todo: Todo) { self.id = todo.id self.title = todo.title self.tags = todo.tags self.isPinned = todo.isPinned + self.isCompleted = todo.isCompleted } } diff --git a/DevLog/Presentation/ViewModel/TodoListViewModel.swift b/DevLog/Presentation/ViewModel/TodoListViewModel.swift index 0da5a01..ca523fd 100644 --- a/DevLog/Presentation/ViewModel/TodoListViewModel.swift +++ b/DevLog/Presentation/ViewModel/TodoListViewModel.swift @@ -37,6 +37,7 @@ final class TodoListViewModel: Store { case setShowEditor(Bool) case swipeTodo(TodoListItem) case tapFilterOption(FilterOption) + case tapToggleCompleted(TodoListItem) case tapTogglePinned(TodoListItem) case undoDelete @@ -50,6 +51,7 @@ final class TodoListViewModel: Store { case upsertTodo(Todo) // Run + case didToggleCompleted(TodoListItem) case didTogglePinned(TodoListItem) case setLoading(Bool) case appendTodos([TodoListItem], nextCursor: TodoCursor?) @@ -62,6 +64,7 @@ final class TodoListViewModel: Store { case loadNextPage case upsert(Todo) case delete(String) + case toggleCompleted(TodoListItem) case togglePinned(TodoListItem) } @@ -91,13 +94,13 @@ final class TodoListViewModel: Store { var effects: [SideEffect] = [] switch action { - case .refresh, .setAlert, .setShowEditor, .swipeTodo, .tapFilterOption, .tapTogglePinned, .undoDelete: + case .refresh, .setAlert, .setShowEditor, .swipeTodo, .tapFilterOption, .tapToggleCompleted, .tapTogglePinned, .undoDelete: effects = reduceByUser(action, state: &state) case .confirmDelete, .onAppear, .loadNextPage, .setScope, .setSearchText, .setToast, .upsertTodo: effects = reduceByView(action, state: &state) - case .didTogglePinned, .setLoading, .appendTodos, .resetPagination, .setHasMore: + case .didToggleCompleted, .didTogglePinned, .setLoading, .appendTodos, .resetPagination, .setHasMore: effects = reduceByRun(action, state: &state) } @@ -145,6 +148,19 @@ final class TodoListViewModel: Store { send(.setAlert(true)) } } + case .toggleCompleted(let item): + Task { + do { + defer { send(.setLoading(false)) } + send(.setLoading(true)) + var todo = try await fetchTodoByIDUseCase.execute(item.id) + todo.isCompleted.toggle() + try await upsertTodoUseCase.execute(todo) + send(.didToggleCompleted(TodoListItem(from: todo))) + } catch { + send(.setAlert(true)) + } + } case .togglePinned(let item): Task { do { @@ -195,6 +211,8 @@ private extension TodoListViewModel { return effects case .tapFilterOption(let option): state.filterOption = option + case .tapToggleCompleted(let todo): + return [.toggleCompleted(todo)] case .tapTogglePinned(let todo): return [.togglePinned(todo)] case .undoDelete: @@ -238,6 +256,10 @@ private extension TodoListViewModel { func reduceByRun(_ action: Action, state: inout State) -> [SideEffect] { switch action { + case .didToggleCompleted(let todo): + if let index = state.todos.firstIndex(where: { $0.id == todo.id }) { + state.todos[index] = todo + } case .didTogglePinned(let todo): if let index = state.todos.firstIndex(where: { $0.id == todo.id }) { state.todos[index] = todo diff --git a/DevLog/UI/Home/TodoListView.swift b/DevLog/UI/Home/TodoListView.swift index 6d736e1..0fd9402 100644 --- a/DevLog/UI/Home/TodoListView.swift +++ b/DevLog/UI/Home/TodoListView.swift @@ -54,7 +54,12 @@ struct TodoListView: View { }) { Image(systemName: "trash") } - + Button(action: { + viewModel.send(.tapToggleCompleted(todo)) + }) { + Image(systemName: todo.isCompleted ? "arrow.uturn.backward" : "checkmark") + } + .tint(Color.green) } } .listStyle(.plain) From 581ba07bf278103a9e772e1865d43a3958ee1c2c Mon Sep 17 00:00:00 2001 From: opficdev Date: Mon, 2 Mar 2026 21:33:17 +0900 Subject: [PATCH 2/8] =?UTF-8?q?feat:=20=EC=99=84=EB=A3=8C=20=EC=8B=9C?= =?UTF-8?q?=EC=A0=90=EC=9D=84=20=EC=A0=80=EC=9E=A5=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DevLog/Data/DTO/TodoDTO.swift | 2 ++ DevLog/Data/Mapper/TodoMapping.swift | 2 ++ DevLog/Domain/Entity/Todo.swift | 1 + DevLog/Infra/Service/TodoService.swift | 6 ++++++ DevLog/Presentation/ViewModel/ProfileViewModel.swift | 6 +++--- DevLog/Presentation/ViewModel/TodoEditorViewModel.swift | 4 ++++ DevLog/Presentation/ViewModel/TodoListViewModel.swift | 1 + 7 files changed, 19 insertions(+), 3 deletions(-) diff --git a/DevLog/Data/DTO/TodoDTO.swift b/DevLog/Data/DTO/TodoDTO.swift index 4402e02..d75f6da 100644 --- a/DevLog/Data/DTO/TodoDTO.swift +++ b/DevLog/Data/DTO/TodoDTO.swift @@ -16,6 +16,7 @@ struct TodoRequest: Encodable { let content: String let createdAt: Date let updatedAt: Date + let completedAt: Date? let dueDate: Date? let tags: [String] let kind: TodoKind @@ -31,6 +32,7 @@ struct TodoResponse { let content: String let createdAt: Date let updatedAt: Date + let completedAt: Date? let dueDate: Date? let tags: [String] let kind: String diff --git a/DevLog/Data/Mapper/TodoMapping.swift b/DevLog/Data/Mapper/TodoMapping.swift index 9cb8dbf..1b5888b 100644 --- a/DevLog/Data/Mapper/TodoMapping.swift +++ b/DevLog/Data/Mapper/TodoMapping.swift @@ -16,6 +16,7 @@ extension TodoRequest { content: entity.content, createdAt: entity.createdAt, updatedAt: entity.updatedAt, + completedAt: entity.completedAt, dueDate: entity.dueDate, tags: entity.tags, kind: entity.kind @@ -38,6 +39,7 @@ extension TodoResponse { content: self.content, createdAt: self.createdAt, updatedAt: self.updatedAt, + completedAt: self.completedAt, dueDate: self.dueDate, tags: self.tags, kind: kind diff --git a/DevLog/Domain/Entity/Todo.swift b/DevLog/Domain/Entity/Todo.swift index e6fdd21..3430618 100644 --- a/DevLog/Domain/Entity/Todo.swift +++ b/DevLog/Domain/Entity/Todo.swift @@ -16,6 +16,7 @@ struct Todo: Identifiable, Hashable { var content: String // 할 일의 설명 var createdAt: Date // 할 일 생성 날짜 var updatedAt: Date // 할 일 수정 날짜 + var completedAt: Date? // 할 일 완료 날짜 var dueDate: Date? // 할 일의 마감 날짜 (선택 사항) var tags: [String] // 할 일에 연결된 태그들 var kind: TodoKind // 할 일의 종류 diff --git a/DevLog/Infra/Service/TodoService.swift b/DevLog/Infra/Service/TodoService.swift index 801e617..3ec1044 100644 --- a/DevLog/Infra/Service/TodoService.swift +++ b/DevLog/Infra/Service/TodoService.swift @@ -130,6 +130,9 @@ final class TodoService { let docRef = collection.document(request.id) var data = try encoder.encode(request) data.removeValue(forKey: TodoFieldKey.id.rawValue) + if request.completedAt == nil { + data[TodoFieldKey.completedAt.rawValue] = NSNull() + } if request.dueDate == nil { data[TodoFieldKey.dueDate.rawValue] = NSNull() } @@ -217,6 +220,7 @@ private extension TodoService { return nil } + let completedAt = (data[TodoFieldKey.completedAt.rawValue] as? Timestamp)?.dateValue() let dueDate = (data[TodoFieldKey.dueDate.rawValue] as? Timestamp)?.dateValue() return TodoResponse( id: documentID, @@ -227,6 +231,7 @@ private extension TodoService { content: content, createdAt: createdAtTimestamp.dateValue(), updatedAt: updatedAtTimestamp.dateValue(), + completedAt: completedAt, dueDate: dueDate, tags: tags, kind: kind @@ -242,6 +247,7 @@ private extension TodoService { case content case createdAt case updatedAt + case completedAt case dueDate case tags case kind diff --git a/DevLog/Presentation/ViewModel/ProfileViewModel.swift b/DevLog/Presentation/ViewModel/ProfileViewModel.swift index e551d87..9a76a20 100644 --- a/DevLog/Presentation/ViewModel/ProfileViewModel.swift +++ b/DevLog/Presentation/ViewModel/ProfileViewModel.swift @@ -241,7 +241,7 @@ private extension ProfileViewModel { for todo in todos { let createdDay = calendar.startOfDay(for: todo.createdAt) - let completedDay = todo.isCompleted ? calendar.startOfDay(for: todo.updatedAt) : nil + let completedDay = todo.completedAt.map { calendar.startOfDay(for: $0) } activitiesByDate[createdDay, default: []].append( ProfileSelectedDayActivity( @@ -305,8 +305,8 @@ private extension ProfileViewModel { let createdDay = calendar.startOfDay(for: todo.createdAt) dailyCreatedCount[createdDay, default: 0] += 1 - if todo.isCompleted { - let completedDay = calendar.startOfDay(for: todo.updatedAt) + if let completedAt = todo.completedAt { + let completedDay = calendar.startOfDay(for: completedAt) dailyCompletedCount[completedDay, default: 0] += 1 } } diff --git a/DevLog/Presentation/ViewModel/TodoEditorViewModel.swift b/DevLog/Presentation/ViewModel/TodoEditorViewModel.swift index f5c0ae5..f1dd17c 100644 --- a/DevLog/Presentation/ViewModel/TodoEditorViewModel.swift +++ b/DevLog/Presentation/ViewModel/TodoEditorViewModel.swift @@ -49,6 +49,7 @@ final class TodoEditorViewModel: Store { private let isCompleted: Bool private let isChecked: Bool private let createdAt: Date? + private let completedAt: Date? private let kind: TodoKind // 새로운 Todo 생성용 생성자 @@ -59,6 +60,7 @@ final class TodoEditorViewModel: Store { self.isCompleted = false self.isChecked = false self.createdAt = nil + self.completedAt = nil self.kind = kind } @@ -70,6 +72,7 @@ final class TodoEditorViewModel: Store { self.isCompleted = todo.isCompleted self.isChecked = todo.isChecked self.createdAt = todo.createdAt + self.completedAt = todo.completedAt self.kind = todo.kind state.title = todo.title state.content = todo.content @@ -141,6 +144,7 @@ extension TodoEditorViewModel { content: state.content, createdAt: self.createdAt ?? date, updatedAt: date, + completedAt: self.completedAt, dueDate: state.dueDate, tags: state.tags.map { $0 }, kind: self.kind diff --git a/DevLog/Presentation/ViewModel/TodoListViewModel.swift b/DevLog/Presentation/ViewModel/TodoListViewModel.swift index ca523fd..44b4062 100644 --- a/DevLog/Presentation/ViewModel/TodoListViewModel.swift +++ b/DevLog/Presentation/ViewModel/TodoListViewModel.swift @@ -155,6 +155,7 @@ final class TodoListViewModel: Store { send(.setLoading(true)) var todo = try await fetchTodoByIDUseCase.execute(item.id) todo.isCompleted.toggle() + todo.completedAt = todo.isCompleted ? Date() : nil try await upsertTodoUseCase.execute(todo) send(.didToggleCompleted(TodoListItem(from: todo))) } catch { From 9e766215a2a41b8d270461c5517d62b1b9e1c4df Mon Sep 17 00:00:00 2001 From: opficdev Date: Mon, 2 Mar 2026 21:57:05 +0900 Subject: [PATCH 3/8] =?UTF-8?q?refactor:=20maxCount=EB=A5=BC=20=EB=8B=AC?= =?UTF-8?q?=20=EB=8B=A8=EC=9C=84=EA=B0=80=20=EC=95=84=EB=8B=8C,=20?= =?UTF-8?q?=EB=B6=84=EA=B8=B0=20=EB=8B=A8=EC=9C=84=EB=A1=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Structure/Profile/ProfileCompletionQuarter.swift | 11 +++++++++-- DevLog/UI/Profile/ProfileHeatmapView.swift | 8 ++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/DevLog/Presentation/Structure/Profile/ProfileCompletionQuarter.swift b/DevLog/Presentation/Structure/Profile/ProfileCompletionQuarter.swift index c8590c4..8cc690a 100644 --- a/DevLog/Presentation/Structure/Profile/ProfileCompletionQuarter.swift +++ b/DevLog/Presentation/Structure/Profile/ProfileCompletionQuarter.swift @@ -8,8 +8,15 @@ import Foundation struct ProfileCompletionQuarter: Identifiable, Hashable { + var id: Date { quarterStart } let quarterStart: Date let months: [ProfileCompletionMonth] - - var id: Date { quarterStart } + var maxCount: Int { + months + .flatMap { $0.weeks } + .flatMap { $0 } + .filter { $0.isInMonth } + .map { $0.createdCount + $0.completedCount } + .max() ?? 0 + } } diff --git a/DevLog/UI/Profile/ProfileHeatmapView.swift b/DevLog/UI/Profile/ProfileHeatmapView.swift index 83aa92a..332b7c4 100644 --- a/DevLog/UI/Profile/ProfileHeatmapView.swift +++ b/DevLog/UI/Profile/ProfileHeatmapView.swift @@ -21,6 +21,7 @@ struct ProfileHeatmapView: View { ForEach(Array(zip(months.indices, months)), id: \.1) { index, month in MonthCompactHeatmapView( month: month, + maxCount: quarter.maxCount, selectedActivityTypes: selectedActivityTypes, selectedDay: selectedDay, onSelectDay: onSelectDay @@ -64,6 +65,7 @@ struct ProfileHeatmapView: View { private struct MonthCompactHeatmapView: View { @Environment(\.colorScheme) private var colorScheme let month: ProfileCompletionMonth + let maxCount: Int let selectedActivityTypes: Set let selectedDay: ProfileCompletionDay? let onSelectDay: (ProfileCompletionDay) -> Void @@ -72,12 +74,6 @@ private struct MonthCompactHeatmapView: View { private let cellSpacing: CGFloat = 4 var body: some View { - let maxCount = month.weeks - .flatMap { $0 } - .filter { $0.isInMonth } - .map(dayCount(for:)) - .max() ?? 0 - VStack(alignment: .leading, spacing: 6) { Text(month.monthStart.formatted(.dateTime.month(.abbreviated))) .frame(height: cellSize) From 990bd82d6d217e4473533486129610d251608714 Mon Sep 17 00:00:00 2001 From: opficdev Date: Mon, 2 Mar 2026 21:59:12 +0900 Subject: [PATCH 4/8] =?UTF-8?q?ui:=20=EC=8B=9C=EA=B7=B8=EB=8B=88=EC=B2=98?= =?UTF-8?q?=20=EC=83=89=EC=9D=B8=20Color.blue=EB=A1=9C=20=ED=86=B5?= =?UTF-8?q?=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DevLog/UI/Home/TodoListView.swift | 2 +- DevLog/UI/Setting/PushNotificationSettingsView.swift | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/DevLog/UI/Home/TodoListView.swift b/DevLog/UI/Home/TodoListView.swift index 0fd9402..e2031ff 100644 --- a/DevLog/UI/Home/TodoListView.swift +++ b/DevLog/UI/Home/TodoListView.swift @@ -59,7 +59,7 @@ struct TodoListView: View { }) { Image(systemName: todo.isCompleted ? "arrow.uturn.backward" : "checkmark") } - .tint(Color.green) + .tint(Color.blue) } } .listStyle(.plain) diff --git a/DevLog/UI/Setting/PushNotificationSettingsView.swift b/DevLog/UI/Setting/PushNotificationSettingsView.swift index 41e8c74..32898b5 100644 --- a/DevLog/UI/Setting/PushNotificationSettingsView.swift +++ b/DevLog/UI/Setting/PushNotificationSettingsView.swift @@ -20,6 +20,7 @@ struct PushNotificationSettingsView: View { )) { Text("푸시 알람 활성화") } + .tint(.blue) }, footer: { Text("설정에서의 푸시 알람 설정과 별개입니다.") }) From 1d018d7f12cb10cac2eba560e48856d2299b4aa0 Mon Sep 17 00:00:00 2001 From: opficdev Date: Mon, 2 Mar 2026 22:17:49 +0900 Subject: [PATCH 5/8] =?UTF-8?q?ui:=20=EC=99=84=EB=A3=8C=EB=90=9C=20Todo?= =?UTF-8?q?=EC=9D=B4=EB=A9=B4=20=EC=B4=88=EB=A1=9D=EC=83=89=20=EC=B2=B4?= =?UTF-8?q?=ED=81=AC=EB=A7=88=ED=81=AC=EA=B0=80=20=EB=B3=B4=EC=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DevLog/UI/Common/Component/TodoItemRow.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/DevLog/UI/Common/Component/TodoItemRow.swift b/DevLog/UI/Common/Component/TodoItemRow.swift index c3681a6..ad6de7d 100644 --- a/DevLog/UI/Common/Component/TodoItemRow.swift +++ b/DevLog/UI/Common/Component/TodoItemRow.swift @@ -23,6 +23,11 @@ struct TodoItemRow: View { .font(.headline) .foregroundStyle(.orange) } + if item.isCompleted { + Image(systemName: "checkmark.circle.fill") + .font(.headline) + .foregroundStyle(.green) + } Text(item.title) .font(.headline) .foregroundStyle(Color(.label)) From 7cf23944bd5d9654b413db2d2e16e641d6ca4ef9 Mon Sep 17 00:00:00 2001 From: opficdev Date: Mon, 2 Mar 2026 22:18:07 +0900 Subject: [PATCH 6/8] =?UTF-8?q?ui:=20=EC=8A=A4=EC=99=80=EC=9D=B4=ED=94=84?= =?UTF-8?q?=20=EC=95=A1=EC=85=98=EC=9D=84=20leading=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20?= =?UTF-8?q?=EC=83=89=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DevLog/UI/Home/TodoListView.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/DevLog/UI/Home/TodoListView.swift b/DevLog/UI/Home/TodoListView.swift index e2031ff..6869037 100644 --- a/DevLog/UI/Home/TodoListView.swift +++ b/DevLog/UI/Home/TodoListView.swift @@ -47,6 +47,12 @@ struct TodoListView: View { Image(systemName: "star\(todo.isPinned ? ".slash" : ".fill")") } .tint(Color.orange) + Button { + viewModel.send(.tapToggleCompleted(todo)) + } label: { + Image(systemName: todo.isCompleted ? "arrow.uturn.backward" : "checkmark") + } + .tint(Color.green) } .swipeActions(edge: .trailing, allowsFullSwipe: true) { Button(role: .destructive, action: { @@ -54,12 +60,6 @@ struct TodoListView: View { }) { Image(systemName: "trash") } - Button(action: { - viewModel.send(.tapToggleCompleted(todo)) - }) { - Image(systemName: todo.isCompleted ? "arrow.uturn.backward" : "checkmark") - } - .tint(Color.blue) } } .listStyle(.plain) From f4dd2c41bc131430dce4f408379392bced0e8875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=9C=A4=EC=A7=84?= Date: Mon, 2 Mar 2026 22:19:58 +0900 Subject: [PATCH 7/8] Delete .claude/settings.local.json --- .claude/settings.local.json | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 .claude/settings.local.json diff --git a/.claude/settings.local.json b/.claude/settings.local.json deleted file mode 100644 index bcea7dd..0000000 --- a/.claude/settings.local.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "permissions": { - "allow": [ - "mcp__xcode__XcodeListWindows", - "mcp__xcode__BuildProject" - ] - } -} From e033a0b6211a254a8ccd2cd3efb85d44ef61c2bd Mon Sep 17 00:00:00 2001 From: opficdev Date: Mon, 2 Mar 2026 22:25:06 +0900 Subject: [PATCH 8/8] =?UTF-8?q?feat:=20Todo=EA=B0=80=20=EC=99=84=EB=A3=8C?= =?UTF-8?q?=EB=90=98=EC=97=88=EC=9D=84=20=EB=95=8C=20updatedAt=EB=8F=84=20?= =?UTF-8?q?=EB=8F=99=EC=9D=BC=ED=95=9C=20=EC=8B=9C=EA=B0=84=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20=ED=95=98?= =?UTF-8?q?=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/settings.local.json | 8 -------- DevLog/Presentation/ViewModel/TodoListViewModel.swift | 4 +++- 2 files changed, 3 insertions(+), 9 deletions(-) delete mode 100644 .claude/settings.local.json diff --git a/.claude/settings.local.json b/.claude/settings.local.json deleted file mode 100644 index bcea7dd..0000000 --- a/.claude/settings.local.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "permissions": { - "allow": [ - "mcp__xcode__XcodeListWindows", - "mcp__xcode__BuildProject" - ] - } -} diff --git a/DevLog/Presentation/ViewModel/TodoListViewModel.swift b/DevLog/Presentation/ViewModel/TodoListViewModel.swift index 44b4062..a565364 100644 --- a/DevLog/Presentation/ViewModel/TodoListViewModel.swift +++ b/DevLog/Presentation/ViewModel/TodoListViewModel.swift @@ -154,8 +154,10 @@ final class TodoListViewModel: Store { defer { send(.setLoading(false)) } send(.setLoading(true)) var todo = try await fetchTodoByIDUseCase.execute(item.id) + let now = Date() todo.isCompleted.toggle() - todo.completedAt = todo.isCompleted ? Date() : nil + todo.completedAt = todo.isCompleted ? now : nil + todo.updatedAt = now try await upsertTodoUseCase.execute(todo) send(.didToggleCompleted(TodoListItem(from: todo))) } catch {