From dc507b3a8799aff273261226d684a81401ee062a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9E=84=ED=98=84=EA=B7=9C?= <48830320+leemhyungyu@users.noreply.github.com> Date: Wed, 25 Sep 2024 21:13:39 +0900 Subject: [PATCH] =?UTF-8?q?[Feature/#232]=20=EC=BB=A4=EC=8A=A4=ED=85=80=20?= =?UTF-8?q?alert=20=EC=A0=81=EC=9A=A9=20(#272)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: SplashView bottleAlert 적용 * feat: PingPongDetailView bottleAlert 적용 * feat: ReportUserView bottleAlert 적용 * feat: SandBeachView bottleAlert 적용 --- .../PingPongDetailFeature.swift | 48 +++++++++++++++++-- .../PingPongDetailFeatureInterface.swift | 20 +++++++- .../PingPongDetail/PingPongDetailView.swift | 1 + .../Introduction/IntroductionFeature.swift | 23 +-------- .../IntroductionFeatureInterface.swift | 24 +--------- .../Introduction/IntroductionView.swift | 2 - .../QuestionAndAnswerFeature.swift | 24 +--------- .../QuestionAndAnswerFeatureInterface.swift | 21 +------- .../QuestionAndAnswerView.swift | 1 - .../Interface/Sources/ReportUserFeature.swift | 32 +++++++++---- .../Sources/ReportUserFeatureInterface.swift | 1 + .../Interface/Sources/ReportUserView.swift | 2 +- .../Sources/SandBeach/SandBeachView.swift | 2 +- .../Sources/SplashView/SplashView.swift | 2 +- 14 files changed, 99 insertions(+), 104 deletions(-) diff --git a/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/PingPongDetail/PingPongDetailFeature.swift b/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/PingPongDetail/PingPongDetailFeature.swift index b24ca8dd..9ee14df5 100644 --- a/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/PingPongDetail/PingPongDetailFeature.swift +++ b/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/PingPongDetail/PingPongDetailFeature.swift @@ -7,10 +7,11 @@ import Foundation -import CoreLoggerInterface import FeatureReportInterface import DomainBottle +import CoreLoggerInterface + import ComposableArchitecture extension PingPongDetailFeature { @@ -42,12 +43,46 @@ extension PingPongDetailFeature { imageURL: imageURL ?? "", userID: userId ?? -1, userName: userName, userAge: userAge ?? -1) return .send(.delegate(.reportButtonDidTapped(userReportProfile))) + case .stopTalkAlertDidRequired: + state.destination = .alert(.init( + title: { TextState("중단하기") }, + actions: { + ButtonState( + role: .cancel, + action: .dismiss, + label: { TextState("계속하기")}) + + ButtonState( + role: .destructive, + action: .confirmStopTalk, + label: { TextState("중단하기") }) + }, + message: { TextState("중단 시 모든 핑퐁 내용이 사라져요. 정말 중단하시겠어요?") } + )) + return .none + + // Destination + case let .destination(.presented(.alert(alert))): + switch alert { + case .confirmStopTalk: + return .run { [bottleID = state.bottleID] send in + try await bottleClient.stopTalk(bottleID: bottleID) + await send(.delegate(.popToRootDidRequired)) + } + + case .dismiss: + state.destination = nil + return .none + } + + // Introduction Delegate case let .introduction(.delegate(delegate)): switch delegate { - case .popToRootDidRequired: - return .send(.delegate(.popToRootDidRequired)) + case .stopTaskButtonTapped: + return .send(.stopTalkAlertDidRequired) } - + + // QuestionAndAnswer Delegate case let .questionAndAnswer(.delegate(delegate)): switch delegate { case .reloadPingPongRequired: @@ -56,8 +91,11 @@ extension PingPongDetailFeature { return .send(.delegate(.popToRootDidRequired)) case .refreshPingPong: return fetchPingPong(state: &state) + case .stopTaskButtonDidTapped: + return .send(.stopTalkAlertDidRequired) } - + + // Matching Delegate case let .matching(.delegate(delegate)): switch delegate { case .otherBottleButtonDidTapped: diff --git a/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/PingPongDetail/PingPongDetailFeatureInterface.swift b/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/PingPongDetail/PingPongDetailFeatureInterface.swift index 45dfb790..5938b3e1 100644 --- a/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/PingPongDetail/PingPongDetailFeatureInterface.swift +++ b/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/PingPongDetail/PingPongDetailFeatureInterface.swift @@ -43,6 +43,8 @@ public struct PingPongDetailFeature { var matching: MatchingFeature.State var selectedTab: PingPongDetailViewTabType + @Presents var destination: Destination.State? + public init( bottleID: Int, isRead: Bool, @@ -67,7 +69,7 @@ public struct PingPongDetailFeature { case pingPongDidFetched(_: BottlePingPong) case backButtonDidTapped case reportButtonDidTapped - + case stopTalkAlertDidRequired // Delegate case delegate(Delegate) @@ -83,6 +85,13 @@ public struct PingPongDetailFeature { case questionAndAnswer(QuestionAndAnswerFeature.Action) case matching(MatchingFeature.Action) case binding(BindingAction) + case destination(PresentationAction) + // Alert + case alert(Alert) + public enum Alert: Equatable { + case confirmStopTalk + case dismiss + } } public var body: some ReducerOf { @@ -97,6 +106,15 @@ public struct PingPongDetailFeature { MatchingFeature() } reducer + .ifLet(\.$destination, action: \.destination) } } +// MARK: - Destination + +extension PingPongDetailFeature { + @Reducer(state: .equatable) + public enum Destination { + case alert(AlertState) + } +} diff --git a/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/PingPongDetail/PingPongDetailView.swift b/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/PingPongDetail/PingPongDetailView.swift index 55cce1f8..9da0026a 100644 --- a/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/PingPongDetail/PingPongDetailView.swift +++ b/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/PingPongDetail/PingPongDetailView.swift @@ -55,6 +55,7 @@ public struct PingPongDetailView: View { } ) .ignoresSafeArea(.all, edges: .bottom) + .bottleAlert($store.scope(state: \.destination?.alert, action: \.destination.alert)) } } diff --git a/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/SubViews/Introduction/IntroductionFeature.swift b/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/SubViews/Introduction/IntroductionFeature.swift index 3a88ad0d..1ba3a024 100644 --- a/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/SubViews/Introduction/IntroductionFeature.swift +++ b/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/SubViews/Introduction/IntroductionFeature.swift @@ -33,26 +33,7 @@ extension IntroductionFeature { return .none case .stopTaskButtonTapped: - state.destination = .alert(.init( - title: { TextState("중단하기") }, - actions: { - ButtonState( - role: .destructive, - action: .confirmStopTalk, - label: { TextState("중단하기") }) - }, - message: { TextState("중단 시 모든 핑퐁 내용이 사라져요. 정말 중단하시겠어요?") } - )) - return .none - - case let .destination(.presented(.alert(alert))): - switch alert { - case .confirmStopTalk: - return .run { [bottleID = state.bottleID] send in - try await bottleClient.stopTalk(bottleID: bottleID) - await send(.delegate(.popToRootDidRequired)) - } - } + return .send(.delegate(.stopTaskButtonTapped)) case .refreshPingPongDidRequired: return .run { [bottleID = state.bottleID] send in @@ -62,7 +43,7 @@ extension IntroductionFeature { await send(.introductionFetched(pingPong.introduction ?? [])) } - case .binding, .alert: + case .binding: return .none default: diff --git a/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/SubViews/Introduction/IntroductionFeatureInterface.swift b/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/SubViews/Introduction/IntroductionFeatureInterface.swift index 52be5fb3..17e4d8df 100644 --- a/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/SubViews/Introduction/IntroductionFeatureInterface.swift +++ b/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/SubViews/Introduction/IntroductionFeatureInterface.swift @@ -68,9 +68,7 @@ public struct IntroductionFeature { + (interest?.etc ?? []) + (interest?.sports ?? []) } - - @Presents var destination: Destination.State? - + public init (bottleID: Int) { self.bottleID = bottleID } @@ -88,32 +86,14 @@ public struct IntroductionFeature { // ETC. case binding(BindingAction) - case destination(PresentationAction) - - case alert(Alert) - public enum Alert: Equatable { - case confirmStopTalk - } - case delegate(Delegate) public enum Delegate { - case popToRootDidRequired + case stopTaskButtonTapped } } public var body: some ReducerOf { reducer - .ifLet(\.$destination, action: \.destination) } } - -// MARK: - Destination - -extension IntroductionFeature { - @Reducer(state: .equatable) - public enum Destination { - case alert(AlertState) - } -} - diff --git a/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/SubViews/Introduction/IntroductionView.swift b/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/SubViews/Introduction/IntroductionView.swift index 16d1f144..9744ee5a 100644 --- a/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/SubViews/Introduction/IntroductionView.swift +++ b/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/SubViews/Introduction/IntroductionView.swift @@ -81,9 +81,7 @@ public struct IntroductionView: View { .padding(.top, 32.0) } .scrollIndicators(.hidden) - .alert($store.scope(state: \.destination?.alert, action: \.destination.alert)) .background(to: ColorToken.background(.primary)) - } } } diff --git a/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/SubViews/QuestionAndAnswer/QuestionAndAnswerFeature.swift b/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/SubViews/QuestionAndAnswer/QuestionAndAnswerFeature.swift index 5a4dc213..a03ed829 100644 --- a/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/SubViews/QuestionAndAnswer/QuestionAndAnswerFeature.swift +++ b/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/SubViews/QuestionAndAnswer/QuestionAndAnswerFeature.swift @@ -83,30 +83,10 @@ extension QuestionAndAnswerFeature { } case .stopTalkButtonDidTapped: - state.destination = .alert(.init( - title: { TextState("중단하기") }, - actions: { - ButtonState( - role: .destructive, - action: .confirmStopTalk, - label: { TextState("중단하기") }) - }, - message: { TextState("중단 시 모든 핑퐁 내용이 사라져요. 정말 중단하시겠어요?") } - )) - return .none + return .send(.delegate(.stopTaskButtonDidTapped)) case .refreshDidPulled: return .send(.delegate(.refreshPingPong)) - - case let .destination(.presented(.alert(alert))): - switch alert { - case .confirmStopTalk: - state.isShowLoadingIndicator = true - return .run { [bottleID = state.bottleID] send in - try await bottleClient.stopTalk(bottleID: bottleID) - await send(.delegate(.popToRootDidRequired)) - } - } case .binding(\.firstLetterTextFieldContent): if state.firstLetterTextFieldContent.count >= 50 { @@ -132,7 +112,7 @@ extension QuestionAndAnswerFeature { } return .none - case .binding, .destination, .alert: + case .binding: return .none default: diff --git a/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/SubViews/QuestionAndAnswer/QuestionAndAnswerFeatureInterface.swift b/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/SubViews/QuestionAndAnswer/QuestionAndAnswerFeatureInterface.swift index f4144743..770ba42a 100644 --- a/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/SubViews/QuestionAndAnswer/QuestionAndAnswerFeatureInterface.swift +++ b/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/SubViews/QuestionAndAnswer/QuestionAndAnswerFeatureInterface.swift @@ -114,9 +114,7 @@ public struct QuestionAndAnswerFeature { } var finalSelectIsSelctedYesButton: Bool var finalSelectIsSelctedNoButton: Bool - - @Presents var destination: Destination.State? - + public init(bottleID: Int) { self.bottleID = bottleID self.isShowLoadingIndicator = false @@ -181,12 +179,6 @@ public struct QuestionAndAnswerFeature { // ETC. case binding(BindingAction) - case destination(PresentationAction) - - case alert(Alert) - public enum Alert: Equatable { - case confirmStopTalk - } case delegate(Delegate) @@ -194,21 +186,12 @@ public struct QuestionAndAnswerFeature { case reloadPingPongRequired case popToRootDidRequired case refreshPingPong + case stopTaskButtonDidTapped } } public var body: some ReducerOf { BindingReducer() reducer - .ifLet(\.$destination, action: \.destination) - } -} - -// MARK: - Destination - -extension QuestionAndAnswerFeature { - @Reducer(state: .equatable) - public enum Destination { - case alert(AlertState) } } diff --git a/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/SubViews/QuestionAndAnswer/QuestionAndAnswerView.swift b/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/SubViews/QuestionAndAnswer/QuestionAndAnswerView.swift index 22c45bfe..24270272 100644 --- a/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/SubViews/QuestionAndAnswer/QuestionAndAnswerView.swift +++ b/Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/SubViews/QuestionAndAnswer/QuestionAndAnswerView.swift @@ -134,7 +134,6 @@ public struct QuestionAndAnswerView: View { LoadingIndicator() } } - .alert($store.scope(state: \.destination?.alert, action: \.destination.alert)) .background(to: ColorToken.background(.primary)) .toolbar(.hidden, for: .bottomBar) diff --git a/Projects/Feature/Report/Interface/Sources/ReportUserFeature.swift b/Projects/Feature/Report/Interface/Sources/ReportUserFeature.swift index 9a008b48..b854751c 100644 --- a/Projects/Feature/Report/Interface/Sources/ReportUserFeature.swift +++ b/Projects/Feature/Report/Interface/Sources/ReportUserFeature.swift @@ -28,10 +28,19 @@ extension ReportUserFeature { print("tapped") state.destination = .alert(.init( title: { TextState("신고하기")}, - actions: { ButtonState( - role: .destructive, - action: .confirmReport, - label: { TextState("신고하기") }) }, + actions: { + ButtonState( + role: .cancel, + action: .confirmReport, + label: { TextState("계속하기") } + ) + + ButtonState( + role: .destructive, + action: .dismiss, + label: { TextState("중단하기") } + ) + }, message: { TextState("접수 후 취소할 수 없으며 해당 사용자는 차단되요.\n정말 신고하시겠어요?")})) return .none @@ -43,10 +52,17 @@ extension ReportUserFeature { } return .none - case .destination(.presented(.alert(.confirmReport))): - return .run { [userProfile = state.userProfile, reportText = state.reportText] send in - try await reportClient.reportUser(userReportInfo: .init(reason: reportText, userId: userProfile.userID)) - await send(.delegate(.reportDidCompleted)) + case let .destination(.presented(.alert(alert))): + switch alert { + case .confirmReport: + return .run { [userProfile = state.userProfile, reportText = state.reportText] send in + try await reportClient.reportUser(userReportInfo: .init(reason: reportText, userId: userProfile.userID)) + await send(.delegate(.reportDidCompleted)) + } + + case .dismiss: + state.destination = nil + return .none } case .binding(\.reportText): diff --git a/Projects/Feature/Report/Interface/Sources/ReportUserFeatureInterface.swift b/Projects/Feature/Report/Interface/Sources/ReportUserFeatureInterface.swift index 9c8b487f..6b1fe780 100644 --- a/Projects/Feature/Report/Interface/Sources/ReportUserFeatureInterface.swift +++ b/Projects/Feature/Report/Interface/Sources/ReportUserFeatureInterface.swift @@ -70,6 +70,7 @@ public struct ReportUserFeature { case alert(Alert) public enum Alert: Equatable { case confirmReport + case dismiss } // ETC diff --git a/Projects/Feature/Report/Interface/Sources/ReportUserView.swift b/Projects/Feature/Report/Interface/Sources/ReportUserView.swift index 3f626967..bef7669e 100644 --- a/Projects/Feature/Report/Interface/Sources/ReportUserView.swift +++ b/Projects/Feature/Report/Interface/Sources/ReportUserView.swift @@ -35,7 +35,7 @@ public struct ReportUserView: View { } } .padding(.horizontal, .md) - .alert($store.scope(state: \.destination?.alert, action: \.destination.alert)) + .bottleAlert($store.scope(state: \.destination?.alert, action: \.destination.alert)) .toolbar(.hidden, for: .bottomBar) } } diff --git a/Projects/Feature/SandBeach/Interface/Sources/SandBeach/SandBeachView.swift b/Projects/Feature/SandBeach/Interface/Sources/SandBeach/SandBeachView.swift index bcfea92b..cb523178 100644 --- a/Projects/Feature/SandBeach/Interface/Sources/SandBeach/SandBeachView.swift +++ b/Projects/Feature/SandBeach/Interface/Sources/SandBeach/SandBeachView.swift @@ -64,7 +64,7 @@ public struct SandBeachView: View { } } } - .alert($store.scope(state: \.destination?.alert, action: \.destination.alert)) + .bottleAlert($store.scope(state: \.destination?.alert, action: \.destination.alert)) .onAppear { store.send(.onAppear) } diff --git a/Projects/Feature/Sources/SplashView/SplashView.swift b/Projects/Feature/Sources/SplashView/SplashView.swift index 52d19d52..7329ec31 100644 --- a/Projects/Feature/Sources/SplashView/SplashView.swift +++ b/Projects/Feature/Sources/SplashView/SplashView.swift @@ -26,7 +26,7 @@ public struct SplashView: View { Image.BottleImageSystem.illustraition(.splash).image } - .alert($store.scope(state: \.destination?.alert, action: \.destination.alert)) + .bottleAlert($store.scope(state: \.destination?.alert, action: \.destination.alert)) .ignoresSafeArea() .task { store.send(.onAppear)