From 090e121d54fb10663ba79e3491a661494ac5f4c4 Mon Sep 17 00:00:00 2001 From: baegteun Date: Thu, 27 Oct 2022 23:13:38 +0900 Subject: [PATCH] =?UTF-8?q?feat=20::=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20-=20=EB=B9=84=EB=B0=80=EB=B2=88=ED=98=B8=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/Application/DI/AppComponent.swift | 3 + Projects/App/Sources/Application/DMSApp.swift | 2 +- .../Sources/Application/NeedleGenerated.swift | 18 +++++ .../SignupPasswordComponent.swift | 12 ++++ .../SignupPassword/SignupPasswordView.swift | 69 +++++++++++++++++++ .../SignupPasswordViewModel.swift | 40 +++++++++++ 6 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 Projects/Features/SignupFeature/Sources/SignupPassword/SignupPasswordComponent.swift create mode 100644 Projects/Features/SignupFeature/Sources/SignupPassword/SignupPasswordView.swift create mode 100644 Projects/Features/SignupFeature/Sources/SignupPassword/SignupPasswordViewModel.swift diff --git a/Projects/App/Sources/Application/DI/AppComponent.swift b/Projects/App/Sources/Application/DI/AppComponent.swift index 3ee45609..5caa4399 100644 --- a/Projects/App/Sources/Application/DI/AppComponent.swift +++ b/Projects/App/Sources/Application/DI/AppComponent.swift @@ -39,6 +39,9 @@ public extension AppComponent { var signupProfileImageComponent: SignupProfileImageComponent { SignupProfileImageComponent(parent: self) } + var signupPasswordComponent: SignupPasswordComponent { + SignupPasswordComponent(parent: self) + } } // MARK: - Main diff --git a/Projects/App/Sources/Application/DMSApp.swift b/Projects/App/Sources/Application/DMSApp.swift index 14074981..bd07e3f9 100644 --- a/Projects/App/Sources/Application/DMSApp.swift +++ b/Projects/App/Sources/Application/DMSApp.swift @@ -12,7 +12,7 @@ struct DMSApp: App { var body: some Scene { WindowGroup { - AppComponent().mainTabComponent.makeView() + AppComponent().signupPasswordComponent.makeView() } } } diff --git a/Projects/App/Sources/Application/NeedleGenerated.swift b/Projects/App/Sources/Application/NeedleGenerated.swift index 5c42b4ce..4673da55 100644 --- a/Projects/App/Sources/Application/NeedleGenerated.swift +++ b/Projects/App/Sources/Application/NeedleGenerated.swift @@ -38,6 +38,17 @@ private class SchoolCodeDependencyc0114744c1c8c7843672Provider: SchoolCodeDepend private func factoryb65c1efbf06b87162473f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject { return SchoolCodeDependencyc0114744c1c8c7843672Provider(appComponent: parent1(component) as! AppComponent) } +private class SignupPasswordDependency778bf5389a70d7df6152Provider: SignupPasswordDependency { + + + init() { + + } +} +/// ^->AppComponent->SignupPasswordComponent +private func factorye93d1d56840ff97c674ae3b0c44298fc1c149afb(_ component: NeedleFoundation.Scope) -> AnyObject { + return SignupPasswordDependency778bf5389a70d7df6152Provider() +} private class SignupEmailAuthCodeVerifyDependencyaf9da1ebf0e9e5f1b708Provider: SignupEmailAuthCodeVerifyDependency { var sendAuthCodeUseCase: any SendAuthCodeUseCase { return appComponent.sendAuthCodeUseCase @@ -156,6 +167,7 @@ extension AppComponent: Registration { localTable["signupEmailVerifyComponent-SignupEmailVerifyComponent"] = { self.signupEmailVerifyComponent as Any } localTable["signupEmailAuthCodeVerifyComponent-SignupEmailAuthCodeVerifyComponent"] = { self.signupEmailAuthCodeVerifyComponent as Any } localTable["signupProfileImageComponent-SignupProfileImageComponent"] = { self.signupProfileImageComponent as Any } + localTable["signupPasswordComponent-SignupPasswordComponent"] = { self.signupPasswordComponent as Any } localTable["mainTabComponent-MainTabComponent"] = { self.mainTabComponent as Any } localTable["homeComponent-HomeComponent"] = { self.homeComponent as Any } localTable["remoteStudentsDataSource-any RemoteStudentsDataSource"] = { self.remoteStudentsDataSource as Any } @@ -185,6 +197,11 @@ extension SchoolCodeComponent: Registration { keyPathToName[\SchoolCodeDependency.checkSchoolCodeUseCase] = "checkSchoolCodeUseCase-any CheckSchoolCodeUseCase" } } +extension SignupPasswordComponent: Registration { + public func registerItems() { + + } +} extension SignupEmailAuthCodeVerifyComponent: Registration { public func registerItems() { keyPathToName[\SignupEmailAuthCodeVerifyDependency.sendAuthCodeUseCase] = "sendAuthCodeUseCase-any SendAuthCodeUseCase" @@ -241,6 +258,7 @@ private func registerProviderFactory(_ componentPath: String, _ factory: @escapi private func register1() { registerProviderFactory("^->AppComponent", factoryEmptyDependencyProvider) registerProviderFactory("^->AppComponent->SchoolCodeComponent", factoryb65c1efbf06b87162473f47b58f8f304c97af4d5) + registerProviderFactory("^->AppComponent->SignupPasswordComponent", factorye93d1d56840ff97c674ae3b0c44298fc1c149afb) registerProviderFactory("^->AppComponent->SignupEmailAuthCodeVerifyComponent", factoryb06be35aa893adde971bf47b58f8f304c97af4d5) registerProviderFactory("^->AppComponent->SignupEmailVerifyComponent", factory3b1904c76335d70151ebf47b58f8f304c97af4d5) registerProviderFactory("^->AppComponent->SignupProfileImageComponent", factory6792674212c15df7e9cfe3b0c44298fc1c149afb) diff --git a/Projects/Features/SignupFeature/Sources/SignupPassword/SignupPasswordComponent.swift b/Projects/Features/SignupFeature/Sources/SignupPassword/SignupPasswordComponent.swift new file mode 100644 index 00000000..cd4ad441 --- /dev/null +++ b/Projects/Features/SignupFeature/Sources/SignupPassword/SignupPasswordComponent.swift @@ -0,0 +1,12 @@ +import SwiftUI +import NeedleFoundation + +public protocol SignupPasswordDependency: Dependency {} + +public final class SignupPasswordComponent: Component { + public func makeView() -> some View { + SignupPasswordView( + viewModel: .init() + ) + } +} diff --git a/Projects/Features/SignupFeature/Sources/SignupPassword/SignupPasswordView.swift b/Projects/Features/SignupFeature/Sources/SignupPassword/SignupPasswordView.swift new file mode 100644 index 00000000..e1170365 --- /dev/null +++ b/Projects/Features/SignupFeature/Sources/SignupPassword/SignupPasswordView.swift @@ -0,0 +1,69 @@ +import DesignSystem +import SwiftUI + +struct SignupPasswordView: View { + private enum FocusField { + case password + case passwordCheck + } + @StateObject var viewModel: SignupPasswordViewModel + @FocusState private var focusField: FocusField? + + public init( + viewModel: SignupPasswordViewModel + ) { + _viewModel = StateObject(wrappedValue: viewModel) + } + + var body: some View { + VStack(spacing: 4) { + HStack { + VStack(alignment: .leading, spacing: 8) { + Text("DMS") + .dmsFont(.title(.extraLarge), color: .PrimaryVariant.primary) + + Text("학교 인증코드 입력") + .dmsFont(.text(.medium), color: .GrayScale.gray6) + + Text("비밀번호는 영문, 숫자, 기호를 포함한 8~20자이어야 합니다.") + .dmsFont(.text(.extraSmall), color: .GrayScale.gray5) + } + + Spacer() + } + .padding(.top, 24) + + VStack(spacing: 56) { + SecureDMSFloatingTextField( + "비밀번호", + text: $viewModel.password, + isError: viewModel.isPasswordRegexError, + errorMessage: "비밀번호 형식이 올바르지 않습니다." + ) { + focusField = .passwordCheck + } + .padding(.top, 56) + .focused($focusField, equals: .password) + + SecureDMSFloatingTextField( + "비밀번호 확인", + text: $viewModel.passwordCheck, + isError: viewModel.isPasswordMismatchedError, + errorMessage: "비밀번호가 일치하지 않습니다." + ) { + viewModel.nextButtonDidTap() + } + .focused($focusField, equals: .passwordCheck) + } + + Spacer() + + DMSWideButton(text: "다음", color: .PrimaryVariant.primary) { + viewModel.nextButtonDidTap() + } + .padding(.bottom, 40) + } + .dmsBackground() + .padding(.horizontal, 24) + } +} diff --git a/Projects/Features/SignupFeature/Sources/SignupPassword/SignupPasswordViewModel.swift b/Projects/Features/SignupFeature/Sources/SignupPassword/SignupPasswordViewModel.swift new file mode 100644 index 00000000..ab31756d --- /dev/null +++ b/Projects/Features/SignupFeature/Sources/SignupPassword/SignupPasswordViewModel.swift @@ -0,0 +1,40 @@ +import BaseFeature +import Combine +import Utility + +final class SignupPasswordViewModel: BaseViewModel { + @Published var password = "" { + didSet { resettingError() } + } + @Published var passwordCheck = "" { + didSet { resettingError() } + } + @Published var isPasswordRegexError = false + @Published var isPasswordMismatchedError = false + + var isEnabledNextStep: Bool { + !password.isEmpty && !passwordCheck.isEmpty + } + + func nextButtonDidTap() { + guard isEnabledNextStep else { + return + } + + let passwordExpression = "^(?=.*[A-Za-z])(?=.*[0-9])(?=.*[!@#$%^&*()_+=-]).{8,20}" + guard password ~= passwordExpression else { + isPasswordRegexError = true + return + } + + guard password == passwordCheck else { + isPasswordMismatchedError = true + return + } + } + + func resettingError() { + isPasswordRegexError = false + isPasswordMismatchedError = false + } +}