Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TNT-206] TraineeMyPage, TraineeInvitationCodeInput 화면 팝업 작성 #50

Merged
merged 3 commits into from
Feb 4, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +28,45 @@ public struct TraineeMyPageFeature {
var appPushNotificationAllowed: Bool
/// 버전 정보
var versionInfo: String
/// 트레이너 연결 여부
var isTrainerConnected: Bool
/// 트레이너 이름
var trainerName: String

// MARK: UI related state
/// 트레이너 연결 여부
var view_isTrainerConnected: Bool {
return !self.trainerName.isEmpty
}
/// 표시되는 팝업
var view_popUp: PopUp?
/// 팝업 표시 여부
var view_isPopUpPresented: Bool

/// `TraineeMyPageFeature.State`의 생성자
/// - Parameters:
/// - userName: 사용자 이름 (기본값: `""`)
/// - userImageUrl: 사용자 프로필 이미지 URL (기본값: `nil`)
/// - appPushNotificationAllowed: 앱 푸시 알림 허용 여부 (기본값: `false`)
/// - versionInfo: 현재 앱 버전 정보 (기본값: `""`)
/// - trainerName: 트레이너 이름, 공백이 아닌 경우 연결된 것으로 표시(기본값: `""`)
/// - view_popUp: 현재 표시되는 팝업 (기본값: `nil`)
/// - view_isPopUpPresented: 팝업이 표시 중인지 여부 (기본값: `false`)
public init(
userName: String,
userName: String = "",
userImageUrl: String? = nil,
appPushNotificationAllowed: Bool,
versionInfo: String,
isTrainerConnected: Bool
appPushNotificationAllowed: Bool = false,
versionInfo: String = "",
trainerName: String = "",
view_popUp: PopUp? = nil,
view_isPopUpPresented: Bool = false
) {
self.userName = userName
self.userImageUrl = userImageUrl
self.appPushNotificationAllowed = appPushNotificationAllowed
self.versionInfo = versionInfo
self.isTrainerConnected = isTrainerConnected
self.trainerName = trainerName
self.view_popUp = view_popUp
self.view_isPopUpPresented = view_isPopUpPresented
}

}

@Dependency(\.userUseCase) private var userUseCase: UserUseCase
Expand Down Expand Up @@ -77,6 +97,10 @@ public struct TraineeMyPageFeature {
case tapLogoutButton
/// 계정 탈퇴 버튼 탭
case tapWithdrawButton
/// 팝업 좌측 secondary 버튼 탭
case tapPopUpSecondaryButton(popUp: PopUp?)
/// 팝업 우측 primary 버튼 탭
case tapPopUpPrimaryButton(popUp: PopUp?)
Comment on lines +100 to +103
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

탈퇴/로그아웃 성공 후 확인 눌렀을 때도 primary case가 실행되는거지요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵 맞습니다! 버튼 하나인 경우 primary 두개인 경우 두번째가 secondary입니다

}
}

Expand All @@ -92,6 +116,7 @@ public struct TraineeMyPageFeature {
case .binding(\.appPushNotificationAllowed):
print("푸쉬알림 변경: \(state.appPushNotificationAllowed)")
return .none

case .binding:
return .none
case .tapEditProfileButton:
Expand All @@ -115,16 +140,27 @@ public struct TraineeMyPageFeature {
return .none

case .tapDisconnectTrainerButton:
print("tapDisconnectTrainerButton")
return .none
return setPopUpStatus(&state, status: .disconnectTrainer(trainerName: state.trainerName))

case .tapLogoutButton:
print("tapLogoutButton")
return .none
return setPopUpStatus(&state, status: .logout)

case .tapWithdrawButton:
print("tapWithdrawButton")
return .none
return setPopUpStatus(&state, status: .withdraw)

case .tapPopUpSecondaryButton(let popUp):
guard popUp != nil else { return .none }
return setPopUpStatus(&state, status: nil)

case .tapPopUpPrimaryButton(let popUp):
guard let popUp else { return .none }
switch popUp {
case .disconnectTrainer, .logout, .withdraw:
return setPopUpStatus(&state, status: popUp.nextPopUp)

case .disconnectCompleted, .logoutCompleted, .withdrawCompleted:
return setPopUpStatus(&state, status: nil)
}
}

case .setNavigating:
Expand All @@ -133,3 +169,99 @@ public struct TraineeMyPageFeature {
}
}
}

// MARK: Internal Logic
private extension TraineeMyPageFeature {
/// 팝업 상태, 표시 상태를 업데이트
/// status nil 입력인 경우 팝업 표시 해제
func setPopUpStatus(_ state: inout State, status: PopUp?) -> Effect<Action> {
state.view_popUp = status
state.view_isPopUpPresented = status != nil
return .none
}
}

