Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
4e7cba8
update: HouseworkItemに承認のためのフィールドを追加
stotic-dev Jan 12, 2026
799b079
update: 家事完了処理の実装
stotic-dev Jan 13, 2026
8c87bd4
Merge remote-tracking branch 'origin/main' into update/impl_approve_h…
stotic-dev Jan 13, 2026
c2f8ff7
update: 承認完了したら家事詳細画面に戻る
stotic-dev Jan 14, 2026
cfe1dfb
hogehoge
stotic-dev Jan 17, 2026
6ba64db
update: テストコードのコンパイルエラーを修正
stotic-dev Jan 17, 2026
c96a6c4
update: 家事承認時にステータスを完了に更新する
stotic-dev Jan 17, 2026
a6ac50f
update:
stotic-dev Jan 17, 2026
6694452
update: レビュー可能かどうかのテストケース追加
stotic-dev Jan 17, 2026
ab13c6d
update: 家事の状態更新のテストケースを追加
stotic-dev Jan 17, 2026
a1a4b92
update: 家事リスト監視期間取得ロジックのテストケース追加
stotic-dev Jan 17, 2026
da12b32
update:
stotic-dev Jan 17, 2026
5058384
fix: TimeZoneを固定にして環境差分のFlakyなテストの修正
stotic-dev Jan 17, 2026
a23a076
fix: 家事日付計算ロジックで直接TimeZoneを指定していたところを修正
stotic-dev Jan 24, 2026
1cce954
Merge remote-tracking branch 'origin/main' into update/impl_approve_h…
stotic-dev Jan 24, 2026
a92c043
fix: VRTの意図しない差分の修正
stotic-dev Jan 24, 2026
d156c1b
CI環境のテストプランにTimeZoneの設定を追加
stotic-dev Jan 31, 2026
98c1299
TimeZoneをHouseworkIndexedDateで指定するようにする
stotic-dev Jan 31, 2026
0e815a6
Localeも指定するよう修正
stotic-dev Jan 31, 2026
525711d
InitCaseの不具合修正
stotic-dev Jan 31, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CI.xctestplan
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
"referenceType" : "built-in"
},
"region" : "JP",
"testTimeoutsEnabled" : true
"testTimeoutsEnabled" : true,
"timeZone" : "Asia\/Tokyo"
},
"testTargets" : [
{
Expand Down
28 changes: 2 additions & 26 deletions homete/Model/Dependencies/HouseworkClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,10 @@ extension HouseworkClient: DependencyClient {
}
} snapshotListener: { id, cohabitantId, anchorDate, offset in

let targetDateList = calcTargetPeriod(
let targetDateList = HouseworkIndexedDate.calcTargetPeriod(
anchorDate: anchorDate,
offsetDays: offset,
calendar: Calendar.autoupdatingCurrent,
locale: .current
calendar: .autoupdatingCurrent
)

return await FirestoreService.shared.addSnapshotListener(id: id) {
Expand All @@ -83,26 +82,3 @@ extension HouseworkClient: DependencyClient {

static let previewValue = HouseworkClient()
}

private extension HouseworkClient {

static func calcTargetPeriod(
anchorDate: Date,
offsetDays: Int,
calendar: Calendar,
locale: Locale
) -> [[String: String]] {

let base = calendar.startOfDay(for: anchorDate)
guard offsetDays >= 0 else {

return [["value": HouseworkIndexedDate(base, locale: locale).value]]
}
// -offset ... +offset の範囲を列挙
return (-offsetDays...offsetDays).compactMap { delta in

guard let date = calendar.date(byAdding: .day, value: delta, to: base) else { return nil }
return ["value": HouseworkIndexedDate(base, locale: locale).value]
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,12 @@ struct DailyHouseworkList: Equatable, Sendable {
static func makeInitialValue(
selectedDate: Date,
items: [HouseworkItem],
calendar: Calendar,
locale: Locale
calendar: Calendar
) -> Self {

return .init(
items: items,
metaData: .init(selectedDate: selectedDate, calendar: calendar, locale: locale)
metaData: .init(selectedDate: selectedDate, calendar: calendar)
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ struct DailyHouseworkMetaData: Equatable {

extension DailyHouseworkMetaData {

init(selectedDate: Date, calendar: Calendar, locale: Locale) {
init(selectedDate: Date, calendar: Calendar) {

let indexedDate = HouseworkIndexedDate(selectedDate, locale: locale)
let indexedDate = HouseworkIndexedDate(selectedDate, calendar: calendar)
let expiredAt = calendar.date(byAdding: .month, value: 1, to: selectedDate) ?? selectedDate
self.init(indexedDate: indexedDate, expiredAt: expiredAt)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ extension HouseworkBoardList {
init(
dailyList: [DailyHouseworkList],
selectedDate: Date,
locale: Locale
calendar: Calendar
) {

items = dailyList
.first {
$0.metaData.indexedDate == .init(selectedDate, locale: locale)
$0.metaData.indexedDate == .init(selectedDate, calendar: calendar)
}?.items ?? []
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,42 @@
import Foundation

struct HouseworkIndexedDate: Equatable, Codable, Hashable {

let value: String

static func calcTargetPeriod(
anchorDate: Date,
offsetDays: Int,
calendar: Calendar
) -> [[String: String]] {

let base = calendar.startOfDay(for: anchorDate)
guard offsetDays >= 0 else {

return [["value": HouseworkIndexedDate(base, calendar: calendar).value]]
}
// -offset ... +offset の範囲を列挙
return (-offsetDays...offsetDays).compactMap { delta in

guard let date = calendar.date(byAdding: .day, value: delta, to: base) else { return nil }
return ["value": HouseworkIndexedDate(date, calendar: calendar).value]
}
}
}

extension HouseworkIndexedDate {

private static let formatStyle = Date.FormatStyle(date: .numeric, time: .omitted)
.year(.extended(minimumLength: 4))
.month(.twoDigits)
.day(.twoDigits)

init(_ date: Date, locale: Locale = .init(identifier: "ja_JP")) {
value = date.formatted(
Self.formatStyle
.locale(locale)
init(_ date: Date, calendar: Calendar) {
let formatStyle = Date.FormatStyle(
date: .numeric,
time: .omitted,
locale: calendar.locale ?? .autoupdatingCurrent,
calendar: calendar,
timeZone: calendar.timeZone
)
.year(.extended(minimumLength: 4))
.month(.twoDigits)
.day(.twoDigits)
value = date.formatted(formatStyle)
}
}
56 changes: 49 additions & 7 deletions homete/Model/Domain/Cohabitant/Housework/HouseworkItem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,38 @@ import Foundation
struct HouseworkItem: Identifiable, Equatable, Sendable, Hashable, Codable {

let id: String
/// 家事の日付情報
let indexedDate: HouseworkIndexedDate
/// 家事のタイトル
let title: String
/// 家事ポイント
let point: Int
/// 家事ステータス
let state: HouseworkState
/// 実行者のユーザID
let executorId: String?
/// 実行日時
let executedAt: Date?
/// 確認者のユーザID
let reviewerId: String?
/// 承認日時
let approvedAt: Date?
/// 確認コメント
let reviewerComment: String?
/// 有効期限
let expiredAt: Date

var formattedIndexedDate: String {

return indexedDate.value
}

/// レビュー可能かどうか
func canReview(ownUserId: String) -> Bool {

return executorId != ownUserId && state != .completed
}

func updatePendingApproval(at now: Date, changer: String) -> Self {

return .init(
Expand All @@ -33,6 +52,26 @@ struct HouseworkItem: Identifiable, Equatable, Sendable, Hashable, Codable {
state: .pendingApproval,
executorId: changer,
executedAt: now,
reviewerId: reviewerId,
approvedAt: approvedAt,
reviewerComment: reviewerComment,
expiredAt: expiredAt
)
}

func updateApproved(at now: Date, reviewer: String, comment: String) -> Self {

return .init(
id: id,
indexedDate: indexedDate,
title: title,
point: point,
state: .completed,
executorId: executorId,
executedAt: executedAt,
reviewerId: reviewer,
approvedAt: now,
reviewerComment: comment,
expiredAt: expiredAt
)
}
Expand All @@ -47,15 +86,12 @@ struct HouseworkItem: Identifiable, Equatable, Sendable, Hashable, Codable {
state: .incomplete,
executorId: nil,
executedAt: nil,
reviewerId: nil,
approvedAt: nil,
reviewerComment: nil,
expiredAt: expiredAt
)
}

func isApprovable(_ userId: String) -> Bool {

guard let executorId else { return false }
return executorId != userId
}
}

extension HouseworkItem {
Expand All @@ -67,7 +103,10 @@ extension HouseworkItem {
metaData: DailyHouseworkMetaData,
state: HouseworkState = .incomplete,
executorId: String? = nil,
executedAt: Date? = nil
executedAt: Date? = nil,
reviewerId: String? = nil,
approvedAt: Date? = nil,
reviewerComment: String? = nil
) {

self.init(
Expand All @@ -78,6 +117,9 @@ extension HouseworkItem {
state: state,
executorId: executorId,
executedAt: executedAt,
reviewerId: reviewerId,
approvedAt: approvedAt,
reviewerComment: reviewerComment,
expiredAt: metaData.expiredAt
)
}
Expand Down
25 changes: 25 additions & 0 deletions homete/Model/Domain/Cohabitant/Housework/HouseworkListStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ final class HouseworkListStore {

Task.detached {

// TODO: PushNotificationContentにファクトリーメソッドを定義する
let notificationContent = PushNotificationContent(
title: "新しい家事が登録されました",
message: newItem.title
Expand Down Expand Up @@ -100,6 +101,30 @@ final class HouseworkListStore {
}
}

func approved(target: HouseworkItem, now: Date, reviwer: Account, comment: String) async throws {

let targetIndexedDate = target.indexedDate
let targetId = target.id

guard let targetItem = items.item(targetId, targetIndexedDate) else {

preconditionFailure("Not found target item(id: \(targetId), indexedDate: \(targetIndexedDate))")
}

let updatedItem = targetItem.updateApproved(at: now, reviewer: reviwer.id, comment: comment)
try await houseworkClient.insertOrUpdateItem(updatedItem, cohabitantId)

Task.detached {

let notificationContent = PushNotificationContent.approvedMessage(
reviwerName: reviwer.userName,
houseworkTitle: target.title,
comment: comment
)
try await self.cohabitantPushNotificationClient.send(self.cohabitantId, notificationContent)
}
}

func returnToIncomplete(target: HouseworkItem, now: Date) async throws {

let targetIndexedDate = target.indexedDate
Expand Down
10 changes: 10 additions & 0 deletions homete/Model/Domain/PushNotificationContent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,13 @@ struct PushNotificationContent: Equatable {
let title: String
let message: String
}

extension PushNotificationContent {

static func approvedMessage(reviwerName: String, houseworkTitle: String, comment: String) -> Self {
return .init(
title: "\(reviwerName)が「\(houseworkTitle)」を承認しました!",
message: comment
)
}
}
39 changes: 39 additions & 0 deletions homete/Views/Components/PreviewUtil/HouseworkUtil.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//
// HouseworkUtil.swift
// homete
//
// Created by Taichi Sato on 2026/01/12.
//

import Foundation

extension HouseworkItem {

static func makeForPreview(
id: String = UUID().uuidString,
title: String = "",
point: Int = 10,
indexedDate: HouseworkIndexedDate = .init(value: "2026/01/01"),
expiredAt: Date = .distantFuture,
state: HouseworkState = .incomplete,
executorId: String? = nil,
executedAt: Date? = nil,
reviewerId: String? = nil,
approvedAt: Date? = nil,
reviewerComment: String? = nil
) -> Self {

return .init(
id: id,
title: title,
point: point,
metaData: .init(indexedDate: indexedDate, expiredAt: expiredAt),
state: state,
executorId: executorId,
executedAt: executedAt,
reviewerId: reviewerId,
approvedAt: approvedAt,
reviewerComment: reviewerComment
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ private extension HouseworkItemPropertyListContent {
title: "洗濯",
point: 10,
metaData: .init(
indexedDate: .init(.init(timeIntervalSince1970: 0)),
indexedDate: .init(value: "1970/01/01"),
expiredAt: .init(timeIntervalSince1970: 0)
),
executedAt: .distantFuture
Expand Down
Loading
Loading