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

πŸ”€ :: (#848) λ‹‰λ„€μž„ λ³€κ²½ 및 열맀 뽑기 λ°˜μ‘ κ΅¬ν˜„ #898

Merged
merged 5 commits into from
Aug 1, 2024
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
Loading