diff --git a/SOPT-Stamp-iOS/SOPT-iOS.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/SOPT-Stamp-iOS/SOPT-iOS.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
deleted file mode 100644
index 18d98100..00000000
--- a/SOPT-Stamp-iOS/SOPT-iOS.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
- IDEDidComputeMac32BitWarning
-
-
-
diff --git a/SOPT-iOS/Plugins/EnvPlugin/ProjectDescriptionHelpers/InfoPlists.swift b/SOPT-iOS/Plugins/EnvPlugin/ProjectDescriptionHelpers/InfoPlists.swift
index 4b94a2aa..a19e8812 100644
--- a/SOPT-iOS/Plugins/EnvPlugin/ProjectDescriptionHelpers/InfoPlists.swift
+++ b/SOPT-iOS/Plugins/EnvPlugin/ProjectDescriptionHelpers/InfoPlists.swift
@@ -34,7 +34,7 @@ public extension Project {
"App Transport Security Settings": ["Allow Arbitrary Loads": true],
"NSAppTransportSecurity": ["NSAllowsArbitraryLoads": true],
"ITSAppUsesNonExemptEncryption": false,
- "UIUserInterfaceStyle": "Light",
+ "UIUserInterfaceStyle": "Dark",
"NSPhotoLibraryUsageDescription": "미션과 관련된 사진을 업로드하기 위해 갤러리 권한이 필요합니다.",
"CFBundleURLTypes": [
[
diff --git a/SOPT-iOS/Plugins/EnvPlugin/ProjectDescriptionHelpers/SettingsDictionary+.swift b/SOPT-iOS/Plugins/EnvPlugin/ProjectDescriptionHelpers/SettingsDictionary+.swift
index e707153d..0a0a62d1 100644
--- a/SOPT-iOS/Plugins/EnvPlugin/ProjectDescriptionHelpers/SettingsDictionary+.swift
+++ b/SOPT-iOS/Plugins/EnvPlugin/ProjectDescriptionHelpers/SettingsDictionary+.swift
@@ -17,7 +17,7 @@ public extension SettingsDictionary {
static let baseSettings: Self = [
"OTHER_LDFLAGS" : [
- "-Xlinker -interposable"
+ "$(inherited)"
]
]
diff --git a/SOPT-iOS/Projects/Core/Sources/Enum/AttendanceStateType.swift b/SOPT-iOS/Projects/Core/Sources/Enum/AttendanceStateType.swift
index b1514218..d6dc6ff0 100644
--- a/SOPT-iOS/Projects/Core/Sources/Enum/AttendanceStateType.swift
+++ b/SOPT-iOS/Projects/Core/Sources/Enum/AttendanceStateType.swift
@@ -8,9 +8,18 @@
import Foundation
-public enum AttendanceStateType: String, CaseIterable {
- case all = "전체"
- case attendance = "출석"
- case tardy = "지각"
- case absent = "결석"
+public enum AttendanceStateType: String {
+ case attendance
+ case tardy
+ case absent
+ case participate
+
+ public var korean: String {
+ switch self {
+ case .attendance: return "출석"
+ case .tardy: return "지각"
+ case .absent: return "결석"
+ case .participate: return "참여"
+ }
+ }
}
diff --git a/SOPT-iOS/Projects/Core/Sources/Enum/UserType.swift b/SOPT-iOS/Projects/Core/Sources/Enum/UserType.swift
index 2c7d4b85..e23de015 100644
--- a/SOPT-iOS/Projects/Core/Sources/Enum/UserType.swift
+++ b/SOPT-iOS/Projects/Core/Sources/Enum/UserType.swift
@@ -8,10 +8,11 @@
import Foundation
-public enum UserType {
- case visitor // 비회원
- case active // 활동 회원
- case inactive // 비활동 회원
+public enum UserType: String {
+ case visitor = "UNAUTHENTICATED" // 비회원
+ case active = "ACTIVE" // 활동 회원
+ case inactive = "INACTIVE" // 비활동 회원
+ case unregisteredInactive = "UNREGISTERED" // 비활동 회원 + 플그 프로필 미등록
public func makeDescription(recentHistory: Int) -> String {
switch self {
@@ -21,6 +22,8 @@ public enum UserType {
return "\(recentHistory)\(I18N.Main.active)"
case .inactive:
return "\(recentHistory)\(I18N.Main.inactive)"
+ case .unregisteredInactive:
+ return I18N.Main.inactiveMember
}
}
}
diff --git a/SOPT-iOS/Projects/Core/Sources/Literals/ExternalURL.swift b/SOPT-iOS/Projects/Core/Sources/Literals/ExternalURL.swift
index 1a8cf1f6..65fafa6c 100644
--- a/SOPT-iOS/Projects/Core/Sources/Literals/ExternalURL.swift
+++ b/SOPT-iOS/Projects/Core/Sources/Literals/ExternalURL.swift
@@ -19,6 +19,10 @@ public struct ExternalURL {
public static let findEmail = "https://forms.gle/XkVFMUPsWWV1DXU38"
}
+ public struct SOPT {
+ public static let project = "https://sopt.org/project"
+ }
+
public struct Playground {
#if DEV || PROD
public static let main = "https://playground.sopt.org"
diff --git a/SOPT-iOS/Projects/Core/Sources/Literals/StringLiterals.swift b/SOPT-iOS/Projects/Core/Sources/Literals/StringLiterals.swift
index 6a87882c..5f2deedf 100644
--- a/SOPT-iOS/Projects/Core/Sources/Literals/StringLiterals.swift
+++ b/SOPT-iOS/Projects/Core/Sources/Literals/StringLiterals.swift
@@ -151,6 +151,8 @@ public struct I18N {
public static let encourage = "안녕하세요, \nSOPT의 열정이 되어주세요!"
public static let hello = "안녕하세요"
public static let welcome = "안녕하세요, \nSOPT에 오신 것을 환영합니다!"
+ public static let failedToGetUserInfo = "활동 정보를 가져올 수 없어요."
+ public static let needToRegisterPlayground = "플레이그라운드에서 프로필을 업데이트하면\n 서비스를 원활하게 사용할 수 있어요."
public static func userHistory(name: String, months: String) -> String {
return "\(name) 님은 \nSOPT와 \(months)개월째"
diff --git a/SOPT-iOS/Projects/Data/Sources/Repository/ShowAttendanceRepository.swift b/SOPT-iOS/Projects/Data/Sources/Repository/ShowAttendanceRepository.swift
index acb372d7..5d84d98b 100644
--- a/SOPT-iOS/Projects/Data/Sources/Repository/ShowAttendanceRepository.swift
+++ b/SOPT-iOS/Projects/Data/Sources/Repository/ShowAttendanceRepository.swift
@@ -26,49 +26,36 @@ public class ShowAttendanceRepository {
extension ShowAttendanceRepository: ShowAttendanceRepositoryInterface {
public func fetchAttendanceScheduleModel() -> AnyPublisher {
// return Future { promise in
-//// promise(.success(AttendanceScheduleModel(type: "HAS_ATTENDANCE",
-//// location: "단국대학교 혜당관",
-//// name: "3차 세미나",
-//// startDate: "2023-04-06T14:14:00", endDate: "2023-04-06T18:00:00", message: "",
-//// attendances: [TodayAttendanceModel(status: "ATTENDANCE", attendedAt: "2023-04-13T14:12:09"),
-//// TodayAttendanceModel(status: "ABSENT", attendedAt:
-//// "2023-04-13T14:10:04")])))
-//
// promise(.success(AttendanceScheduleModel(type: "HAS_ATTENDANCE",
-// location: "한국대학교 혜당관",
-// name: "2차 행사",
-// startDate: "2023-04-06T14:14:00", endDate: "2023-04-06T18:00:00",
-// message: "행사도 참여하고, 출석점수도 받고, 일석이조!",
-// attendances: [TodayAttendanceModel(status: "ATTENDANCE", attendedAt: "2023-04-13T14:12:09"),
-// TodayAttendanceModel(status: "ABSENT", attendedAt: "2023-04-13T14:10:04")])))
-//
-//// promise(.success(AttendanceScheduleModel(type: "NO_SESSION",
-//// location: "",
-//// name: "",
-//// startDate: "", endDate: "", message: "",
-//// attendances: [TodayAttendanceModel(status: "", attendedAt: ""),
-//// TodayAttendanceModel(status: "", attendedAt: "")])))
-// }
-// .eraseToAnyPublisher()
+// location: "솝트대학교 IT 창업관",
+// name: "3차 세미나",
+// startDate: "2023-04-29T14:00:00", endDate: "2023-04-29T18:00:00",
+// message: "",
+// attendances: [TodayAttendanceModel(status: "ATTENDANCE", attendedAt: "2023-04-29T14:00:00"),
+// TodayAttendanceModel(status: "ABSENT", attendedAt: "2023-04-29T14:02:00")])))
+// }.eraseToAnyPublisher()
+
return self.attendanceService.fetchAttendanceSchedule()
- .compactMap { $0.data?.toDomain() }
- .eraseToAnyPublisher()
+ .compactMap { $0.data?.toDomain() }
+ .eraseToAnyPublisher()
}
public func fetchAttendanceScoreModel() -> AnyPublisher {
// return Future { promise in
-// promise(.success(AttendanceScoreModel.init(part: "iOS",
-// generation: 31,
-// name: "윤수빈",
-// score: 2.0,
-// total: TotalScoreModel(attendance: 2, absent: 0, tardy: 1, participate: 1),
-// attendances: [AttendanceModel(attribute: "ETC", name: "솝커톤", status: "TARDY", date: "4월 22일"),
-// AttendanceModel(attribute: "SEMINAR", name: "iOS 2차 세미나", status: "ATTENDANCE", date: "4월 15일"),
-// AttendanceModel(attribute: "SEMINAR", name: "iOS 1차 세미나", status: "ATTENDANCE", date: "4월 8일"),
-// AttendanceModel(attribute: "ETC", name: "OT", status: "PARTICIPATE", date: "4월 1일")])))
+// promise(.success(AttendanceScoreModel.init(part: "디자인",
+// generation: 32,
+// name: "김솝트",
+// score: 1.0,
+// total: TotalScoreModel(attendance: 2, absent: 1, tardy: 1, participate: 1),
+// attendances: [AttendanceModel(attribute: "ETC", name: "솝커톤", status: "PARTICIPATE", date: "4월 22일"),
+// AttendanceModel(attribute: "ETC", name: "1차 행사", status: "ATTENDANCE", date: "4월 15일"),
+// AttendanceModel(attribute: "SEMINAR", name: "2차 세미나", status: "ATTENDANCE", date: "4월 08일"),
+// AttendanceModel(attribute: "SEMINAR", name: "1차 세미나", status: "ABSENT", date: "4월 01일"),
+// AttendanceModel(attribute: "ETC", name: "OT", status: "TARDY", date: "3월 25일")])))
// }.eraseToAnyPublisher()
+
return self.attendanceService.fetchAttendanceScore()
- .compactMap{ $0.data?.toDomain() }
- .eraseToAnyPublisher()
+ .compactMap{ $0.data?.toDomain() }
+ .eraseToAnyPublisher()
}
}
diff --git a/SOPT-iOS/Projects/Data/Sources/Repository/SignInRepository.swift b/SOPT-iOS/Projects/Data/Sources/Repository/SignInRepository.swift
index 519cab37..c43fad63 100644
--- a/SOPT-iOS/Projects/Data/Sources/Repository/SignInRepository.swift
+++ b/SOPT-iOS/Projects/Data/Sources/Repository/SignInRepository.swift
@@ -28,11 +28,18 @@ public class SignInRepository {
}
extension SignInRepository: SignInRepositoryInterface {
-
- public func requestSignIn(token: String) -> AnyPublisher {
+ public func requestSignIn(token: String) -> AnyPublisher {
authService.signIn(token: token)
- .catch({ _ in
- return self.userService.reissuance()
+ .catch ({ error in
+ guard
+ let error = error as? SOPTAPPError,
+ case .network(let statusCode) = error,
+ statusCode == 400
+ else {
+ return self.userService.reissuance()
+ }
+
+ return Fail(error: error).eraseToAnyPublisher()
})
.map { entity in
UserDefaultKeyList.Auth.appAccessToken = entity.accessToken
@@ -43,7 +50,6 @@ extension SignInRepository: SignInRepositoryInterface {
: false
return true
}
- .replaceError(with: false)
.withUnretained(self)
.flatMap { owner, isSuccessed in
guard isSuccessed else {
diff --git a/SOPT-iOS/Projects/Domain/Sources/Model/UserMainInfoModel.swift b/SOPT-iOS/Projects/Domain/Sources/Model/UserMainInfoModel.swift
index cdae37cb..2730bddd 100644
--- a/SOPT-iOS/Projects/Domain/Sources/Model/UserMainInfoModel.swift
+++ b/SOPT-iOS/Projects/Domain/Sources/Model/UserMainInfoModel.swift
@@ -8,6 +8,8 @@
import Foundation
+import Core
+
public struct UserMainInfoModel {
public let status, name: String
public let profileImage: String?
@@ -17,6 +19,19 @@ public struct UserMainInfoModel {
public let responseMessage: String?
public var withError: Bool = false
+ public var userType: UserType {
+ switch status {
+ case "": // 플그 미등록인 경우
+ return .unregisteredInactive
+ case UserType.active.rawValue:
+ return .active
+ case UserType.inactive.rawValue:
+ return .inactive
+ default:
+ return .visitor
+ }
+ }
+
public init(status: String, name: String, profileImage: String?, historyList: [Int], attendanceScore: Float?, announcement: String?, responseMessage: String?) {
self.status = status
self.name = name
diff --git a/SOPT-iOS/Projects/Domain/Sources/RepositoryInterface/SignInRepositoryInterface.swift b/SOPT-iOS/Projects/Domain/Sources/RepositoryInterface/SignInRepositoryInterface.swift
index e822de80..0b7b6a4f 100644
--- a/SOPT-iOS/Projects/Domain/Sources/RepositoryInterface/SignInRepositoryInterface.swift
+++ b/SOPT-iOS/Projects/Domain/Sources/RepositoryInterface/SignInRepositoryInterface.swift
@@ -11,5 +11,5 @@ import Combine
// TODO: - User 유형 설정 방식 생각하기
public protocol SignInRepositoryInterface {
- func requestSignIn(token: String) -> AnyPublisher
+ func requestSignIn(token: String) -> AnyPublisher
}
diff --git a/SOPT-iOS/Projects/Domain/Sources/UseCase/MainUseCase.swift b/SOPT-iOS/Projects/Domain/Sources/UseCase/MainUseCase.swift
index dc61cbd7..61739519 100644
--- a/SOPT-iOS/Projects/Domain/Sources/UseCase/MainUseCase.swift
+++ b/SOPT-iOS/Projects/Domain/Sources/UseCase/MainUseCase.swift
@@ -37,6 +37,7 @@ extension DefaultMainUseCase: MainUseCase {
.sink { event in
print("MainUseCase: \(event)")
} receiveValue: { [weak self] userMainInfoModel in
+ self?.setUserType(with: userMainInfoModel?.userType)
self?.userMainInfo.send(userMainInfoModel)
}.store(in: self.cancelBag)
}
@@ -49,4 +50,15 @@ extension DefaultMainUseCase: MainUseCase {
self?.serviceState.send(serviceStateModel)
}.store(in: self.cancelBag)
}
+
+ private func setUserType(with userType: UserType?) {
+ switch userType {
+ case .none, .unregisteredInactive, .inactive: // nil인 경우도 플그 미등록 유저로 취급
+ UserDefaultKeyList.Auth.isActiveUser = false
+ case .active:
+ UserDefaultKeyList.Auth.isActiveUser = true
+ default:
+ UserDefaultKeyList.Auth.isActiveUser = false
+ }
+ }
}
diff --git a/SOPT-iOS/Projects/Domain/Sources/UseCase/SignInUseCase.swift b/SOPT-iOS/Projects/Domain/Sources/UseCase/SignInUseCase.swift
index 8a288798..a6616d07 100644
--- a/SOPT-iOS/Projects/Domain/Sources/UseCase/SignInUseCase.swift
+++ b/SOPT-iOS/Projects/Domain/Sources/UseCase/SignInUseCase.swift
@@ -10,16 +10,23 @@ import Combine
import Core
+// NOTE: unregistered 없어지면 당장 삭제할거임
+public enum SiginInHandleableType {
+ case loginSuccess
+ case loginFailure
+ case unregistedProfile
+}
+
public protocol SignInUseCase {
func requestSignIn(token: String)
- var signInSuccess: CurrentValueSubject { get set }
+ var signInSuccess: CurrentValueSubject { get set }
}
public class DefaultSignInUseCase {
private let repository: SignInRepositoryInterface
private var cancelBag = CancelBag()
- public var signInSuccess = CurrentValueSubject(false)
+ public var signInSuccess = CurrentValueSubject(.loginFailure)
public init(repository: SignInRepositoryInterface) {
self.repository = repository
@@ -29,11 +36,19 @@ public class DefaultSignInUseCase {
extension DefaultSignInUseCase: SignInUseCase {
public func requestSignIn(token: String) {
repository.requestSignIn(token: token)
- .replaceError(with: false)
.sink { event in
- print("SignInUseCase: \(event)")
+ switch event {
+ case .failure(let error):
+ // NOTE: signin에서 400이 날아오는 경우는 현재 기준 한가지 경우.
+ // 4월 19일 기준으로 대응됨. 만약 다르게 날아오거나 에러스펙을 새로 정의하는 경우 다시 리팩토링 해야 함.
+ // @승호. 2023 04 19
+
+ self.signInSuccess.send(.unregistedProfile)
+ case .finished:
+ print("SignInUseCase: \(event)")
+ }
} receiveValue: { isSuccessed in
- self.signInSuccess.send(isSuccessed)
+ self.signInSuccess.send(isSuccessed ? .loginSuccess : .loginFailure)
}.store(in: self.cancelBag)
}
}
diff --git a/SOPT-iOS/Projects/Features/AppMyPageFeature/Sources/AppMypageScene/AppMyPageViewController.swift b/SOPT-iOS/Projects/Features/AppMyPageFeature/Sources/AppMypageScene/AppMyPageViewController.swift
index c8779643..d73b04e5 100644
--- a/SOPT-iOS/Projects/Features/AppMyPageFeature/Sources/AppMypageScene/AppMyPageViewController.swift
+++ b/SOPT-iOS/Projects/Features/AppMyPageFeature/Sources/AppMypageScene/AppMyPageViewController.swift
@@ -139,6 +139,17 @@ public final class AppMyPageVC: UIViewController, AppMyPageViewControllable {
frame: self.view.frame
)
+ // MARK: For UnregisteredInActive
+
+ private lazy var etcForUnregisteredInActiveSectionGroup = MypageSectionGroupView(
+ headerTitle: I18N.MyPage.etcSectionGroupTitle,
+ subviews: [
+ self.logoutListItem,
+ self.withDrawalListItem
+ ],
+ frame: self.view.frame
+ )
+
public init(
userType: UserType,
viewModel: AppMyPageViewModel,
@@ -187,6 +198,12 @@ extension AppMyPageVC {
self.servicePolicySectionGroup,
self.etcForVisitorsSectionGroup
)
+
+ case .unregisteredInactive:
+ self.contentStackView.addArrangedSubviews(
+ self.servicePolicySectionGroup,
+ self.etcForUnregisteredInActiveSectionGroup
+ )
}
}
@@ -264,7 +281,9 @@ extension AppMyPageVC {
}
self.withDrawalListItem.addTapGestureRecognizer {
- let viewController = self.factory.makeWithdrawalVC().viewController
+ let viewController = self.factory.makeWithdrawalVC(
+ userType: self.userType
+ ).viewController
self.navigationController?.pushViewController(viewController, animated: true)
}
diff --git a/SOPT-iOS/Projects/Features/AttendanceFeature/Sources/ShowAttendanceScene/VC/ShowAttendanceVC.swift b/SOPT-iOS/Projects/Features/AttendanceFeature/Sources/ShowAttendanceScene/VC/ShowAttendanceVC.swift
index ad50d2d6..e0eead42 100644
--- a/SOPT-iOS/Projects/Features/AttendanceFeature/Sources/ShowAttendanceScene/VC/ShowAttendanceVC.swift
+++ b/SOPT-iOS/Projects/Features/AttendanceFeature/Sources/ShowAttendanceScene/VC/ShowAttendanceVC.swift
@@ -33,18 +33,22 @@ public final class ShowAttendanceVC: UIViewController, ShowAttendanceViewControl
}
}
- private var viewdidload = PassthroughSubject()
-
+ private var viewWillAppear = PassthroughSubject()
+
// MARK: - UI Components
- private let containerScrollView = UIScrollView()
+ private lazy var containerScrollView: UIScrollView = {
+ let sv = UIScrollView()
+ sv.showsVerticalScrollIndicator = false
+ sv.refreshControl = refresher
+ sv.isExclusiveTouch = true
+ return sv
+ }()
+
private let contentView = UIView()
- private lazy var navibar = OPNavigationBar(self, type: .bothButtons)
+ private lazy var navibar = OPNavigationBar(self, type: .oneLeftButton)
.addMiddleLabel(title: I18N.Attendance.attendance)
- .addRightButtonAction {
- self.refreshButtonDidTap()
- }
private lazy var headerScheduleView: TodayScheduleView = {
switch sceneType {
@@ -63,6 +67,18 @@ public final class ShowAttendanceVC: UIViewController, ShowAttendanceViewControl
return button
}()
+ private let refresher: UIRefreshControl = {
+ let rf = UIRefreshControl()
+ rf.tintColor = .gray
+ return rf
+ }()
+
+ private lazy var infoButton: UIButton = {
+ let button = UIButton(type: .system)
+ button.addTarget(self, action: #selector(infoButtonDidTap), for: .touchUpInside)
+ return button
+ }()
+
// MARK: - Initialization
public init(viewModel: ShowAttendanceViewModel,
@@ -81,10 +97,14 @@ public final class ShowAttendanceVC: UIViewController, ShowAttendanceViewControl
public override func viewDidLoad() {
super.viewDidLoad()
self.bindViewModels()
- self.bindViews()
self.setUI()
self.setLayout()
- self.viewdidload.send(())
+ self.swipeRecognizer()
+ }
+
+ public override func viewWillAppear(_ animated: Bool) {
+ super.viewWillAppear(animated)
+ self.viewWillAppear.send(())
}
}
@@ -94,14 +114,15 @@ extension ShowAttendanceVC {
private func setUI() {
self.navigationController?.navigationBar.isHidden = true
- self.view.backgroundColor = .black
- containerScrollView.backgroundColor = .black
+ self.view.backgroundColor = DSKitAsset.Colors.black100.color
+ containerScrollView.backgroundColor = DSKitAsset.Colors.black100.color
}
private func setLayout() {
view.addSubviews(navibar, containerScrollView, attendanceButton)
containerScrollView.addSubview(contentView)
contentView.addSubviews(headerScheduleView, attendanceScoreView)
+ attendanceScoreView.addSubview(infoButton)
navibar.snp.makeConstraints {
$0.top.leading.trailing.equalTo(view.safeAreaLayoutGuide)
@@ -115,6 +136,7 @@ extension ShowAttendanceVC {
contentView.snp.makeConstraints {
$0.edges.equalToSuperview()
+ $0.width.equalToSuperview()
}
headerScheduleView.snp.makeConstraints {
@@ -133,6 +155,12 @@ extension ShowAttendanceVC {
$0.bottom.equalTo(view.safeAreaLayoutGuide)
$0.height.equalTo(56)
}
+
+ infoButton.snp.makeConstraints {
+ $0.top.equalToSuperview().inset(58)
+ $0.trailing.equalToSuperview().inset(32)
+ $0.width.height.equalTo(24)
+ }
}
}
@@ -140,17 +168,12 @@ extension ShowAttendanceVC {
extension ShowAttendanceVC {
- private func bindViews() {
+ private func bindViewModels() {
- navibar.rightButtonTapped
+ let viewWillAppear = viewWillAppear.asDriver()
+ let refreshStarted = refresher.publisher(for: .valueChanged)
+ .mapVoid()
.asDriver()
- .withUnretained(self)
- .sink { owner, _ in
- owner.refreshButtonDidTap()
- }.store(in: self.cancelBag)
- }
-
- private func bindViewModels() {
attendanceButton.publisher(for: .touchUpInside)
.withUnretained(self)
@@ -162,8 +185,8 @@ extension ShowAttendanceVC {
}
.store(in: self.cancelBag)
- let input = ShowAttendanceViewModel.Input(viewDidLoad: viewdidload.asDriver(),
- refreshButtonTapped: navibar.rightButtonTapped)
+ let input = ShowAttendanceViewModel.Input(viewWillAppear: viewWillAppear,
+ refreshStarted: refreshStarted)
let output = self.viewModel.transform(from: input, cancelBag: self.cancelBag)
output.$scheduleModel
@@ -180,19 +203,21 @@ extension ShowAttendanceVC {
self.headerScheduleView.updateLayout(.unscheduledDay)
self.setAttendanceButton(isEnabled: false)
}
+ self.endRefresh()
})
.store(in: self.cancelBag)
output.$scoreModel
.sink { model in
guard let model else { return }
+ self.infoButton.setImage(DSKitAsset.Assets.opInfo.image, for: .normal)
self.setScoreData(model)
+ self.endRefresh()
}.store(in: self.cancelBag)
}
- @objc
- private func refreshButtonDidTap() {
- print("refresh button did tap")
+ private func endRefresh() {
+ self.refresher.endRefreshing()
}
private func setScheduledData(_ model: AttendanceScheduleModel) {
@@ -209,7 +234,7 @@ extension ShowAttendanceVC {
private func setScoreData(_ model: AttendanceScoreModel) {
attendanceScoreView.setMyInfoData(name: model.name, part: model.part, generation: model.generation,
count: model.score)
- attendanceScoreView.setMyTotalScoreData(attendance: model.total.attendance, tardy: model.total.tardy, absent: model.total.absent)
+ attendanceScoreView.setMyTotalScoreData(attendance: model.total.attendance, tardy: model.total.tardy, absent: model.total.absent, participate: model.total.participate)
attendanceScoreView.setMyAttendanceTableData(model.attendances)
}
@@ -218,4 +243,20 @@ extension ShowAttendanceVC {
attendanceButton.isEnabled = isEnabled
attendanceButton.setTitle(title, for: .normal)
}
+
+ @objc
+ private func infoButtonDidTap() {
+ if let url = URL(string: "https://sopt.org/rules") {
+ UIApplication.shared.open(url)
+ }
+ }
+}
+
+// MARK: - UIGestureRecognizerDelegate
+
+extension ShowAttendanceVC: UIGestureRecognizerDelegate {
+
+ private func swipeRecognizer() {
+ self.navigationController?.interactivePopGestureRecognizer?.delegate = self
+ }
}
diff --git a/SOPT-iOS/Projects/Features/AttendanceFeature/Sources/ShowAttendanceScene/ViewModel/ShowAttendanceViewModel.swift b/SOPT-iOS/Projects/Features/AttendanceFeature/Sources/ShowAttendanceScene/ViewModel/ShowAttendanceViewModel.swift
index 39467caa..d0638ef6 100644
--- a/SOPT-iOS/Projects/Features/AttendanceFeature/Sources/ShowAttendanceScene/ViewModel/ShowAttendanceViewModel.swift
+++ b/SOPT-iOS/Projects/Features/AttendanceFeature/Sources/ShowAttendanceScene/ViewModel/ShowAttendanceViewModel.swift
@@ -29,8 +29,8 @@ public final class ShowAttendanceViewModel: ViewModelType {
// MARK: - Inputs
public struct Input {
- let viewDidLoad: Driver
- let refreshButtonTapped: Driver
+ let viewWillAppear: Driver
+ let refreshStarted: Driver
}
// MARK: - Outputs
@@ -54,7 +54,7 @@ extension ShowAttendanceViewModel {
self.bindOutput(output: output, cancelBag: cancelBag)
- input.viewDidLoad.merge(with: input.refreshButtonTapped)
+ input.viewWillAppear.merge(with: input.refreshStarted)
.withUnretained(self)
.sink { owner, _ in
owner.useCase.fetchAttendanceSchedule()
diff --git a/SOPT-iOS/Projects/Features/AttendanceFeature/Sources/ShowAttendanceScene/Views/AttendanceScoreComponents/MyAttendanceStateTVC.swift b/SOPT-iOS/Projects/Features/AttendanceFeature/Sources/ShowAttendanceScene/Views/AttendanceScoreComponents/MyAttendanceStateTVC.swift
index 429aadb7..39cf7474 100644
--- a/SOPT-iOS/Projects/Features/AttendanceFeature/Sources/ShowAttendanceScene/Views/AttendanceScoreComponents/MyAttendanceStateTVC.swift
+++ b/SOPT-iOS/Projects/Features/AttendanceFeature/Sources/ShowAttendanceScene/Views/AttendanceScoreComponents/MyAttendanceStateTVC.swift
@@ -82,14 +82,16 @@ extension MyAttendanceStateTVC {
extension MyAttendanceStateTVC {
func setData(model: AttendanceModel) {
-
- if model.status == "ATTENDANCE" {
+ guard let status = AttendanceStateType(rawValue: model.status.lowercased()) else { return }
+
+ switch status {
+ case .attendance:
stateImageView.image = DSKitAsset.Assets.opStateAttendance.image
- } else if model.status == "ABSENT" {
+ case .absent:
stateImageView.image = DSKitAsset.Assets.opStateAbsent.image
- } else if model.status == "TARDY" {
+ case .tardy:
stateImageView.image = DSKitAsset.Assets.opStateTardy.image
- } else {
+ case .participate:
stateImageView.image = DSKitAsset.Assets.opStateParticipate.image
}
diff --git a/SOPT-iOS/Projects/Features/AttendanceFeature/Sources/ShowAttendanceScene/Views/AttendanceScoreComponents/MyInformationWithScoreView.swift b/SOPT-iOS/Projects/Features/AttendanceFeature/Sources/ShowAttendanceScene/Views/AttendanceScoreComponents/MyInformationWithScoreView.swift
index c8abddc6..b185f381 100644
--- a/SOPT-iOS/Projects/Features/AttendanceFeature/Sources/ShowAttendanceScene/Views/AttendanceScoreComponents/MyInformationWithScoreView.swift
+++ b/SOPT-iOS/Projects/Features/AttendanceFeature/Sources/ShowAttendanceScene/Views/AttendanceScoreComponents/MyInformationWithScoreView.swift
@@ -28,13 +28,6 @@ final class MyInformationWithScoreView: UIView {
private let currentScoreLabel = UILabel()
- private lazy var infoButton: UIButton = {
- let button = UIButton(type: .system)
- button.setImage(DSKitAsset.Assets.opInfo.image, for: .normal)
- button.addTarget(self, action: #selector(infoButtonDidTap), for: .touchUpInside)
- return button
- }()
-
// MARK: - Initialization
override init(frame: CGRect) {
@@ -53,7 +46,7 @@ extension MyInformationWithScoreView {
private func setLayout() {
- addSubviews(nameLabel, currentScoreLabel, infoButton)
+ addSubviews(nameLabel, currentScoreLabel)
nameLabel.snp.makeConstraints {
$0.top.leading.equalToSuperview()
@@ -63,25 +56,13 @@ extension MyInformationWithScoreView {
$0.top.equalTo(nameLabel.snp.bottom).offset(8)
$0.leading.equalToSuperview()
}
-
- infoButton.snp.makeConstraints {
- $0.trailing.bottom.equalToSuperview()
- }
}
}
-
// MARK: - Methods
extension MyInformationWithScoreView {
- @objc
- private func infoButtonDidTap() {
- if let url = URL(string: "https://sopt.org/rules") {
- UIApplication.shared.open(url)
- }
- }
-
func setData(name: String, part: String, generation: Int, count: Double) {
nameLabel.text = "\(generation)기 \(part)파트 \(name)"
chageFontAndColor(with: "\(doubleToString(count))점")
diff --git a/SOPT-iOS/Projects/Features/AttendanceFeature/Sources/ShowAttendanceScene/Views/AttendanceScoreComponents/SingleScoreView.swift b/SOPT-iOS/Projects/Features/AttendanceFeature/Sources/ShowAttendanceScene/Views/AttendanceScoreComponents/SingleScoreView.swift
index 3610eaa7..a47f3d86 100644
--- a/SOPT-iOS/Projects/Features/AttendanceFeature/Sources/ShowAttendanceScene/Views/AttendanceScoreComponents/SingleScoreView.swift
+++ b/SOPT-iOS/Projects/Features/AttendanceFeature/Sources/ShowAttendanceScene/Views/AttendanceScoreComponents/SingleScoreView.swift
@@ -37,9 +37,7 @@ final class SingleScoreView: UIView {
init(type: AttendanceStateType, count: Int = 0) {
super.init(frame: .zero)
- updateScoreTypeLabel(type)
setLayout(type)
- setData(count)
}
required init?(coder: NSCoder) {
@@ -51,10 +49,6 @@ final class SingleScoreView: UIView {
extension SingleScoreView {
- private func updateScoreTypeLabel(_ type: AttendanceStateType) {
- singleScoreTitleLabel.text = type.rawValue
- }
-
private func setLayout(_ type: AttendanceStateType) {
addSubviews(singleScoreTitleLabel, singleScoreCountLabel)
@@ -69,13 +63,22 @@ extension SingleScoreView {
$0.centerX.equalToSuperview()
}
}
+
+ private func setDefaultLayout(_ type: AttendanceStateType) {
+ updateScoreTypeLabel(type)
+ }
+
+ private func updateScoreTypeLabel(_ type: AttendanceStateType) {
+ singleScoreTitleLabel.text = type.korean
+ }
}
// MARK: - Methods
extension SingleScoreView {
- func setData(_ count: Int) {
+ func setData(_ count: Int, _ type: AttendanceStateType) {
+ setDefaultLayout(type)
singleScoreCountLabel.text = "\(count)회"
}
}
diff --git a/SOPT-iOS/Projects/Features/AttendanceFeature/Sources/ShowAttendanceScene/Views/AttendanceScoreView.swift b/SOPT-iOS/Projects/Features/AttendanceFeature/Sources/ShowAttendanceScene/Views/AttendanceScoreView.swift
index c57ff8ef..943e197d 100644
--- a/SOPT-iOS/Projects/Features/AttendanceFeature/Sources/ShowAttendanceScene/Views/AttendanceScoreView.swift
+++ b/SOPT-iOS/Projects/Features/AttendanceFeature/Sources/ShowAttendanceScene/Views/AttendanceScoreView.swift
@@ -30,13 +30,13 @@ final class AttendanceScoreView: UIView {
/// 2. 전체 출결 점수 영역
- private let allScoreView = SingleScoreView(type: .all)
private let attendanceScoreView = SingleScoreView(type: .attendance)
private let tardyScoreView = SingleScoreView(type: .tardy)
private let absentScoreView = SingleScoreView(type: .absent)
+ private let participateScoreView = SingleScoreView(type: .participate)
private lazy var myScoreContainerStackView: UIStackView = {
- let stackView = UIStackView(arrangedSubviews: [allScoreView, attendanceScoreView, tardyScoreView, absentScoreView])
+ let stackView = UIStackView(arrangedSubviews: [attendanceScoreView, tardyScoreView, absentScoreView, participateScoreView])
stackView.backgroundColor = DSKitAsset.Colors.black40.color
stackView.clipsToBounds = true
stackView.layer.cornerRadius = 8
@@ -53,7 +53,6 @@ final class AttendanceScoreView: UIView {
private let attendanceScoreDescriptiopnLabel: UILabel = {
let label = UILabel()
label.font = .Main.body2
- label.text = I18N.Attendance.myAttendance
label.textColor = DSKitAsset.Colors.gray60.color
return label
}()
@@ -135,8 +134,7 @@ extension AttendanceScoreView {
attendanceTableView.register(MyAttendanceStateTVC.self, forCellReuseIdentifier: MyAttendanceStateTVC.className)
}
- func updateTableviewHeight() {
-
+ private func updateTableviewHeight() {
attendanceTableView.snp.updateConstraints {
$0.height.equalTo(attendanceModelList.count * 40)
}
@@ -146,19 +144,20 @@ extension AttendanceScoreView {
myInfoContainerView.setData(name: name, part: part, generation: generation, count: count)
}
- func setMyTotalScoreData(attendance: Int, tardy: Int, absent: Int) {
- allScoreView.setData(attendance + tardy + absent)
- attendanceScoreView.setData(attendance)
- tardyScoreView.setData(tardy)
- absentScoreView.setData(absent)
+ func setMyTotalScoreData(attendance: Int, tardy: Int, absent: Int, participate: Int) {
+ attendanceScoreView.setData(attendance, .attendance)
+ tardyScoreView.setData(tardy, .tardy)
+ absentScoreView.setData(absent, .absent)
+ participateScoreView.setData(participate, .participate)
}
func setMyAttendanceTableData(_ model: [AttendanceModel]) {
+ attendanceScoreDescriptiopnLabel.text = I18N.Attendance.myAttendance
+
attendanceModelList = model
updateTableviewHeight()
attendanceTableView.reloadData()
}
-
}
// MARK: - UITableViewDelegate, UITableViewDataSource
diff --git a/SOPT-iOS/Projects/Features/AttendanceFeature/Sources/ShowAttendanceScene/Views/TodayScheduleView.swift b/SOPT-iOS/Projects/Features/AttendanceFeature/Sources/ShowAttendanceScene/Views/TodayScheduleView.swift
index 677423f4..899c415d 100644
--- a/SOPT-iOS/Projects/Features/AttendanceFeature/Sources/ShowAttendanceScene/Views/TodayScheduleView.swift
+++ b/SOPT-iOS/Projects/Features/AttendanceFeature/Sources/ShowAttendanceScene/Views/TodayScheduleView.swift
@@ -22,7 +22,6 @@ final class TodayScheduleView: UIView {
private let dateImageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleToFill
- imageView.image = DSKitAsset.Assets.opDate.image
return imageView
}()
@@ -36,7 +35,6 @@ final class TodayScheduleView: UIView {
private let placeImageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleToFill
- imageView.image = DSKitAsset.Assets.opPlace.image
return imageView
}()
@@ -50,7 +48,6 @@ final class TodayScheduleView: UIView {
private let titleLabel: UILabel = {
let label = UILabel()
label.textColor = .white
- label.text = I18N.Attendance.today + I18N.Attendance.unscheduledDay + I18N.Attendance.dayIs
label.font = .Main.headline2
return label
}()
@@ -148,6 +145,7 @@ extension TodayScheduleView {
if case .unscheduledDay = type {
todayInfoStackView.isHidden = true
+ titleLabel.text = I18N.Attendance.today + I18N.Attendance.unscheduledDay + I18N.Attendance.dayIs
addSubview(titleLabel)
titleLabel.snp.makeConstraints {
$0.top.bottom.equalToSuperview().inset(32)
@@ -155,11 +153,19 @@ extension TodayScheduleView {
}
}
}
+
+ private func setDefaultLayout() {
+ dateImageView.image = DSKitAsset.Assets.opDate.image
+ placeImageView.image = DSKitAsset.Assets.opPlace.image
+ }
}
+// MARK: - Methods
+
extension TodayScheduleView {
func setData(date: String, place: String, todaySchedule: String, description: String?) {
+ setDefaultLayout()
dateLabel.text = date
placeLabel.text = place
titleLabel.text = I18N.Attendance.today + todaySchedule + I18N.Attendance.dayIs
diff --git a/SOPT-iOS/Projects/Features/AuthFeature/Sources/SignInScene/VC/SignInVC.swift b/SOPT-iOS/Projects/Features/AuthFeature/Sources/SignInScene/VC/SignInVC.swift
index d2438cb4..020d1a9e 100644
--- a/SOPT-iOS/Projects/Features/AuthFeature/Sources/SignInScene/VC/SignInVC.swift
+++ b/SOPT-iOS/Projects/Features/AuthFeature/Sources/SignInScene/VC/SignInVC.swift
@@ -196,16 +196,21 @@ extension SignInVC {
output.isSignInSuccess
.removeDuplicates()
- .sink { [weak self] isSuccessed in
- guard let self = self else { return }
- if isSuccessed {
- self.setRootViewToMain()
- }
- }.store(in: self.cancelBag)
+ .sink { [weak self] type in
+ guard let self = self else { return }
+
+ switch type {
+ case .loginSuccess:
+ self.setRootViewToMain()
+ case .unregistedProfile:
+ self.setRootViewToMain(isInActiveUser: true)
+ case .loginFailure: break
+ }
+ }.store(in: self.cancelBag)
}
- private func setRootViewToMain() {
- let userType = UserDefaultKeyList.Auth.getUserType()
+ private func setRootViewToMain(isInActiveUser: Bool = false) {
+ let userType = isInActiveUser ? .unregisteredInactive : UserDefaultKeyList.Auth.getUserType()
let navigation = UINavigationController(rootViewController: factory.makeMainVC(userType: userType).viewController)
ViewControllerUtils.setRootViewController(window: self.view.window!, viewController: navigation, withAnimation: true)
}
diff --git a/SOPT-iOS/Projects/Features/AuthFeature/Sources/SignInScene/ViewModel/SignInViewModel.swift b/SOPT-iOS/Projects/Features/AuthFeature/Sources/SignInScene/ViewModel/SignInViewModel.swift
index 8521e0ad..49e89d96 100644
--- a/SOPT-iOS/Projects/Features/AuthFeature/Sources/SignInScene/ViewModel/SignInViewModel.swift
+++ b/SOPT-iOS/Projects/Features/AuthFeature/Sources/SignInScene/ViewModel/SignInViewModel.swift
@@ -25,7 +25,7 @@ public class SignInViewModel: ViewModelType {
// MARK: - Outputs
public struct Output {
- var isSignInSuccess = PassthroughSubject()
+ var isSignInSuccess = PassthroughSubject()
}
// MARK: - init
diff --git a/SOPT-iOS/Projects/Features/BaseFeatureDependency/Sources/Alert/AlertVC.swift b/SOPT-iOS/Projects/Features/BaseFeatureDependency/Sources/Alert/AlertVC.swift
index 4721e132..f966a2a4 100644
--- a/SOPT-iOS/Projects/Features/BaseFeatureDependency/Sources/Alert/AlertVC.swift
+++ b/SOPT-iOS/Projects/Features/BaseFeatureDependency/Sources/Alert/AlertVC.swift
@@ -153,7 +153,7 @@ extension AlertVC {
descriptionLabel.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.centerY.equalToSuperview().offset(-6)
- make.leading.trailing.equalToSuperview().inset(30)
+ make.leading.trailing.equalToSuperview().inset(7)
}
}
}
diff --git a/SOPT-iOS/Projects/Features/MainFeature/Sources/MainScene/Cells/UsersHistory/UserHistoryCVC.swift b/SOPT-iOS/Projects/Features/MainFeature/Sources/MainScene/Cells/UsersHistory/UserHistoryCVC.swift
index 2699d88f..c0df368e 100644
--- a/SOPT-iOS/Projects/Features/MainFeature/Sources/MainScene/Cells/UsersHistory/UserHistoryCVC.swift
+++ b/SOPT-iOS/Projects/Features/MainFeature/Sources/MainScene/Cells/UsersHistory/UserHistoryCVC.swift
@@ -95,7 +95,8 @@ extension UserHistoryCVC {
}
// 플그에 기수 정보 입력 안한 비활동 회원 대응 (추후 제거)
- if userType == .inactive {
+ if userType == .inactive || userType == .unregisteredInactive {
+ self.userTypeLabel.backgroundColor = DSKitAsset.Colors.black40.color
if allHistory == nil {
self.userTypeLabel.text = I18N.Main.inactiveMember
}
diff --git a/SOPT-iOS/Projects/Features/MainFeature/Sources/MainScene/Cells/UsersHistory/UserHistoryHeaderView.swift b/SOPT-iOS/Projects/Features/MainFeature/Sources/MainScene/Cells/UsersHistory/UserHistoryHeaderView.swift
index 3d7e61ed..a60eeb8e 100644
--- a/SOPT-iOS/Projects/Features/MainFeature/Sources/MainScene/Cells/UsersHistory/UserHistoryHeaderView.swift
+++ b/SOPT-iOS/Projects/Features/MainFeature/Sources/MainScene/Cells/UsersHistory/UserHistoryHeaderView.swift
@@ -62,7 +62,7 @@ extension UserHistoryHeaderView {
if userType == .visitor {
let text = I18N.Main.encourage
setAttributedTextToUserInfoLabel(text: text, name: nil)
- } else if userType == .inactive {
+ } else if userType == .inactive || userType == .unregisteredInactive {
let text = I18N.Main.welcome
setAttributedTextToUserInfoLabel(text: text, name: nil)
}
diff --git a/SOPT-iOS/Projects/Features/MainFeature/Sources/MainScene/VC/MainVC.swift b/SOPT-iOS/Projects/Features/MainFeature/Sources/MainScene/VC/MainVC.swift
index 311045d4..5e8e735e 100644
--- a/SOPT-iOS/Projects/Features/MainFeature/Sources/MainScene/VC/MainVC.swift
+++ b/SOPT-iOS/Projects/Features/MainFeature/Sources/MainScene/VC/MainVC.swift
@@ -103,17 +103,30 @@ extension MainVC {
output.getUserMainInfoDidComplete
.sink { [weak self] _ in
- guard let userMainInfo = self?.viewModel.userMainInfo, userMainInfo.withError == false else {
+ guard let userMainInfo = self?.viewModel.userMainInfo else {
+ self?.collectionView.reloadData()
+ return
+ }
+
+ guard userMainInfo.withError == false else {
self?.presentNetworkAlertVC()
return
}
self?.collectionView.reloadData()
}.store(in: self.cancelBag)
-
+
output.isServiceAvailable
.sink { isServiceAvailable in
print("현재 앱 서비스 사용 가능(심사 X)?: \(isServiceAvailable)")
}.store(in: self.cancelBag)
+
+ // 플그 프로필 미등록 유저 알림
+ output.needPlaygroundProfileRegistration
+ .sink { [weak self] needRegistration in
+ if needRegistration {
+ self?.presentPlaygroundRegisterationAlertVC()
+ }
+ }.store(in: self.cancelBag)
}
private func bindViews() {
@@ -174,6 +187,19 @@ extension MainVC {
self.present(networkAlertVC, animated: false)
}
+
+ private func presentPlaygroundRegisterationAlertVC() {
+ let alertVC = self.factory.makeAlertVC(
+ type: .networkErr,
+ theme: .main,
+ title: I18N.Main.failedToGetUserInfo,
+ description: I18N.Main.needToRegisterPlayground,
+ customButtonTitle: "",
+ customAction: nil)
+ .viewController
+
+ self.present(alertVC, animated: false)
+ }
}
// MARK: - UICollectionViewDelegate
@@ -190,24 +216,29 @@ extension MainVC: UICollectionViewDelegate {
self.navigationController?.pushViewController(viewController, animated: true)
return
}
-
- let safariViewController = SFSafariViewController(url: URL(string: service.serviceDomainLink)!)
- safariViewController.playgroundStyle()
- self.present(safariViewController, animated: true)
-
+
+ var needOfficialProject = service == .project && viewModel.userType == .visitor
+ let serviceDomainURL = needOfficialProject
+ ? ExternalURL.SOPT.project
+ : service.serviceDomainLink
+ showSafariVC(url: serviceDomainURL)
case (2, _):
guard let service = viewModel.otherServiceList[safe: indexPath.item] else { return }
- let safariViewController = SFSafariViewController(url: URL(string: service.serviceDomainLink)!)
- safariViewController.playgroundStyle()
- self.present(safariViewController, animated: true)
+ showSafariVC(url: service.serviceDomainLink)
case(3, _):
- guard viewModel.userType != .visitor else { return }
+ guard viewModel.userType != .visitor && viewModel.userType != .unregisteredInactive else { return }
presentSoptampFeature()
default: break
}
}
+
+ private func showSafariVC(url: String) {
+ let safariViewController = SFSafariViewController(url: URL(string: url)!)
+ safariViewController.playgroundStyle()
+ self.present(safariViewController, animated: true)
+ }
}
// MARK: - UICollectionViewDataSource
diff --git a/SOPT-iOS/Projects/Features/MainFeature/Sources/MainScene/ViewModel/MainViewModel.swift b/SOPT-iOS/Projects/Features/MainFeature/Sources/MainScene/ViewModel/MainViewModel.swift
index 53513711..f51d60a3 100644
--- a/SOPT-iOS/Projects/Features/MainFeature/Sources/MainScene/ViewModel/MainViewModel.swift
+++ b/SOPT-iOS/Projects/Features/MainFeature/Sources/MainScene/ViewModel/MainViewModel.swift
@@ -36,6 +36,7 @@ public class MainViewModel: ViewModelType {
public struct Output {
var getUserMainInfoDidComplete = PassthroughSubject()
var isServiceAvailable = PassthroughSubject()
+ var needPlaygroundProfileRegistration = PassthroughSubject()
}
// MARK: - init
@@ -69,8 +70,14 @@ extension MainViewModel {
private func bindOutput(output: Output, cancelBag: CancelBag) {
useCase.userMainInfo.asDriver()
.sink { [weak self] userMainInfo in
- self?.userMainInfo = userMainInfo
+ guard let self = self else { return }
+ self.userMainInfo = userMainInfo
+ self.userType = userMainInfo?.userType ?? .unregisteredInactive
+ self.setServiceList(with: self.userType)
output.getUserMainInfoDidComplete.send()
+ if self.userType == .unregisteredInactive {
+ output.needPlaygroundProfileRegistration.send(true)
+ }
}.store(in: self.cancelBag)
useCase.serviceState.asDriver()
@@ -88,7 +95,7 @@ extension MainViewModel {
case .active:
self.mainServiceList = [.attendance, .member, .project]
self.otherServiceList = [.officialHomepage, .crew]
- case .inactive:
+ case .inactive, .unregisteredInactive:
self.mainServiceList = [.faq, .member, .project]
self.otherServiceList = [.crew, .officialHomepage]
}
diff --git a/SOPT-iOS/Projects/Features/SettingFeature/Interface/Sources/SettingFeatureViewControllable.swift b/SOPT-iOS/Projects/Features/SettingFeature/Interface/Sources/SettingFeatureViewControllable.swift
index b01da894..432c6983 100644
--- a/SOPT-iOS/Projects/Features/SettingFeature/Interface/Sources/SettingFeatureViewControllable.swift
+++ b/SOPT-iOS/Projects/Features/SettingFeature/Interface/Sources/SettingFeatureViewControllable.swift
@@ -6,6 +6,8 @@
// Copyright © 2023 SOPT-iOS. All rights reserved.
//
+import Core
+
import BaseFeatureDependency
public protocol SettingViewControllable: ViewControllable { }
@@ -18,7 +20,9 @@ public protocol PrivacyPolicyViewControllable: ViewControllable { }
public protocol TermsOfServiceViewControllable: ViewControllable { }
-public protocol WithdrawalViewControllable: ViewControllable { }
+public protocol WithdrawalViewControllable: ViewControllable {
+ var userType: UserType { get set }
+}
public protocol SettingFeatureViewBuildable {
func makeSettingVC() -> SettingViewControllable
@@ -26,5 +30,5 @@ public protocol SettingFeatureViewBuildable {
func makeSentenceEditVC() -> SentenceEditViewControllable
func makePrivacyPolicyVC() -> PrivacyPolicyViewControllable
func makeTermsOfServiceVC() -> TermsOfServiceViewControllable
- func makeWithdrawalVC() -> WithdrawalViewControllable
+ func makeWithdrawalVC(userType: UserType) -> WithdrawalViewControllable
}
diff --git a/SOPT-iOS/Projects/Features/SettingFeature/Sources/SettingScene/VC/SettingVC.swift b/SOPT-iOS/Projects/Features/SettingFeature/Sources/SettingScene/VC/SettingVC.swift
index be7f6ad0..93e8bc22 100644
--- a/SOPT-iOS/Projects/Features/SettingFeature/Sources/SettingScene/VC/SettingVC.swift
+++ b/SOPT-iOS/Projects/Features/SettingFeature/Sources/SettingScene/VC/SettingVC.swift
@@ -156,7 +156,7 @@ extension SettingVC {
extension SettingVC: WithdrawButtonDelegate {
func withdrawButtonTapped() {
- let withdrawalVC = factory.makeWithdrawalVC().viewController
+ let withdrawalVC = factory.makeWithdrawalVC(userType: .visitor).viewController
navigationController?.pushViewController(withdrawalVC, animated: true)
}
}
diff --git a/SOPT-iOS/Projects/Features/SettingFeature/Sources/SettingScene/VC/WithdrawalVC.swift b/SOPT-iOS/Projects/Features/SettingFeature/Sources/SettingScene/VC/WithdrawalVC.swift
index b6939228..b28b74e7 100644
--- a/SOPT-iOS/Projects/Features/SettingFeature/Sources/SettingScene/VC/WithdrawalVC.swift
+++ b/SOPT-iOS/Projects/Features/SettingFeature/Sources/SettingScene/VC/WithdrawalVC.swift
@@ -9,6 +9,7 @@
import UIKit
import DSKit
import SafariServices
+import Combine
import Core
@@ -23,6 +24,7 @@ public class WithdrawalVC: UIViewController, WithdrawalViewControllable {
public var viewModel: WithdrawalViewModel!
public var factory: (AuthFeatureViewBuildable & AlertViewBuildable)!
private let cancelBag = CancelBag()
+ public var userType: UserType = .active
// MARK: - UI Components
@@ -119,6 +121,18 @@ extension WithdrawalVC {
let withdrawalButtonTapped = self.withdrawalButton
.publisher(for: .touchUpInside)
+ .withUnretained(self)
+ .filter({ owner, _ in
+ guard owner.userType != .unregisteredInactive else {
+ owner.showLoading()
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.8) {
+ owner.showToastAndChangeRootView()
+ owner.stopLoading()
+ }
+ return false
+ }
+ return true
+ })
.mapVoid()
.asDriver()
diff --git a/SOPT-iOS/Projects/Features/StampFeature/Sources/MissionListScene/Cells/MissionListCVC.swift b/SOPT-iOS/Projects/Features/StampFeature/Sources/MissionListScene/Cells/MissionListCVC.swift
index 189a9207..ea5b6a34 100644
--- a/SOPT-iOS/Projects/Features/StampFeature/Sources/MissionListScene/Cells/MissionListCVC.swift
+++ b/SOPT-iOS/Projects/Features/StampFeature/Sources/MissionListScene/Cells/MissionListCVC.swift
@@ -155,6 +155,7 @@ final class MissionListCVC: UICollectionViewCell, UICollectionViewRegisterable {
private let purposeLabel: UILabel = {
let label = UILabel()
label.text = "세미나 끝나고 뒷풀이 2시까지 달리기"
+ label.textColor = .black
label.setTypoStyle(.SoptampFont.caption1D)
label.numberOfLines = 2
return label
diff --git a/SOPT-iOS/Projects/Modules/DSKit/Sources/Components/OperationComponents/OPNavigationBar.swift b/SOPT-iOS/Projects/Modules/DSKit/Sources/Components/OperationComponents/OPNavigationBar.swift
index b9446f60..69ddb6a7 100644
--- a/SOPT-iOS/Projects/Modules/DSKit/Sources/Components/OperationComponents/OPNavigationBar.swift
+++ b/SOPT-iOS/Projects/Modules/DSKit/Sources/Components/OperationComponents/OPNavigationBar.swift
@@ -39,7 +39,7 @@ public final class OPNavigationBar: UIView {
// MARK: - initialization
- public init(_ vc: UIViewController, type: OPNaviType, backgroundColor: UIColor = .black) {
+ public init(_ vc: UIViewController, type: OPNaviType, backgroundColor: UIColor = DSKitAsset.Colors.black100.color) {
super.init(frame: .zero)
self.vc = vc
self.setUI(type, backgroundColor: backgroundColor)
diff --git a/SOPT-iOS/Projects/Modules/Network/Sources/Foundation/BaseService.swift b/SOPT-iOS/Projects/Modules/Network/Sources/Foundation/BaseService.swift
index 0af8f1e7..305f98b1 100644
--- a/SOPT-iOS/Projects/Modules/Network/Sources/Foundation/BaseService.swift
+++ b/SOPT-iOS/Projects/Modules/Network/Sources/Foundation/BaseService.swift
@@ -14,6 +14,19 @@ import Core
import Alamofire
import Moya
+
+public enum SOPTAPPError: Error {
+ case network(statusCode: Int)
+ case unknown
+
+ init(error: Error, statusCode: Int? = 0) {
+ guard let statusCode else { self = .unknown ; return }
+
+ self = .network(statusCode: statusCode)
+ }
+}
+
+
open class BaseService {
typealias API = Target
@@ -88,6 +101,35 @@ extension BaseService {
}
}.eraseToAnyPublisher()
}
+
+ func requestObjectWithNetworkErrorInCombine(_ target: API) -> AnyPublisher {
+ return Future { promise in
+ self.provider.request(target) { response in
+ switch response {
+ case .success(let value):
+ do {
+ guard let response = value.response else { throw NSError(domain: "이 경우는 생각 업씀", code: -1000) }
+
+ switch response.statusCode {
+ case 200...399:
+ let decoder = JSONDecoder()
+ let body = try decoder.decode(T.self, from: value.data)
+ promise(.success(body))
+ case 400...599:
+ // NOTE: (@승호) 여기에서 서버와 에러 처리 핸들링 해서 Error도 json Decode 해야 함
+ // 임시로 Error 처리
+ throw SOPTAPPError(error: NSError(domain: "임시에러", code: -1001), statusCode: response.statusCode)
+ default: break
+ }
+ } catch let error {
+ promise(.failure(error))
+ }
+ case .failure(let error):
+ promise(.failure(error))
+ }
+ }
+ }.eraseToAnyPublisher()
+ }
func requestObjectInCombineNoResult(_ target: API) -> AnyPublisher {
return Future { promise in
diff --git a/SOPT-iOS/Projects/Modules/Network/Sources/Service/AuthService.swift b/SOPT-iOS/Projects/Modules/Network/Sources/Service/AuthService.swift
index facca679..88f0ca66 100644
--- a/SOPT-iOS/Projects/Modules/Network/Sources/Service/AuthService.swift
+++ b/SOPT-iOS/Projects/Modules/Network/Sources/Service/AuthService.swift
@@ -20,6 +20,6 @@ public protocol AuthService {
extension DefaultAuthService: AuthService {
public func signIn(token: String) -> AnyPublisher {
- return requestObjectInCombine(.signIn(token: token))
+ return requestObjectWithNetworkErrorInCombine(.signIn(token: token))
}
}
diff --git a/SOPT-iOS/Projects/SOPT-iOS/Sources/Application/SceneDelegate.swift b/SOPT-iOS/Projects/SOPT-iOS/Sources/Application/SceneDelegate.swift
index cf314e71..8d562e5c 100644
--- a/SOPT-iOS/Projects/SOPT-iOS/Sources/Application/SceneDelegate.swift
+++ b/SOPT-iOS/Projects/SOPT-iOS/Sources/Application/SceneDelegate.swift
@@ -25,6 +25,8 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
window?.windowScene = scene
// let rootVC = container.makeShowAttendanceVC().viewController
let rootVC = container.makeSplashVC().viewController
+// let rootVC = container.makeMainVC(userType: .active).viewController
+
window?.rootViewController = UINavigationController(rootViewController: rootVC)
window?.makeKeyAndVisible()
}
diff --git a/SOPT-iOS/Projects/SOPT-iOS/Sources/ModuleFactory/DIContainer.swift b/SOPT-iOS/Projects/SOPT-iOS/Sources/ModuleFactory/DIContainer.swift
index ea047aed..c5148c95 100644
--- a/SOPT-iOS/Projects/SOPT-iOS/Sources/ModuleFactory/DIContainer.swift
+++ b/SOPT-iOS/Projects/SOPT-iOS/Sources/ModuleFactory/DIContainer.swift
@@ -236,13 +236,14 @@ extension DIContainer: Features {
return termsOfServiceVC
}
- func makeWithdrawalVC() -> WithdrawalViewControllable {
+ func makeWithdrawalVC(userType: UserType) -> WithdrawalViewControllable {
let withdrawalVC = WithdrawalVC()
let repository = SettingRepository(authService: authService, stampService: stampService, userService: userService)
let useCase = DefaultSettingUseCase(repository: repository)
let viewModel = WithdrawalViewModel(useCase: useCase)
withdrawalVC.viewModel = viewModel
withdrawalVC.factory = self
+ withdrawalVC.userType = userType
return withdrawalVC
}
diff --git a/SOPT-iOS/Tuist/Dependencies.swift b/SOPT-iOS/Tuist/Dependencies.swift
index 49042f1d..7c42f5f1 100644
--- a/SOPT-iOS/Tuist/Dependencies.swift
+++ b/SOPT-iOS/Tuist/Dependencies.swift
@@ -14,12 +14,12 @@ let spm = SwiftPackageManagerDependencies([
.remote(url: "https://github.com/SnapKit/SnapKit.git", requirement: .upToNextMinor(from: "5.0.0")),
.remote(url: "https://github.com/Moya/Moya.git", requirement: .upToNextMajor(from: "15.0.0")),
.remote(url: "https://github.com/devxoul/Then", requirement: .upToNextMajor(from: "2")),
- .remote(url: "https://github.com/onevcat/Kingfisher.git", requirement: .upToNextMajor(from: "7.0.0")),
+ .remote(url: "https://github.com/onevcat/Kingfisher.git", requirement: .upToNextMajor(from: "7.6.2")),
.remote(url: "https://github.com/FLEXTool/FLEX.git", requirement: .upToNextMajor(from: "4.3.0")),
.remote(url: "https://github.com/krzysztofzablocki/Inject.git", requirement: .upToNextMajor(from: "1.0.5")),
.remote(url: "https://github.com/Quick/Quick.git", requirement: .upToNextMajor(from: "5.0.0")),
.remote(url: "https://github.com/Quick/Nimble.git", requirement: .upToNextMajor(from: "10.0.0")),
- .remote(url: "https://github.com/airbnb/lottie-ios", requirement: .upToNextMajor(from: "3.0.0"))
+ .remote(url: "https://github.com/airbnb/lottie-ios", requirement: .upToNextMajor(from: "4.1.3"))
], baseSettings: Settings.settings(
configurations: XCConfig.framework
))