Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 30 additions & 11 deletions Keychy/Keychy/Core/DeepLink/DeepLinkManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,19 @@ enum DeepLinkType {
case notification // 푸시 알림
}

enum DeepLinkError {
case notFound // 존재하지 않는 링크
case missingType // type 필드 없음
case typeMismatch // URL 타입과 문서 타입 불일치
}

@Observable
class DeepLinkManager {
static let shared = DeepLinkManager()

var pendingPostOfficeId: String?
var pendingDeepLinkType: DeepLinkType?
var pendingError: DeepLinkError?

private init() {}

Expand All @@ -31,19 +38,26 @@ class DeepLinkManager {

// 1. Firestore에서 PostOffice 조회
db.collection("PostOffice").document(postOfficeId).getDocument { snapshot, error in
guard let data = snapshot?.data(),
let documentTypeString = data["type"] as? String,
let documentType = PostOfficeType(rawValue: documentTypeString) else {
// 문서가 존재하지 않거나 에러 발생
guard error == nil, let data = snapshot?.data() else {
print("존재하지 않는 링크입니다")
// TODO: UI 상 처리 필요
DispatchQueue.main.async {
self.pendingPostOfficeId = postOfficeId
self.pendingDeepLinkType = type
self.pendingError = .notFound
}
return
}

// 2. type 필드 확인
guard let documentTypeString = data["type"] as? String,
let documentType = PostOfficeType(rawValue: documentTypeString) else {
print("type 필드 없음")
// TODO: UI 상 처리 필요
DispatchQueue.main.async {
self.pendingPostOfficeId = postOfficeId
self.pendingDeepLinkType = type
self.pendingError = .missingType
}
return
}

Expand All @@ -52,31 +66,36 @@ class DeepLinkManager {

guard isValid else {
print("타입 불일치 - URL: \(type), Document: \(documentType)")
// TODO: UI 상 처리 필요
DispatchQueue.main.async {
self.pendingPostOfficeId = postOfficeId
self.pendingDeepLinkType = type
self.pendingError = .typeMismatch
}
return
}

self.pendingPostOfficeId = postOfficeId
self.pendingDeepLinkType = type

// 4. 검증 통과 → 정상 처리
DispatchQueue.main.async {
self.pendingPostOfficeId = postOfficeId
self.pendingDeepLinkType = type
self.pendingError = nil
}
}
}

func consumePendingDeepLink() -> (postOfficeId: String, type: DeepLinkType)? {
func consumePendingDeepLink() -> (postOfficeId: String, type: DeepLinkType, error: DeepLinkError?)? {
guard let postOfficeId = pendingPostOfficeId,
let type = pendingDeepLinkType else {
return nil
}

let error = pendingError

self.pendingPostOfficeId = nil
self.pendingDeepLinkType = nil
self.pendingError = nil

return (postOfficeId, type)
return (postOfficeId, type, error)
}

static func createTestReceiveLink(postOfficeId: String) -> URL? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ class KeyringCollectViewModel {
var isAccepting: Bool = false
var isAccepted: Bool = false

// DeepLink Error
var hasDeepLinkError: Bool = false

// Alert States
var showAcceptCompleteAlert: Bool = false
var showInvenFullAlert: Bool = false
Expand All @@ -27,13 +30,20 @@ class KeyringCollectViewModel {
private let postOfficeId: String

// MARK: - Init
init(collectionViewModel: CollectionViewModel, postOfficeId: String) {
init(collectionViewModel: CollectionViewModel, postOfficeId: String, deepLinkError: DeepLinkError? = nil) {
self.collectionViewModel = collectionViewModel
self.postOfficeId = postOfficeId
self.hasDeepLinkError = (deepLinkError != nil)
}

// MARK: - 데이터 로드
func loadKeyringData() {
// DeepLink 에러가 있으면 바로 종료 (errorView로 연결)
if hasDeepLinkError {
self.isLoading = false
return
}

print("PostOffice 데이터 로드 시작")

collectionViewModel.fetchPostOfficeData(postOfficeId: postOfficeId) { postOfficeData in
Expand Down Expand Up @@ -143,11 +153,7 @@ class KeyringCollectViewModel {
false
}

var backgroundImageName: ImageResource {
// 로딩 중이 아니고, (이미 수락됨 또는 에러 또는 keyring이 nil)
if !isLoading && (keyring == nil) {
return .whiteBackground
}
return .greenBackground
var shouldShowWhiteBackground: Bool {
hasDeepLinkError || (!isLoading && (keyring == nil))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ class KeyringReceiveViewModel {
var isAccepted: Bool = false
var isAlreadyReceived: Bool = false

// DeepLink Error
var hasDeepLinkError: Bool = false

// Alert States
var showAcceptCompleteAlert: Bool = false
var showInvenFullAlert: Bool = false
Expand All @@ -29,13 +32,20 @@ class KeyringReceiveViewModel {
private let postOfficeId: String

// MARK: - Init
init(collectionViewModel: CollectionViewModel, postOfficeId: String) {
init(collectionViewModel: CollectionViewModel, postOfficeId: String, deepLinkError: DeepLinkError? = nil) {
self.collectionViewModel = collectionViewModel
self.postOfficeId = postOfficeId
self.hasDeepLinkError = (deepLinkError != nil)
}

// MARK: - 데이터 로드
func loadKeyringData() {
// DeepLink 에러가 있으면 바로 종료 (errorView로 연결)
if hasDeepLinkError {
self.isLoading = false
return
}

print("PostOffice 데이터 로드 시작")

collectionViewModel.fetchPostOfficeData(postOfficeId: postOfficeId) { postOfficeData in
Expand Down Expand Up @@ -196,11 +206,7 @@ class KeyringReceiveViewModel {
false
}

var backgroundImageName: String {
// 로딩 중이 아니고, (이미 수락됨 또는 에러 또는 keyring이 nil)
if !isLoading && (isAlreadyReceived || keyring == nil) {
return "WhiteBackground"
}
return "GreenBackground"
var shouldShowWhiteBackground: Bool {
hasDeepLinkError || (!isLoading && (isAlreadyReceived || keyring == nil))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ struct KeyringCollectView: View {
@State var viewModel: KeyringCollectViewModel
@State private var scene: KeyringCellScene?

init(viewModel: CollectionViewModel, postOfficeId: String) {
init(viewModel: CollectionViewModel, postOfficeId: String, deepLinkError: DeepLinkError? = nil) {
_viewModel = State(
initialValue: KeyringCollectViewModel(
collectionViewModel: viewModel,
postOfficeId: postOfficeId
postOfficeId: postOfficeId,
deepLinkError: deepLinkError
)
)
}
Expand All @@ -38,10 +39,15 @@ struct KeyringCollectView: View {

alertOverlayView(geometry: geometry)

customNavigationBar
.blur(radius: viewModel.shouldApplyBlur ? 15 : 0)
.adaptiveTopPadding()
.zIndex(0)
// 정상 키링 수신 화면일 때만 네비게이션 바 표시
if !viewModel.isLoading &&
!viewModel.hasDeepLinkError &&
viewModel.keyring != nil {
customNavigationBar
.blur(radius: viewModel.shouldApplyBlur ? 15 : 0)
.adaptiveTopPadding()
.zIndex(0)
}
}
}
.ignoresSafeArea()
Expand Down Expand Up @@ -100,23 +106,34 @@ struct KeyringCollectView: View {

private var errorView: some View {
VStack(spacing: 20) {
VStack(spacing: 0) {
Image(.emptyViewIcon)
VStack(spacing: 10) {
Image(.noInternetBangMark)
.resizable()
.frame(width: 124, height: 111)
.frame(width: 26, height: 48)
.padding(.bottom, 15)

Text("키링을 불러올 수 없습니다.")
Text("키링을 불러 올 수 없습니다")
.typography(.suit18SB)
.foregroundColor(.black100)

Text("유효하지 않거나\n더 이상 사용할 수 없는 링크입니다")
.typography(.suit15R)
.multilineTextAlignment(.center)
.foregroundColor(.black100)
.padding(.vertical, 15)
.padding(.bottom, 15)

Button {
dismiss()
} label: {
Text("닫기")
.typography(.suit15R)
.foregroundColor(.main500)
.padding(.vertical, 15)
.typography(.suit17B)
.foregroundColor(.black100)
.padding(.vertical, 13.5)
.padding(.horizontal, 20)
.background(
RoundedRectangle(cornerRadius: 15)
.fill(.gray50)
)
}
}
}
Expand Down Expand Up @@ -217,10 +234,15 @@ struct KeyringCollectView: View {

@ViewBuilder
private var backgroundImage: some View {
Image(viewModel.backgroundImageName)
.resizable()
.scaledToFill()
.ignoresSafeArea()
if viewModel.shouldShowWhiteBackground {
Color.white
.ignoresSafeArea()
} else {
Image(.greenBackground)
.resizable()
.scaledToFill()
.ignoresSafeArea()
}
}
}

Expand Down
Loading