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

Feat/Scrum 131 회원가입 도메인 & 프레젠테이션 로직 구현 #36

Conversation

derrickkim0109
Copy link
Collaborator

@derrickkim0109 derrickkim0109 commented Jul 7, 2024

PR 타입

어떤 변경에 대한 PR인가요?

  • 버그 수정
  • Feature / 신기능
  • 코드 스타일 업데이트 (formatting, local variables)
  • 리팩토링 (no functional changes, no api changes)
  • 빌드 관련 변경사항
  • CI 관련된 변경사항
  • Documentation content changes
  • 구조 변경
  • Other... 추가 설명 요망:

배경

  • 온보딩 flow에서 있는 각 뷰의 인터렉션이 정상 작동하도록 만들어야 합니다.

목표

  • 약관 동의 화면에서 각 동의가 클릭 될 시 전체 동의도 클릭되고 다음 버튼 활성화
  • 성별 및 출생년 선택 시 다음 버튼 활성화
  • 프로필 텍스트 입력 시 다음 버튼 활성화
  • Login API 정상호출
  • UserSignUpRequest 수정
  • 다음 화면으로 이동 Coordinator Onboarding에서 관리할 수 있도록 구현
  • Combine Cocoa로 뷰 바인딩
  • SignUp 로직 추가
  • 자동로그인 기능 정상화

결과 (Optional)

  • 각 인터렉션에 맞게 다음 버튼이 활성화 되고 다음 화면으로 넘어갈 수 있도록 coordinator에서 각 메서드를 통해 처리됩니다.

질문

  • 토큰 만료라는 에러가 발생해서 자동로그인 API가 정상작동하지 않고 있어요. 이 부분은 추후 API가 정상화 되고 진행할까하는데 어떻게 생각하세요?

@derrickkim0109 derrickkim0109 self-assigned this Jul 7, 2024
Copy link
Collaborator Author

@derrickkim0109 derrickkim0109 left a comment

Choose a reason for hiding this comment

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

추가적으로 수정이 필요한 부분 말씀해주시면 감사하겠습니다~!

Comment on lines -22 to -23
let viewController = MainRootViewController()
navigationController.pushViewController(viewController, animated: false)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

사용하지 않는 코드라 제거했습니다.

