Skip to content
Merged
4 changes: 0 additions & 4 deletions .swiftformat
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,6 @@
# Void
--voidtype void

# Self keyword (명시적으로 삽입)
--self insert

# Imports 정렬 (testable은 하단, 빈 줄로 구분)
--importgrouping testable-bottom

Expand Down Expand Up @@ -91,7 +88,6 @@
--enable preferForLoop
--enable wrapConditionalBodies
--enable wrapEnumCases
--enable wrapSwitchCases

# ============================
# Disable Rules
Expand Down
3 changes: 2 additions & 1 deletion App/Sources/MyiAppApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ struct MyiAppApp: App {

var body: some Scene {
WindowGroup {
RootView(store: self.store)
RootView(store: store)
.onAppear { store.send(.checkAuth) }
}
}
}
61 changes: 56 additions & 5 deletions App/Sources/Root/RootFeature.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import AuthFeature
import ComposableArchitecture
import Core
import Domain
import SwiftUI

@Reducer
Expand All @@ -14,20 +16,66 @@ public struct RootFeature {
}
}

public enum Action {
public enum Action: Equatable {
case auth(AuthFeature.Action)
case checkAuth
case authCheckResponse(Result<Route, CaregiverError>)
}

public enum Route: Equatable {
case login
case registerBaby
case main
}

@Dependency(\.authClient)
var authClient
@Dependency(\.caregiverClient)
var caregiverClient

public init() {}

public var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .auth(.loginResponse(.success)):
case .checkAuth:
return .run { send in
do {
guard let user = try await authClient.currentUser() else {
await send(.authCheckResponse(.success(.login)))
return
}

let caregiver = try await caregiverClient.fetchCaregiver(user.id)
if caregiver.lastSelectedBabyID == nil {
await send(.authCheckResponse(.success(.registerBaby)))
} else {
await send(.authCheckResponse(.success(.main)))
}
} catch {
await send(.authCheckResponse(.success(.login)))
}
}

case let .authCheckResponse(.success(route)):
switch route {
case .login:
state = .auth(.login(AuthFeature.LoginFeature.State()))
case .registerBaby:
state = .auth(.registerBaby(AuthFeature.RegisterBabyFeature.State()))
case .main:
state = .main
}
return .none

case .auth(.login(.loginResponse(.success))):
return .send(.checkAuth)

case .auth(.registerBaby(.delegate(.registered))):
state = .main
return .none

case .auth:
case .auth, .authCheckResponse:
return .none
}
}
Expand All @@ -45,14 +93,17 @@ public struct RootView: View {
}

