Skip to content

Commit

Permalink
Merge pull request #898 from wakmusic/848-feature-change-nickname
Browse files Browse the repository at this point in the history
🔀 :: (#848) 닉네임 변경 및 열매 뽑기 반응 구현
  • Loading branch information
KangTaeHoon authored Aug 1, 2024
2 parents 0d6c31a + facac71 commit db0c4c1
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import NeedleFoundation
import NoticeDomainInterface
import SignInFeatureInterface
import TeamFeatureInterface
import UserDomainInterface
import UIKit

public protocol MyInfoDependency: Dependency {
Expand All @@ -20,13 +21,17 @@ public protocol MyInfoDependency: Dependency {
var fruitDrawFactory: any FruitDrawFactory { get }
var fruitStorageFactory: any FruitStorageFactory { get }
var fetchNoticeIDListUseCase: any FetchNoticeIDListUseCase { get }
var setUserNameUseCase: any SetUserNameUseCase { get }
var fetchUserInfoUseCase: any FetchUserInfoUseCase { get }
}

public final class MyInfoComponent: Component<MyInfoDependency>, MyInfoFactory {
public func makeView() -> UIViewController {
return MyInfoViewController.viewController(
reactor: MyInfoReactor(
fetchNoticeIDListUseCase: dependency.fetchNoticeIDListUseCase
fetchNoticeIDListUseCase: dependency.fetchNoticeIDListUseCase,
setUserNameUseCase: dependency.setUserNameUseCase,
fetchUserInfoUseCase: dependency.fetchUserInfoUseCase
),
profilePopUpComponent: dependency.profilePopComponent,
textPopUpFactory: dependency.textPopUpFactory,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ final class MyInfoReactor: Reactor {
case mailNavigationDidTap
case teamNavigationDidTap
case settingNavigationDidTap
case completedFruitDraw
case changeNicknameButtonDidTap(String)
case changedUserInfo(UserInfo?)
case changedReadNoticeIDs([Int])
case requiredLogin
Expand All @@ -30,7 +32,10 @@ final class MyInfoReactor: Reactor {
case updateProfileImage(String)
case updateNickname(String)
case updatePlatform(String)
case updateFruitCount(Int)
case updateIsAllNoticesRead(Bool)
case showToast(String)
case dismissEditSheet
}

enum NavigateType {
Expand All @@ -49,25 +54,35 @@ final class MyInfoReactor: Reactor {
var profileImage: String
var nickname: String
var platform: String
var fruitCount: Int
var isAllNoticesRead: Bool
@Pulse var loginButtonDidTap: Bool?
@Pulse var profileImageDidTap: Bool?
@Pulse var navigateType: NavigateType?
@Pulse var showToast: String?
@Pulse var dismissEditSheet: Bool?
}

var initialState: State
private let fetchNoticeIDListUseCase: any FetchNoticeIDListUseCase
private let setUsernameUseCase: any SetUserNameUseCase
private let fetchUserInfoUseCase: any FetchUserInfoUseCase
private var disposeBag = DisposeBag()

init(
fetchNoticeIDListUseCase: any FetchNoticeIDListUseCase
fetchNoticeIDListUseCase: any FetchNoticeIDListUseCase,
setUserNameUseCase: any SetUserNameUseCase,
fetchUserInfoUseCase: any FetchUserInfoUseCase
) {
self.fetchNoticeIDListUseCase = fetchNoticeIDListUseCase
self.setUsernameUseCase = setUserNameUseCase
self.fetchUserInfoUseCase = fetchUserInfoUseCase
self.initialState = .init(
isLoggedIn: false,
profileImage: "",
nickname: "",
platform: "",
platform: "",
fruitCount: 0,
isAllNoticesRead: false
)
observeUserInfoChanges()
Expand Down Expand Up @@ -99,12 +114,17 @@ final class MyInfoReactor: Reactor {
updateIsLoggedIn(userInfo),
updateProfileImage(userInfo),
updateNickname(userInfo),
updatePlatform(userInfo)
updatePlatform(userInfo),
updateFruitCount(userInfo)
)
case let .changedReadNoticeIDs(readIDs):
return updateIsAllNoticesRead(readIDs)
case .requiredLogin:
return navigateLogin()
case .completedFruitDraw:
return fetchUserInfo()
case let .changeNicknameButtonDidTap(newNickname):
return updateRemoteNickname(newNickname)
}
}

Expand Down Expand Up @@ -134,6 +154,13 @@ final class MyInfoReactor: Reactor {

case let .updateIsAllNoticesRead(isAllNoticesRead):
newState.isAllNoticesRead = isAllNoticesRead

case let .updateFruitCount(count):
newState.fruitCount = count
case let .showToast(message):
newState.showToast = message
case .dismissEditSheet:
newState.dismissEditSheet = true
}
return newState
}
Expand All @@ -156,6 +183,26 @@ private extension MyInfoReactor {
}
.disposed(by: disposeBag)
}

func fetchUserInfo() -> Observable<Mutation> {
return fetchUserInfoUseCase.execute()
.asObservable()
.flatMap { entity -> Observable<Mutation> in
PreferenceManager.shared.setUserInfo(
ID: entity.id,
platform: entity.platform,
profile: entity.profile,
name: entity.name,
itemCount: entity.itemCount
)
return .empty()
}
.catch { error in
let error = error.asWMError
return Observable.just(.showToast(error.errorDescription ?? "알 수 없는 오류가 발생하였습니다."))
}

}

func updateIsAllNoticesRead(_ readIDs: [Int]) -> Observable<Mutation> {
return fetchNoticeIDListUseCase.execute()
Expand All @@ -177,7 +224,36 @@ private extension MyInfoReactor {
guard let profile = userInfo?.profile else { return .empty() }
return .just(.updateProfileImage(profile))
}


func updateRemoteNickname(_ newNickname: String) -> Observable<Mutation> {
setUsernameUseCase.execute(name: newNickname)
.andThen(
fetchUserInfoUseCase.execute()
.asObservable()
.flatMap { entity -> Observable<Mutation> in
PreferenceManager.shared.setUserInfo(
ID: entity.id,
platform: entity.platform,
profile: entity.profile,
name: entity.name,
itemCount: entity.itemCount
)
return .concat(
.just(.showToast("닉네임이 변경되었습니다.")),
.just(.dismissEditSheet)
)

}
)
.catch { error in
let error = error.asWMError
return .concat(
.just(.showToast(error.errorDescription ?? "알 수 없는 오류가 발생하였습니다.")),
.just(.dismissEditSheet)
)
}
}

func updateNickname(_ userInfo: UserInfo?) -> Observable<Mutation> {
guard let userInfo = userInfo else { return .empty() }
return .just(.updateNickname(userInfo.decryptedName))
Expand All @@ -187,6 +263,11 @@ private extension MyInfoReactor {
guard let platform = userInfo?.platform else { return .empty() }
return .just(.updatePlatform(platform))
}

func updateFruitCount(_ userInfo: UserInfo?) -> Observable<Mutation> {
guard let count = userInfo?.itemCount else { return .empty() }
return .just(.updateFruitCount(count))
}

func loginButtonDidTap() -> Observable<Mutation> {
return .just(.loginButtonDidTap)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ final class MyInfoViewController: BaseReactorViewController<MyInfoReactor>, Edit
}

override func bindState(reactor: MyInfoReactor) {
reactor.pulse(\.$showToast)
.compactMap { $0 }
.bind(with: self, onNext: { owner, message in
owner.showToast(text: message, font: DesignSystemFontFamily.Pretendard.light.font(size: 14))
})
.disposed(by: disposeBag)

reactor.state.map(\.isAllNoticesRead)
.distinctUntilChanged()
.bind(with: self) { owner, isAllNoticesRead in
Expand Down Expand Up @@ -113,6 +120,13 @@ final class MyInfoViewController: BaseReactorViewController<MyInfoReactor>, Edit
owner.myInfoView.profileView.updatePlatform(platform: platform)
}
.disposed(by: disposeBag)

reactor.state.map(\.fruitCount)
.distinctUntilChanged()
.bind(with: self) { owner, count in
owner.myInfoView.updateFruitCount(count: count)
}
.disposed(by: disposeBag)

reactor.pulse(\.$loginButtonDidTap)
.compactMap { $0 }
Expand All @@ -131,6 +145,13 @@ final class MyInfoViewController: BaseReactorViewController<MyInfoReactor>, Edit
})
.disposed(by: disposeBag)

reactor.pulse(\.$dismissEditSheet)
.compactMap { $0 }
.bind(with: self, onNext: { owner, _ in
owner.hideEditSheet()
})
.disposed(by: disposeBag)

reactor.pulse(\.$navigateType)
.compactMap { $0 }
.bind(with: self) { owner, navigate in
Expand Down Expand Up @@ -257,7 +278,9 @@ extension MyInfoViewController: EditSheetViewDelegate {
showBottomSheet(content: vc, size: .fixed(352 + SAFEAREA_BOTTOM_HEIGHT()))
case .nickname:
guard let vc = multiPurposePopUpFactory
.makeView(type: .nickname, key: "", completion: nil) as? MultiPurposePopupViewController
.makeView(type: .nickname, key: "", completion: { [weak self] text in
self?.reactor?.action.onNext(.changeNicknameButtonDidTap(text))
}) as? MultiPurposePopupViewController
else { return }
showBottomSheet(content: vc, size: .fixed(296))
}
Expand All @@ -275,7 +298,6 @@ extension MyInfoViewController: EqualHandleTappedType {

extension MyInfoViewController: FruitDrawViewControllerDelegate {
func completedFruitDraw(itemCount: Int) {
#warning("획득한 열매 갯수입니다. 다음 처리 진행해주세요.")
LogManager.printDebug("itemCount: \(itemCount)")
reactor?.action.onNext(.completedFruitDraw)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@ import SnapKit
import Then
import UIKit

private protocol DrawActionProtocol {
private protocol FruitDrawStateProtocol {
func updateFruitCount(count: Int)
}

private protocol FruitDrawActionProtocol {
var drawButtonDidTap: Observable<Void> { get }
}

final class DrawButtonView: UIView {
final class FruitDrawButtonView: UIView {
let backgroundView = UIView().then {
$0.backgroundColor = .white
$0.layer.borderWidth = 1
Expand Down Expand Up @@ -56,7 +60,7 @@ final class DrawButtonView: UIView {
}
}

extension DrawButtonView {
extension FruitDrawButtonView {
func addView() {
self.addSubviews(
backgroundView,
Expand Down Expand Up @@ -89,6 +93,14 @@ extension DrawButtonView {
}
}

extension Reactive: DrawActionProtocol where Base: DrawButtonView {
extension FruitDrawButtonView: FruitDrawStateProtocol {
func updateFruitCount(count: Int) {
countLabel.text = String(count)
}


}

extension Reactive: FruitDrawActionProtocol where Base: FruitDrawButtonView {
var drawButtonDidTap: Observable<Void> { base.drawButton.rx.tap.asObservable() }
}
15 changes: 10 additions & 5 deletions Projects/Features/MyInfoFeature/Sources/Views/MyInfoView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Utility

private protocol MyInfoStateProtocol {
func updateIsHiddenLoginWarningView(isLoggedIn: Bool)
func updateFruitCount(count: Int)
}

private protocol MyInfoActionProtocol {
Expand All @@ -35,7 +36,7 @@ final class MyInfoView: UIView {
$0.isHidden = true
}

let drawButtonView = DrawButtonView()
let fruitDrawButtonView = FruitDrawButtonView()

let vStackView = UIStackView().then {
$0.axis = .vertical
Expand Down Expand Up @@ -103,7 +104,7 @@ private extension MyInfoView {
contentView.addSubviews(
loginWarningView,
profileView,
drawButtonView,
fruitDrawButtonView,
vStackView,
newNotiIndicator
)
Expand Down Expand Up @@ -147,7 +148,7 @@ private extension MyInfoView {
$0.height.equalTo(162)
}

drawButtonView.snp.makeConstraints {
fruitDrawButtonView.snp.makeConstraints {
$0.horizontalEdges.equalToSuperview().inset(20)
$0.height.equalTo(52)
$0.top.equalTo(loginWarningView.snp.bottom).offset(52)
Expand All @@ -156,7 +157,7 @@ private extension MyInfoView {
vStackView.snp.makeConstraints {
$0.height.equalTo(200)
$0.horizontalEdges.equalToSuperview().inset(20)
$0.top.equalTo(drawButtonView.snp.bottom).offset(16)
$0.top.equalTo(fruitDrawButtonView.snp.bottom).offset(16)
$0.bottom.equalToSuperview()
}

Expand Down Expand Up @@ -186,6 +187,10 @@ extension MyInfoView: MyInfoStateProtocol {
loginWarningView.isHidden = false
}
}

func updateFruitCount(count: Int) {
fruitDrawButtonView.updateFruitCount(count: count)
}
}

extension Reactive: MyInfoActionProtocol where Base: MyInfoView {
Expand All @@ -198,7 +203,7 @@ extension Reactive: MyInfoActionProtocol where Base: MyInfoView {

var loginButtonDidTap: Observable<Void> { base.loginWarningView.rx.loginButtonDidTap }
var profileImageDidTap: Observable<Void> { base.profileView.rx.profileImageDidTap }
var drawButtonDidTap: Observable<Void> { base.drawButtonView.rx.drawButtonDidTap }
var drawButtonDidTap: Observable<Void> { base.fruitDrawButtonView.rx.drawButtonDidTap }
var fruitNavigationButtonDidTap: Observable<Void> { base.fruitNavigationButton.rx.tap.asObservable() }
var qnaNavigationButtonDidTap: Observable<Void> { base.qnaNavigationButton.rx.tap.asObservable() }
var notiNavigationButtonDidTap: Observable<Void> { base.notiNavigationButton.rx.tap.asObservable() }
Expand Down

0 comments on commit db0c4c1

Please sign in to comment.