Comment on lines +31 to +65
public init(agree: Bool, title: String, agreement: String) {
self.agree = agree
self.title = title
self.agreement = agreement
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

사용처에서 initializer를 사용해야 해서 구현했습니다.

Comment on lines 11 to 35
public var socialAccessToken: String?
public var oAuthType: OAuthType?
public var nickname: String?
public var gender: GenderEntity?
public var birthYear: String?
public var terms: [Term]

public init(
socialAccessToken: String? = nil,
oAuthType: OAuthType? = nil,
nickname: String? = nil,
gender: GenderEntity? = nil,
birthYear: String? = nil,
terms: [Term] = []
) {
self.socialAccessToken = socialAccessToken
self.oAuthType = oAuthType
self.nickname = nickname
self.gender = gender
self.birthYear = birthYear
self.terms = terms
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

논의한 대로 Onboarding 화면 별로 나눠서 데이터를 이동시켜야 해서 Optional로 수정했습니다~!

Comment on lines +19 to +31
private let navigationBar = NavigationBar()

lazy var backButton: UIButton = {
let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false

let userInterfaceStyle = traitCollection.userInterfaceStyle
let image = userInterfaceStyle == .light ? FeelinImages.backLight : FeelinImages.backDark
button.setImage(image, for: .normal)

return button
}()

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

NavigationBar 뷰에 백버튼을 주입하는 방식으로 구현했습니다.

private lazy var nicknameTextField = FeelinLineInputField(placeholder: "닉네임")


lazy var nicknameTextField = FeelinLineInputField(placeholder: "닉네임")
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

해당 Custom TextField의 TextField에 접근하기 위해 internal로 변경했습니다.

Comment on lines 48 to +59
lazy var ageAgreeButton: UIButton = {
return self.createAgreementButton("만 14세 이상 가입 동의")
return self.createAgreementButton(TermEntity.ageAgree.title)
}()

lazy var serviceUsageAgreeButton: UIButton = {
return self.createAgreementButton("서비스 이용약관 동의")
return self.createAgreementButton(TermEntity.serviceUsage.title)
}()

lazy var personalInfoAgreeButton: UIButton = {
return self.createAgreementButton("개인정보처리방침 동의")
return self.createAgreementButton(TermEntity.personalInfo.title)
}()

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

title, agreement에 대한 부분은 따로 관리가 필요하다고 생각해서 TermEntity를 구현해 각 title의 내용을 관리할 수 있도록 구현했습니다.

Comment on lines +22 to +40
lazy var backButton: UIButton = {
let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false

let userInterfaceStyle = traitCollection.userInterfaceStyle
let image = userInterfaceStyle == .light ? FeelinImages.backLight : FeelinImages.backDark
button.setImage(image, for: .normal)

return button
}()

let skipButton: UIButton = {
let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("건너뛰기", for: .normal)
button.titleLabel?.font = SharedDesignSystemFontFamily.Pretendard.regular.font(size: 16)
button.setTitleColor(Colors.gray05, for: .normal)
return button
}()
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

navigationBar에 backButton과 skipButton을 넣습니다.

flex.addItem(titleLabel)
.marginTop(72)
.marginTop(28)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

네비게이션 바의 추가 구현으로 해당 값을 수정했ㅅ브니다.

Comment on lines +38 to +49
profileCharacterCollectionView.publisher(for: [.didSelectItem, .didDeselectItem])
.sink { [weak self] indexPath in
guard let self = self else { return }

if let cell = self.profileCharacterCollectionView.cellForItem(at: indexPath) as? ProfileCharacterCell {
let isSelected = self.profileCharacterCollectionView.indexPathsForSelectedItems?.contains(indexPath) ?? false
cell.setSelected(isSelected)
selectButton.isEnabled = isSelected
selectedProfileIndex = indexPath.row
}
}
.store(in: &cancellables)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

collectionView도 combine cocoa가 될 수 있도록 변경했습니다.

Comment on lines +35 to +39
public var isValid: Bool = true {
didSet {
separator.backgroundColor = isValid ? Colors.gray02 : Colors.alertWarning
}
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

잘못 작성된 텍스트라면 다음 버튼이 활성화되지 않도록 하기 위해 해당 프로퍼티를 추가했습니다.

@derrickkim0109 derrickkim0109 force-pushed the SCRUM-131-SignUp-BusinessLogic branch from 23f5b7b to b1b16a7 Compare July 8, 2024 14:19
@derrickkim0109
Copy link
Collaborator Author

  • Auto Login에 필요한 Response 객체 추가
  • ProfileViewController Input, Output 구조 변경
  • Sign up 비지니스 로직 추가

Copy link
Collaborator

@inwoodev inwoodev left a comment

Choose a reason for hiding this comment

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

고생하셨습니다. 몇 가지 코멘트 확인 요청드려요~

Comment on lines +4 to +68
public final class NavigationBar: UIView {
private let rootFlexContainer = UIView()
private let leftBarView = UIView()
private let titleView = UIView()
private let rightBarView = UIView()

public init() {
super.init(frame: .zero)
backgroundColor = Colors.background
setupDefault()
addUIComponents()
}

@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError()
}

public override func layoutSubviews() {
super.layoutSubviews()
rootFlexContainer.pin.all()
rootFlexContainer.flex.layout()
}
}

public extension NavigationBar {
func addTitleView(_ contentView: UIView) {
titleView.flex.define { flex in
flex.addItem(contentView).grow(1).shrink(1).marginHorizontal(5)
}
titleView.flex.layout()
}

func addLeftBarView(_ contentView: UIView) {
leftBarView.flex.define { flex in
flex.addItem(contentView).width(40).height(40)
}
leftBarView.flex.layout()
}

func addRightBarView(_ contentView: UIView) {
rightBarView.flex.define { flex in
flex.addItem(contentView).width(60).height(40)
}
rightBarView.flex.layout()
}
}

private extension NavigationBar {
func setupDefault() {
rootFlexContainer.flex.direction(.row).alignItems(.center)
leftBarView.flex.width(40).height(40)
titleView.flex.grow(1).alignItems(.center).justifyContent(.center)
rightBarView.flex.width(60).height(40)
}

func addUIComponents() {
addSubview(rootFlexContainer)
rootFlexContainer.flex.define { flex in
flex.addItem(leftBarView)
flex.addItem(titleView).grow(1).shrink(1)
flex.addItem(rightBarView)
}
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

고생하셨습니다~ 요긴하게 사용하겠네요~!!

Comment on lines 64 to 119
LoginViewControllerDelegate,
UseAgreementViewControllerDelegate,
UserInformationViewControllerDelegate,
ProfileViewControllerDelegate {
public func showUseAgreementViewController(model: UserSignUpEntity) {
let viewController = UseAgreementViewController(model: model)
viewController.coordinator = self
navigationController.pushViewController(viewController, animated: true)
}

public func showServiceUsageViewController() {

}

public func showPersonalInfoUsageViewController() {

}

public func showUserInformationViewController(model: UserSignUpEntity) {
let viewController = UserInformationViewController(model: model)
viewController.coordinator = self
navigationController.pushViewController(viewController, animated: true)
}

public func showProfileViewController(model: UserSignUpEntity) {
let viewController = ProfileViewController(model: model)
viewController.coordinator = self
navigationController.pushViewController(viewController, animated: true)
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

네비게이션 같은 경우 show동사를 활용하는걸까요?
그렇다면 modal 같은 경우 어떤 동사를 활용해 볼 수 있을까요~?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

이 부분은 push~로 변경되어있습니다.

Comment on lines +29 to +105
public extension UICollectionView {
func publisher(for events: [PublisherEvent]) -> AnyPublisher<IndexPath, Never> {
return CombineCollectionViewPublisher(collectionView: self, events: events)
.eraseToAnyPublisher()
}

enum PublisherEvent {
case didSelectItem
case didDeselectItem
}
}

private struct CombineCollectionViewPublisher: Publisher {
typealias Output = IndexPath
typealias Failure = Never

private let collectionView: UICollectionView
private let events: [UICollectionView.PublisherEvent]

init(collectionView: UICollectionView, events: [UICollectionView.PublisherEvent]) {
self.collectionView = collectionView
self.events = events
}

func receive<S>(subscriber: S) where S : Subscriber, Never == S.Failure, IndexPath == S.Input {
let subscription = CombineCollectionViewSubscription(
subscriber: subscriber,
collectionView: collectionView,
events: events
)
subscriber.receive(subscription: subscription)
}
}

private final class CombineCollectionViewSubscription<S: Subscriber>: NSObject, Subscription, UICollectionViewDelegate where S.Input == IndexPath, S.Failure == Never {
private var subscriber: S?
private weak var collectionView: UICollectionView?
private let events: [UICollectionView.PublisherEvent]

init(
subscriber: S,
collectionView: UICollectionView,
events: [UICollectionView.PublisherEvent]
) {
self.subscriber = subscriber
self.collectionView = collectionView
self.events = events
super.init()
self.collectionView?.delegate = self
}

/// Subscribers.Demand는 Combine의 백프레셔(Backpressure)를 제어하기 위한 것
/// 여기서는 기본적으로 무시하고 이벤트가 발생할 때마다 전송하는 방식으로 구현
func request(_ demand: Subscribers.Demand) { }

func cancel() {
subscriber = nil
}

func collectionView(
_ collectionView: UICollectionView,
didSelectItemAt indexPath: IndexPath
) {
if events.contains(.didSelectItem) {
_ = subscriber?.receive(indexPath)
}
}

func collectionView(
_ collectionView: UICollectionView,
didDeselectItemAt indexPath: IndexPath
) {
if events.contains(.didDeselectItem) {
_ = subscriber?.receive(indexPath)
}
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

lgtm~~👍👍👍

Comment on lines +18 to +23
public override var isSelected: Bool {
didSet {
updateImage()
}
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

맞습니다~ isChecked는 불필요한 값이었어요 ㅎㅎ

Comment on lines 238 to 240
let mockData = """
{
"status": "회원가입이 완료되었습니다.",
"data": {
"accessToken": "\(expectedAccessToken)",
"refreshToken": "\(expectedRefreshToken)"
}
}
""".data(using: .utf8)!
Copy link
Collaborator

Choose a reason for hiding this comment

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

태현님, 요거 모델 수정해야할듯 해요!! 저희 status는 안받기로 합의된걸로 기억합니당~

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

수정했습니다.

Comment on lines 72 to 79
let profileImagePublisher = CurrentValueSubject<String, Never>(ProfileCharacterType.defaultCharacter)

nicknameTextFieldPublisher
.sink { [weak self] isEnabled in
guard let self = self else { return }
nextButton.isEnabled = isEnabled && nicknameTextField.isValid
profileSelectionPublisher
.sink { character in
profileImagePublisher.send(character)
}
.store(in: &cancellables)

let nextButtonPublisher = nextButton.publisher(for: .touchUpInside)
.eraseToAnyPublisher()

let combinedPublisher = nextButtonPublisher
.combineLatest(combinedSignUpModelPublisher)
.map { $1 }
.eraseToAnyPublisher()

let input = ProfileViewModel.Input(
combinedSignUpModelPublisher: combinedPublisher
nicknameTextPublisher: nicknameTextPublisher.eraseToAnyPublisher(),
profileImagePublisher: profileImagePublisher.eraseToAnyPublisher(),
nextButtonTapPublisher: nextButton.publisher(for: .touchUpInside).eraseToAnyPublisher()
)
Copy link
Collaborator

Choose a reason for hiding this comment

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

디코로 말씀드린거 같이 하나의 publisher를 input에 주입하는 방향으로 수정하셔도 좋을 듯 해요~ p3

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

수정했습니다~!

Comment on lines 59 to 69
func convertProfileImage(input: Input) -> AnyPublisher<UIImage, Never> {
input.profileImagePublisher
.map { [weak self] profileCharacter in
guard let image = ProfileCharacterType(rawValue: profileCharacter)?.image else {
self?.profileImageErrorPublisher.send(profileCharacter)
return UIImage()
}
return image
}
.eraseToAnyPublisher()
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

요거 image는 optional이어도 될듯 한데 어떻게 생각하시나요~ p3

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

좋습니다~! 수정했습니다.

Comment on lines 77 to 88
.compactMap { (nickname, profileCharacter) -> UserSignUpEntity? in
guard let nickname = nickname, !nickname.isEmpty, nickname.count < 10 else { return nil }
return UserSignUpEntity(nickname: nickname, profileCharacter: profileCharacter)
}
.eraseToAnyPublisher()
Copy link
Collaborator

Choose a reason for hiding this comment

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

compactMap을 통해 optional한 값이 방출되는게 조금 마음에 걸립니다...ㅎ

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

수정했습니다.

Comment on lines 83 to 95
return input.nextButtonTapPublisher
.combineLatest(combinedSignUpModelPublisher)
.flatMap { (tap, entity) in
return Just(SignUpResult.success).eraseToAnyPublisher()
}
.eraseToAnyPublisher()
Copy link
Collaborator

Choose a reason for hiding this comment

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

CombineLatest 중첩인데 작동 잘 되는지 확인 요청 드려요~ p2

Copy link
Collaborator Author

@derrickkim0109 derrickkim0109 Aug 15, 2024

Choose a reason for hiding this comment

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

확인 결과 잘 작동합니다. zip으로 변경 시 nickname을 최신 값으로 가져올 수 없어 combineLatest 중첩이 필요합니다.

혹시 다른 방법이 있을까요..?

Copy link
Collaborator

Choose a reason for hiding this comment

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

아닙니다~~ 확인차 코멘트 드린거에요. 잘 작동한다면 굳이 다른 방법을 찾지 않아도 될듯 합니다~

}

private let signUpUseCase: SignUpUseCase
private var userSignUpEntity: UserSignUpEntity
private var profileImageErrorPublisher = PassthroughSubject<String, Never>()
Copy link
Collaborator

Choose a reason for hiding this comment

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

profileImageErrorPublisher가 꼭 필요한가 싶기는 합니다. api콜을 통해서 이미지를 가져오지 않기도 하고 이미지 갯수가 많은 것도 아니어서요~! p4

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

제거했습니다.

derrickkim0109 and others added 24 commits August 15, 2024 12:03
- error로 없는 user일 경우 회원가입으로 가는 Flow
- MockRecentLoginRecordService 추가
- accessToken, refreshToken 이름 수정
Comment on lines 80 to +130
extension OnboardingCoordinator: CoordinatorDelegate,
LoginViewControllerDelegate {
LoginViewControllerDelegate,
UseAgreementViewControllerDelegate,
UserInformationViewControllerDelegate,
ProfileViewControllerDelegate,
WelcomeViewControllerDelegate {
public func pushUseAgreementViewController(model: UserSignUpEntity) {
let viewController = UseAgreementViewController(model: model)
viewController.coordinator = self
navigationController.pushViewController(viewController, animated: true)
}

public func pushServiceUsageViewController() {

}

public func pushPersonalInfoUsageViewController() {

}

public func pushUserInformationViewController(model: UserSignUpEntity) {
let viewController = UserInformationViewController(model: model)
viewController.coordinator = self
navigationController.pushViewController(viewController, animated: true)
}

public func pushProfileViewController(model: UserSignUpEntity) {
registerSignUpDependencies()
let viewModel = profileDependencies(model: model)
let viewController = ProfileViewController(viewModel: viewModel)
viewController.coordinator = self
navigationController.pushViewController(viewController, animated: true)
}

public func pushWelcomeViewController() {
let viewController = WelcomeViewController()
viewController.coordinator = self
navigationController.pushViewController(viewController, animated: true)
}

public func connectTabBarFlow() {
navigationController.popToRootViewController(animated: false)
let onboardingCoordinator = TabBarCoordinator(
navigationController: navigationController
)

onboardingCoordinator.delegate = self
onboardingCoordinator.start()
childCoordinators.append(onboardingCoordinator)
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

👍👍

Copy link
Collaborator

@inwoodev inwoodev left a comment

Choose a reason for hiding this comment

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

확인했습니다~ input & output로직도 공들이신만큼 개선되어보입니다. 머지하셔도 좋습니다~ 얼른 다음 feature로 넘어가시죠

@derrickkim0109 derrickkim0109 merged commit f3960ca into project-lyrics:develop Aug 15, 2024
@derrickkim0109 derrickkim0109 deleted the SCRUM-131-SignUp-BusinessLogic branch August 16, 2024 02:34
derrickkim0109 added a commit to derrickkim0109/app-iOS that referenced this pull request Aug 16, 2024
* docs: issue templates 업데이트

* docs: issue templates 업데이트

* docs: issue templates 업데이트

* docs: issue templates 업데이트

* remove: Feature Onboarding View 파일 폴더링

* feat<SharedDesignSystem>: NavigationBar View 구현

* feat<SharedUtil>: CocoaCombine 추가 구현

- UICollectionView didSelect, didDeselectItemAt
- UITextField

* chore: 불필요한 개행 및 코드 제거

* refactor: FeelinAPI 부분 수정

* feat: Sign Up을 위한 Entity Model 구현

* refactor: Login ViewController 로그인 Error 타입 변경

* refactor: UserSignUpRequest init 추가 구현

* feat: UseAgreementVC binding 구현 및 Navigation Bar 추가

* feat: UserInformationVC binding 구현 및 Navigation Bar 추가

* refactor: ProfileVC binding 구현 및 navigation Bar 추가

* feat: Onboarding Coordinator 추가 구현

* refactor: UserSignUpRequest 프로퍼티 네이밍 변경

* refactor: 불필요한 추가 설정 제거

* refactor: 화면 전환 메서드 show -> push로 네이밍 변경

* feat: FeelinAPI signUp case 추가

* test: NetworkProvider SignUp 테스트 코드 구현

* refactor: 닉네임 텍스트 정규식 수정

* feat: Welcome View 구현

- coordinator 연동 (WelcomeViewController push 및 TabBarCoordinator로 이동)

* refactor: Login Logic 수정

- error로 없는 user일 경우 회원가입으로 가는 Flow
- MockRecentLoginRecordService 추가
- accessToken, refreshToken 이름 수정

* feat: UserSignUp UseCase 추가

- SignUpService
- SignUpError
- FeelinError
- Request, Entity 객체 수정

* feat: ProfileViewModel 추가

* refactor: ProfileViewController에 ViewModel 주입

* refactor: 년생 데이터 "년" 문구 분리

* feat: ProfileViewController SignUp 로직 및 UI Interaction 추가

* refactor: 자동로그인 로직 수정

* docs: issue templates 업데이트

* docs: issue templates 업데이트

* docs: issue templates 업데이트

* docs: issue templates 업데이트

* chore: 불필요한 개행 및 코드 제거

* refactor: UserSignUpRequest init 추가 구현

* refactor: UserSignUpRequest 프로퍼티 네이밍 변경

* feat: FeelinAPI signUp case 추가

* test: NetworkProvider SignUp 테스트 코드 구현

* refactor: Login Logic 수정

- error로 없는 user일 경우 회원가입으로 가는 Flow
- MockRecentLoginRecordService 추가
- accessToken, refreshToken 이름 수정

* feat: UserSignUp UseCase 추가

- SignUpService
- SignUpError
- FeelinError
- Request, Entity 객체 수정

* refactor: ProfileViewController에 ViewModel 주입

* chore: 불필요한 부분 제거

* refactor: Network feelinAPIError로 수정되어 userNotFound시 case로 변경

* refactor: SignUp API 실패시 Alert 추가

* refactor: Request 객체 프로퍼티 타입 변경

* refactor: 자동로그인 리턴 타입 수정 및 accessToken으로 변경

* refactor: 로그인 실패시 알림 문구 변경

* refactor: ProfileViewController Input, output 구조 변경

* refactor: Feelin Default Response 추가

* refactor: Error Code 추가

* docs: issue templates 업데이트

* docs: issue templates 업데이트

* docs: issue templates 업데이트

* docs: issue templates 업데이트

* feat: FeelinAPI signUp case 추가

* test: NetworkProvider SignUp 테스트 코드 구현

* refactor: Login Logic 수정

- error로 없는 user일 경우 회원가입으로 가는 Flow
- MockRecentLoginRecordService 추가
- accessToken, refreshToken 이름 수정

* feat: ProfileViewModel 추가

* refactor: ProfileViewController에 ViewModel 주입

* feat: ProfileViewController SignUp 로직 및 UI Interaction 추가

* docs: issue templates 업데이트

* docs: issue templates 업데이트

* docs: issue templates 업데이트

* docs: issue templates 업데이트

* test: NetworkProvider SignUp 테스트 코드 구현

* refactor: Login Logic 수정

- error로 없는 user일 경우 회원가입으로 가는 Flow
- MockRecentLoginRecordService 추가
- accessToken, refreshToken 이름 수정

* feat: ProfileViewModel 추가

* refactor: ProfileViewController에 ViewModel 주입

* feat: ProfileViewController SignUp 로직 및 UI Interaction 추가

* refactor: Network feelinAPIError로 수정되어 userNotFound시 case로 변경

* refactor: 로그인 실패시 알림 문구 변경

* refactor: ProfileViewController Input, output 구조 변경

* refactor: Error Code 추가

* chore: 불필요한 부분 제거

* refactor: 불필요한 Publisher 제거 및 수정

* refactor: FeelinDefalutResponse 프로퍼티 네임 변경

* refactor: Profile Image Optional하게 받을 수 있도록 변경 및 불필요한 코드 제거

* refactor: NetworkProviderTests Mock Data 변경

* refactor: 회원가입 데이터 로직 수정

* chore: 파라미터 빈값 처리

* chore: 불필요한 코드 제거

* refactor: Profile ViewModel Sign up 코드 수정
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants