From d80377c06a8a15e616ebb1de5cd03e6e66a7b81b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cxixn2=E2=80=9D?= Date: Wed, 9 Apr 2025 11:17:13 +0900 Subject: [PATCH 01/10] =?UTF-8?q?=F0=9F=8E=A8=20::=20[#13]=20Button=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=A3=BC=EC=84=9D=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/DesignSystem/Component/Button/WasherButton.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/Projects/App/Sources/DesignSystem/Component/Button/WasherButton.swift b/Projects/App/Sources/DesignSystem/Component/Button/WasherButton.swift index abd608b..778edc7 100644 --- a/Projects/App/Sources/DesignSystem/Component/Button/WasherButton.swift +++ b/Projects/App/Sources/DesignSystem/Component/Button/WasherButton.swift @@ -42,8 +42,6 @@ public struct WasherButton: View { .fill(isPressed ? Color.color(.main100) : Color.color(.main100)) ) .scaleEffect(isPressed ? 0.9 : 1.0) - - } .buttonStyle(PlainButtonStyle()) .gesture( From 64bca39e31b8caa893eb47b8b7ef5d23bd8e0e89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cxixn2=E2=80=9D?= Date: Wed, 9 Apr 2025 11:34:39 +0900 Subject: [PATCH 02/10] =?UTF-8?q?=F0=9F=92=84=20::=20[#13]=20=ED=9A=8C?= =?UTF-8?q?=EC=9B=90=EA=B0=80=EC=9E=85=20=ED=99=94=EB=A9=B4=20=EC=A0=9C?= =?UTF-8?q?=EC=9E=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SignUpFeature/View/SignUpView.swift | 92 +++++++++++++------ 1 file changed, 62 insertions(+), 30 deletions(-) diff --git a/Projects/App/Sources/Feature/AuthFeature/SignUpFeature/View/SignUpView.swift b/Projects/App/Sources/Feature/AuthFeature/SignUpFeature/View/SignUpView.swift index f79cf83..66946d8 100644 --- a/Projects/App/Sources/Feature/AuthFeature/SignUpFeature/View/SignUpView.swift +++ b/Projects/App/Sources/Feature/AuthFeature/SignUpFeature/View/SignUpView.swift @@ -10,42 +10,74 @@ import SwiftUI struct SignUpView: View { @StateObject var authViewModel: AuthViewModel + @State var nameTextField: String = "" + @State var nameIsError: Bool = false + @State var schoolNumberTextField: String = "" + @State var schoolNumberIsError: Bool = false + @State var domitoryRoomTextField: String = "" + @State var domitoryRoomIsError: Bool = false var body: some View { - VStack { - Button { - authViewModel.setupEmail(email: "s23053") - authViewModel.setupPassword(password: "washertest1!") - authViewModel.setupName(name: "서지완") - authViewModel.setupGrade(grade: "3") - authViewModel.setupClassRoom(classRoom: "3") - authViewModel.setupNumber(number: "14") - authViewModel.setupGender(gender: "MAN") - authViewModel.setupRoom(room: "415") - authViewModel.signUp { statusCode in - if (200...299).contains(statusCode) { - print("\(statusCode) | 회원가입 성공") - } else { - print("\(statusCode) | 회원가입 실패") - } + VStack(spacing: 34) { + ZStack { + HStack { + WasherAsset.washerLeftButton.swiftUIImage + .padding(.leading, 26) + + Spacer() } - } label: { - Text("회원가입 테스트 버튼") - } - Button { - authViewModel.setupEmail(email: "s23053") - authViewModel.setupPassword(password: "washertest1!") - authViewModel.signIn { statusCode in - if (200...299).contains(statusCode) { - print("\(statusCode) | 로그인 성공") - } else { - print("\(statusCode) | 로그인 실패") - } + Spacer() + + VStack(spacing: 6) { + Text("회원가입") + .font(.pretendard(.bold, size: 18)) + .foregroundStyle(.black) + + Text("로그인 시 사용할 정보를 입력해주세요") + .font(.pretendard(.regular, size: 12)) + .color(.gray300) } - } label: { - Text("로그인 테스트 버튼") + } + .padding(.top, 50) + + WasherTextField( + "이름을 입력해주세요", + text: $nameTextField, + title: "이름", + errorText: "이름을 잘못 입력했습니다.", + isError: nameIsError + ) + .padding(.top, 38) + + WasherTextField( + "학번을 입력해주세요", + text: $schoolNumberTextField, + title: "학번", + errorText: "숫자 4자리만 입력이 가능합니다. (ex.3314)", + isError: schoolNumberIsError + ) + + WasherTextField( + "기숙사 호실을 입력해주세요", + text: $domitoryRoomTextField, + title: "호실", + errorText: "숫자 3자리만 입력이 가능합니다. (ex.415)", + isError: domitoryRoomIsError + ) + + WasherButton( + text: "다음", + horizontalPadding: 173, + verticalPadding: 17 + ) + + Spacer() } } } + +#Preview { + SignUpView(authViewModel: AuthViewModel()) +} From eacfce9775ed6a6e4f2d2f61b85c0df37e697d7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cxixn2=E2=80=9D?= Date: Wed, 9 Apr 2025 11:36:47 +0900 Subject: [PATCH 03/10] =?UTF-8?q?=F0=9F=92=9A=20::=20[#11]=20CI=20Swift@v2?= =?UTF-8?q?=20->=20Swift@v1=EC=9C=BC=EB=A1=9C=20=EB=8B=A4=EC=9A=B4?= =?UTF-8?q?=EA=B7=B8=EB=A0=88=EC=9D=B4=EB=93=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/Washer_CI.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Washer_CI.yml b/.github/workflows/Washer_CI.yml index 72d5cfa..1eda230 100644 --- a/.github/workflows/Washer_CI.yml +++ b/.github/workflows/Washer_CI.yml @@ -15,7 +15,7 @@ jobs: uses: actions/checkout@v4 - name: Setup Swift - uses: swift-actions/setup-swift@v2 + uses: swift-actions/setup-swift@v1 with: swift-version: '5.9' From 6956bfa1adc121a0d4b22cb3168ab67941521ffc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cxixn2=E2=80=9D?= Date: Wed, 9 Apr 2025 11:38:23 +0900 Subject: [PATCH 04/10] =?UTF-8?q?=F0=9F=92=9A=20::=20[#11]=20CI=20Swift@v2?= =?UTF-8?q?=20->=20Swift@main=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/Washer_CI.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Washer_CI.yml b/.github/workflows/Washer_CI.yml index 1eda230..37dc460 100644 --- a/.github/workflows/Washer_CI.yml +++ b/.github/workflows/Washer_CI.yml @@ -15,7 +15,7 @@ jobs: uses: actions/checkout@v4 - name: Setup Swift - uses: swift-actions/setup-swift@v1 + uses: swift-actions/setup-swift@main with: swift-version: '5.9' From 6e73a95b79138fbe3961b939f6a84a21f89dd69d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cxixn2=E2=80=9D?= Date: Wed, 9 Apr 2025 12:00:01 +0900 Subject: [PATCH 05/10] =?UTF-8?q?=E2=9C=A8=20::=20[#13]=20=ED=9A=8C?= =?UTF-8?q?=EC=9B=90=EA=B0=80=EC=9E=85=20=ED=85=8D=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=ED=95=84=EB=93=9C=20=EC=A0=95=EA=B7=9C=EC=8B=9D=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../App/Sources/Extension/Validator.swift | 6 +++ .../SignUpFeature/View/SignUpView.swift | 53 ++++++++++++++++--- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/Projects/App/Sources/Extension/Validator.swift b/Projects/App/Sources/Extension/Validator.swift index 17c94ab..f8456c1 100644 --- a/Projects/App/Sources/Extension/Validator.swift +++ b/Projects/App/Sources/Extension/Validator.swift @@ -22,3 +22,9 @@ struct Validator { .evaluate(with: password) } } + +extension Character { + var isHangul: Bool { + return ("가"..."힣").contains(self) + } +} diff --git a/Projects/App/Sources/Feature/AuthFeature/SignUpFeature/View/SignUpView.swift b/Projects/App/Sources/Feature/AuthFeature/SignUpFeature/View/SignUpView.swift index 66946d8..3a4b813 100644 --- a/Projects/App/Sources/Feature/AuthFeature/SignUpFeature/View/SignUpView.swift +++ b/Projects/App/Sources/Feature/AuthFeature/SignUpFeature/View/SignUpView.swift @@ -23,12 +23,9 @@ struct SignUpView: View { HStack { WasherAsset.washerLeftButton.swiftUIImage .padding(.leading, 26) - Spacer() } - Spacer() - VStack(spacing: 6) { Text("회원가입") .font(.pretendard(.bold, size: 18)) @@ -38,7 +35,6 @@ struct SignUpView: View { .font(.pretendard(.regular, size: 12)) .color(.gray300) } - } .padding(.top, 50) @@ -46,36 +42,77 @@ struct SignUpView: View { "이름을 입력해주세요", text: $nameTextField, title: "이름", - errorText: "이름을 잘못 입력했습니다.", + errorText: "이름은 한글 2~4자여야 합니다.", isError: nameIsError ) .padding(.top, 38) + .onChange(of: nameTextField) { newValue in + nameTextField = String(newValue.prefix(4)) + + let isOnlyHangul = nameTextField.allSatisfy { $0.isHangul } + nameIsError = !(isOnlyHangul && (2...4).contains(nameTextField.count)) + } WasherTextField( "학번을 입력해주세요", text: $schoolNumberTextField, title: "학번", - errorText: "숫자 4자리만 입력이 가능합니다. (ex.3314)", + errorText: "형식이 올바르지 않습니다. (예: 2312)", isError: schoolNumberIsError ) + .onChange(of: schoolNumberTextField) { newValue in + schoolNumberTextField = String(newValue.prefix(4)).filter { $0.isNumber } + schoolNumberIsError = !isValidSchoolNumber(schoolNumberTextField) + } WasherTextField( "기숙사 호실을 입력해주세요", text: $domitoryRoomTextField, title: "호실", - errorText: "숫자 3자리만 입력이 가능합니다. (ex.415)", + errorText: "형식이 올바르지 않습니다. (예: 315)", isError: domitoryRoomIsError ) + .onChange(of: domitoryRoomTextField) { newValue in + domitoryRoomTextField = String(newValue.prefix(3)).filter { $0.isNumber } + domitoryRoomIsError = !isValidRoomNumber(domitoryRoomTextField) + } WasherButton( text: "다음", horizontalPadding: 173, verticalPadding: 17 - ) + ) {} + .disabled(!isFormValid) Spacer() } } + + // MARK: - 정규식 검사 함수들 + + func isValidName(_ name: String) -> Bool { + let regex = #"^[가-힣]{2,4}$"# + return name.range(of: regex, options: .regularExpression) != nil + } + + func isValidSchoolNumber(_ number: String) -> Bool { + let regex = #"^[1-3][1-4](0[1-9]|1[0-8])$"# + return number.range(of: regex, options: .regularExpression) != nil + } + + func isValidRoomNumber(_ number: String) -> Bool { + let regex = #"^[2-5](0[0-9]|1[0-9]|20)$"# + return number.range(of: regex, options: .regularExpression) != nil + } + + var isFormValid: Bool { + return isValidName(nameTextField) && + isValidSchoolNumber(schoolNumberTextField) && + isValidRoomNumber(domitoryRoomTextField) && + !nameTextField.isEmpty && + !schoolNumberTextField.isEmpty && + !domitoryRoomTextField.isEmpty + } } #Preview { From f8d8c49df87b432db47d01c7eac7802987503b1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cxixn2=E2=80=9D?= Date: Fri, 18 Apr 2025 21:17:04 +0900 Subject: [PATCH 06/10] =?UTF-8?q?=F0=9F=8E=A8=20::=20[#13]=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EA=B0=84?= =?UTF-8?q?=EA=B2=A9=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Component/Button/WasherButton.swift | 2 +- .../Component/TextField/WasherTextField.swift | 6 +- .../Sources/DesignSystem/DesignModifire.swift | 2 +- .../InfoInputFeature/View/InfoInputView.swift | 111 +++++++++++- .../SignInFeature/View/SignInView.swift | 7 +- .../SignUpFeature/View/SignUpView.swift | 169 +++++++++++------- 6 files changed, 219 insertions(+), 78 deletions(-) diff --git a/Projects/App/Sources/DesignSystem/Component/Button/WasherButton.swift b/Projects/App/Sources/DesignSystem/Component/Button/WasherButton.swift index 778edc7..52fe199 100644 --- a/Projects/App/Sources/DesignSystem/Component/Button/WasherButton.swift +++ b/Projects/App/Sources/DesignSystem/Component/Button/WasherButton.swift @@ -38,7 +38,7 @@ public struct WasherButton: View { .padding(.vertical, verticalPadding) .padding(.horizontal, horizontalPadding) .background( - RoundedRectangle(cornerRadius: 30) + RoundedRectangle(cornerRadius: 8) .fill(isPressed ? Color.color(.main100) : Color.color(.main100)) ) .scaleEffect(isPressed ? 0.9 : 1.0) diff --git a/Projects/App/Sources/DesignSystem/Component/TextField/WasherTextField.swift b/Projects/App/Sources/DesignSystem/Component/TextField/WasherTextField.swift index 74f360a..23cea97 100644 --- a/Projects/App/Sources/DesignSystem/Component/TextField/WasherTextField.swift +++ b/Projects/App/Sources/DesignSystem/Component/TextField/WasherTextField.swift @@ -63,11 +63,11 @@ struct WasherTextField: View { } } .padding(.horizontal, 16) - .frame(height: 44) + .frame(height: 42) .onSubmit(onSubmit) .focused($isFocused) .foregroundColor(.color(.gray700)) - .font(.pretendard(.semiBold, size: 14)) + .font(.pretendard(.semiBold, size: 12)) if isSecure { Button { @@ -96,7 +96,7 @@ struct WasherTextField: View { if isError { Text(errorText) .foregroundStyle(.red) - .font(.pretendard(.regular, size: 12)) + .font(.pretendard(.regular, size: 11)) } } .padding(.horizontal, 16) diff --git a/Projects/App/Sources/DesignSystem/DesignModifire.swift b/Projects/App/Sources/DesignSystem/DesignModifire.swift index 44bba90..76f83d8 100644 --- a/Projects/App/Sources/DesignSystem/DesignModifire.swift +++ b/Projects/App/Sources/DesignSystem/DesignModifire.swift @@ -66,7 +66,7 @@ struct DesignModifireView: View { var body: some View { Text("Hello, Pretendard!") .font(.pretendard(.semiBold, size: 20)) - .color(.gray600) + .color(.gray200) } } diff --git a/Projects/App/Sources/Feature/AuthFeature/InfoInputFeature/View/InfoInputView.swift b/Projects/App/Sources/Feature/AuthFeature/InfoInputFeature/View/InfoInputView.swift index f693590..5c97a85 100644 --- a/Projects/App/Sources/Feature/AuthFeature/InfoInputFeature/View/InfoInputView.swift +++ b/Projects/App/Sources/Feature/AuthFeature/InfoInputFeature/View/InfoInputView.swift @@ -8,12 +8,119 @@ import SwiftUI +import SwiftUI + struct InfoInputView: View { + @StateObject var authViewModel: AuthViewModel + @State var nameTextField: String = "" + @State var nameIsError: Bool = false + @State var schoolNumberTextField: String = "" + @State var schoolNumberIsError: Bool = false + @State var domitoryRoomTextField: String = "" + @State var domitoryRoomIsError: Bool = false + var body: some View { - Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) + VStack(spacing: 34) { + ZStack { + HStack { + WasherAsset.washerLeftButton.swiftUIImage + .padding(.leading, 26) + Spacer() + } + + VStack(spacing: 6) { + Text("회원가입") + .font(.pretendard(.bold, size: 18)) + .foregroundStyle(.black) + + Text("로그인 시 사용할 정보를 입력해주세요") + .font(.pretendard(.regular, size: 12)) + .color(.gray300) + } + } + .padding(.top, 50) + + WasherTextField( + "이름을 입력해주세요", + text: $nameTextField, + title: "이름", + errorText: "이름은 한글 2~4자여야 합니다.", + isError: nameIsError + ) + .padding(.top, 38) + .onChange(of: nameTextField) { newValue in + nameTextField = String(newValue.prefix(4)) + + let isOnlyHangul = nameTextField.allSatisfy { $0.isHangul } + nameIsError = !(isOnlyHangul && (2...4).contains(nameTextField.count)) + } + .padding(.horizontal, 16) + + WasherTextField( + "학번을 입력해주세요", + text: $schoolNumberTextField, + title: "학번", + errorText: "형식이 올바르지 않습니다. (예: 2312)", + isError: schoolNumberIsError + ) + .onChange(of: schoolNumberTextField) { newValue in + schoolNumberTextField = String(newValue.prefix(4)).filter { $0.isNumber } + schoolNumberIsError = !isValidSchoolNumber(schoolNumberTextField) + } + .padding(.horizontal, 16) + + WasherTextField( + "기숙사 호실을 입력해주세요", + text: $domitoryRoomTextField, + title: "호실", + errorText: "형식이 올바르지 않습니다. (예: 315)", + isError: domitoryRoomIsError + ) + .onChange(of: domitoryRoomTextField) { newValue in + domitoryRoomTextField = String(newValue.prefix(3)).filter { $0.isNumber } + domitoryRoomIsError = !isValidRoomNumber(domitoryRoomTextField) + } + .padding(.horizontal, 16) + + WasherButton( + text: "다음", + horizontalPadding: 173, + verticalPadding: 17 + ) {} + .disabled(!isFormValid) + + Spacer() + } + } + + // MARK: - 정규식 검사 함수들 + + func isValidName(_ name: String) -> Bool { + let regex = #"^[가-힣]{2,4}$"# + return name.range(of: regex, options: .regularExpression) != nil + } + + func isValidSchoolNumber(_ number: String) -> Bool { + let regex = #"^[1-3][1-4](0[1-9]|1[0-8])$"# + return number.range(of: regex, options: .regularExpression) != nil + } + + func isValidRoomNumber(_ number: String) -> Bool { + let regex = #"^[2-5](0[0-9]|1[0-9]|20)$"# + return number.range(of: regex, options: .regularExpression) != nil + } + + var isFormValid: Bool { + return isValidName(nameTextField) && + isValidSchoolNumber(schoolNumberTextField) && + isValidRoomNumber(domitoryRoomTextField) && + !nameTextField.isEmpty && + !schoolNumberTextField.isEmpty && + !domitoryRoomTextField.isEmpty } } + #Preview { - InfoInputView() + InfoInputView(authViewModel: AuthViewModel()) } diff --git a/Projects/App/Sources/Feature/AuthFeature/SignInFeature/View/SignInView.swift b/Projects/App/Sources/Feature/AuthFeature/SignInFeature/View/SignInView.swift index a7c4b42..095d428 100644 --- a/Projects/App/Sources/Feature/AuthFeature/SignInFeature/View/SignInView.swift +++ b/Projects/App/Sources/Feature/AuthFeature/SignInFeature/View/SignInView.swift @@ -47,6 +47,8 @@ struct SignInView: View { errorText: "이메일 형식이 맞지 않습니다.", isError: computedEmailError ) + .padding(.leading, 16) + .padding(.trailing, 8) Text("@") .font(.pretendard(.medium, size: 18)) @@ -54,7 +56,7 @@ struct SignInView: View { .padding(.top, 32) Text("gsm.hs.kr") - .font(.pretendard(.medium, size: 14)) + .font(.pretendard(.medium, size: 12)) .color(.gray400) .padding(.horizontal, 16) .frame(height: 44) @@ -62,7 +64,7 @@ struct SignInView: View { RoundedRectangle(cornerRadius: 8) .color(.gray50) ) - .padding(.horizontal, 16) + .padding(.horizontal, 8) .padding(.top, 20) } .padding(.top, 64) @@ -76,6 +78,7 @@ struct SignInView: View { isSecure: true ) .padding(.top, 34) + .padding(.horizontal, 16) Button { isLoggedIn.toggle() diff --git a/Projects/App/Sources/Feature/AuthFeature/SignUpFeature/View/SignUpView.swift b/Projects/App/Sources/Feature/AuthFeature/SignUpFeature/View/SignUpView.swift index 3a4b813..2888a88 100644 --- a/Projects/App/Sources/Feature/AuthFeature/SignUpFeature/View/SignUpView.swift +++ b/Projects/App/Sources/Feature/AuthFeature/SignUpFeature/View/SignUpView.swift @@ -10,15 +10,30 @@ import SwiftUI struct SignUpView: View { @StateObject var authViewModel: AuthViewModel - @State var nameTextField: String = "" - @State var nameIsError: Bool = false - @State var schoolNumberTextField: String = "" - @State var schoolNumberIsError: Bool = false - @State var domitoryRoomTextField: String = "" - @State var domitoryRoomIsError: Bool = false + @State var emailTextField: String = "" + @State var emailIsError: Bool = false + @State var authenticationCodeNumberTextField: String = "" + @State var authenticationCodeIsError: Bool = false + @State var passwordTextField: String = "" + @State var passwordIsError: Bool = false + @State var passwordCheckTextField: String = "" + @State var passwordCheckIsError: Bool = false + @State var authenticationSuccess: Bool = false + + private var computedEmailError: Bool { + !emailTextField.isEmpty && !Validator.isValidEmail(emailTextField) + } + + private var computedPasswordError: Bool { + !passwordTextField.isEmpty && !Validator.isValidPassword(passwordTextField) + } + + private var computedPasswordCheckError: Bool { + !passwordCheckTextField.isEmpty && passwordTextField != passwordCheckTextField + } var body: some View { - VStack(spacing: 34) { + VStack(spacing: 0) { ZStack { HStack { WasherAsset.washerLeftButton.swiftUIImage @@ -38,81 +53,97 @@ struct SignUpView: View { } .padding(.top, 50) - WasherTextField( - "이름을 입력해주세요", - text: $nameTextField, - title: "이름", - errorText: "이름은 한글 2~4자여야 합니다.", - isError: nameIsError - ) - .padding(.top, 38) - .onChange(of: nameTextField) { newValue in - nameTextField = String(newValue.prefix(4)) + HStack(alignment: .top, spacing: 0) { + WasherTextField( + "이메일을 입력해주세요.", + text: $emailTextField, + title: "이메일", + errorText: "이메일 형식이 맞지 않습니다.", + isError: computedEmailError + ) + .padding(.leading, 16) + .padding(.trailing, 8) + + Text("@") + .font(.pretendard(.medium, size: 18)) + .color(.gray400) + .padding(.top, 32) + + Text("gsm.hs.kr") + .font(.pretendard(.medium, size: 12)) + .color(.gray400) + .padding(.horizontal, 16) + .frame(height: 44) + .background( + RoundedRectangle(cornerRadius: 8) + .color(.gray50) + ) + .padding(.horizontal, 8) + .padding(.trailing, 8) + .padding(.top, 20) + } + .padding(.top, 72) + + HStack(alignment: .bottom, spacing: 10) { + WasherTextField( + "인증번호를 입력해주세요", + text: $authenticationCodeNumberTextField, + title: "인증코드", + errorText: "비밀번호가 틀렸습니다.", + isError: authenticationCodeIsError + ) + + Text("확인") + .font(.pretendard(.semiBold, size: 12)) + .padding(.vertical, 14) + .padding(.horizontal, 35) + .background( + RoundedRectangle(cornerRadius: 4) + .color(.gray300) + ) + } + .padding(.horizontal, 16) + .padding(.top, 34) + + HStack { + if authenticationSuccess == false { + Text("인증번호가 발송되었습니다 ") + .font(.pretendard(.regular, size: 12)) + .color(.gray400) + .padding(.leading, 16) + .padding(.top, 6) + } - let isOnlyHangul = nameTextField.allSatisfy { $0.isHangul } - nameIsError = !(isOnlyHangul && (2...4).contains(nameTextField.count)) + Spacer() } WasherTextField( - "학번을 입력해주세요", - text: $schoolNumberTextField, - title: "학번", - errorText: "형식이 올바르지 않습니다. (예: 2312)", - isError: schoolNumberIsError + "8~16자 영어, 숫자, 특수문자 1개 이상", + text: $passwordTextField, + title: "비밀번호", + errorText: "비밀번호는 8~16자, 특수문자 포함 필수", + isError: computedPasswordError, + isSecure: true ) - .onChange(of: schoolNumberTextField) { newValue in - schoolNumberTextField = String(newValue.prefix(4)).filter { $0.isNumber } - schoolNumberIsError = !isValidSchoolNumber(schoolNumberTextField) - } + .padding(.top, 34) + .padding(.horizontal, 16) WasherTextField( - "기숙사 호실을 입력해주세요", - text: $domitoryRoomTextField, - title: "호실", - errorText: "형식이 올바르지 않습니다. (예: 315)", - isError: domitoryRoomIsError + "비밀번호를 다시 입력해주세요", + text: $passwordCheckTextField, + errorText: "비밀번호가 틀렸습니다.", + isError: passwordCheckIsError, + isSecure: true ) - .onChange(of: domitoryRoomTextField) { newValue in - domitoryRoomTextField = String(newValue.prefix(3)).filter { $0.isNumber } - domitoryRoomIsError = !isValidRoomNumber(domitoryRoomTextField) + .onChange(of: passwordCheckTextField) { _ in + passwordCheckIsError = computedPasswordCheckError } - - WasherButton( - text: "다음", - horizontalPadding: 173, - verticalPadding: 17 - ) {} - .disabled(!isFormValid) + .padding(.top, 8) + .padding(.horizontal, 16) Spacer() } } - - // MARK: - 정규식 검사 함수들 - - func isValidName(_ name: String) -> Bool { - let regex = #"^[가-힣]{2,4}$"# - return name.range(of: regex, options: .regularExpression) != nil - } - - func isValidSchoolNumber(_ number: String) -> Bool { - let regex = #"^[1-3][1-4](0[1-9]|1[0-8])$"# - return number.range(of: regex, options: .regularExpression) != nil - } - - func isValidRoomNumber(_ number: String) -> Bool { - let regex = #"^[2-5](0[0-9]|1[0-9]|20)$"# - return number.range(of: regex, options: .regularExpression) != nil - } - - var isFormValid: Bool { - return isValidName(nameTextField) && - isValidSchoolNumber(schoolNumberTextField) && - isValidRoomNumber(domitoryRoomTextField) && - !nameTextField.isEmpty && - !schoolNumberTextField.isEmpty && - !domitoryRoomTextField.isEmpty - } } #Preview { From e42e8597a00146830b9c86fd2af67afcb43c809a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cxixn2=E2=80=9D?= Date: Fri, 18 Apr 2025 21:44:48 +0900 Subject: [PATCH 07/10] =?UTF-8?q?=F0=9F=92=84=20::=20[#13]=20TextField=20?= =?UTF-8?q?=EB=A7=88=EC=A7=84=EA=B0=92=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Component/Button/WasherButton.swift | 21 +++++++++--------- .../Component/TextField/WasherTextField.swift | 2 +- .../InfoInputFeature/View/InfoInputView.swift | 22 ++++++++++++++----- .../SignInFeature/View/SignInView.swift | 10 ++++----- .../SignUpFeature/View/SignUpView.swift | 12 +++++----- 5 files changed, 40 insertions(+), 27 deletions(-) diff --git a/Projects/App/Sources/DesignSystem/Component/Button/WasherButton.swift b/Projects/App/Sources/DesignSystem/Component/Button/WasherButton.swift index 52fe199..5203cf3 100644 --- a/Projects/App/Sources/DesignSystem/Component/Button/WasherButton.swift +++ b/Projects/App/Sources/DesignSystem/Component/Button/WasherButton.swift @@ -32,16 +32,17 @@ public struct WasherButton: View { Button(action: { self.action() }) { - Text(text) - .font(.pretendard(.semiBold, size: 14)) - .color(.gray50) - .padding(.vertical, verticalPadding) - .padding(.horizontal, horizontalPadding) - .background( - RoundedRectangle(cornerRadius: 8) - .fill(isPressed ? Color.color(.main100) : Color.color(.main100)) - ) - .scaleEffect(isPressed ? 0.9 : 1.0) + ZStack { + RoundedRectangle(cornerRadius: 8) + .fill(isPressed ? Color.color(.main100) : Color.color(.main100)) + + Text(text) + .font(.pretendard(.semiBold, size: 14)) + .color(.gray50) + } + .padding(.horizontal, horizontalPadding) + .frame(height: 44) + .scaleEffect(isPressed ? 0.9 : 1.0) } .buttonStyle(PlainButtonStyle()) .gesture( diff --git a/Projects/App/Sources/DesignSystem/Component/TextField/WasherTextField.swift b/Projects/App/Sources/DesignSystem/Component/TextField/WasherTextField.swift index 23cea97..22f4b7d 100644 --- a/Projects/App/Sources/DesignSystem/Component/TextField/WasherTextField.swift +++ b/Projects/App/Sources/DesignSystem/Component/TextField/WasherTextField.swift @@ -99,6 +99,6 @@ struct WasherTextField: View { .font(.pretendard(.regular, size: 11)) } } - .padding(.horizontal, 16) + //.padding(.horizontal, 16) } } diff --git a/Projects/App/Sources/Feature/AuthFeature/InfoInputFeature/View/InfoInputView.swift b/Projects/App/Sources/Feature/AuthFeature/InfoInputFeature/View/InfoInputView.swift index 5c97a85..f96e0d9 100644 --- a/Projects/App/Sources/Feature/AuthFeature/InfoInputFeature/View/InfoInputView.swift +++ b/Projects/App/Sources/Feature/AuthFeature/InfoInputFeature/View/InfoInputView.swift @@ -54,7 +54,7 @@ struct InfoInputView: View { let isOnlyHangul = nameTextField.allSatisfy { $0.isHangul } nameIsError = !(isOnlyHangul && (2...4).contains(nameTextField.count)) } - .padding(.horizontal, 16) + .padding(.horizontal, 26) WasherTextField( "학번을 입력해주세요", @@ -67,7 +67,7 @@ struct InfoInputView: View { schoolNumberTextField = String(newValue.prefix(4)).filter { $0.isNumber } schoolNumberIsError = !isValidSchoolNumber(schoolNumberTextField) } - .padding(.horizontal, 16) + .padding(.horizontal, 26) WasherTextField( "기숙사 호실을 입력해주세요", @@ -80,12 +80,24 @@ struct InfoInputView: View { domitoryRoomTextField = String(newValue.prefix(3)).filter { $0.isNumber } domitoryRoomIsError = !isValidRoomNumber(domitoryRoomTextField) } - .padding(.horizontal, 16) + .padding(.horizontal, 26) + + HStack(spacing: 0) { + Text("남자") + .padding(.horizontal, 26) + .background( + RoundedRectangle(cornerRadius: 8) + ) + + Text("여자") + .background( + RoundedRectangle(cornerRadius: 8) + ) + } WasherButton( text: "다음", - horizontalPadding: 173, - verticalPadding: 17 + horizontalPadding: 26 ) {} .disabled(!isFormValid) diff --git a/Projects/App/Sources/Feature/AuthFeature/SignInFeature/View/SignInView.swift b/Projects/App/Sources/Feature/AuthFeature/SignInFeature/View/SignInView.swift index 095d428..e092f20 100644 --- a/Projects/App/Sources/Feature/AuthFeature/SignInFeature/View/SignInView.swift +++ b/Projects/App/Sources/Feature/AuthFeature/SignInFeature/View/SignInView.swift @@ -47,7 +47,7 @@ struct SignInView: View { errorText: "이메일 형식이 맞지 않습니다.", isError: computedEmailError ) - .padding(.leading, 16) + .padding(.leading, 26) .padding(.trailing, 8) Text("@") @@ -65,6 +65,7 @@ struct SignInView: View { .color(.gray50) ) .padding(.horizontal, 8) + .padding(.trailing, 18) .padding(.top, 20) } .padding(.top, 64) @@ -78,7 +79,7 @@ struct SignInView: View { isSecure: true ) .padding(.top, 34) - .padding(.horizontal, 16) + .padding(.horizontal, 26) Button { isLoggedIn.toggle() @@ -93,14 +94,13 @@ struct SignInView: View { Spacer() } - .padding(.leading, 16) + .padding(.leading, 26) .padding(.top, 6) } WasherButton( text: "로그인", - horizontalPadding: 166, - verticalPadding: 17 + horizontalPadding: 26 ) { authViewModel.setupEmail(email: emailTextField) authViewModel.setupPassword(password: passwordTextField) diff --git a/Projects/App/Sources/Feature/AuthFeature/SignUpFeature/View/SignUpView.swift b/Projects/App/Sources/Feature/AuthFeature/SignUpFeature/View/SignUpView.swift index 2888a88..f822ee6 100644 --- a/Projects/App/Sources/Feature/AuthFeature/SignUpFeature/View/SignUpView.swift +++ b/Projects/App/Sources/Feature/AuthFeature/SignUpFeature/View/SignUpView.swift @@ -61,7 +61,7 @@ struct SignUpView: View { errorText: "이메일 형식이 맞지 않습니다.", isError: computedEmailError ) - .padding(.leading, 16) + .padding(.leading, 26) .padding(.trailing, 8) Text("@") @@ -79,7 +79,7 @@ struct SignUpView: View { .color(.gray50) ) .padding(.horizontal, 8) - .padding(.trailing, 8) + .padding(.trailing, 18) .padding(.top, 20) } .padding(.top, 72) @@ -102,7 +102,7 @@ struct SignUpView: View { .color(.gray300) ) } - .padding(.horizontal, 16) + .padding(.horizontal, 26) .padding(.top, 34) HStack { @@ -110,7 +110,7 @@ struct SignUpView: View { Text("인증번호가 발송되었습니다 ") .font(.pretendard(.regular, size: 12)) .color(.gray400) - .padding(.leading, 16) + .padding(.leading, 26) .padding(.top, 6) } @@ -126,7 +126,7 @@ struct SignUpView: View { isSecure: true ) .padding(.top, 34) - .padding(.horizontal, 16) + .padding(.horizontal, 26) WasherTextField( "비밀번호를 다시 입력해주세요", @@ -139,7 +139,7 @@ struct SignUpView: View { passwordCheckIsError = computedPasswordCheckError } .padding(.top, 8) - .padding(.horizontal, 16) + .padding(.horizontal, 26) Spacer() } From 3e6ef5a6b9e8b4da68891f33b78d36905ccef42e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cxixn2=E2=80=9D?= Date: Sat, 19 Apr 2025 21:47:30 +0900 Subject: [PATCH 08/10] =?UTF-8?q?=F0=9F=92=84=20::=20[#13]=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=EC=9E=85=EB=A0=A5=20=ED=99=94=EB=A9=B4=20=EC=A0=9C?= =?UTF-8?q?=EC=9E=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../InfoInputFeature/View/InfoInputView.swift | 53 ++++++++++++++----- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/Projects/App/Sources/Feature/AuthFeature/InfoInputFeature/View/InfoInputView.swift b/Projects/App/Sources/Feature/AuthFeature/InfoInputFeature/View/InfoInputView.swift index f96e0d9..c434631 100644 --- a/Projects/App/Sources/Feature/AuthFeature/InfoInputFeature/View/InfoInputView.swift +++ b/Projects/App/Sources/Feature/AuthFeature/InfoInputFeature/View/InfoInputView.swift @@ -18,9 +18,11 @@ struct InfoInputView: View { @State var schoolNumberIsError: Bool = false @State var domitoryRoomTextField: String = "" @State var domitoryRoomIsError: Bool = false + @State var selectedGender: String = "남자" + let genders = ["남자", "여자"] var body: some View { - VStack(spacing: 34) { + VStack(spacing: 0) { ZStack { HStack { WasherAsset.washerLeftButton.swiftUIImage @@ -55,6 +57,7 @@ struct InfoInputView: View { nameIsError = !(isOnlyHangul && (2...4).contains(nameTextField.count)) } .padding(.horizontal, 26) + .padding(.top, 34) WasherTextField( "학번을 입력해주세요", @@ -68,6 +71,7 @@ struct InfoInputView: View { schoolNumberIsError = !isValidSchoolNumber(schoolNumberTextField) } .padding(.horizontal, 26) + .padding(.top, 34) WasherTextField( "기숙사 호실을 입력해주세요", @@ -81,27 +85,51 @@ struct InfoInputView: View { domitoryRoomIsError = !isValidRoomNumber(domitoryRoomTextField) } .padding(.horizontal, 26) + .padding(.top, 34) - HStack(spacing: 0) { - Text("남자") - .padding(.horizontal, 26) - .background( - RoundedRectangle(cornerRadius: 8) - ) + HStack { + Text("성별") + .font(.pretendard(.bold, size: 14)) + .color(.main100) + .padding(.top, 34) + + Spacer() + } + .padding(.leading, 26) - Text("여자") - .background( + HStack(spacing: 4) { + ForEach(genders, id: \.self) { gender in + ZStack { RoundedRectangle(cornerRadius: 8) - ) + .fill(selectedGender == gender ? Color.color(.main300) : Color.color(.gray50)) + + Text(gender) + .font(.pretendard(.semiBold, size: 14)) + .color(.gray700) + } + .frame(height: 42) + .onTapGesture { + selectedGender = gender + Haptic.impact(style: .soft) + } + } } + .padding(.horizontal, 26) + .padding(.top, 8) + + Spacer() + + Rectangle() + .frame(height: 2) + .color(.gray50) WasherButton( text: "다음", horizontalPadding: 26 ) {} .disabled(!isFormValid) - - Spacer() + .padding(.top, 10) + .padding(.bottom, 30) } } @@ -132,7 +160,6 @@ struct InfoInputView: View { } } - #Preview { InfoInputView(authViewModel: AuthViewModel()) } From 9f15bebc2aa4c1dd2eb85452de601aa9ff065ec0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cxixn2=E2=80=9D?= Date: Tue, 29 Apr 2025 20:13:43 +0900 Subject: [PATCH 09/10] =?UTF-8?q?=F0=9F=92=84=20::=20[#13]=20=ED=9A=8C?= =?UTF-8?q?=EC=9B=90=EA=B0=80=EC=9E=85=20=EC=9D=B8=EC=A6=9D=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EB=B0=9C=EC=86=A1=20=EB=B2=84=ED=8A=BC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../InfoInputFeature/View/InfoInputView.swift | 6 +- .../SignUpFeature/View/SignUpView.swift | 64 +++++++++++++++---- 2 files changed, 52 insertions(+), 18 deletions(-) diff --git a/Projects/App/Sources/Feature/AuthFeature/InfoInputFeature/View/InfoInputView.swift b/Projects/App/Sources/Feature/AuthFeature/InfoInputFeature/View/InfoInputView.swift index c434631..0368bae 100644 --- a/Projects/App/Sources/Feature/AuthFeature/InfoInputFeature/View/InfoInputView.swift +++ b/Projects/App/Sources/Feature/AuthFeature/InfoInputFeature/View/InfoInputView.swift @@ -8,8 +8,6 @@ import SwiftUI -import SwiftUI - struct InfoInputView: View { @StateObject var authViewModel: AuthViewModel @State var nameTextField: String = "" @@ -63,7 +61,7 @@ struct InfoInputView: View { "학번을 입력해주세요", text: $schoolNumberTextField, title: "학번", - errorText: "형식이 올바르지 않습니다. (예: 2312)", + errorText: "형식이 올바르지 않습니다. (예: 3314)", isError: schoolNumberIsError ) .onChange(of: schoolNumberTextField) { newValue in @@ -77,7 +75,7 @@ struct InfoInputView: View { "기숙사 호실을 입력해주세요", text: $domitoryRoomTextField, title: "호실", - errorText: "형식이 올바르지 않습니다. (예: 315)", + errorText: "형식이 올바르지 않습니다. (예: 415)", isError: domitoryRoomIsError ) .onChange(of: domitoryRoomTextField) { newValue in diff --git a/Projects/App/Sources/Feature/AuthFeature/SignUpFeature/View/SignUpView.swift b/Projects/App/Sources/Feature/AuthFeature/SignUpFeature/View/SignUpView.swift index f822ee6..c966501 100644 --- a/Projects/App/Sources/Feature/AuthFeature/SignUpFeature/View/SignUpView.swift +++ b/Projects/App/Sources/Feature/AuthFeature/SignUpFeature/View/SignUpView.swift @@ -20,17 +20,6 @@ struct SignUpView: View { @State var passwordCheckIsError: Bool = false @State var authenticationSuccess: Bool = false - private var computedEmailError: Bool { - !emailTextField.isEmpty && !Validator.isValidEmail(emailTextField) - } - - private var computedPasswordError: Bool { - !passwordTextField.isEmpty && !Validator.isValidPassword(passwordTextField) - } - - private var computedPasswordCheckError: Bool { - !passwordCheckTextField.isEmpty && passwordTextField != passwordCheckTextField - } var body: some View { VStack(spacing: 0) { @@ -59,7 +48,7 @@ struct SignUpView: View { text: $emailTextField, title: "이메일", errorText: "이메일 형식이 맞지 않습니다.", - isError: computedEmailError + isError: Validator.hasEmailError(emailTextField) ) .padding(.leading, 26) .padding(.trailing, 8) @@ -84,6 +73,13 @@ struct SignUpView: View { } .padding(.top, 72) + WasherButton( + text: "인증번호 발송", + horizontalPadding: 26 + ) + .disabled(emailTextField.isEmpty || Validator.hasEmailError(emailTextField)) + .padding(.top, 34) + HStack(alignment: .bottom, spacing: 10) { WasherTextField( "인증번호를 입력해주세요", @@ -122,7 +118,7 @@ struct SignUpView: View { text: $passwordTextField, title: "비밀번호", errorText: "비밀번호는 8~16자, 특수문자 포함 필수", - isError: computedPasswordError, + isError: Validator.hasPasswordError(passwordTextField), isSecure: true ) .padding(.top, 34) @@ -136,16 +132,56 @@ struct SignUpView: View { isSecure: true ) .onChange(of: passwordCheckTextField) { _ in - passwordCheckIsError = computedPasswordCheckError + passwordCheckIsError = Validator.hasPasswordCheckError(passwordTextField, passwordCheckTextField) } .padding(.top, 8) .padding(.horizontal, 26) Spacer() + + Rectangle() + .frame(height: 2) + .color(.gray50) + + WasherButton( + text: "완료", + horizontalPadding: 26 + ) {} + .disabled(!Validator.isSignUpFormValid( + email: emailTextField, + password: passwordTextField, + passwordCheck: passwordCheckTextField + )) + .padding(.top, 10) + .padding(.bottom, 30) } } } +extension Validator { + static func hasEmailError(_ email: String) -> Bool { + !email.isEmpty && !isValidEmail(email) + } + + static func hasPasswordError(_ password: String) -> Bool { + !password.isEmpty && !isValidPassword(password) + } + + static func hasPasswordCheckError(_ password: String, _ passwordCheck: String) -> Bool { + !passwordCheck.isEmpty && password != passwordCheck + } + + static func isSignUpFormValid(email: String, password: String, passwordCheck: String) -> Bool { + isValidEmail(email) && + isValidPassword(password) && + password == passwordCheck && + !email.isEmpty && + !password.isEmpty && + !passwordCheck.isEmpty + } +} + + #Preview { SignUpView(authViewModel: AuthViewModel()) } From 3e7a5a4fba6505202e35194abed3b9059e1d990f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cxixn2=E2=80=9D?= Date: Wed, 30 Apr 2025 11:06:44 +0900 Subject: [PATCH 10/10] =?UTF-8?q?=F0=9F=92=84=20::=20[#13]=20=ED=9A=8C?= =?UTF-8?q?=EC=9B=90=EA=B0=80=EC=9E=85=20=EC=9D=B8=EC=A6=9D=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EB=B2=84=ED=8A=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SignUpFeature/View/SignUpView.swift | 35 ++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/Projects/App/Sources/Feature/AuthFeature/SignUpFeature/View/SignUpView.swift b/Projects/App/Sources/Feature/AuthFeature/SignUpFeature/View/SignUpView.swift index c966501..d095006 100644 --- a/Projects/App/Sources/Feature/AuthFeature/SignUpFeature/View/SignUpView.swift +++ b/Projects/App/Sources/Feature/AuthFeature/SignUpFeature/View/SignUpView.swift @@ -89,14 +89,21 @@ struct SignUpView: View { isError: authenticationCodeIsError ) - Text("확인") - .font(.pretendard(.semiBold, size: 12)) - .padding(.vertical, 14) - .padding(.horizontal, 35) - .background( - RoundedRectangle(cornerRadius: 4) - .color(.gray300) + Button { + + } label: { + Text("확인") + .foregroundStyle(.white) + .font(.pretendard(.semiBold, size: 12)) + .padding(.vertical, 14) + .padding(.horizontal, 35) + .background( + RoundedRectangle(cornerRadius: 4) + .color(.main100) ) + } + .disabled(!Validator.isValidAuthCode(authenticationCodeNumberTextField)) + .opacity(Validator.isValidAuthCode(authenticationCodeNumberTextField) ? 1.0 : 0.5) } .padding(.horizontal, 26) .padding(.top, 34) @@ -148,10 +155,10 @@ struct SignUpView: View { horizontalPadding: 26 ) {} .disabled(!Validator.isSignUpFormValid( - email: emailTextField, - password: passwordTextField, - passwordCheck: passwordCheckTextField - )) + email: emailTextField, + password: passwordTextField, + passwordCheck: passwordCheckTextField + )) .padding(.top, 10) .padding(.bottom, 30) } @@ -179,8 +186,12 @@ extension Validator { !password.isEmpty && !passwordCheck.isEmpty } -} + static func isValidAuthCode(_ code: String) -> Bool { + let pattern = #"^\d{5}$"# + return code.range(of: pattern, options: .regularExpression) != nil + } +} #Preview { SignUpView(authViewModel: AuthViewModel())