public var body: some View {
switch self.store.state {
switch store.state {
case .auth:
if let authStore = store.scope(state: \.auth, action: \.auth) {
AuthView(store: authStore)
}

case .main:
Text("Main Content") // HomeFeatureView 연동
Text("Main Content (HomeView)")
.onAppear {
print("Main Content Shown")
}
}
}
}
3 changes: 2 additions & 1 deletion Core/Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ let project = Project(
.target(
name: "Core",
destinations: .iOS,
product: .staticFramework,
product: .framework,
bundleId: BundleID.core,
deploymentTargets: DeploymentTarget.iOS,
infoPlist: .default,
sources: ["Sources/**"],
scripts: [.swiftFormat],
dependencies: [
.project(target: "Domain", path: "../Domain"),
.external(name: "FirebaseCore"),
.external(name: "FirebaseAuth"),
.external(name: "FirebaseFirestore"),
.external(name: "ComposableArchitecture"),
Expand Down
6 changes: 3 additions & 3 deletions Core/Sources/Clients/AuthClient+Live.swift
Original file line number Diff line number Diff line change
Expand Up @@ -215,13 +215,13 @@ private final class AppleSignInDelegate: NSObject, ASAuthorizationControllerDele
didCompleteWithAuthorization authorization: ASAuthorization
) {
if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
self.completion(.success(appleIDCredential))
completion(.success(appleIDCredential))
} else {
self.completion(.failure(AuthError.unknown))
completion(.failure(AuthError.unknown))
}
}

func authorizationController(controller _: ASAuthorizationController, didCompleteWithError error: Error) {
self.completion(.failure(error))
completion(.failure(error))
}
}
32 changes: 32 additions & 0 deletions Core/Sources/Clients/CaregiverClient+Live.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,38 @@ extension CaregiverClient {
} catch {
throw CaregiverError.internalError(error)
}
},
registerBaby: { caregiverID, baby async throws(CaregiverError) in
let babyRef = db.collection("babies").document(baby.id)
let userRef = db.collection("users").document(caregiverID)

let babyData: [String: Any] = [
"id": baby.id,
"name": baby.name,
"birthDate": Timestamp(date: baby.birthDate),
"gender": baby.gender.rawValue,
"bloodType": baby.bloodType?.rawValue as Any,
"caregivers": [userRef],
"createdAt": FieldValue.serverTimestamp(),
"updatedAt": FieldValue.serverTimestamp()
]

do {
_ = try await db.runTransaction { transaction, _ in
// 1. 아기 문서 생성 (기존 문서가 있으면 덮어쓰거나 에러 처리 - 여기서는 setData)
transaction.setData(babyData, forDocument: babyRef)

// 2. 보호자 문서에 아기 참조 추가 및 lastSelectedBabyID 업데이트
transaction.updateData([
"babies": FieldValue.arrayUnion([babyRef]),
"lastSelectedBabyId": baby.id
], forDocument: userRef)

return nil
}
} catch {
throw CaregiverError.internalError(error)
}
}
)
}
Expand Down
3 changes: 2 additions & 1 deletion Core/Sources/Clients/DependencyValues+Core.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ extension CaregiverClient: @retroactive DependencyKey {
Self(
fetchCaregiver: { _ in fatalError("Unimplemented") },
registerCaregiver: { _ in fatalError("Unimplemented") },
connectCaregiver: { _, _ in fatalError("Unimplemented") }
connectCaregiver: { _, _ in fatalError("Unimplemented") },
registerBaby: { _, _ in fatalError("Unimplemented") }
)
}
}
Expand Down
5 changes: 4 additions & 1 deletion Domain/Sources/Protocols/CaregiverClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ public struct CaregiverClient: Sendable {
public var fetchCaregiver: @Sendable (String) async throws(CaregiverError) -> Caregiver
public var registerCaregiver: @Sendable (Caregiver) async throws(CaregiverError) -> Void
public var connectCaregiver: @Sendable (String, String) async throws(CaregiverError) -> Void
public var registerBaby: @Sendable (String, Baby) async throws(CaregiverError) -> Void

public init(
fetchCaregiver: @escaping @Sendable (String) async throws(CaregiverError) -> Caregiver,
registerCaregiver: @escaping @Sendable (Caregiver) async throws(CaregiverError) -> Void,
connectCaregiver: @escaping @Sendable (String, String) async throws(CaregiverError) -> Void
connectCaregiver: @escaping @Sendable (String, String) async throws(CaregiverError) -> Void,
registerBaby: @escaping @Sendable (String, Baby) async throws(CaregiverError) -> Void
) {
self.fetchCaregiver = fetchCaregiver
self.registerCaregiver = registerCaregiver
self.connectCaregiver = connectCaregiver
self.registerBaby = registerBaby
}
}
2 changes: 1 addition & 1 deletion Domain/Sources/UseCases/RegisterCaregiverUseCase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ public struct RegisterCaregiverUseCase: RegisterCaregiverUseCaseProtocol {
throw CaregiverError.invalidInteraction
}

try await self.client.registerCaregiver(caregiver)
try await client.registerCaregiver(caregiver)
}
}
6 changes: 4 additions & 2 deletions Domain/Testing/CaregiverClient+Mock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@ extension CaregiverClient {
Self(
fetchCaregiver: { _ throws(CaregiverError) in .mock },
registerCaregiver: { _ throws(CaregiverError) in },
connectCaregiver: { _, _ throws(CaregiverError) in }
connectCaregiver: { _, _ throws(CaregiverError) in },
registerBaby: { _, _ throws(CaregiverError) in }
)
}

public static func failing(error: CaregiverError) -> Self {
Self(
fetchCaregiver: { _ throws(CaregiverError) in throw error },
registerCaregiver: { _ throws(CaregiverError) in throw error },
connectCaregiver: { _, _ throws(CaregiverError) in throw error }
connectCaregiver: { _, _ throws(CaregiverError) in throw error },
registerBaby: { _, _ throws(CaregiverError) in throw error }
)
}
}
Expand Down
4 changes: 2 additions & 2 deletions Domain/Tests/ClientTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ struct ClientTests {
private actor AuthMockState {
var isLoginCalled = false
func setIsLoginCalled(_ value: Bool) {
self.isLoginCalled = value
isLoginCalled = value
}
}

Expand Down Expand Up @@ -47,7 +47,7 @@ struct ClientTests {
private actor RecordMockState {
var savedRecord: Record?
func setSavedRecord(_ record: Record) {
self.savedRecord = record
savedRecord = record
}
}

Expand Down
5 changes: 3 additions & 2 deletions Domain/Tests/UseCases/RegisterCaregiverUseCaseTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@ struct RegisterCaregiverUseCaseTests {
actor State {
var isCalled = false
func setCalled() {
self.isCalled = true
isCalled = true
}
}
let state = State()

let mockClient = CaregiverClient(
fetchCaregiver: { _ throws(CaregiverError) in .mock },
registerCaregiver: { _ throws(CaregiverError) in await state.setCalled() },
connectCaregiver: { _, _ throws(CaregiverError) in }
connectCaregiver: { _, _ throws(CaregiverError) in },
registerBaby: { _, _ throws(CaregiverError) in }
)
let useCase = RegisterCaregiverUseCase(client: mockClient)
let caregiver = Caregiver.mock
Expand Down
Loading
Loading