diff --git a/Projects/App/Project.swift b/Projects/App/Project.swift index bc49afd5..2596d0dd 100644 --- a/Projects/App/Project.swift +++ b/Projects/App/Project.swift @@ -28,7 +28,7 @@ let project = Project.makeModule( "UILaunchStoryboardName": "LaunchScreen", "BGTaskSchedulerPermittedIdentifiers": "com.oksusu.susu.app", "CFBundleShortVersionString": "1.0.6", - "CFBundleVersion": "2024093034", + "CFBundleVersion": "2024100235", "UIUserInterfaceStyle": "Light", "ITSAppUsesNonExemptEncryption": "No", "AppstoreAPPID": "6503701515", diff --git a/Projects/Core/SSNetwork/Sources/DataModel/EnvelopeDetailResponse.swift b/Projects/Core/SSNetwork/Sources/DataModel/EnvelopeDetailResponse.swift index 4d5ec1fe..0278314b 100644 --- a/Projects/Core/SSNetwork/Sources/DataModel/EnvelopeDetailResponse.swift +++ b/Projects/Core/SSNetwork/Sources/DataModel/EnvelopeDetailResponse.swift @@ -8,7 +8,7 @@ import Foundation -public struct EnvelopeDetailResponse: Decodable { +public struct EnvelopeDetailResponse: Decodable, Equatable { public let envelope: EnvelopeModel public let category: CategoryWithCustomModel public let relationship: RelationshipModel @@ -21,4 +21,18 @@ public struct EnvelopeDetailResponse: Decodable { case friendRelationship case friend } + + public init( + envelope: EnvelopeModel, + category: CategoryWithCustomModel, + relationship: RelationshipModel, + friendRelationship: FriendRelationshipModel, + friend: FriendModel + ) { + self.envelope = envelope + self.category = category + self.relationship = relationship + self.friendRelationship = friendRelationship + self.friend = friend + } } diff --git a/Projects/Core/SSNetwork/Sources/Moya+Asynchronous.swift b/Projects/Core/SSNetwork/Sources/Moya+Asynchronous.swift index 690aadc8..15ed8769 100644 --- a/Projects/Core/SSNetwork/Sources/Moya+Asynchronous.swift +++ b/Projects/Core/SSNetwork/Sources/Moya+Asynchronous.swift @@ -55,12 +55,12 @@ public extension MoyaProvider { continuation.resume(returning: res) return } - if let isSUSUError = String(data: response.data, encoding: .utf8) { - os_log("\(isSUSUError)") - } continuation.resume(with: .failure(MoyaError.statusCode(response))) case let .failure(error): + if let errorDescription = error.errorDescription { + os_log("errorDescription: \(errorDescription) \n localizedDescription: \(error.localizedDescription)") + } let willSendError: Error switch error { case let .statusCode(response): diff --git a/Projects/Feature/MyPage/Sources/MyPageEdit/MyPageEdit.swift b/Projects/Feature/MyPage/Sources/MyPageEdit/MyPageEdit.swift index fbbb6d1d..ed95fda4 100644 --- a/Projects/Feature/MyPage/Sources/MyPageEdit/MyPageEdit.swift +++ b/Projects/Feature/MyPage/Sources/MyPageEdit/MyPageEdit.swift @@ -56,13 +56,16 @@ struct MyPageEdit { } init() { - userInfo = MyPageSharedState.shared.getMyUserInfoDTO() ?? .init(id: 0, name: "", gender: nil, birth: nil) + let userInfo = MyPageSharedState.shared.getMyUserInfoDTO() ?? .init(id: 0, name: "", gender: nil, birth: nil) + self.userInfo = userInfo _selectedBottomSheetItem = .init(nil) + let initialSelectedGenderItem = Gender.getGenderByKey(userInfo.gender) _genderSectionProperty = .init( .init( titleText: "성별", items: .default, isCustomItem: nil, + initialSelectedID: initialSelectedGenderItem?.id, customTextFieldPrompt: nil, isEssentialProperty: false ) @@ -72,11 +75,13 @@ struct MyPageEdit { init(_ userInfo: UserInfoResponse) { self.userInfo = userInfo _selectedBottomSheetItem = .init(nil) + let initialSelectedGenderItem = Gender.getGenderByKey(userInfo.gender) _genderSectionProperty = .init( .init( titleText: "성별", items: .default, isCustomItem: nil, + initialSelectedID: initialSelectedGenderItem?.id, customTextFieldPrompt: nil, isEssentialProperty: false ) @@ -174,7 +179,9 @@ struct MyPageEdit { SSToastReducer() } - Reduce { state, action in + Reduce { + state, + action in switch action { case let .view(currentAction): return viewAction(&state, currentAction) @@ -206,7 +213,7 @@ struct MyPageEdit { let currentGenderID = Gender.getGenderByKey(genderString)?.id state.nameTextFieldText = state.userInfo.name - state.genderSection = .init(singleSelectButtonHelper: state.$genderSectionProperty, initialSelectedID: currentGenderID) + state.genderSection = .init(singleSelectButtonHelper: state.$genderSectionProperty) return .none case .async(.updateUserInformation): @@ -267,3 +274,5 @@ struct SelectYearBottomSheetItem: SSSelectBottomSheetPropertyItemable { /// BottomSheet에 표시될 연도 입니다. var id: Int } + +private extension UserInfoResponse {} diff --git a/Projects/Feature/Received/Sources/LedgerDetail/LedgerDetailEdit/LedgerDetailEdit.swift b/Projects/Feature/Received/Sources/LedgerDetail/LedgerDetailEdit/LedgerDetailEdit.swift index da3d1e29..b9b34790 100644 --- a/Projects/Feature/Received/Sources/LedgerDetail/LedgerDetailEdit/LedgerDetailEdit.swift +++ b/Projects/Feature/Received/Sources/LedgerDetail/LedgerDetailEdit/LedgerDetailEdit.swift @@ -43,8 +43,7 @@ struct LedgerDetailEdit: FeatureViewAction, FeatureAsyncAction, FeatureInnerActi self.ledgerProperty = ledgerProperty _editProperty = .init(ledgerDetailEditProperty) categorySection = .init( - singleSelectButtonHelper: _editProperty.categoryEditProperty, - initialSelectedID: ledgerProperty.categoryID + singleSelectButtonHelper: _editProperty.categoryEditProperty ) } } diff --git a/Projects/Feature/Received/Sources/LedgerDetail/LedgerDetailEdit/LedgerDetailEditProperty.swift b/Projects/Feature/Received/Sources/LedgerDetail/LedgerDetailEdit/LedgerDetailEditProperty.swift index 9121ae1e..99048371 100644 --- a/Projects/Feature/Received/Sources/LedgerDetail/LedgerDetailEdit/LedgerDetailEditProperty.swift +++ b/Projects/Feature/Received/Sources/LedgerDetail/LedgerDetailEdit/LedgerDetailEditProperty.swift @@ -38,6 +38,7 @@ struct LedgerDetailEditProperty: Equatable { titleText: "카테고리", items: category, isCustomItem: currentCustomItem, + initialSelectedID: ledgerDetailProperty.categoryID, customTextFieldPrompt: "경조사 이름", isEssentialProperty: true ) diff --git a/Projects/Feature/Received/Sources/LedgerDetail/LedgerDetailRouter/LedgerDetailRouter.swift b/Projects/Feature/Received/Sources/LedgerDetail/LedgerDetailRouter/LedgerDetailRouter.swift index 2e7807ca..a55b8822 100644 --- a/Projects/Feature/Received/Sources/LedgerDetail/LedgerDetailRouter/LedgerDetailRouter.swift +++ b/Projects/Feature/Received/Sources/LedgerDetail/LedgerDetailRouter/LedgerDetailRouter.swift @@ -56,7 +56,7 @@ struct LedgerDetailRouter { func handleEnvelopeDetailDelegateAction(state _: inout State, action: SpecificEnvelopeDetailReducer.Action.DelegateAction) -> Effect { switch action { case let .tappedEnvelopeEditButton(property): - return .ssRun { [id = property.id] _ in + return .ssRun { [id = property.envelope.id] _ in let editState = try await SpecificEnvelopeEditReducer.State(envelopeID: id, isShowCategory: false) LedgerDetailRouterPublisher.send(.envelopeEdit(editState)) } diff --git a/Projects/Feature/SSEditSingleSelectButton/Sources/SingleSelectButtonProperty.swift b/Projects/Feature/SSEditSingleSelectButton/Sources/SingleSelectButtonProperty.swift index 50bde424..a4b1b469 100644 --- a/Projects/Feature/SSEditSingleSelectButton/Sources/SingleSelectButtonProperty.swift +++ b/Projects/Feature/SSEditSingleSelectButton/Sources/SingleSelectButtonProperty.swift @@ -21,6 +21,8 @@ public struct SingleSelectButtonProperty: Equa public var customTextFieldPrompt: String? public var isSaved: Bool = false public var isEssentialProperty = true + public let initialSelectedCustomTitle: String? + public let initialSelectedID: Item.ID? public var allItems: [Item] { return (items + [isCustomItem]).compactMap { $0 } @@ -30,10 +32,19 @@ public struct SingleSelectButtonProperty: Equa return selectedItem?.id == isCustomItem?.id } - public init(titleText: String, items: [Item], isCustomItem: Item?, customTextFieldPrompt: String?, isEssentialProperty: Bool = true) { + public init( + titleText: String, + items: [Item], + isCustomItem: Item?, + initialSelectedID: Item.ID?, + customTextFieldPrompt: String?, + isEssentialProperty: Bool = true + ) { self.titleText = titleText self.items = items self.isCustomItem = isCustomItem + initialSelectedCustomTitle = isCustomItem?.title + self.initialSelectedID = initialSelectedID self.customTextFieldPrompt = customTextFieldPrompt self.isEssentialProperty = isEssentialProperty } @@ -75,6 +86,7 @@ public struct SingleSelectButtonProperty: Equa } public mutating func resetCustomTextField() { + selectedItem = nil isCustomItem?.title = "" isSaved = false isStartedAddingNewCustomItem = false diff --git a/Projects/Feature/SSEditSingleSelectButton/Sources/SingleSelectButtonReducer.swift b/Projects/Feature/SSEditSingleSelectButton/Sources/SingleSelectButtonReducer.swift index c43fa0fb..948cf143 100644 --- a/Projects/Feature/SSEditSingleSelectButton/Sources/SingleSelectButtonReducer.swift +++ b/Projects/Feature/SSEditSingleSelectButton/Sources/SingleSelectButtonReducer.swift @@ -20,11 +20,10 @@ public struct SingleSelectButtonReducer { @Shared var singleSelectButtonHelper: SingleSelectButtonProperty var customTextFieldText: String - public init(singleSelectButtonHelper: Shared>, initialSelectedID: Item.ID?) { + public init(singleSelectButtonHelper: Shared>) { _singleSelectButtonHelper = singleSelectButtonHelper customTextFieldText = "" - self.initialSelectedID = initialSelectedID - + initialSelectedID = singleSelectButtonHelper.wrappedValue.initialSelectedID setCustomTextField() } diff --git a/Projects/Feature/SSEnvelope/Sources/Network/EnvelopeNetwork.swift b/Projects/Feature/SSEnvelope/Sources/Network/EnvelopeNetwork.swift index d6ffe3b9..60091ef3 100644 --- a/Projects/Feature/SSEnvelope/Sources/Network/EnvelopeNetwork.swift +++ b/Projects/Feature/SSEnvelope/Sources/Network/EnvelopeNetwork.swift @@ -22,7 +22,7 @@ struct EnvelopeNetwork { var getEnvelopeDetailPropertyByEnvelopeID: @Sendable (_ id: Int64) async throws -> EnvelopeDetailProperty @Sendable static func _getEnvelopeDetailPropertyByEnvelopeID(_ id: Int64) async throws -> EnvelopeDetailProperty { let data: EnvelopeDetailResponse = try await provider.request(.searchEnvelopeByID(id)) - return data.convertToEnvelopeDetailLProperty() + return data } var deleteEnvelope: @Sendable (_ id: Int64) async throws -> Void @@ -37,21 +37,15 @@ struct EnvelopeNetwork { let relations = responseRelations.sorted { $0.id < $1.id } let envelopeDetailResponse: EnvelopeDetailResponse = try await provider.request(.searchEnvelopeByID(envelopeID)) - let envelopeProperty = envelopeDetailResponse.convertToEnvelopeDetailLProperty() - guard var customCategoryItem = events.first(where: { $0.isCustom }), - var customRelationItem = relations.first(where: { $0.isCustom }) - else { - throw NSError(domain: "", code: 3) - } + let customCategoryItem = events.first(where: { $0.isCustom }) ?? .editCustomDefault + let customRelationItem = relations.first(where: { $0.isCustom }) ?? .editCustomDefault + let targetCategoryItems = events.filter { $0.isCustom == false } let targetRelationItems = relations.filter { $0.isCustom == false } - customCategoryItem.title = envelopeDetailResponse.category.customCategory ?? "" - customRelationItem.title = envelopeDetailResponse.friendRelationship.customRelation ?? "" - return .init( - envelopeDetailProperty: envelopeProperty, + envelopeDetailProperty: envelopeDetailResponse, eventItems: targetCategoryItems, customEventItem: customCategoryItem, relationItems: targetRelationItems, @@ -70,21 +64,11 @@ struct EnvelopeNetwork { // TODO: 작업하기 let dto: CreateAndUpdateEnvelopeResponse = try await provider.request(.editEnvelopes(id: id, body)) return .init( - id: dto.envelope.id, - type: dto.envelope.type, - ledgerID: nil, - price: dto.envelope.amount, - eventName: dto.category.customCategory ?? dto.category.category, - eventID: dto.category.id, - friendID: dto.friend.id, - name: dto.friend.name, - relation: dto.friendRelationship.customRelation ?? dto.relationship.relation, - relationID: dto.relationship.id, - date: CustomDateFormatter.getDate(from: dto.envelope.handedOverAt) ?? .now, - isVisited: dto.envelope.hasVisited, - gift: dto.envelope.gift, - contacts: dto.friend.phoneNumber, - memo: dto.envelope.memo + envelope: dto.envelope, + category: dto.category, + relationship: dto.relationship, + friendRelationship: dto.friendRelationship, + friend: dto.friend ) } @@ -194,25 +178,14 @@ private extension Date { } } -private extension EnvelopeDetailResponse { - func convertToEnvelopeDetailLProperty() -> EnvelopeDetailProperty { - let data = self - return .init( - id: data.envelope.id, - type: data.envelope.type, - ledgerID: nil, - price: data.envelope.amount, - eventName: data.category.customCategory ?? data.category.category, - eventID: data.category.id, - friendID: data.friend.id, - name: data.friend.name, - relation: data.friendRelationship.customRelation != nil ? data.friendRelationship.customRelation! : data.relationship.relation, - relationID: data.relationship.id, - date: .getDate(from: data.envelope.handedOverAt) ?? .now, - isVisited: data.envelope.hasVisited, - gift: data.envelope.gift, - contacts: data.friend.phoneNumber, - memo: data.envelope.memo - ) +private extension CreateEnvelopeEventProperty { + static var editCustomDefault: Self { + .init(id: 2048, seq: 2048, name: "", style: "blue60", isActive: true, isCustom: true, isMiscCategory: true) + } +} + +extension CreateEnvelopeRelationItemProperty { + static var editCustomDefault: Self { + .init(id: 2048, relation: "", description: "", isCustom: true) } } diff --git a/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeDetail/EnvelopeDetailProperty.swift b/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeDetail/EnvelopeDetailProperty.swift index 0ce38225..a269c3d4 100644 --- a/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeDetail/EnvelopeDetailProperty.swift +++ b/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeDetail/EnvelopeDetailProperty.swift @@ -7,68 +7,36 @@ // import Foundation +import SSNetwork -public struct EnvelopeDetailProperty: Equatable, Identifiable { - /// 봉투의 아이디 입니다. - public let id: Int64 - /// Send OR RECEIVED - var type: String - /// 장부 아이디 입니다. - var ledgerID: Int64? - /// 현재 봉투의 가격을 나타냅니다. - let price: Int64 - /// 현재 봉투의 경조사 이름을 나타냅니다. - let eventName: String - /// 현재 봉투 카테고리 ID를 나타냅니다. - let eventID: Int - /// 봉투를 받은 사람의 ID입니다. - let friendID: Int64 - /// 봉투를 받은 사람의 이름을 나타냅니다. - let name: String - /// 현재 봉투를 주고받은 사람과의 관계를 나타냅니다. - let relation: String - /// 봉투 relationID를 나타냅니다. - let relationID: Int - /// 현재 봉투를 주고받은 날짜를 나타냅니다. - let date: Date - /// 현재 봉투의 대상이되는 경조사에 참석 여부를 나타냅니다. - let isVisited: Bool? - /// 봉투의 선물을 나타냅니다. - var gift: String? - /// 봉투의 연락처를 나타냅니다. - var contacts: String? - /// 봉투의 메모를 나타냅니다. - var memo: String? +public typealias EnvelopeDetailProperty = EnvelopeDetailResponse + +extension EnvelopeDetailProperty { + var eventNameTitle: String { "경조사" } + var nameTitle: String { "이름" } + var relationTitle: String { "나와의 관계" } + var dateTitle: String { "날짜" } + var visitedTitle: String { "방문여부" } + var giftTitle: String { "선물" } + var contactTitle: String { "연락처" } + var memoTitle: String { "메모" } var priceText: String { - return (CustomNumberFormatter.formattedByThreeZero(price) ?? "0") + "원" + return (CustomNumberFormatter.formattedByThreeZero(envelope.amount) ?? "0") + "원" } var dateText: String { + let date = CustomDateFormatter.getDate(from: envelope.handedOverAt) ?? .now return CustomDateFormatter.getKoreanDateString(from: date) } - var isVisitedText: String? { - if let isVisited { - return isVisited ? "예" : "아니오" - } - return nil - } - - var eventNameTitle = "경조사" - var nameTitle = "이름" - var relationTitle = "나와의 관계" - var dateTitle = "날짜" - var visitedTitle = "방문여부" - var giftTitle = "선물" - var contactTitle = "연락처" - var memoTitle = "메모" - func makeListContent(isShowCategory: Bool) -> [(String, String)] { - var res = isShowCategory ? [(eventNameTitle, eventName)] : [] + let categoryName = category.customCategory ?? category.category + let relationName = friendRelationship.customRelation ?? relationship.relation + var res = isShowCategory ? [(eventNameTitle, categoryName)] : [] res.append(contentsOf: [ - (nameTitle, name), - (relationTitle, relation), + (nameTitle, friend.name), + (relationTitle, relationName), (dateTitle, dateText), ]) res.append(contentsOf: makeOptionalListContent()) @@ -77,68 +45,19 @@ public struct EnvelopeDetailProperty: Equatable, Identifiable { func makeOptionalListContent() -> [(String, String)] { var res: [(String, String)] = [] - if let isVisitedText { - res.append((visitedTitle, isVisitedText)) + if let hasVisited = envelope.hasVisited { + let visitedText: String = hasVisited ? "예" : "아니오" + res.append((visitedTitle, visitedText)) } - if let gift { + if let gift = envelope.gift { res.append((giftTitle, gift)) } - if let contacts { + if let contacts = friend.phoneNumber { res.append((contactTitle, contacts)) } - if let memo { + if let memo = envelope.memo { res.append((memoTitle, memo)) } return res } - - init( - id: Int64, - type: String, - ledgerID: Int64? = nil, - price: Int64, - eventName: String, - eventID: Int, - friendID: Int64, - name: String, - relation: String, - relationID: Int, - date: Date, - isVisited: Bool?, - gift: String? = nil, - contacts: String? = nil, - memo: String? = nil, - eventNameTitle: String = "경조사", - nameTitle: String = "이름", - relationTitle: String = "나와의 관계", - dateTitle: String = "날짜", - visitedTitle: String = "방문여부", - giftTitle: String = "선물", - contactTitle: String = "연락처", - memoTitle: String = "메모" - ) { - self.id = id - self.type = type - self.ledgerID = ledgerID - self.price = price - self.eventName = eventName - self.eventID = eventID - self.friendID = friendID - self.name = name - self.relation = relation - self.relationID = relationID - self.date = date - self.isVisited = isVisited - self.gift = gift - self.contacts = contacts - self.memo = memo - self.eventNameTitle = eventNameTitle - self.nameTitle = nameTitle - self.relationTitle = relationTitle - self.dateTitle = dateTitle - self.visitedTitle = visitedTitle - self.giftTitle = giftTitle - self.contactTitle = contactTitle - self.memoTitle = memoTitle - } } diff --git a/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeDetail/SpecificEnvelopeDetailReducer.swift b/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeDetail/SpecificEnvelopeDetailReducer.swift index 52a79967..5ae139c3 100644 --- a/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeDetail/SpecificEnvelopeDetailReducer.swift +++ b/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeDetail/SpecificEnvelopeDetailReducer.swift @@ -23,16 +23,14 @@ public struct SpecificEnvelopeDetailReducer { var isDeleteAlertPresent = false var isLoading = false var header: HeaderViewFeature.State = .init(.init(type: .depth2DoubleText("편집", "삭제"))) - var envelopeDetailProperty: EnvelopeDetailProperty + var envelopeDetailProperty: EnvelopeDetailProperty? var envelopeID: Int64 var isUpdateEnvelope: Bool = false let isShowCategory: Bool public init(envelopeID: Int64, isShowCategory: Bool = true) { self.envelopeID = envelopeID self.isShowCategory = isShowCategory - envelopeDetailProperty = .init( - id: -1, type: "", price: 0, eventName: "", eventID: 0, friendID: 0, name: "", relation: "", relationID: 0, date: .now, isVisited: false - ) + envelopeDetailProperty = nil } } @@ -108,14 +106,21 @@ public struct SpecificEnvelopeDetailReducer { public func asyncAction(_ state: inout State, _ action: AsyncAction) -> ComposableArchitecture.Effect { switch action { case .deleteEnvelope: - return .ssRun { [id = state.envelopeDetailProperty.id] _ in + + return .ssRun { [id = state.envelopeID] _ in try await network.deleteEnvelope(id) specificEnvelopePublisher.sendDeleteEnvelopeBy(ID: id) await dismiss() } case .pushEditing: let property = state.envelopeDetailProperty - return .send(.delegate(.tappedEnvelopeEditButton(property))) + return .ssRun { send in + guard let property else { + let errorMessage = "envelopeDetailProperty가 생성되지 않은 상태에서 edit화면으로 이동하려고 합니다." + throw SUSUError(error: NSError(), response: nil, requestData: errorMessage) + } + await send(.delegate(.tappedEnvelopeEditButton(property))) + } case .getEnvelopeDetailProperty: return .ssRun { [id = state.envelopeID] send in diff --git a/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeDetail/SpecificEnvelopeDetailView.swift b/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeDetail/SpecificEnvelopeDetailView.swift index 07d35257..f2998028 100644 --- a/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeDetail/SpecificEnvelopeDetailView.swift +++ b/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeDetail/SpecificEnvelopeDetailView.swift @@ -25,19 +25,19 @@ public struct SpecificEnvelopeDetailView: View { // MARK: Content @ViewBuilder - private func makeContentView() -> some View { + private func makeContentView(_ envelopeDetailProperty: EnvelopeDetailProperty) -> some View { VStack(alignment: .leading) { Spacer() .frame(height: 24) VStack(alignment: .leading, spacing: 16) { - Text(store.envelopeDetailProperty.priceText) + Text(envelopeDetailProperty.priceText) .modifier(SSTypoModifier(.title_xxl)) .foregroundStyle(SSColor.gray100) ScrollView(showsIndicators: false) { LazyVStack(spacing: 0) { - let listViewContent = store.envelopeDetailProperty.makeListContent(isShowCategory: store.isShowCategory) + let listViewContent = envelopeDetailProperty.makeListContent(isShowCategory: store.isShowCategory) ForEach(0 ..< listViewContent.count, id: \.self) { ind in let (title, description) = listViewContent[ind] makeListView(title: title, description: description) @@ -74,8 +74,10 @@ public struct SpecificEnvelopeDetailView: View { .ignoresSafeArea() VStack(spacing: 0) { HeaderView(store: store.scope(state: \.header, action: \.scope.header)) - makeContentView() - .padding(.horizontal, Metrics.horizontalSpacing) + if let envelopeDetailProperty = store.envelopeDetailProperty { + makeContentView(envelopeDetailProperty) + .padding(.horizontal, Metrics.horizontalSpacing) + } } } .navigationBarBackButtonHidden() diff --git a/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeEdit/EditProperty/ContactEditProperty.swift b/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeEdit/EditProperty/ContactEditProperty.swift new file mode 100644 index 00000000..7006a340 --- /dev/null +++ b/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeEdit/EditProperty/ContactEditProperty.swift @@ -0,0 +1,40 @@ +// +// ContactEditProperty.swift +// SSEnvelope +// +// Created by MaraMincho on 10/2/24. +// Copyright © 2024 com.oksusu. All rights reserved. +// + +import Foundation +import SSRegexManager + +// MARK: - ContactEditProperty + +struct ContactEditProperty: Equatable, EnvelopeEditPropertiable { + var contact: String + let originalContact: String + init(contact: String?) { + let contact = contact ?? "" + self.contact = contact + originalContact = contact + } + + var isValid: Bool { + if !contact.isEmpty { + return RegexManager.isValidContacts(contact) + } + return true + } + + var isChanged: Bool { + originalContact != contact + } + + var isShowToast: Bool { + if !contact.isEmpty { + return ToastRegexManager.isShowToastByContacts(contact) + } + return false + } +} diff --git a/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeEdit/EditProperty/DateEditProperty.swift b/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeEdit/EditProperty/DateEditProperty.swift new file mode 100644 index 00000000..0c6c46eb --- /dev/null +++ b/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeEdit/EditProperty/DateEditProperty.swift @@ -0,0 +1,33 @@ +// +// DateEditProperty.swift +// SSEnvelope +// +// Created by MaraMincho on 10/2/24. +// Copyright © 2024 com.oksusu. All rights reserved. +// + +import Foundation + +// MARK: - DateEditProperty + +struct DateEditProperty: Equatable, EnvelopeEditPropertiable { + let originalDate: Date + var date: Date + var isInitialState = false + var dateText: String { + return CustomDateFormatter.getKoreanDateString(from: date) + } + + init(date: Date) { + self.date = date + originalDate = date + } + + var isValid: Bool { + true + } + + var isChanged: Bool { + originalDate != date + } +} diff --git a/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeEdit/EditProperty/EnvelopeEditPropertiable.swift b/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeEdit/EditProperty/EnvelopeEditPropertiable.swift new file mode 100644 index 00000000..a87d7a6d --- /dev/null +++ b/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeEdit/EditProperty/EnvelopeEditPropertiable.swift @@ -0,0 +1,14 @@ +// +// EnvelopeEditPropertiable.swift +// SSEnvelope +// +// Created by MaraMincho on 10/2/24. +// Copyright © 2024 com.oksusu. All rights reserved. +// + +import Foundation + +protocol EnvelopeEditPropertiable { + var isValid: Bool { get } + var isChanged: Bool { get } +} diff --git a/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeEdit/EditProperty/GiftEditProperty.swift b/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeEdit/EditProperty/GiftEditProperty.swift new file mode 100644 index 00000000..c9391324 --- /dev/null +++ b/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeEdit/EditProperty/GiftEditProperty.swift @@ -0,0 +1,41 @@ +// +// GiftEditProperty.swift +// SSEnvelope +// +// Created by MaraMincho on 10/2/24. +// Copyright © 2024 com.oksusu. All rights reserved. +// + +import Foundation +import SSRegexManager + +// MARK: - GiftEditProperty + +struct GiftEditProperty: Equatable, EnvelopeEditPropertiable { + let originalGift: String + var gift: String + + init(gift: String?) { + let gift = gift ?? "" + self.gift = gift + originalGift = gift + } + + var isValid: Bool { + if !gift.isEmpty { + return RegexManager.isValidGift(gift) + } + return true + } + + var isChanged: Bool { + originalGift != gift + } + + var isShowToast: Bool { + if !gift.isEmpty { + return ToastRegexManager.isShowToastByGift(gift) + } + return false + } +} diff --git a/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeEdit/EditProperty/MemoEditProperty.swift b/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeEdit/EditProperty/MemoEditProperty.swift new file mode 100644 index 00000000..dbed172d --- /dev/null +++ b/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeEdit/EditProperty/MemoEditProperty.swift @@ -0,0 +1,40 @@ +// +// MemoEditProperty.swift +// SSEnvelope +// +// Created by MaraMincho on 10/2/24. +// Copyright © 2024 com.oksusu. All rights reserved. +// + +import Foundation +import SSRegexManager + +// MARK: - MemoEditProperty + +struct MemoEditProperty: Equatable, EnvelopeEditPropertiable { + let originalMemo: String + var memo: String + init(memo: String?) { + let memo = memo ?? "" + self.memo = memo + originalMemo = memo + } + + var isValid: Bool { + if !memo.isEmpty { + return RegexManager.isValidMemo(memo) + } + return true + } + + var isChanged: Bool { + originalMemo != memo + } + + var isShowToast: Bool { + if !memo.isEmpty { + return ToastRegexManager.isShowToastByMemo(memo) + } + return false + } +} diff --git a/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeEdit/EditProperty/NameEditProperty.swift b/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeEdit/EditProperty/NameEditProperty.swift new file mode 100644 index 00000000..a3bd437d --- /dev/null +++ b/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeEdit/EditProperty/NameEditProperty.swift @@ -0,0 +1,35 @@ +// +// NameEditProperty.swift +// SSEnvelope +// +// Created by MaraMincho on 10/2/24. +// Copyright © 2024 com.oksusu. All rights reserved. +// + +import Foundation +import SSRegexManager + +// MARK: - NameEditProperty + +/// EditName을 하기 위해 사용됩니다. +struct NameEditProperty: Equatable, EnvelopeEditPropertiable { + let originalText: String + var textFieldText: String + + var isValid: Bool { + RegexManager.isValidName(textFieldText) + } + + var isChanged: Bool { + originalText != textFieldText + } + + var isShowToast: Bool { + ToastRegexManager.isShowToastByName(textFieldText) + } + + init(textFieldText: String) { + self.textFieldText = textFieldText + originalText = textFieldText + } +} diff --git a/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeEdit/EditProperty/PriceEditProperty.swift b/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeEdit/EditProperty/PriceEditProperty.swift new file mode 100644 index 00000000..95ad828b --- /dev/null +++ b/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeEdit/EditProperty/PriceEditProperty.swift @@ -0,0 +1,47 @@ +// +// PriceEditProperty.swift +// SSEnvelope +// +// Created by MaraMincho on 10/2/24. +// Copyright © 2024 com.oksusu. All rights reserved. +// + +import Foundation +import SSRegexManager + +// MARK: - PriceEditProperty + +struct PriceEditProperty: Equatable, EnvelopeEditPropertiable { + let originalPriceValue: String + var price: Int64 + var priceTextFieldText: String + var priceText: String { + CustomNumberFormatter.formattedByThreeZero(price, subFixString: "원") ?? "" + } + + init(price: Int64) { + self.price = price + priceTextFieldText = price.description + originalPriceValue = price.description + } + + mutating func setPriceTextFieldText(_ text: String) { + priceTextFieldText = text.isEmpty ? "0" : text + guard let currentValue = Int64(priceTextFieldText) else { + return + } + price = currentValue + } + + var isValid: Bool { + RegexManager.isValidPrice(priceTextFieldText) + } + + var isChanged: Bool { + originalPriceValue != priceTextFieldText + } + + var isShowToast: Bool { + ToastRegexManager.isShowToastByPrice(priceTextFieldText) + } +} diff --git a/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeEdit/EditProperty/VisitedSelectButtonItem.swift b/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeEdit/EditProperty/VisitedSelectButtonItem.swift new file mode 100644 index 00000000..93d9d978 --- /dev/null +++ b/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeEdit/EditProperty/VisitedSelectButtonItem.swift @@ -0,0 +1,63 @@ +// +// VisitedSelectButtonItem.swift +// SSEnvelope +// +// Created by MaraMincho on 10/2/24. +// Copyright © 2024 com.oksusu. All rights reserved. +// + +import Foundation +import SSEditSingleSelectButton + +// MARK: - VisitedEditProperty + +struct VisitedEditProperty: Equatable, EnvelopeEditPropertiable { + let originalVisited: Bool? + var isVisited: Bool? + + init(isVisited: Bool?) { + self.isVisited = isVisited + originalVisited = isVisited + } + + var isValid: Bool { + return true + } + + var isChanged: Bool { + originalVisited != isVisited + } +} + +// MARK: - VisitedSelectButtonItem + +public struct VisitedSelectButtonItem: SingleSelectButtonItemable { + public var id: Int + public var title: String = "" + var isVisited: Bool + init(id: Int, title: String = "", isVisited: Bool) { + self.id = id + self.title = title + self.isVisited = isVisited + } + + mutating func setTitle(by isVisited: Bool) { + title = isVisited ? "예" : "아니오" + } +} + +extension VisitedSelectButtonItem { + static func defaultItems() -> [Self] { + return [ + yes, no, + ] + } + + static var yes: Self { + .init(id: 0, title: "예", isVisited: true) + } + + static var no: Self { + .init(id: 1, title: "아니오", isVisited: false) + } +} diff --git a/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeEdit/SpecificEnvelopeEditHelper.swift b/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeEdit/SpecificEnvelopeEditHelper.swift index 7acbce29..09ab6ae3 100644 --- a/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeEdit/SpecificEnvelopeEditHelper.swift +++ b/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeEdit/SpecificEnvelopeEditHelper.swift @@ -13,6 +13,20 @@ import SSRegexManager // MARK: - SpecificEnvelopeEditHelper public struct SpecificEnvelopeEditHelper: Equatable { + var envelopeEditProperties: [EnvelopeEditPropertiable] { + [ + priceProperty, + eventSectionButtonHelper, + relationSectionButtonHelper, + nameEditProperty, + dateEditProperty, + visitedSectionButtonHelper, + giftEditProperty, + contactEditProperty, + memoEditProperty, + ] + } + var envelopeDetailProperty: EnvelopeDetailProperty var priceProperty: PriceEditProperty @@ -45,52 +59,48 @@ public struct SpecificEnvelopeEditHelper: Equatable { ) { self.envelopeDetailProperty = envelopeDetailProperty - priceProperty = .init(price: envelopeDetailProperty.price) + priceProperty = .init(price: envelopeDetailProperty.envelope.amount) eventSectionButtonCustomItem = customEventItem + eventSectionButtonCustomItem.name = envelopeDetailProperty.category.customCategory ?? "" eventSectionButtonHelper = .init( titleText: envelopeDetailProperty.eventNameTitle, items: eventItems, isCustomItem: eventSectionButtonCustomItem, - customTextFieldPrompt: "경조사 이름" - ) - - eventSectionButtonHelper = .init( - titleText: envelopeDetailProperty.eventNameTitle, - items: eventItems, - isCustomItem: eventSectionButtonCustomItem, + initialSelectedID: envelopeDetailProperty.category.id, customTextFieldPrompt: "경조사 이름" ) // 만약 현재 관계가 default 이벤트에 존재 하지 않는다면 relationSectionButtonCustomItem = customRelationItem - + relationSectionButtonCustomItem.relation = envelopeDetailProperty.friendRelationship.customRelation ?? "" relationSectionButtonHelper = .init( titleText: envelopeDetailProperty.relationTitle, items: relationItems, isCustomItem: relationSectionButtonCustomItem, + initialSelectedID: envelopeDetailProperty.relationship.id, customTextFieldPrompt: "관계 이름" ) - nameEditProperty = .init(textFieldText: envelopeDetailProperty.name) - - dateEditProperty = .init(date: envelopeDetailProperty.date) + nameEditProperty = .init(textFieldText: envelopeDetailProperty.friend.name) + let date = CustomDateFormatter.getDate(from: envelopeDetailProperty.envelope.handedOverAt) ?? .now + dateEditProperty = .init(date: date) + // has visited? visitedSectionButtonHelper = .init( titleText: envelopeDetailProperty.visitedTitle, items: VisitedSelectButtonItem.defaultItems(), isCustomItem: nil, + initialSelectedID: envelopeDetailProperty.hasVisitedID, customTextFieldPrompt: nil, isEssentialProperty: false ) - visitedEditProperty = .init(isVisited: envelopeDetailProperty.isVisited ?? true) - - giftEditProperty = .init(gift: envelopeDetailProperty.gift ?? "") - - contactEditProperty = .init(contact: envelopeDetailProperty.contacts ?? "") - - memoEditProperty = .init(memo: envelopeDetailProperty.memo ?? "") + // Additional Property initialize + visitedEditProperty = .init(isVisited: envelopeDetailProperty.envelope.hasVisited) + giftEditProperty = .init(gift: envelopeDetailProperty.envelope.gift) + contactEditProperty = .init(contact: envelopeDetailProperty.friend.phoneNumber) + memoEditProperty = .init(memo: envelopeDetailProperty.envelope.memo) } mutating func changeName(_ name: String) { @@ -153,176 +163,39 @@ public struct SpecificEnvelopeEditHelper: Equatable { priceProperty.isShowToast } - func isValidToSave() -> Bool { - (priceProperty.isValid) && - (eventSectionButtonHelper.isValid()) && - (nameEditProperty.isValid) && - (relationSectionButtonHelper.isValid()) && - (memoEditProperty.isValid) && - (contactEditProperty.isValid) && - (giftEditProperty.isValid) && - (visitedEditProperty.isValid) - // 데이트는 항상 참이니까 제외 - } -} - -// MARK: - PriceEditProperty - -struct PriceEditProperty: Equatable { - var price: Int64 - var priceTextFieldText: String - var priceText: String - - init(price: Int64) { - self.price = price - priceTextFieldText = price.description - priceText = CustomNumberFormatter.formattedByThreeZero(price, subFixString: "원") ?? "" - } - - mutating func setPriceTextFieldText(_ text: String) { - priceTextFieldText = text.isEmpty ? "0" : text - guard let currentValue = Int64(priceTextFieldText) else { - return - } - price = currentValue - priceText = CustomNumberFormatter.formattedByThreeZero(currentValue, subFixString: "원") ?? "" - } - - var isValid: Bool { - RegexManager.isValidPrice(priceTextFieldText) - } - - var isShowToast: Bool { - ToastRegexManager.isShowToastByPrice(priceTextFieldText) - } -} - -// MARK: - GiftEditProperty - -struct GiftEditProperty: Equatable { - var gift: String - - init(gift: String) { - self.gift = gift - } - - var isValid: Bool { - RegexManager.isValidGift(gift) || gift.isEmpty - } - - var isShowToast: Bool { - ToastRegexManager.isShowToastByGift(gift) - } -} - -// MARK: - ContactEditProperty - -struct ContactEditProperty: Equatable { - var contact: String - - init(contact: String) { - self.contact = contact - } - - var isValid: Bool { - RegexManager.isValidContacts(contact) || contact.isEmpty - } - - var isShowToast: Bool { - ToastRegexManager.isShowToastByContacts(contact) - } -} - -// MARK: - MemoEditProperty - -struct MemoEditProperty: Equatable { - var memo: String - init(memo: String) { - self.memo = memo - } - - var isValid: Bool { - RegexManager.isValidMemo(memo) || memo.isEmpty - } - - var isShowToast: Bool { - ToastRegexManager.isShowToastByMemo(memo) + func isChangedProperty() -> Bool { + false } -} - -// MARK: - VisitedEditProperty -struct VisitedEditProperty: Equatable { - var isVisited: Bool - - init(isVisited: Bool) { - self.isVisited = isVisited - } - - var isValid: Bool { - return true - } -} - -// MARK: - VisitedSelectButtonItem - -public struct VisitedSelectButtonItem: SingleSelectButtonItemable { - public var id: Int - public var title: String = "" - var isVisited: Bool - init(id: Int, title: String = "", isVisited: Bool) { - self.id = id - self.title = title - self.isVisited = isVisited - } - - mutating func setTitle(by isVisited: Bool) { - title = isVisited ? "예" : "아니오" - } -} - -extension VisitedSelectButtonItem { - static func defaultItems() -> [Self] { - return [ - yes, no, - ] - } - - static var yes: Self { - .init(id: 0, title: "예", isVisited: true) - } - - static var no: Self { - .init(id: 1, title: "아니오", isVisited: false) + func isValidToSave() -> Bool { + let isChanged = !envelopeEditProperties.filter(\.isChanged).isEmpty + let isValid = envelopeEditProperties.filter { $0.isValid == false }.isEmpty + return isValid && isChanged } } -// MARK: - DateEditProperty - -struct DateEditProperty: Equatable { - var date: Date - var isInitialState = false - - var dateText: String { - return CustomDateFormatter.getKoreanDateString(from: date) - } - - init(date: Date) { - self.date = date +private extension EnvelopeDetailProperty { + var hasVisitedID: VisitedSelectButtonItem.ID? { + guard let hasVisited = envelope.hasVisited else { + return nil + } + return hasVisited ? VisitedSelectButtonItem.yes.id : VisitedSelectButtonItem.no.id } } -// MARK: - NameEditProperty - -/// EditName을 하기 위해 사용됩니다. -struct NameEditProperty: Equatable { - var textFieldText: String +// MARK: - SingleSelectButtonHelper + EnvelopeEditPropertiable +extension SingleSelectButtonHelper: EnvelopeEditPropertiable { var isValid: Bool { - RegexManager.isValidName(textFieldText) + isValid() } - var isShowToast: Bool { - ToastRegexManager.isShowToastByName(textFieldText) + var isChanged: Bool { + // 커스텀 아이템이 되었고, 과거에 커스텀 아이템 타이틀이 존재했다면 + if let initialCustomTitle = initialSelectedCustomTitle, isCustomItemSelected { + return initialCustomTitle != selectedItem?.title + } + // 커스텀 아이템이 선택되지 않았다면 + return initialSelectedID != selectedItem?.id } } diff --git a/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeEdit/SpecificEnvelopeEditReducer.swift b/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeEdit/SpecificEnvelopeEditReducer.swift index 5338a721..eb2f8d6f 100644 --- a/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeEdit/SpecificEnvelopeEditReducer.swift +++ b/Projects/Feature/SSEnvelope/Sources/SpecificEnvelopeEdit/SpecificEnvelopeEditReducer.swift @@ -35,24 +35,9 @@ public struct SpecificEnvelopeEditReducer { init(editHelper: SpecificEnvelopeEditHelper, isShowCategory: Bool = true) { self.isShowCategory = isShowCategory _editHelper = .init(editHelper) - let initialVisited: VisitedSelectButtonItem? = - if let isVisited = editHelper.envelopeDetailProperty.isVisited { - isVisited ? .yes : .no - } else { - nil - } - eventSection = .init( - singleSelectButtonHelper: _editHelper.eventSectionButtonHelper, - initialSelectedID: editHelper.envelopeDetailProperty.eventID - ) - relationSection = .init( - singleSelectButtonHelper: _editHelper.relationSectionButtonHelper, - initialSelectedID: editHelper.envelopeDetailProperty.relationID - ) - visitedSection = .init( - singleSelectButtonHelper: _editHelper.visitedSectionButtonHelper, - initialSelectedID: initialVisited?.id - ) + eventSection = .init(singleSelectButtonHelper: _editHelper.eventSectionButtonHelper) + relationSection = .init(singleSelectButtonHelper: _editHelper.relationSectionButtonHelper) + visitedSection = .init(singleSelectButtonHelper: _editHelper.visitedSectionButtonHelper) } public init(envelopeID: Int64, isShowCategory: Bool = true) async throws { @@ -93,7 +78,6 @@ public struct SpecificEnvelopeEditReducer { public enum AsyncAction: Equatable { case editFriendsAndEnvelope - case updateEnvelopes(friendID: Int64) } @Dependency(\.envelopeNetwork) var network @@ -233,70 +217,62 @@ extension SpecificEnvelopeEditReducer: FeatureViewAction, FeatureInnerAction, Fe } } + func updateEnvelope(_ state: State, friendID: Int64, send: Send) async throws { + guard let selectedCategoryItem = state.editHelper.eventSectionButtonHelper.selectedItem else { + return + } + + let customCategory = selectedCategoryItem.id == state.editHelper.eventSectionButtonHelper.isCustomItem?.id ? + state.editHelper.eventSectionButtonHelper.isCustomItem?.title : nil + + let giftText: String = state.editHelper.giftEditProperty.gift + let queryGiftText: String? = giftText.isEmpty ? nil : giftText + + let memoText: String = state.editHelper.memoEditProperty.memo + let queryMemoText: String? = memoText.isEmpty ? nil : memoText + + let envelopeRequestBody = CreateAndUpdateEnvelopeRequest( + type: state.editHelper.envelopeDetailProperty.envelope.type, + friendId: friendID, + ledgerId: nil, + amount: state.editHelper.priceProperty.price, + gift: queryGiftText, + memo: queryMemoText, + hasVisited: state.editHelper.visitedSectionButtonHelper.selectedItem?.isVisited, + handedOverAt: CustomDateFormatter.getFullDateString(from: state.editHelper.dateEditProperty.date), + category: .init(id: state.editHelper.eventSectionButtonHelper.selectedItem?.id ?? 0, customCategory: customCategory) + ) + + let envelopeID = state.editHelper.envelopeDetailProperty.envelope.id + + let envelopeProperty = try await network.editEnvelopes(envelopeID, envelopeRequestBody) + UpdateEnvelopeDetailPropertyPublisher.send(envelopeProperty) + await send(.delegate(.tappedSaveButton(envelopeID: envelopeID))) + await dismiss() + } + public func asyncAction(_ state: inout State, _ action: AsyncAction) -> ComposableArchitecture.Effect { switch action { case .editFriendsAndEnvelope: - guard let selectedRelationItem = state.editHelper.relationSectionButtonHelper.selectedItem, - let customItem = state.editHelper.relationSectionButtonHelper.isCustomItem, - let selectedItemID = state.editHelper.relationSectionButtonHelper.selectedItem?.id + guard let selectedRelationItem = state.editHelper.relationSectionButtonHelper.selectedItem else { return .none } - - // 만약 선택된 아이템이 customItem일 경우 - let customRelation = selectedItemID == customItem.id ? customItem.title : nil let phoneNumber = state.editHelper.contactEditProperty.contact - - let friendID = state.editHelper.envelopeDetailProperty.friendID + let customItemTitle = state.editHelper.relationSectionButtonHelper.isCustomItem?.relation let friendRequestBody = CreateAndUpdateFriendRequest( name: state.editHelper.nameEditProperty.textFieldText, phoneNumber: phoneNumber.isEmpty ? nil : phoneNumber, relationshipId: selectedRelationItem.id, - customRelation: customRelation + customRelation: customItemTitle ) - return .ssRun { send in + let friendID = state.editHelper.envelopeDetailProperty.friend.id + return .ssRun { [state = state] send in await send(.inner(.isLoading(true))) let updatedFriendID = try await network.editFriends(friendID, friendRequestBody) - await send(.async(.updateEnvelopes(friendID: updatedFriendID))) - await send(.inner(.isLoading(false))) - } - - case let .updateEnvelopes(friendID): - guard let selectedCategoryItem = state.editHelper.eventSectionButtonHelper.selectedItem - else { - return .none - } - - let customCategory = selectedCategoryItem.id == state.editHelper.eventSectionButtonHelper.isCustomItem?.id ? - state.editHelper.eventSectionButtonHelper.isCustomItem?.title : nil - - let giftText: String = state.editHelper.giftEditProperty.gift - let queryGiftText: String? = giftText.isEmpty ? nil : giftText - - let memoText: String = state.editHelper.memoEditProperty.memo - let queryMemoText: String? = memoText.isEmpty ? nil : memoText - - let envelopeRequestBody = CreateAndUpdateEnvelopeRequest( - type: state.editHelper.envelopeDetailProperty.type, - friendId: friendID, - ledgerId: state.editHelper.envelopeDetailProperty.ledgerID, - amount: state.editHelper.priceProperty.price, - gift: queryGiftText, - memo: queryMemoText, - hasVisited: state.editHelper.visitedSectionButtonHelper.selectedItem?.isVisited, - handedOverAt: CustomDateFormatter.getFullDateString(from: state.editHelper.dateEditProperty.date), - category: .init(id: state.editHelper.eventSectionButtonHelper.selectedItem?.id ?? 0, customCategory: customCategory) - ) - - let envelopeID = state.editHelper.envelopeDetailProperty.id - return .ssRun { send in - await send(.inner(.isLoading(true))) - let envelopeProperty = try await network.editEnvelopes(envelopeID, envelopeRequestBody) - UpdateEnvelopeDetailPropertyPublisher.send(envelopeProperty) + try await updateEnvelope(state, friendID: updatedFriendID, send: send) await send(.inner(.isLoading(false))) - await send(.delegate(.tappedSaveButton(envelopeID: envelopeID))) - await dismiss() } } } diff --git a/Projects/Feature/Sent/Sources/SpecificEnvelope/SpecificEnvelopeHistoryRouter/SpecificEnvelopeHistoryRouter.swift b/Projects/Feature/Sent/Sources/SpecificEnvelope/SpecificEnvelopeHistoryRouter/SpecificEnvelopeHistoryRouter.swift index 780427b0..59bb6455 100644 --- a/Projects/Feature/Sent/Sources/SpecificEnvelope/SpecificEnvelopeHistoryRouter/SpecificEnvelopeHistoryRouter.swift +++ b/Projects/Feature/Sent/Sources/SpecificEnvelope/SpecificEnvelopeHistoryRouter/SpecificEnvelopeHistoryRouter.swift @@ -51,7 +51,7 @@ struct SpecificEnvelopeHistoryRouter { func handleEnvelopeDetailDelegateAction(state _: inout State, action: SpecificEnvelopeDetailReducer.Action.DelegateAction) -> Effect { switch action { case let .tappedEnvelopeEditButton(property): - return .ssRun { [id = property.id] _ in + return .ssRun { [id = property.envelope.id] _ in let editState = try await SpecificEnvelopeEditReducer.State(envelopeID: id) SpecificEnvelopeHistoryRouterPublisher.push(.specificEnvelopeHistoryEdit(editState)) }