Reputation: 153
I want to implement a functionality where when a user clicks a URL to reset their password, it directs them to the "PasswordReset" screen in my app.
Currently, when I click the URL (ex: https://app.myApp.com/auth/reset?token=1234), it opens up to the "FirstView" screen instead of the "PasswordReset" screen.
I noticed when I print the URL in the "myApp struct", it prints the correct URL above, but if I print the URL in the "RootView struct", it shows up as nil. What steps can I take to ensure that the URL loads to the "PasswordReset" screen?
@main
struct myApp: App {
@State var route: URL?
var body: some Scene {
WindowGroup {
RootView(url: route)
.onOpenURL { url in
let _ = print(url) // prints: https://app.myApp.com/auth/reset?token=1234
self.route = url
}
}
}
}
struct RootView: View {
@ObservedObject var authenticator = Authenticator.shared
@State var url: URL?
var body: some View {
let _ = print(url) // prints: nil
// if user clicks on url to reset password, PasswordResetView should load
if url?.pathComponents.contains("reset") ?? false,
let resetToken = url?.queryDictionary?["token"] {
NavigationView {
PasswordResetView(viewModel: .init(onFinish: { url = nil }))
.onAppear {
self.authenticator.accessToken = resetToken
}
}
// if user had accessToken (can log in), the MainTabView should load
} else if authenticator.accessToken != nil {
MainTabView()
// if user has no accessToken, FirstView should load
} else {
NavigationView {
FirstView()
}
}
}
}
extension URL {
var queryDictionary: [String: String]? {
guard let query = self.query else { return nil }
var queryStrings = [String: String]()
for pair in query.components(separatedBy: "&") {
let key = pair.components(separatedBy: "=")[0]
let value = pair
.components(separatedBy: "=")[1]
.replacingOccurrences(of: "+", with: " ")
.removingPercentEncoding ?? ""
queryStrings[key] = value
}
return queryStrings
}
}
Upvotes: 2
Views: 1557
Reputation: 153
Here's my solution to this issue:
struct myApp: App {
@ObservedObject var authenticator = Authenticator.shared
@State var route: URL?
@State var urlToken: String?
var body: some Scene {
WindowGroup {
RootView(url: route)
.onOpenURL { url in
self.route = url
if url.pathComponents.contains("reset"), let token = url.queryDictionary?["token"] {
self.urlToken = token
}
}
.fullScreenCover(item: $urlToken) { _ in
NavigationView {
PasswordResetView(viewModel: .init(onFinish: {
route = nil
urlToken = nil
}))
.onAppear {
self.authenticator.accessToken = urlToken
}
}
}
}
}
}
struct RootView: View {
@ObservedObject var authenticator = Authenticator.shared
var body: some View {
if authenticator.accessToken != nil {
MainTabView()
} else {
NavigationView {
FirstView()
}
}
}
}
Upvotes: 2