feat(auth): 인증 후 콘텐츠 설정과 개발용 모의 인증을 추가한다

This commit is contained in:
Yu Sung
2026-10-13 11:37:03 +09:00
parent e34a51b411
commit 61bfa46c11
20 changed files with 1203 additions and 181 deletions
+168 -52
View File
@@ -14,6 +14,9 @@ final class MyPageViewModel: ObservableObject {
private let authRepository = AuthRepository()
private let noticeRepository = NoticeRepository()
private var subscription = Set<AnyCancellable>()
private var pendingAuthReceiptId: String?
private var pendingAuthRequest: AuthVerifyRequest?
private var pendingAuthSuccess: (() -> Void)?
@Published var latestNotice: NoticeItem? = nil
@@ -28,6 +31,16 @@ final class MyPageViewModel: ObservableObject {
@Published var isShowPopup = false
@Published var isLoading = false
@Published var isShowAuthView = false
@Published var isShowAuthContentSettings = false
@Published var authIsAdultContentVisible = true {
didSet {
if !authIsAdultContentVisible {
authContentType = .ALL
}
}
}
@Published var authContentType: ContentType = .ALL
@Published private(set) var isSubmittingAuth = false
func getMypage() {
isLoading = true
@@ -73,61 +86,164 @@ final class MyPageViewModel: ObservableObject {
}
func authVerify(_ data: [String: Any], onSuccess: (() -> Void)? = nil) {
isLoading = true
let _data = data["data"] as? [String: Any]
if let data = _data {
let receiptId = data["receipt_id"] as! String
authRepository.authCertificate(receiptId: receiptId)
.sink { result in
switch result {
case .finished:
DEBUG_LOG("finish")
case .failure(let error):
ERROR_LOG(error.localizedDescription)
}
} receiveValue: { [unowned self] response in
self.isLoading = false
let responseData = response.data
do {
let jsonDecoder = JSONDecoder()
let decoded = try jsonDecoder.decode(ApiResponse<AuthResponse>.self, from: responseData)
if let data = decoded.data, decoded.success {
if data.gender == 0 {
UserDefaults.set(ContentType.FEMALE.rawValue, forKey: .contentPreference)
} else {
UserDefaults.set(ContentType.MALE.rawValue, forKey: .contentPreference)
}
if let onSuccess = onSuccess {
onSuccess()
} else {
AppState.shared.isRestartApp = true
AppState.shared.setAppStep(step: .splash)
}
} else {
if let message = decoded.message {
self.errorMessage = message
} else {
self.errorMessage = I18n.MyPage.Auth.verificationErrorWithSupport
}
self.isShowPopup = true
}
} catch {
self.errorMessage = I18n.MyPage.Auth.verificationErrorWithSupport
self.isShowPopup = true
}
}
.store(in: &subscription)
} else {
isLoading = false
guard Thread.isMainThread else {
DispatchQueue.main.async { [weak self] in
self?.authVerify(data, onSuccess: onSuccess)
}
return
}
guard pendingAuthReceiptId == nil, !isSubmittingAuth else { return }
guard let payload = data["data"] as? [String: Any],
let receiptId = payload["receipt_id"] as? String,
!receiptId.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
errorMessage = I18n.Main.Auth.authenticationError
isShowPopup = true
return
}
pendingAuthReceiptId = receiptId
pendingAuthSuccess = onSuccess
authIsAdultContentVisible = true
authContentType = .ALL
}
func presentAuthContentSettings() {
guard Thread.isMainThread else {
DispatchQueue.main.async { [weak self] in
self?.presentAuthContentSettings()
}
return
}
guard pendingAuthReceiptId != nil, !isSubmittingAuth else { return }
isShowAuthContentSettings = true
}
func confirmAuthContentSettings() {
guard Thread.isMainThread else {
DispatchQueue.main.async { [weak self] in
self?.confirmAuthContentSettings()
}
return
}
guard let receiptId = pendingAuthReceiptId, !isSubmittingAuth else { return }
pendingAuthRequest = AuthVerifyRequest(
receiptId: receiptId,
isAdultContentVisible: authIsAdultContentVisible,
contentType: authIsAdultContentVisible ? authContentType : .ALL
)
isSubmittingAuth = true
isShowAuthContentSettings = false
}
func submitPendingAuthVerification() {
guard Thread.isMainThread else {
DispatchQueue.main.async { [weak self] in
self?.submitPendingAuthVerification()
}
return
}
guard isSubmittingAuth, let request = pendingAuthRequest else { return }
pendingAuthRequest = nil
authRepository.authCertificate(request: request)
.receive(on: DispatchQueue.main)
.sink { [weak self] result in
if case .failure = result {
self?.handleAuthSubmissionFailure()
}
} receiveValue: { [weak self] response in
guard let self = self else { return }
guard (200..<300).contains(response.statusCode) else {
self.handleAuthSubmissionFailure()
return
}
do {
let decoded = try JSONDecoder().decode(ApiResponse<AuthResponse>.self, from: response.data)
guard decoded.success, decoded.data != nil else {
self.handleAuthSubmissionFailure()
return
}
if self.pendingAuthSuccess != nil {
self.synchronizeAuthenticatedMember()
} else {
UserDefaults.set(request.isAdultContentVisible, forKey: .isAdultContentVisible)
UserDefaults.set(request.contentType.rawValue, forKey: .contentPreference)
self.restartAfterAuthVerification()
}
} catch {
self.handleAuthSubmissionFailure()
}
}
.store(in: &subscription)
}
private func handleAuthSubmissionFailure() {
pendingAuthRequest = nil
isSubmittingAuth = false
errorMessage = I18n.MyPage.Auth.verificationErrorWithSupport
isShowPopup = true
isShowAuthContentSettings = true
}
private func synchronizeAuthenticatedMember() {
repository.getMemberInfo()
.receive(on: DispatchQueue.main)
.sink { [weak self] result in
if case .failure = result {
self?.restartAfterAuthVerification()
}
} receiveValue: { [weak self] response in
guard let self = self else { return }
guard (200..<300).contains(response.statusCode) else {
self.restartAfterAuthVerification()
return
}
do {
let decoded = try JSONDecoder().decode(ApiResponse<GetMemberInfoResponse>.self, from: response.data)
guard let data = decoded.data, decoded.success, data.isAuth else {
self.restartAfterAuthVerification()
return
}
UserDefaults.set(data.can, forKey: .can)
UserDefaults.set(data.point, forKey: .point)
UserDefaults.set(data.isAuth, forKey: .auth)
UserDefaults.set(data.role.rawValue, forKey: .role)
UserDefaults.set(data.auditionNotice ?? false, forKey: .isAuditionNotification)
UserDefaults.set(data.countryCode, forKey: .countryCode)
UserDefaults.set(data.isAdultContentVisible, forKey: .isAdultContentVisible)
UserDefaults.set(data.isAdultContentVisible ? data.contentType : ContentType.ALL.rawValue, forKey: .contentPreference)
self.isAuth = data.isAuth
let onSuccess = self.pendingAuthSuccess
self.clearPendingAuthVerification()
onSuccess?()
} catch {
self.restartAfterAuthVerification()
}
}
.store(in: &subscription)
}
private func clearPendingAuthVerification() {
pendingAuthReceiptId = nil
pendingAuthRequest = nil
pendingAuthSuccess = nil
isSubmittingAuth = false
isShowAuthContentSettings = false
}
private func restartAfterAuthVerification() {
clearPendingAuthVerification()
AppState.shared.isRestartApp = true
AppState.shared.setAppStep(step: .splash)
}
func getLatestNotice() {