public extension TraineeMyPageFeature {
/// 본 화면에 팝업으로 표시되는 목록
enum PopUp: Equatable, Sendable {
/// 트레이너와 연결을 해제할까요?
case disconnectTrainer(trainerName: String)
/// 트레이너와 연결이 해제되었어요
case disconnectCompleted(trainerName: String)
/// 현재 계정을 로그아웃 할까요?
case logout
/// 로그아웃이 완료되었어요
case logoutCompleted
/// 계정을 탈퇴할까요?
case withdraw
/// 계정 탈퇴가 완료되었어요
case withdrawCompleted

var nextPopUp: PopUp? {
switch self {
case .disconnectTrainer(let name):
return .disconnectCompleted(trainerName: name)
case .logout:
return .logoutCompleted
case .withdraw:
return .withdrawCompleted
case .disconnectCompleted, .logoutCompleted, .withdrawCompleted:
return nil
}
}

var title: String {
switch self {
case .disconnectTrainer(let name):
return "\(name) 트레이너와 연결을 해제할까요?"
case .disconnectCompleted(let name):
return "\(name) 트레이너와 연결이 해제되었어요"
case .logout:
return "현재 계정을 로그아웃 할까요?"
case .logoutCompleted:
return "로그아웃이 완료되었어요"
case .withdraw:
return "계정을 탈퇴할까요?"
case .withdrawCompleted:
return "계정 탈퇴가 완료되었어요"
}
}

var message: String {
switch self {
case .disconnectTrainer(let name):
return "힘께 나눴던 기록들이 사라져요"
case .disconnectCompleted(let name):
return "더 폭발적인 케미로 다시 만나요!"
case .logout, .logoutCompleted:
return "언제든지 다시 로그인 할 수 있어요!"
case .withdraw:
return "운동 및 식단 기록에 대한 데이터가 사라져요!"
case .withdrawCompleted:
return "다음에 더 폭발적인 케미로 다시 만나요! 💣"
}
}

var showAlertIcon: Bool {
switch self {
case .disconnectTrainer, .logout, .withdraw:
return true
case .disconnectCompleted, .logoutCompleted, .withdrawCompleted:
return false
}
}

var secondaryAction: Action.View? {
switch self {
case .disconnectTrainer, .logout, .withdraw:
return .tapPopUpSecondaryButton(popUp: self)
case .disconnectCompleted, .logoutCompleted, .withdrawCompleted:
return nil
}
}

var primaryAction: Action.View {
return .tapPopUpPrimaryButton(popUp: self)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ public struct TraineeMyPageView: View {
}
.background(Color.neutral50)
.navigationBarBackButtonHidden()
.tPopUp(isPresented: $store.view_isPopUpPresented) {
PopUpView()
}
}

// MARK: - Sections
Expand All @@ -47,9 +50,9 @@ public struct TraineeMyPageView: View {

Text(store.userName)
.typographyStyle(.heading2, with: .neutral950)
.padding(.bottom, store.isTrainerConnected ? 8 : 16)
.padding(.bottom, store.view_isTrainerConnected ? 8 : 16)

if store.isTrainerConnected {
if store.view_isTrainerConnected {
TButton(
title: "개인정보 수정",
config: .small,
Expand All @@ -64,7 +67,7 @@ public struct TraineeMyPageView: View {
@ViewBuilder
private func TopItemSection() -> some View {
VStack(spacing: 12) {
if !store.isTrainerConnected {
if !store.view_isTrainerConnected {
ProfileItemView(title: "트레이너 연결하기", tapAction: { send(.tapConnectTrainerButton) })
.padding(.vertical, 4)
.background(Color.common0)
Expand Down Expand Up @@ -100,7 +103,7 @@ public struct TraineeMyPageView: View {
@ViewBuilder
private func BottomItemSection() -> some View {
VStack(spacing: 12) {
if store.isTrainerConnected {
if store.view_isTrainerConnected {
ProfileItemView(title: "트레이너와 연결끊기", tapAction: { send(.tapDisconnectTrainerButton) })
.padding(.vertical, 4)
.background(Color.common0)
Expand All @@ -116,6 +119,30 @@ public struct TraineeMyPageView: View {
.clipShape(.rect(cornerRadius: 12))
}
}

@ViewBuilder
private func PopUpView() -> some View {
if let popUp = store.view_popUp {
// secondaryAction nil 인 경우 제외하고 버튼 배열 구성
let buttons: [TPopupAlertState.ButtonState] = [
popUp.secondaryAction.map { action in
.init(title: "취소", style: .secondary, action: .init(action: { send(action) }))
},
.init(title: "확인", style: .primary, action: .init(action: { send(popUp.primaryAction) }))
].compactMap { $0 }

TPopUpAlertView(
alertState: .init(
title: popUp.title,
message: popUp.message,
showAlertIcon: popUp.showAlertIcon,
buttons: buttons
)
)
} else {
EmptyView()
}
}
}

private extension TraineeMyPageView {
Expand Down
Loading