-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #57 from YAPP-Github/TNT-208-appCoordinate
[TNT-208] App Coordinator 로직 작성
- Loading branch information
Showing
9 changed files
with
617 additions
and
1 deletion.
There are no files selected for viewing
79 changes: 79 additions & 0 deletions
79
TnT/Projects/Presentation/Sources/Coordinator/AppFlow/AppFlowCoordinatorFeature.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
// | ||
// AppFlowCoordinatorFeature.swift | ||
// Presentation | ||
// | ||
// Created by 박민서 on 2/4/25. | ||
// Copyright © 2025 yapp25thTeamTnT. All rights reserved. | ||
// | ||
|
||
import SwiftUI | ||
import ComposableArchitecture | ||
|
||
import Domain | ||
|
||
@Reducer | ||
public struct AppFlowCoordinatorFeature { | ||
@ObservableState | ||
public struct State: Equatable { | ||
var userType: UserType? | ||
|
||
// MARK: SubFeature state | ||
var trainerMainState: TrainerMainFlowFeature.State? | ||
var traineeMainState: TraineeMainFlowFeature.State? | ||
var onboardingState: OnboardingFlowFeature.State? | ||
|
||
public init( | ||
userType: UserType? = nil, | ||
onboardingState: OnboardingFlowFeature.State? = .init(), | ||
trainerMainState: TrainerMainFlowFeature.State? = nil, | ||
traineeMainState: TraineeMainFlowFeature.State? = nil | ||
) { | ||
self.userType = userType | ||
self.onboardingState = onboardingState | ||
self.trainerMainState = trainerMainState | ||
self.traineeMainState = traineeMainState | ||
} | ||
} | ||
|
||
public enum Action { | ||
/// 하위 코디네이터에서 일어나는 액션을 처리합니다 | ||
case subFeature(SubFeatureAction) | ||
case onAppear | ||
|
||
@CasePathable | ||
public enum SubFeatureAction: Sendable { | ||
/// 온보딩 플로우 코디네이터에서 발생하는 액션 처리 | ||
case onboardingFlow(OnboardingFlowFeature.Action) | ||
/// 트레이너 메인탭 플로우 코디네이터에서 발생하는 액션 처리 | ||
case trainerMainFlow(TrainerMainFlowFeature.Action) | ||
/// 트레이니 메인탭 플로우 코디네이터에서 발생하는 액션 처리 | ||
case traineeMainFlow(TraineeMainFlowFeature.Action) | ||
} | ||
} | ||
|
||
public init() {} | ||
|
||
public var body: some Reducer<State, Action> { | ||
Reduce { state, action in | ||
switch action { | ||
case .subFeature(let internalAction): | ||
switch internalAction { | ||
case .onboardingFlow: | ||
return .none | ||
|
||
case .trainerMainFlow: | ||
return .none | ||
|
||
case .traineeMainFlow: | ||
return .none | ||
} | ||
|
||
case .onAppear: | ||
return .none | ||
} | ||
} | ||
.ifLet(\.onboardingState, action: \.subFeature.onboardingFlow) { OnboardingFlowFeature() } | ||
.ifLet(\.trainerMainState, action: \.subFeature.trainerMainFlow) { TrainerMainFlowFeature() } | ||
.ifLet(\.traineeMainState, action: \.subFeature.traineeMainFlow) { TraineeMainFlowFeature() } | ||
} | ||
} |
42 changes: 42 additions & 0 deletions
42
TnT/Projects/Presentation/Sources/Coordinator/AppFlow/AppFlowCoordinatorView.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
// | ||
// AppFlowCoordinatorView.swift | ||
// Presentation | ||
// | ||
// Created by 박민서 on 2/4/25. | ||
// Copyright © 2025 yapp25thTeamTnT. All rights reserved. | ||
// | ||
|
||
import SwiftUI | ||
import ComposableArchitecture | ||
|
||
public struct AppFlowCoordinatorView: View { | ||
let store: StoreOf<AppFlowCoordinatorFeature> | ||
|
||
public init(store: StoreOf<AppFlowCoordinatorFeature>) { | ||
self.store = store | ||
} | ||
|
||
public var body: some View { | ||
Group { | ||
if let userType = store.userType { | ||
switch userType { | ||
case .trainee: | ||
if let store = store.scope(state: \.traineeMainState, action: \.subFeature.traineeMainFlow) { | ||
TraineeMainFlowView(store: store) | ||
} | ||
case .trainer: | ||
if let store = store.scope(state: \.trainerMainState, action: \.subFeature.trainerMainFlow) { | ||
TrainerMainFlowView(store: store) | ||
} | ||
} | ||
} else { | ||
if let store = store.scope(state: \.onboardingState, action: \.subFeature.onboardingFlow) { | ||
OnboardingFlowView(store: store) | ||
} | ||
} | ||
} | ||
.onAppear { | ||
store.send(.onAppear) | ||
} | ||
} | ||
} |
109 changes: 109 additions & 0 deletions
109
TnT/Projects/Presentation/Sources/Coordinator/OnboardingFlow/OnboardingFlowFeature.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
// | ||
// OnboardingNavigationFeature.swift | ||
// Presentation | ||
// | ||
// Created by 박서연 on 1/24/25. | ||
// Copyright © 2025 yapp25thTeamTnT. All rights reserved. | ||
// | ||
|
||
import SwiftUI | ||
import ComposableArchitecture | ||
|
||
import Domain | ||
|
||
@Reducer | ||
public struct OnboardingFlowFeature { | ||
@ObservableState | ||
public struct State: Equatable { | ||
public var path: StackState<Path.State> | ||
|
||
public init(path: StackState<Path.State> = .init([.snsLogin(.init())])) { | ||
self.path = path | ||
} | ||
} | ||
|
||
public enum Action: Sendable { | ||
/// 현재 표시되고 있는 path 화면 내부에서 일어나는 액션을 처리합니다. | ||
case path(StackActionOf<Path>) | ||
case onAppear | ||
} | ||
|
||
public init() {} | ||
|
||
public var body: some ReducerOf<Self> { | ||
Reduce { state, action in | ||
switch action { | ||
case let .path(action): | ||
switch action { | ||
|
||
case .element(id: _, action: .snsLogin(.view(.tappedAppleLogin))): | ||
state.path.append(.trainerSignUpComplete(.init())) | ||
return .none | ||
|
||
/// 트레이너 프로필 생성 완료 -> 다음 버튼 tapped | ||
case .element(id: _, action: .trainerSignUpComplete(.setNavigating)): | ||
state.path.append(.trainerMakeInvitationCode(MakeInvitationCodeFeature.State())) | ||
return .none | ||
|
||
/// 트레이너의 초대코드 화면 -> 건너뛰기 버튼 tapped | ||
case .element(id: _, action: .trainerMakeInvitationCode(.setNavigation)): | ||
// 추후에 홈과 연결 | ||
return .none | ||
|
||
/// 약관 화면 -> 트레이너/트레이니 선택 화면 이동 | ||
case .element(id: _, action: .userTypeSelection): | ||
return .none | ||
|
||
default: | ||
return .none | ||
} | ||
|
||
case .onAppear: | ||
return .none | ||
} | ||
} | ||
.forEach(\.path, action: \.path) | ||
} | ||
} | ||
|
||
extension OnboardingFlowFeature { | ||
@Reducer(state: .equatable, .sendable) | ||
public enum Path { | ||
// MARK: Common | ||
/// SNS 로그인 뷰 | ||
case snsLogin(LoginFeature) | ||
/// 약관동의뷰 | ||
case term(TermFeature) | ||
/// 트레이너/트레이니 선택 뷰 | ||
case userTypeSelection(UserTypeSelectionFeature) | ||
/// 트레이너/트레이니의 이름 입력 뷰 | ||
case createProfile(CreateProfileFeature) | ||
|
||
// MARK: Trainer | ||
/// 트레이너 회원 가입 완료 뷰 | ||
/// TODO: 트레이너/트레이니 회원 가입 완료 화면으로 통합 필요 | ||
case trainerSignUpComplete(TrainerSignUpCompleteFeature) | ||
/// 트레이너의 초대코드 발급 뷰 | ||
case trainerMakeInvitationCode(MakeInvitationCodeFeature) | ||
/// 트레이너의 트레이니 프로필 확인 뷰 | ||
case trainerConnectedTraineeProfile(ConnectedTraineeProfileFeature) | ||
|
||
// MARK: Trainee | ||
/// 트레이니 기본 정보 입력 | ||
case traineeBasicInfoInput(TraineeBasicInfoInputFeature) | ||
/// 트레이니 PT 목적 입력 | ||
case traineeTrainingPurpose(TraineeTrainingPurposeFeature) | ||
/// 트레이니 주의사항 입력 | ||
case traineePrecautionInput(TraineePrecautionInputFeature) | ||
/// 트레이니 프로필 생성 완료 | ||
/// TODO: 트레이너/트레이니 회원 가입 완료 화면으로 통합 필요 | ||
case traineeProfileCompletion(TraineeProfileCompletionFeature) | ||
/// 트레이니 초대 코드입력 | ||
case traineeInvitationCodeInput(TraineeInvitationCodeInputFeature) | ||
/// 트레이니 수업 정보 입력 | ||
case traineeTrainingInfoInput(TraineeTrainingInfoInputFeature) | ||
/// 트레이니 연결 완료 | ||
/// TODO: 트레이너/트레이니 연결 완료 화면으로 통합 필요 | ||
case traineeConnectionComplete(TraineeConnectionCompleteFeature) | ||
} | ||
} |
62 changes: 62 additions & 0 deletions
62
TnT/Projects/Presentation/Sources/Coordinator/OnboardingFlow/OnboardingFlowView.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
// | ||
// OnboardingNavigationView.swift | ||
// Presentation | ||
// | ||
// Created by 박민서 on 2/4/25. | ||
// Copyright © 2025 yapp25thTeamTnT. All rights reserved. | ||
// | ||
|
||
import SwiftUI | ||
import ComposableArchitecture | ||
|
||
import DesignSystem | ||
|
||
public struct OnboardingFlowView: View { | ||
@Bindable var store: StoreOf<OnboardingFlowFeature> | ||
|
||
public init(store: StoreOf<OnboardingFlowFeature>) { | ||
self.store = store | ||
} | ||
|
||
public var body: some View { | ||
NavigationStack(path: $store.scope(state: \.path, action: \.path)) { | ||
EmptyView() | ||
} destination: { store in | ||
switch store.case { | ||
// MARK: Common | ||
case .snsLogin(let store): | ||
LoginView(store: store) | ||
case .term(let store): | ||
TermView(store: store) | ||
case .userTypeSelection(let store): | ||
UserTypeSelectionView(store: store) | ||
case .createProfile(let store): | ||
CreateProfileView(store: store) | ||
|
||
// MARK: Trainer | ||
case .trainerSignUpComplete(let store): | ||
TrainerSignUpCompleteView(store: store) | ||
case .trainerMakeInvitationCode(let store): | ||
MakeInvitationCodeView(store: store) | ||
case .trainerConnectedTraineeProfile(let store): | ||
ConnectedTraineeProfileView(store: store) | ||
|
||
// MARK: Trainee | ||
case .traineeBasicInfoInput(let store): | ||
TraineeBasicInfoInputView(store: store) | ||
case .traineeTrainingPurpose(let store): | ||
TraineeTrainingPurposeView(store: store) | ||
case .traineePrecautionInput(let store): | ||
TraineePrecautionInputView(store: store) | ||
case .traineeProfileCompletion(let store): | ||
TraineeProfileCompletionView(store: store) | ||
case .traineeInvitationCodeInput(let store): | ||
TraineeInvitationCodeInputView(store: store) | ||
case .traineeTrainingInfoInput(let store): | ||
TraineeTrainingInfoInputView(store: store) | ||
case .traineeConnectionComplete(let store): | ||
TraineeConnectionCompleteView(store: store) | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.