Is there a pretty way of presenting multiple alerts via destination enum? #3501
-
Hello everyone. I am trying to incorporate multiple alerts and a sheet destination into a single destination enum.
I don't like that one has to dig into Any ideas to do this in a more ergonomic way? |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
Hi @iharandreyev, there is no need for the import SwiftUI
@Reducer
struct SheetFeature { }
@Reducer
struct MultipleAlertsFeature {
@ObservableState
struct State {
@Presents
var destination: Destination.State?
}
@CasePathable
enum Action {
case destination(PresentationAction<Destination.Action>)
case showProceedAlertButtonTapped
case showInfoAlertButtonTapped
case showSheetButtonTapped
}
@Reducer
enum Destination {
case proceedAlert(AlertState<ProceedingAlertAction>)
case infoAlert(AlertState<InfoAlertAction>)
case sheetFeature(SheetFeature)
}
@CasePathable
enum ProceedingAlertAction {
case proceed
}
@CasePathable
enum InfoAlertAction {
case showInfo
}
var body: some ReducerOf<Self> {
Reduce(internal: { state, action in
switch action {
case .showProceedAlertButtonTapped:
state.destination = .proceedAlert(createProceedAlert())
return .none
case .destination(.presented(.proceedAlert(.proceed))):
print("Proceed action triggered")
return .none
case .showInfoAlertButtonTapped:
state.destination = .infoAlert(createInfoAlert())
return .none
case .destination(.presented(.infoAlert(.showInfo))):
print("Show info action triggered")
return .none
case .showSheetButtonTapped:
state.destination = .sheetFeature(.init())
return .none
default:
return .none
}
})
.ifLet(\.$destination, action: \.destination)
}
func createProceedAlert() -> AlertState<ProceedingAlertAction> {
AlertState(
title: {
TextState("Proceeding alert title")
},
actions: {
ButtonState(
role: .cancel,
label: {
TextState("Dismiss")
}
)
ButtonState(
action: .proceed,
label: {
TextState("Proceed")
}
)
},
message: {
TextState("Proceed alert message")
}
)
}
func createInfoAlert() -> AlertState<InfoAlertAction> {
AlertState(
title: {
TextState("Info alert title")
},
actions: {
ButtonState(
role: .cancel,
label: {
TextState("Dismiss")
}
)
ButtonState(
action: .showInfo,
label: {
TextState("Show Info")
}
)
},
message: {
TextState("Into alert message")
}
)
}
}
struct MultipleAlertsFeatureView: View {
@Perception.Bindable
var store: StoreOf<MultipleAlertsFeature>
var body: some View {
WithPerceptionTracking {
VStack {
Button("Show proceed alert") {
store.send(.showProceedAlertButtonTapped)
}
Button("Show info alert") {
store.send(.showInfoAlertButtonTapped)
}
Button("Show sheet") {
store.send(.showSheetButtonTapped)
}
}
.alert($store.scope(state: \.destination?.proceedAlert, action: \.destination.proceedAlert))
.alert($store.scope(state: \.destination?.infoAlert, action: \.destination.infoAlert))
.sheet(item: $store.scope(state: \.destination?.sheetFeature, action: \.destination.sheetFeature)) { sheetFeature in
// type check
let _: StoreOf<SheetFeature> = sheetFeature
return Text("Some sheet")
}
}
}
}
#Preview {
MultipleAlertsFeatureView(
store: .init(
initialState: .init(),
reducer: {
MultipleAlertsFeature()//._printChanges()
}
)
)
} |
Beta Was this translation helpful? Give feedback.
Hi @iharandreyev, there is no need for the
SomeAlert
reducer. You can just useAlertState
directly in yourDestination
and it will work fine. Here's a fix to your code: