Skip to content

Commit

Permalink
✨ :: [#38] Add Signup 기능구현 / 코드 발송, 인증 기능추가
Browse files Browse the repository at this point in the history
  • Loading branch information
Xixn2 committed Nov 4, 2024
1 parent ebca280 commit e36b18e
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 22 deletions.
48 changes: 48 additions & 0 deletions Projects/App/Sources/Extension/TimeManager.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//
// TimeManager.swift
// Expo-iOS
//
// Created by 서지완 on 11/4/24.
// Copyright © 2024 SchoolofCompany. All rights reserved.
//

import SwiftUI
import Combine

class TimerManager: ObservableObject {
@Published var remainingTime = 180
@Published var timerActive = false
private var timer: Timer?

func startTimer() {
// 타이머가 활성화되어 있을 경우, 초기화 및 재시작
if timerActive {
resetTimer()
}

timerActive = true
remainingTime = 180

timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
if self.remainingTime > 0 {
self.remainingTime -= 1
} else {
timer.invalidate()
self.timerActive = false
}
}
}

func resetTimer() {
timer?.invalidate()
timer = nil
timerActive = false
remainingTime = 180
}

func timeFormatted(_ totalSeconds: Int) -> String {
let minutes = totalSeconds / 60
let seconds = totalSeconds % 60
return String(format: "%02d:%02d", minutes, seconds)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public final class AuthViewModel: ObservableObject {
private var emailStatus: String = ""
private var phoneNumber: String = ""
private var nickname: String = ""
private var code: String = ""

private var passwordServe: String = ""

Expand Down Expand Up @@ -72,6 +73,10 @@ public final class AuthViewModel: ObservableObject {
self.name = name
}

func setupCode(code: String) {
self.code = code
}

func setupGender(gender: String) {
self.gender = gender
}
Expand Down Expand Up @@ -107,6 +112,48 @@ public final class AuthViewModel: ObservableObject {
}

func verifyAuthCode(completion: @escaping (Bool) -> Void) {
authProvider.request(.codeVerify(phoneNumber: phoneNumber, code: code)) { response in
switch response {
case .success(let result):
do {
let statusCode = result.statusCode
if let responseData = try? JSONSerialization.jsonObject(with: result.data, options: []) as? [String: Any],
let message = responseData["message"] as? String {
print("Server message: \(message)")
} else {
print("Response data could not be parsed or 'message' key is missing")

}

print(self.phoneNumber)
print(self.code)

switch statusCode {
case 200..<300:
print("OK")
completion(true)
case 404:
print("인증 코드를 찾을 수 없을때 / 인증되지 않은 사용자일때 / 찾을 수 없는 사용자 일때")
completion(false)
case 429:
print("인증번호 검증 요청이 5번을 초과할 경우")
completion(false)
case 500:
print("SERVER ERROR")
completion(false)
default:
print(result)
completion(false)
}
}
case .failure(let err):
print("Error: \(err.localizedDescription)")
completion(false)
}
}
}

func sendVerifyAuthCode(completion: @escaping (Bool) -> Void) {
authProvider.request(.codeSend(param: SendCodeRequest(phoneNumber: phoneNumber))) { response in
switch response {
case .success(let result):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@ struct SignupView: View {
@State private var userNumberTextField: String = ""
@State private var codeTextField: String = ""
@State private var showError: Bool = false
@StateObject private var timerManager = TimerManager()
@State private var codeState = false
@State private var isActive = false
@StateObject var viewModel: AuthViewModel
@Environment(\.dismiss) var dismiss
@State var communicationStatus = false
@State private var remainingTime = 180

var body: some View {
NavigationStack {
Expand Down Expand Up @@ -97,20 +100,48 @@ struct SignupView: View {
horizontalPadding: 22,
verticalPadding: 12
){
// Action
viewModel.setupCode(code: codeTextField)
viewModel.setupPhoneNumber(phoneNumber: userNumberTextField)
viewModel.verifyAuthCode { isSuccess1 in
if isSuccess1 {
print("전화번호 인증 성공!!")
viewModel.verifyAuthCode { isSuccess2 in
if isSuccess2 {
print("인증 성공!!")
} else {
print("전화번호 인증 실패 ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠ")
print("인증 실패 ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠ")
}
}
}
.padding(.trailing, 16)
}
.padding(.top, 8)

HStack(spacing: 0) {
Button {
timerManager.startTimer()
codeState = true

viewModel.setupPhoneNumber(phoneNumber: userNumberTextField)
viewModel.sendVerifyAuthCode { isSuccess1 in
if isSuccess1 {
print("전화번호 발송 성공!!")
} else {
print("전화번호 발송 실패 ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠ")
}
}
} label: {
Text("인증번호")
Text(codeState ? "재발송" : "발송")
}

if timerManager.timerActive {
Text(timerManager.timeFormatted(timerManager.remainingTime))
.padding(.leading, 6)
}
Spacer()
}
.padding(.leading, 16)
.padding(.top, 6)
.expoFont(.caption2R)
.expoColor(ExpoColor.gray300)

ExpoButton(
text: "로그인",
Expand Down Expand Up @@ -154,6 +185,7 @@ struct SignupView: View {
}
}

#Preview {
SignupView(viewModel: AuthViewModel())
}
//
//#Preview {
// SignupView(viewModel: AuthViewModel())
//}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// CodeVeritfyRequest.swift
// Domain
//
// Created by 서지완 on 11/4/24.
// Copyright © 2024 SchoolofCompany. All rights reserved.
//

import Foundation

public struct CodeVeritfyRequest: Codable {
var phoneNumber: String
var code: String

public init(phoneNumber: String, code: String) {
self.phoneNumber = phoneNumber
self.code = code
}
}


38 changes: 24 additions & 14 deletions Projects/Domain/Sources/Services/Auth/AuthAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public enum AuthAPI {
case refreshToken(refreshToken: String)
case logoutToken(refreshToken: String)
case codeSend(param: SendCodeRequest)
case codeVerify(phoneNumber: String, code: String)
}

extension AuthAPI: TargetType {
Expand All @@ -32,7 +33,7 @@ extension AuthAPI: TargetType {
return "auth"
case .logoutToken:
return ""
case .codeSend:
case .codeSend, .codeVerify:
return "sms"
}
}
Expand All @@ -41,6 +42,8 @@ extension AuthAPI: TargetType {
switch self {
case .signUp, .signIn, .codeSend:
return .post
case .codeVerify:
return .get
case .refreshToken:
return .patch
case .logoutToken:
Expand All @@ -53,20 +56,27 @@ extension AuthAPI: TargetType {
}

public var task: Task {
switch self {
case .signUp(let param):
return .requestJSONEncodable(param)
case .signIn(let param):
return .requestJSONEncodable(param)
case .codeSend(let param):
return .requestJSONEncodable(param)
case .refreshToken:
return .requestPlain
case let .logoutToken(refreshToken):
let parameters: [String: Any] = ["refreshToken": refreshToken]
return .requestParameters(parameters: parameters, encoding: JSONEncoding.default)
switch self {
case .signUp(let param):
return .requestJSONEncodable(param)
case .signIn(let param):
return .requestJSONEncodable(param)
case .codeSend(let param):
return .requestJSONEncodable(param)
case let .codeVerify(phoneNumber, code): // phoneNumber와 code를 쿼리 파라미터로 추가
let parameters: [String: Any] = [
"phoneNumber": phoneNumber,
"code": code
]
return .requestParameters(parameters: parameters, encoding: URLEncoding.default) // 쿼리 파라미터로 전송
case .refreshToken:
return .requestPlain
case let .logoutToken(refreshToken):
let parameters: [String: Any] = ["refreshToken": refreshToken]
return .requestParameters(parameters: parameters, encoding: JSONEncoding.default)
}
}
}


public var headers: [String : String]? {
switch self {
Expand Down

0 comments on commit e36b18e

Please sign in to comment.