Skip to content

Commit

Permalink
feat #165 인증코드 남은 시간 timer 표시 구현, 인증코드 재전송 로직 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
minsangKang committed Oct 1, 2024
1 parent da9b22c commit b18b090
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 28 deletions.
75 changes: 58 additions & 17 deletions Project_Timer/Present/Signup/Email/SignupEmailModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,34 @@ import SwiftUI

// MARK: State
class SignupEmailModel: ObservableObject {

// MARK: State

@Published var contentWidth: CGFloat = .zero
@Published var focus: TTSignupTextFieldView.type?
@Published var isWarningEmail: Bool = false
@Published var validVerificationCode: Bool?
@Published var getVerificationSuccess: Bool = false
@Published var stage: Stage = .email

@Published var email: String = ""
@Published var authCode: String = ""
@Published var authCodeRemainSeconds: Int? // authCode 만료까지 남은 초

// MARK: Action

enum Action {
case resendAuthCode
}
public func action(_ action: Action) {
switch action {
case .resendAuthCode:
self.postAuthCode()
}
}

// MARK: Properties

enum Stage {
case email
case verificationCode
Expand Down Expand Up @@ -43,16 +71,9 @@ class SignupEmailModel: ObservableObject {
}
}
}
@Published var contentWidth: CGFloat = .zero
@Published var focus: TTSignupTextFieldView.type?
@Published var isWarningEmail: Bool = false
@Published var validVerificationCode: Bool?
@Published var getVerificationSuccess: Bool = false
@Published var stage: Stage = .email

@Published var email: String = ""
@Published var verificationCode: String = ""
private var verificationKey = ""
private var postAuthCodeTerminateDate: Date? // authCode 만료 시점
private var authKey: String? // authCode 전송시 서버로부터 받은 5분간 유효한 authKey
private var timer: Timer? // authCode 전송 후 남은 시간, 1초간 업데이트

private let getUsernameNotExistUseCase: GetUsernameNotExistUseCase
private let postAuthCodeUseCase: PostAuthCodeUseCase
Expand Down Expand Up @@ -84,7 +105,7 @@ class SignupEmailModel: ObservableObject {

// verificationCodeTextField underline 컬러
var authCodeTintColor: Color {
if validVerificationCode == false && verificationCode.isEmpty {
if validVerificationCode == false && authCode.isEmpty {
return Colors.wrongTextField.toColor
} else {
return focus == .verificationCode ? Color.blue : UIColor.placeholderText.toColor
Expand All @@ -98,7 +119,7 @@ class SignupEmailModel: ObservableObject {
venderInfo: self.infos.venderInfo,
emailInfo: SignupEmailInfo(
email: self.email,
verificationKey: self.verificationCode)
verificationKey: self.authCode)
)
}

Expand All @@ -109,7 +130,7 @@ class SignupEmailModel: ObservableObject {
venderInfo: self.infos.venderInfo,
emailInfo: SignupEmailInfo(
email: self.email,
verificationKey: self.verificationCode),
verificationKey: self.authCode),
passwordInfo: nil
)
}
Expand Down Expand Up @@ -168,27 +189,45 @@ extension SignupEmailModel {
}
}

/// 인증코드 전송
/// 인증코드 전송, 전송 시점 저장 및 authKey 수신 후 저장
private func postAuthCode() {
self.postAuthCodeTerminateDate = Calendar.current.date(byAdding: .minute, value: 1, to: Date())
self.postAuthCodeUseCase.execute(type: .signup(email: self.email))
.sink { [weak self] completion in
guard case .failure(let networkError) = completion else { return }
print("ERROR", #function)
self?.handleCheckEmailError(networkError)
} receiveValue: { [weak self] postAuthCodeInfo in
print("authKey: \(postAuthCodeInfo.authKey)")
self?.authKey = postAuthCodeInfo.authKey
self?.resetVerificationCode()
self?.runTimer()
}
.store(in: &self.cancellables)
}

// 인증코드 유효시간 표시 timer 동작
func runTimer() {
DispatchQueue.main.async { [weak self] in
self?.timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { [weak self] timer in
guard let postAuthCodeTerminateDate = self?.postAuthCodeTerminateDate else { return }
let remainSeconds = Int(postAuthCodeTerminateDate.timeIntervalSinceNow)
if remainSeconds <= 0 {
self?.timer?.invalidate()
self?.timer = nil
}
self?.authCodeRemainSeconds = remainSeconds
})
}
}

// 인증코드 done 액션
func checkVerificationCode() {
validVerificationCode = verificationCode.count > 7
validVerificationCode = authCode.count > 7
// stage 변화 -> @StateFocus 반영
if validVerificationCode == true {
// verificationKey 수신 필요
verificationKey = "abcd1234"
authCode = "abcd1234"
getVerificationSuccess = true
} else {
resetVerificationCode()
Expand All @@ -201,7 +240,9 @@ extension SignupEmailModel {
}

private func resetVerificationCode() {
self.verificationCode = ""
self.authCode = ""
self.timer?.invalidate()
self.timer = nil
self.stage = .verificationCode
}
}
Expand Down
31 changes: 20 additions & 11 deletions Project_Timer/Present/Signup/Email/SignupEmailView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -149,28 +149,37 @@ struct SignupEmailView: View {
.frame(height: 35)

HStack(alignment: .center, spacing: 16) {
TTSignupTextFieldView(type: .verificationCode, keyboardType: .alphabet, text: $model.verificationCode, focus: $focus) {
TTSignupTextFieldView(type: .verificationCode, keyboardType: .alphabet, text: $model.authCode, focus: $focus) {
model.checkVerificationCode()
}
.frame(maxWidth: .infinity)
// MARK: Timer 구현 필요
Text("4 : 59")

Text(remainTime(remainSeconds: model.authCodeRemainSeconds))
.font(Fonts.HGGGothicssiP40g(size: 18))
// MARK: 재전송 구현 필요
Button {
// MARK: ViewModel 내에서 네트워킹이 필요한 부분
print("resend")
} label: {
Text(Localized.string(.SignUp_Button_Resend))
.font(Typographys.font(.normal_3, size: 18))
.monospacedDigit()

if model.authCodeRemainSeconds == 0 {
Button {
model.action(.resendAuthCode)
} label: {
Text(Localized.string(.SignUp_Button_Resend))
.font(Typographys.font(.normal_3, size: 18))
}
}
}

TTSignupTextFieldUnderlineView(color: model.authCodeTintColor)
TTSignupTextFieldWarning(warning: Localized.string(.SignUp_Error_WrongCode), visible: model.validVerificationCode == false && model.verificationCode.isEmpty)
TTSignupTextFieldWarning(warning: Localized.string(.SignUp_Error_WrongCode), visible: model.validVerificationCode == false && model.authCode.isEmpty)
.id(TTSignupTextFieldView.type.verificationCode)
}
}

func remainTime(remainSeconds: Int?) -> String {
guard let remainSeconds else { return "0:00" }
let minutes = Int(remainSeconds) / 60
let seconds = Int(remainSeconds) % 60
return String(format: "%d:%02d", minutes, seconds)
}
}
}

Expand Down

0 comments on commit b18b090

Please sign in to comment.