stub in signup view and toggle when button tapped

This commit is contained in:
Satindar Dhillon
2022-07-28 15:32:47 -07:00
parent 7dc1722ad2
commit 4e7010f7c1
4 changed files with 280 additions and 133 deletions

View File

@ -0,0 +1,263 @@
import Models
import Services
import SwiftUI
import Utils
import Views
enum EmailAuthState {
case signIn
case signUp
case loading
}
@MainActor final class EmailAuthViewModel: ObservableObject {
@Published var loginError: LoginError?
@Published var emailAuthState = EmailAuthState.loading
func loadAuthState() {
// check tokens here to determine pending/active/no user
emailAuthState = .signUp
}
func submitCredentials(
email: String,
password: String,
authenticator: Authenticator
) async {
do {
try await authenticator.submitEmailLogin(email: email, password: password)
} catch {
loginError = error as? LoginError
}
}
}
struct EmailAuthView: View {
@Environment(\.presentationMode) private var presentationMode
@StateObject private var viewModel = EmailAuthViewModel()
@ViewBuilder var primaryContent: some View {
switch viewModel.emailAuthState {
case .signUp:
EmailSignupFormView(viewModel: viewModel)
case .signIn:
EmailLoginFormView(viewModel: viewModel)
case .loading:
VStack {
Spacer()
ProgressView()
Spacer()
}
}
}
var body: some View {
NavigationView {
ZStack {
Color.appBackground.edgesIgnoringSafeArea(.all)
primaryContent
.frame(maxWidth: 300)
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .barTrailing) {
Button(
action: { presentationMode.wrappedValue.dismiss() },
label: { Image(systemName: "xmark").foregroundColor(.appGrayTextContrast) }
)
}
}
}
}
.task {
viewModel.loadAuthState()
}
}
}
struct EmailLoginFormView: View {
enum FocusedField {
case email, password
}
@Environment(\.horizontalSizeClass) var horizontalSizeClass
@EnvironmentObject var authenticator: Authenticator
@ObservedObject var viewModel: EmailAuthViewModel
@FocusState private var focusedField: FocusedField?
@State private var email = ""
@State private var password = ""
var body: some View {
VStack(spacing: 0) {
VStack(spacing: 28) {
ScrollView(showsIndicators: false) {
if horizontalSizeClass == .regular {
Spacer(minLength: 150)
}
VStack {
VStack(alignment: .leading, spacing: 6) {
Text("Email")
.font(.appFootnote)
.foregroundColor(.appGrayText)
TextField("", text: $email)
.textContentType(.emailAddress)
.textInputAutocapitalization(.never)
.disableAutocorrection(true)
.focused($focusedField, equals: .email)
}
.padding(.bottom, 8)
VStack(alignment: .leading, spacing: 6) {
Text("Password")
.font(.appFootnote)
.foregroundColor(.appGrayText)
SecureField("", text: $password)
.textContentType(.password)
.textInputAutocapitalization(.never)
.disableAutocorrection(true)
.focused($focusedField, equals: .password)
}
.padding(.bottom, 16)
Button(
action: {
Task {
await viewModel.submitCredentials(
email: email,
password: password,
authenticator: authenticator
)
}
},
label: { Text("Submit") }
)
.buttonStyle(SolidCapsuleButtonStyle(color: .appDeepBackground, width: 300))
if let loginError = viewModel.loginError {
LoginErrorMessageView(loginError: loginError)
}
HStack {
Button(
action: { viewModel.emailAuthState = .signUp },
label: {
Text("Don't have an account?")
.foregroundColor(.appGrayTextContrast)
.underline()
}
)
.padding(.vertical)
Spacer()
}
}
.textFieldStyle(StandardTextFieldStyle())
.onSubmit {
if focusedField == .email {
focusedField = .password
} else {
focusedField = nil
}
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
Spacer()
}
}
.navigationTitle("Sign In")
}
}
struct EmailSignupFormView: View {
enum FocusedField {
case email, password, fullName, username
}
@Environment(\.horizontalSizeClass) var horizontalSizeClass
@EnvironmentObject var authenticator: Authenticator
@ObservedObject var viewModel: EmailAuthViewModel
@FocusState private var focusedField: FocusedField?
@State private var email = ""
@State private var password = ""
var body: some View {
VStack(spacing: 0) {
VStack(spacing: 28) {
ScrollView(showsIndicators: false) {
if horizontalSizeClass == .regular {
Spacer(minLength: 150)
}
VStack {
VStack(alignment: .leading, spacing: 6) {
Text("Email")
.font(.appFootnote)
.foregroundColor(.appGrayText)
TextField("", text: $email)
.textContentType(.emailAddress)
.textInputAutocapitalization(.never)
.disableAutocorrection(true)
.focused($focusedField, equals: .email)
}
.padding(.bottom, 8)
VStack(alignment: .leading, spacing: 6) {
Text("Password")
.font(.appFootnote)
.foregroundColor(.appGrayText)
SecureField("", text: $password)
.textContentType(.password)
.textInputAutocapitalization(.never)
.disableAutocorrection(true)
.focused($focusedField, equals: .password)
}
.padding(.bottom, 16)
Button(
action: {
Task {
await viewModel.submitCredentials(
email: email,
password: password,
authenticator: authenticator
)
}
},
label: { Text("Submit") }
)
.buttonStyle(SolidCapsuleButtonStyle(color: .appDeepBackground, width: 300))
if let loginError = viewModel.loginError {
LoginErrorMessageView(loginError: loginError)
}
HStack {
Button(
action: { viewModel.emailAuthState = .signIn },
label: {
Text("Already have an account?")
.foregroundColor(.appGrayTextContrast)
.underline()
}
)
.padding(.vertical)
Spacer()
}
}
.textFieldStyle(StandardTextFieldStyle())
.onSubmit {
if focusedField == .email {
focusedField = .password
} else {
focusedField = nil
}
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
Spacer()
}
}
.navigationTitle("Sign Up")
}
}

View File

@ -1,118 +0,0 @@
import Models
import Services
import SwiftUI
import Utils
import Views
@MainActor final class EmailLoginViewModel: ObservableObject {
@Published var loginError: LoginError?
func submitCredentials(
email: String,
password: String,
authenticator: Authenticator
) async {
do {
try await authenticator.submitEmailLogin(email: email, password: password)
} catch {
loginError = error as? LoginError
}
}
}
struct EmailLoginView: View {
@Environment(\.horizontalSizeClass) var horizontalSizeClass
@Environment(\.presentationMode) private var presentationMode
@EnvironmentObject var authenticator: Authenticator
@EnvironmentObject var dataService: DataService
@StateObject private var viewModel = EmailLoginViewModel()
@State private var email = ""
@State private var password = ""
var body: some View {
NavigationView {
ZStack {
Color.appBackground.edgesIgnoringSafeArea(.all)
VStack(spacing: 0) {
VStack(spacing: 28) {
ScrollView(showsIndicators: false) {
if horizontalSizeClass == .regular {
Spacer(minLength: 150)
}
VStack {
VStack(alignment: .leading, spacing: 6) {
Text("Email")
.font(.appFootnote)
.foregroundColor(.appGrayText)
TextField("", text: $email)
.textContentType(.emailAddress)
.textInputAutocapitalization(.never)
.disableAutocorrection(true)
}
.padding(.bottom, 8)
VStack(alignment: .leading, spacing: 6) {
Text("Password")
.font(.appFootnote)
.foregroundColor(.appGrayText)
SecureField("", text: $password)
.textContentType(.password)
.textInputAutocapitalization(.never)
.disableAutocorrection(true)
}
.padding(.bottom, 16)
Button(
action: {
Task {
await viewModel.submitCredentials(
email: email,
password: password,
authenticator: authenticator
)
}
},
label: { Text("Submit") }
)
.buttonStyle(SolidCapsuleButtonStyle(color: .appDeepBackground, width: 300))
if let loginError = viewModel.loginError {
LoginErrorMessageView(loginError: loginError)
}
HStack {
Button(
action: { print("switch to email signup") },
label: {
Text("Don't have an account?")
.foregroundColor(.appGrayTextContrast)
.underline()
}
)
.padding(.vertical)
Spacer()
}
}
.textFieldStyle(StandardTextFieldStyle())
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
Spacer()
}
}
.frame(maxWidth: 300)
.navigationTitle("Sign In")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .barTrailing) {
Button(
action: { presentationMode.wrappedValue.dismiss() },
label: { Image(systemName: "xmark").foregroundColor(.appGrayTextContrast) }
)
}
}
}
}
}
}

View File

@ -230,7 +230,7 @@ struct WelcomeView: View {
}
.padding()
.sheet(isPresented: $showEmailLoginModal) {
EmailLoginView()
EmailAuthView()
}
.sheet(isPresented: $showDebugModal) {
DebugMenuView(selectedEnvironment: $selectedEnvironment)

View File

@ -11,23 +11,25 @@ export function ResetSent(props: LoginFormProps): JSX.Element {
width: '100vw',
height: '100vh',
bg: '$omnivoreYellow',
overflowY: 'clip'
overflowY: 'clip',
}}
>
<Box css={{
width: '100%',
margin: '40px',
color: '$omnivoreGray',
'@xl': { margin: '138px' },
}}>
<h1>Reset email sent</h1>
<Box>
If there is an account assosciated with the email specified we sent a
password reset link. Click the link to reset your password. You may need
to check your spam folder.
<Box
css={{
width: '100%',
margin: '40px',
color: '$omnivoreGray',
'@xl': { margin: '138px' },
}}
>
<h1>Reset email sent</h1>
<Box>
If there is an account associated with the email specified we sent a
password reset link. Click the link to reset your password. You may
need to check your spam folder.
</Box>
</Box>
</Box>
</HStack>
</HStack>
</>
)
}