diff --git a/NotToDo/NotToDo.xcodeproj/project.pbxproj b/NotToDo/NotToDo.xcodeproj/project.pbxproj index 0934dbf..162380c 100644 --- a/NotToDo/NotToDo.xcodeproj/project.pbxproj +++ b/NotToDo/NotToDo.xcodeproj/project.pbxproj @@ -11,6 +11,7 @@ 090FA2F52960B70400918AED /* SnapKit in Frameworks */ = {isa = PBXBuildFile; productRef = 090FA2F42960B70400918AED /* SnapKit */; }; 090FA2F82960B74000918AED /* Then in Frameworks */ = {isa = PBXBuildFile; productRef = 090FA2F72960B74000918AED /* Then */; }; 090FA2FB2960B87500918AED /* Moya in Frameworks */ = {isa = PBXBuildFile; productRef = 090FA2FA2960B87500918AED /* Moya */; }; + 0951EE8D297130DF004A3B5B /* AchieveCalendarResponseDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0951EE8C297130DF004A3B5B /* AchieveCalendarResponseDTO.swift */; }; 09611EE7296FD52700561CAA /* RecommendService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09611EE6296FD52700561CAA /* RecommendService.swift */; }; 09611EEA296FDC6300561CAA /* RecommendDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09611EE9296FDC6300561CAA /* RecommendDTO.swift */; }; 09611EED296FDD4200561CAA /* RecommendAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09611EEC296FDD4200561CAA /* RecommendAPI.swift */; }; @@ -33,11 +34,12 @@ 099F0728296B94790036CF55 /* StatisticsEmptyTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 099F0727296B94790036CF55 /* StatisticsEmptyTableViewCell.swift */; }; 099F072A296B98B90036CF55 /* SituationTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 099F0729296B98B90036CF55 /* SituationTitleView.swift */; }; 099F073D296C2F770036CF55 /* CustomSegmentedControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 099F073C296C2F770036CF55 /* CustomSegmentedControl.swift */; }; - 09D3C535296FFD3500F1488D /* SituationStasticsResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D3C534296FFD3500F1488D /* SituationStasticsResponse.swift */; }; + 09AF3FD229719DD900518D52 /* String+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09AF3FD129719DD900518D52 /* String+.swift */; }; + 09AF3FD429719E2200518D52 /* Date+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09AF3FD329719E2200518D52 /* Date+.swift */; }; + 09D3C535296FFD3500F1488D /* SituationStasticsResponseDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D3C534296FFD3500F1488D /* SituationStasticsResponseDTO.swift */; }; 09D3C538296FFD7C00F1488D /* AchieveAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D3C537296FFD7C00F1488D /* AchieveAPI.swift */; }; 09D3C53D29700DC800F1488D /* AchieveService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D3C53C29700DC800F1488D /* AchieveService.swift */; }; - 09D3C53F29700F7B00F1488D /* MissionStatisticsAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D3C53E29700F7B00F1488D /* MissionStatisticsAPI.swift */; }; - 09D3C5412970101400F1488D /* MissionStatisticsReponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D3C5402970101400F1488D /* MissionStatisticsReponse.swift */; }; + 09D3C5412970101400F1488D /* MissionStatisticsReponseDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D3C5402970101400F1488D /* MissionStatisticsReponseDTO.swift */; }; 09F695D9296C332D00877EA7 /* CompositionalLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09F695D8296C332D00877EA7 /* CompositionalLayout.swift */; }; 09F695DB296C52B600877EA7 /* MissionTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09F695DA296C52B600877EA7 /* MissionTableViewCell.swift */; }; 09F695DD296C52F000877EA7 /* SituationTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09F695DC296C52F000877EA7 /* SituationTableViewCell.swift */; }; @@ -149,6 +151,7 @@ /* Begin PBXFileReference section */ 090FA2E6295F51BB00918AED /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; + 0951EE8C297130DF004A3B5B /* AchieveCalendarResponseDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AchieveCalendarResponseDTO.swift; sourceTree = ""; }; 09611EE6296FD52700561CAA /* RecommendService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecommendService.swift; sourceTree = ""; }; 09611EE9296FDC6300561CAA /* RecommendDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecommendDTO.swift; sourceTree = ""; }; 09611EEC296FDD4200561CAA /* RecommendAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecommendAPI.swift; sourceTree = ""; }; @@ -170,11 +173,12 @@ 099F0727296B94790036CF55 /* StatisticsEmptyTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatisticsEmptyTableViewCell.swift; sourceTree = ""; }; 099F0729296B98B90036CF55 /* SituationTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SituationTitleView.swift; sourceTree = ""; }; 099F073C296C2F770036CF55 /* CustomSegmentedControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomSegmentedControl.swift; sourceTree = ""; }; - 09D3C534296FFD3500F1488D /* SituationStasticsResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SituationStasticsResponse.swift; sourceTree = ""; }; + 09AF3FD129719DD900518D52 /* String+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+.swift"; sourceTree = ""; }; + 09AF3FD329719E2200518D52 /* Date+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+.swift"; sourceTree = ""; }; + 09D3C534296FFD3500F1488D /* SituationStasticsResponseDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SituationStasticsResponseDTO.swift; sourceTree = ""; }; 09D3C537296FFD7C00F1488D /* AchieveAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AchieveAPI.swift; sourceTree = ""; }; 09D3C53C29700DC800F1488D /* AchieveService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AchieveService.swift; sourceTree = ""; }; - 09D3C53E29700F7B00F1488D /* MissionStatisticsAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MissionStatisticsAPI.swift; sourceTree = ""; }; - 09D3C5402970101400F1488D /* MissionStatisticsReponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MissionStatisticsReponse.swift; sourceTree = ""; }; + 09D3C5402970101400F1488D /* MissionStatisticsReponseDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MissionStatisticsReponseDTO.swift; sourceTree = ""; }; 09F695D8296C332D00877EA7 /* CompositionalLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = CompositionalLayout.swift; path = ../ViewControllers/CompositionalLayout.swift; sourceTree = ""; }; 09F695DA296C52B600877EA7 /* MissionTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MissionTableViewCell.swift; sourceTree = ""; }; 09F695DC296C52F000877EA7 /* SituationTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SituationTableViewCell.swift; sourceTree = ""; }; @@ -328,8 +332,9 @@ 09611EEE296FFC5D00561CAA /* Achieve */ = { isa = PBXGroup; children = ( - 09D3C534296FFD3500F1488D /* SituationStasticsResponse.swift */, - 09D3C5402970101400F1488D /* MissionStatisticsReponse.swift */, + 09D3C534296FFD3500F1488D /* SituationStasticsResponseDTO.swift */, + 0951EE8C297130DF004A3B5B /* AchieveCalendarResponseDTO.swift */, + 09D3C5402970101400F1488D /* MissionStatisticsReponseDTO.swift */, ); path = Achieve; sourceTree = ""; @@ -385,7 +390,6 @@ isa = PBXGroup; children = ( 09D3C537296FFD7C00F1488D /* AchieveAPI.swift */, - 09D3C53E29700F7B00F1488D /* MissionStatisticsAPI.swift */, ); path = Achieve; sourceTree = ""; @@ -464,6 +468,8 @@ 3B3405DD295B162600D44722 /* UITabBar+.swift */, 3BED5327295C018700157A3B /* adjust+.swift */, 3B5B34AB29618441002E1161 /* UIButton+.swift */, + 09AF3FD129719DD900518D52 /* String+.swift */, + 09AF3FD329719E2200518D52 /* Date+.swift */, 3B576323296403CB00E03637 /* UILabel+.swift */, 3B4187CE296D342900F0FBF4 /* UIViewController+.swift */, 3B882606296DDC0E00A51B50 /* UIDevice+.swift */, @@ -1220,6 +1226,7 @@ 3B162874295AD7860077AE7B /* AppDelegate.swift in Sources */, 3BEF92AF29686A8E0090A290 /* HomeCalendarCollectionViewCell.swift in Sources */, 096BE0172966A142009ED396 /* CustomTabBarCell.swift in Sources */, + 09AF3FD429719E2200518D52 /* Date+.swift in Sources */, 3BE07017296F44D3002CC50A /* MyInfoViewController.swift in Sources */, 3B0155872971512C00E7BBF1 /* MissionCalendarDayCell.swift in Sources */, 3BE07006296F43A2002CC50A /* UIStackView+.swift in Sources */, @@ -1227,9 +1234,9 @@ 3BE07005296F43A2002CC50A /* UIColor+.swift in Sources */, 3BE6CBC32969D700003A8A7B /* MissionModel.swift in Sources */, 096BE01F2966A1FA009ED396 /* NestedView.swift in Sources */, - 09D3C53F29700F7B00F1488D /* MissionStatisticsAPI.swift in Sources */, 09F695DB296C52B600877EA7 /* MissionTableViewCell.swift in Sources */, - 09D3C5412970101400F1488D /* MissionStatisticsReponse.swift in Sources */, + 09D3C5412970101400F1488D /* MissionStatisticsReponseDTO.swift in Sources */, + 0951EE8D297130DF004A3B5B /* AchieveCalendarResponseDTO.swift in Sources */, 3BE0700C296F43A2002CC50A /* UIView+.swift in Sources */, 3BE07013296F4456002CC50A /* NetworkResult.swift in Sources */, 09F695DD296C52F000877EA7 /* SituationTableViewCell.swift in Sources */, @@ -1237,13 +1244,14 @@ 6C8826122967D85F0005E222 /* AddSituationModel.swift in Sources */, 6C600BCC2969FCBC00421D7A /* EmptyRecentViewCell.swift in Sources */, 3BE07004296F43A2002CC50A /* UIDevice+.swift in Sources */, - 09D3C535296FFD3500F1488D /* SituationStasticsResponse.swift in Sources */, + 09D3C535296FFD3500F1488D /* SituationStasticsResponseDTO.swift in Sources */, 6CCBCF9729707A790093C0F3 /* AddMissionReqeustDTO.swift in Sources */, 6CA2EFBE296FD28400D3E66B /* AddMissionService.swift in Sources */, 3BBE56F5296C4ED100771DE4 /* ThirdOnboardingViewController.swift in Sources */, 3BBE56E7296C214600771DE4 /* FirstOnboardingView.swift in Sources */, 09F695D9296C332D00877EA7 /* CompositionalLayout.swift in Sources */, 3B4B90C62965CB8D008C5CA8 /* myInfoUserCollectionViewCell.swift in Sources */, + 09AF3FD229719DD900518D52 /* String+.swift in Sources */, 6C88260F2967D8280005E222 /* AddSituationCollectionViewCell.swift in Sources */, 3B59AFB8296346650050FF49 /* Numbers.swift in Sources */, 6CDC2D212966C86D00BFF5F4 /* AddMissionTextField.swift in Sources */, diff --git a/NotToDo/NotToDo/Global/Extensions/Date+.swift b/NotToDo/NotToDo/Global/Extensions/Date+.swift new file mode 100644 index 0000000..0c14846 --- /dev/null +++ b/NotToDo/NotToDo/Global/Extensions/Date+.swift @@ -0,0 +1,17 @@ +// +// Date+.swift +// NotToDo +// +// Created by JEONGEUN KIM on 2023/01/13. +// + +import Foundation + +extension Date { + func toString() -> String { + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = "yyyy.MM.dd" + dateFormatter.timeZone = TimeZone(identifier: "UTC") + return dateFormatter.string(from: self) + } +} diff --git a/NotToDo/NotToDo/Global/Extensions/String+.swift b/NotToDo/NotToDo/Global/Extensions/String+.swift new file mode 100644 index 0000000..a462d9c --- /dev/null +++ b/NotToDo/NotToDo/Global/Extensions/String+.swift @@ -0,0 +1,23 @@ +// +// String+.swift +// NotToDo +// +// Created by JEONGEUN KIM on 2023/01/13. +// + +import Foundation + +extension String { + + func toDate() -> Date? { + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = "yyyy.MM.dd" + dateFormatter.timeZone = TimeZone(identifier: "UTC") + if let date = dateFormatter.date(from: self) { + return date + } else { + return nil + } + } +} + diff --git a/NotToDo/NotToDo/Network/API/Achieve/AchieveAPI.swift b/NotToDo/NotToDo/Network/API/Achieve/AchieveAPI.swift index 0c18295..c67bcb7 100644 --- a/NotToDo/NotToDo/Network/API/Achieve/AchieveAPI.swift +++ b/NotToDo/NotToDo/Network/API/Achieve/AchieveAPI.swift @@ -9,24 +9,26 @@ import Foundation import Moya -final class SituationStatisticsAPI { +final class AchieveAPI { - static let shared: SituationStatisticsAPI = SituationStatisticsAPI() - - private let situationStatisticsProvider = MoyaProvider(plugins: [MoyaLoggingPlugin()]) + static let shared: AchieveAPI = AchieveAPI() + private let achieveProvider = MoyaProvider(plugins: [MoyaLoggingPlugin()]) + private init() { } - public private(set) var situationStatisticsData: GeneralArrayResponse? - + public private(set) var situationStatisticsData: GeneralArrayResponse? + public private(set) var missionStatisticsData: GeneralArrayResponse? + public private(set) var achieveCalendarData: GeneralResponse? + // MARK: - GET - func getSituationStatistics(completion: @escaping (GeneralArrayResponse?) -> Void) { - situationStatisticsProvider.request(.situationStatistics) { result in + func getSituationStatistics(completion: @escaping (GeneralArrayResponse?) -> Void) { + achieveProvider.request(.situationStatistics) { result in switch result { case .success(let response): do { - self.situationStatisticsData = try response.map(GeneralArrayResponse?.self) + self.situationStatisticsData = try response.map(GeneralArrayResponse?.self) guard let situationStatisticsData = self.situationStatisticsData else { return } completion(situationStatisticsData) } catch let err { @@ -38,4 +40,42 @@ final class SituationStatisticsAPI { } } } + + // MARK: - GET + + func getMissionStatistics(completion: @escaping (GeneralArrayResponse?) -> Void) { + achieveProvider.request(.missionStatistics) { result in + switch result { + case .success(let response): + do { + self.missionStatisticsData = try response.map(GeneralArrayResponse?.self) + guard let situationStatisticsData = self.missionStatisticsData else { return } + completion(self.missionStatisticsData) + } catch let err { + print(err.localizedDescription, 500) + } + case .failure(let err): + print(err.localizedDescription) + completion(nil) + } + } + } + + // MARK: - GET + + func getAchieveCalendar(month: String, completion: @escaping (NetworkResult) -> Void) { + achieveProvider.request(.achieveCalendar(month: month)) { response in + switch response { + case let .success(response): + let statusCode = response.statusCode + let data = response.data + let networkResult = NetworkBase.judgeStatus(by: statusCode, data, + [AchieveCalendarResponseDTO].self) + completion(networkResult) + case let .failure(err): + print(err) + } + } + } + } diff --git a/NotToDo/NotToDo/Network/API/Recommend/RecommendAPI.swift b/NotToDo/NotToDo/Network/API/Recommend/RecommendAPI.swift index aebd974..92e3ef2 100644 --- a/NotToDo/NotToDo/Network/API/Recommend/RecommendAPI.swift +++ b/NotToDo/NotToDo/Network/API/Recommend/RecommendAPI.swift @@ -17,16 +17,16 @@ final class RecommendAPI { private init() { } - public private(set) var recommendData: GeneralArrayResponse? + public private(set) var recommendData: GeneralArrayResponse? // MARK: - GET - func getRecommend(index: Int, completion: @escaping (GeneralArrayResponse?) -> Void) { + func getRecommend(index: Int, completion: @escaping (GeneralArrayResponse?) -> Void) { recommendProvider.request(.recommendEnvirionment(id: index )) { result in switch result { case .success(let response): do { - self.recommendData = try response.map(GeneralArrayResponse?.self) + self.recommendData = try response.map(GeneralArrayResponse?.self) guard let recommendData = self.recommendData else { return } completion(recommendData) } catch let err { diff --git a/NotToDo/NotToDo/Network/Base/URLConstant.swift b/NotToDo/NotToDo/Network/Base/URLConstant.swift index 1b2c5ec..2a71e19 100644 --- a/NotToDo/NotToDo/Network/Base/URLConstant.swift +++ b/NotToDo/NotToDo/Network/Base/URLConstant.swift @@ -26,7 +26,7 @@ struct URLConstant { // MARK: - Achieve - static let achieveCalendar = "/mission/month/" + static let achieveCalendar = "/mission/month" static let situationStatistics = "/mission/stat/situation" static let missionStatistics = "/mission/stat/notTodo" diff --git a/NotToDo/NotToDo/Network/DataModel/Achieve/AchieveCalendarResponseDTO.swift b/NotToDo/NotToDo/Network/DataModel/Achieve/AchieveCalendarResponseDTO.swift new file mode 100644 index 0000000..9a12629 --- /dev/null +++ b/NotToDo/NotToDo/Network/DataModel/Achieve/AchieveCalendarResponseDTO.swift @@ -0,0 +1,29 @@ +// +// AchieveCalendarResponse.swift +// NotToDo +// +// Created by JEONGEUN KIM on 2023/01/13. +// + +import Foundation + +struct AchieveCalendarResponseDTO: Codable { + let actionDate: String + let count: Int + + func toDate(dateString: String) -> Date? { + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = "yyyy.MM.dd" + dateFormatter.timeZone = TimeZone(identifier: "UTC") + if let date = dateFormatter.date(from: dateString) { + return date + } else { + return nil + } + } + + func convert() -> [Date: Int] { + guard let date = self.toDate(dateString: actionDate) else { return [:]} + return [date: count] + } +} diff --git a/NotToDo/NotToDo/Network/DataModel/Achieve/MissionStatisticsReponse.swift b/NotToDo/NotToDo/Network/DataModel/Achieve/MissionStatisticsReponseDTO.swift similarity index 67% rename from NotToDo/NotToDo/Network/DataModel/Achieve/MissionStatisticsReponse.swift rename to NotToDo/NotToDo/Network/DataModel/Achieve/MissionStatisticsReponseDTO.swift index 52c4f9c..6031fcb 100644 --- a/NotToDo/NotToDo/Network/DataModel/Achieve/MissionStatisticsReponse.swift +++ b/NotToDo/NotToDo/Network/DataModel/Achieve/MissionStatisticsReponseDTO.swift @@ -7,8 +7,7 @@ import Foundation -// MARK: - MissionStatistcsResponse -struct MissionStatistcsResponse: Codable { +struct MissionStatistcsResponseDTO: Codable { let count: Int let title: String } diff --git a/NotToDo/NotToDo/Network/DataModel/Achieve/SituationStasticsResponse.swift b/NotToDo/NotToDo/Network/DataModel/Achieve/SituationStasticsResponseDTO.swift similarity index 72% rename from NotToDo/NotToDo/Network/DataModel/Achieve/SituationStasticsResponse.swift rename to NotToDo/NotToDo/Network/DataModel/Achieve/SituationStasticsResponseDTO.swift index e190b14..34aaeaf 100644 --- a/NotToDo/NotToDo/Network/DataModel/Achieve/SituationStasticsResponse.swift +++ b/NotToDo/NotToDo/Network/DataModel/Achieve/SituationStasticsResponseDTO.swift @@ -7,14 +7,12 @@ import Foundation -// MARK: - SituationStatistcsResponseElement -struct SituationStatistcsResponse: Codable { +struct SituationStatistcsResponseDTO: Codable { let id, count: Int let name: String let missions: [SituationMissions] } -// MARK: - Mission struct SituationMissions: Codable { let count: Int let title: String diff --git a/NotToDo/NotToDo/Network/DataModel/Recommend/RecommendDTO.swift b/NotToDo/NotToDo/Network/DataModel/Recommend/RecommendDTO.swift index e4e3c57..1f42164 100644 --- a/NotToDo/NotToDo/Network/DataModel/Recommend/RecommendDTO.swift +++ b/NotToDo/NotToDo/Network/DataModel/Recommend/RecommendDTO.swift @@ -6,15 +6,11 @@ // import Foundation -// MARK: - RecommendElement -struct RecommendElementResponse: Codable, Hashable { +struct RecommendElementResponseDTO: Codable, Hashable { let title: String let recommendActions: [RecommendAction] } -// MARK: - RecommendAction struct RecommendAction: Codable, Hashable { let name: String } - -typealias Recommend = [RecommendElementResponse] diff --git a/NotToDo/NotToDo/Network/Service/Achieve/AchieveService.swift b/NotToDo/NotToDo/Network/Service/Achieve/AchieveService.swift index 71d9766..c04830d 100644 --- a/NotToDo/NotToDo/Network/Service/Achieve/AchieveService.swift +++ b/NotToDo/NotToDo/Network/Service/Achieve/AchieveService.swift @@ -22,15 +22,15 @@ extension AchieveService: TargetType { var path: String { switch self { - case .achieveCalendar(month: let month): - return URLConstant.achieveCalendar+"/\(month)" + case .achieveCalendar(let month): + return URLConstant.achieveCalendar + "/\(month)" case .missionStatistics: return URLConstant.missionStatistics case .situationStatistics: return URLConstant.situationStatistics } } - + var method: Moya.Method { switch self { case .achieveCalendar, .missionStatistics, .situationStatistics: diff --git a/NotToDo/NotToDo/Presentation/AchievementScene/Cells/MissionTableViewCell.swift b/NotToDo/NotToDo/Presentation/AchievementScene/Cells/MissionTableViewCell.swift index 7eb9986..ad31282 100644 --- a/NotToDo/NotToDo/Presentation/AchievementScene/Cells/MissionTableViewCell.swift +++ b/NotToDo/NotToDo/Presentation/AchievementScene/Cells/MissionTableViewCell.swift @@ -73,7 +73,7 @@ extension MissionTableViewCell { } } - func configure(_ item: MissionStatistcsResponse) { + func configure(_ item: MissionStatistcsResponseDTO) { label.text = item.title numberLabel.text = "\(item.count)회" } diff --git a/NotToDo/NotToDo/Presentation/AchievementScene/Cells/StatisticsEmptyTableViewCell.swift b/NotToDo/NotToDo/Presentation/AchievementScene/Cells/StatisticsEmptyTableViewCell.swift index 4c21bd7..9a23748 100644 --- a/NotToDo/NotToDo/Presentation/AchievementScene/Cells/StatisticsEmptyTableViewCell.swift +++ b/NotToDo/NotToDo/Presentation/AchievementScene/Cells/StatisticsEmptyTableViewCell.swift @@ -10,16 +10,16 @@ import UIKit class StatisticsEmptyTableViewCell: UITableViewCell { // MARK: - Properties - + static var identifier = "StatisticsEmptyTableViewCell" // MARK: - UI Components - + private lazy var mainTitle = UILabel() private lazy var iconImage = UIImageView() // MARK: - Life Cycle - + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) setUI() diff --git a/NotToDo/NotToDo/Presentation/AchievementScene/ViewControllers/AchievementViewController.swift b/NotToDo/NotToDo/Presentation/AchievementScene/ViewControllers/AchievementViewController.swift index f8bc9dd..c3e79d6 100644 --- a/NotToDo/NotToDo/Presentation/AchievementScene/ViewControllers/AchievementViewController.swift +++ b/NotToDo/NotToDo/Presentation/AchievementScene/ViewControllers/AchievementViewController.swift @@ -28,32 +28,43 @@ final class AchievementViewController: UIViewController { private var titleView = TitleView() private lazy var segmentedControl = CustomSegmentedControl(items: [I18N.missionStatisticsMessage, I18N.situationStatisticsMessage]) private lazy var calendarView = CustomCalendar(frame: .zero) - private lazy var missionView = MissionStatisticsView(frame: view.bounds) private lazy var situationView = SituationStatisticsView(frame: view.bounds) private var bottomLabel = UILabel() - private lazy var dateFormatter = DateFormatter() - let calendar = Calendar(identifier: Calendar.Identifier.gregorian) + private var dateFormatter = DateFormatter().then { + $0.dateFormat = "yyyy-MM" + } private lazy var safeArea = self.view.safeAreaLayoutGuide - var situationList: [SituationStatistcsResponse] = [] - var missionList: [MissionStatistcsResponse] = [] + var situationList: [SituationStatistcsResponseDTO] = [] + var missionList: [MissionStatistcsResponseDTO] = [] + var dataSource: [String: Int] = [:] // MARK: - View Life Cycle + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + requestAchieveAPI() + requestMonthAPI(month: dateFormatter.string(from: calendarView.calendar.today!)) + } + override func viewDidLoad() { super.viewDidLoad() configSituationView() setUI() setLayout() - requestAchieveAPI() } } // MARK: - Methods extension AchievementViewController { + func reloadMonthData(month: String) { + print(month) + requestMonthAPI(month: month) + } + func setUI() { view.backgroundColor = .BG @@ -63,22 +74,26 @@ extension AchievementViewController { $0.backgroundColor = .BG } calendarView.do { + $0.monthCalendarClosure = { [self] result in + let month = result + self.reloadMonthData(month: month) + } $0.layer.borderWidth = 1 $0.layer.borderColor = UIColor.nottodoGray2?.cgColor $0.calendar.delegate = self + $0.calendar.dataSource = self + $0.calendar.register(MissionCalendarDayCell.self, forCellReuseIdentifier: String(describing: MissionCalendarDayCell.self)) } + bottomLabel.do { $0.text = I18N.statistcisBottomMessage $0.font = .PretendardMedium(size: 12.adjusted) $0.textColor = .nottodoGray2 -// if missionView.missionList.isEmpty && situationView.situationList.isEmpty { -// $0.isHidden = true -// } } } private func requestAchieveAPI() { - MissionStatisticsAPI.shared.getMissionStatistics { [weak self] response in + AchieveAPI.shared.getMissionStatistics { [weak self] response in guard self != nil else { return } guard let response = response else { return } self?.missionList = response.data! @@ -88,7 +103,7 @@ extension AchievementViewController { self?.relayout() dump(response) } - SituationStatisticsAPI.shared.getSituationStatistics { [weak self] response in + AchieveAPI.shared.getSituationStatistics { [weak self] response in guard self != nil else { return } guard let response = response else { return } self?.situationList = response.data! @@ -96,10 +111,33 @@ extension AchievementViewController { self?.situationView.setUI() self?.situationView.expangindTableView.reloadData() self?.relayout() - print(response) dump(response) } } + + func requestMonthAPI(month: String) { + AchieveAPI.shared.getAchieveCalendar(month: month) { [self] result in + switch result { + case let .success(data): + guard let data = data as? [AchieveCalendarResponseDTO] else { return } + self.dataSource = [:] + for item in data { + self.dataSource[item.actionDate] = item.count + } + calendarView.calendar.reloadData() + + case .requestErr: + print("requestErr") + case .pathErr: + print("pathErr") + case .serverErr: + print("serverErr") + case .networkFail: + print("networkFail") + } + } + } + func configMissionView() { missionView.missionList = missionList } @@ -211,13 +249,35 @@ extension AchievementViewController { } } -extension AchievementViewController: FSCalendarDelegate, FSCalendarDataSource { +extension AchievementViewController: FSCalendarDelegate { func calendarCurrentPageDidChange(_ calendar: FSCalendar) { calendarView.calendar.reloadData() calendarView.headerLabel.text = calendarView.dateFormatter.string(from: calendar.currentPage) } - func calendar(_ calendar: FSCalendar, shouldSelect date: Date, at monthPosition: FSCalendarMonthPosition) -> Bool { return false } } + +extension AchievementViewController: FSCalendarDataSource { + + func calendar(_ calendar: FSCalendar, cellFor date: Date, at position: FSCalendarMonthPosition) -> FSCalendarCell { + let cell = calendar.dequeueReusableCell(withIdentifier: String(describing: MissionCalendarDayCell.self), for: date, at: position) as! MissionCalendarDayCell + + if let count = self.dataSource[date.toString()] { + switch count { + case 0: + cell.configure(.none) + case 1: + cell.configure(.step1) + case 2: + cell.configure(.step2) + case 3: + cell.configure(.step3) + default: + cell.configure(.none) + } + } + return cell + } +} diff --git a/NotToDo/NotToDo/Presentation/AchievementScene/Views/CustomCalendarView.swift b/NotToDo/NotToDo/Presentation/AchievementScene/Views/CustomCalendarView.swift index a173670..cef6537 100644 --- a/NotToDo/NotToDo/Presentation/AchievementScene/Views/CustomCalendarView.swift +++ b/NotToDo/NotToDo/Presentation/AchievementScene/Views/CustomCalendarView.swift @@ -14,19 +14,21 @@ import Then class CustomCalendar: UIView { // MARK: - UI Components - + var calendar: FSCalendar! = FSCalendar(frame: .zero) private lazy var hStack = UIStackView(arrangedSubviews: [leftBtn, rightBtn]) lazy var headerLabel = UILabel() private lazy var leftBtn = UIButton() private lazy var rightBtn = UIButton() private lazy var headerImage = UIImageView() - private var currentPage: Date? + var currentPage: Date? private lazy var today: Date = { return Date() }() lazy var dateFormatter = DateFormatter() + var monthData: [AchieveCalendarResponseDTO] = [] + var monthCalendarClosure: ((_ month: String) -> Void)? // MARK: - View Life Cycle - + override init(frame: CGRect) { super.init(frame: .zero) setUI() @@ -95,8 +97,8 @@ extension CustomCalendar { $0.directionalHorizontalEdges.equalToSuperview().inset(23.adjusted) $0.bottom.equalToSuperview().inset(26.adjusted) } - } + private func calendarText() { calendar.calendarHeaderView.isHidden = true calendar.calendarWeekdayView.weekdayLabels[0].text = "일" @@ -117,7 +119,7 @@ extension CustomCalendar { calendar.appearance.titleWeekendColor = .nottodoBlack calendar.appearance.titleTodayColor = .blue calendar.appearance.todayColor = .clear - } + } private func setUpCalendar() { self.calendar.placeholderType = .fillHeadTail @@ -132,11 +134,17 @@ extension CustomCalendar { dateComponents.month = isPrev ? -1 : 1 self.currentPage = cal.date(byAdding: dateComponents, to: self.currentPage ?? self.today) self.calendar.setCurrentPage(self.currentPage!, animated: true) + self.dateFormatter.dateFormat = "yyyy-MM" + let stringDate = self.dateFormatter.string(from: calendar.currentPage) + monthCalendarClosure?(stringDate) } - + func calendarCurrentPageDidChange(_ calendar: FSCalendar) { calendar.reloadData() self.headerLabel.text = self.dateFormatter.string(from: calendar.currentPage) + self.dateFormatter.dateFormat = "yyyy-MM" + let stringDate = self.dateFormatter.string(from: calendar.currentPage) + monthCalendarClosure?(stringDate) } @objc func prevBtnTapped(_sender: UIButton) { diff --git a/NotToDo/NotToDo/Presentation/AchievementScene/Views/MissionStatisticsView.swift b/NotToDo/NotToDo/Presentation/AchievementScene/Views/MissionStatisticsView.swift index f1e4bc9..af49aff 100644 --- a/NotToDo/NotToDo/Presentation/AchievementScene/Views/MissionStatisticsView.swift +++ b/NotToDo/NotToDo/Presentation/AchievementScene/Views/MissionStatisticsView.swift @@ -14,7 +14,7 @@ class MissionStatisticsView: UIView { // MARK: - Properties - var missionList: [MissionStatistcsResponse] = [] + var missionList: [MissionStatistcsResponseDTO] = [] // MARK: - UI Components @@ -25,7 +25,6 @@ class MissionStatisticsView: UIView { override init(frame: CGRect) { super.init(frame: .zero) -// setUI() register() setLayout() } @@ -83,7 +82,7 @@ extension MissionStatisticsView { } } -extension MissionStatisticsView: UITableViewDataSource, UITableViewDelegate { +extension MissionStatisticsView: UITableViewDelegate { func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { if missionList.isEmpty { return 300 @@ -99,6 +98,8 @@ extension MissionStatisticsView: UITableViewDataSource, UITableViewDelegate { return self.missionList.count } } +} +extension MissionStatisticsView: UITableViewDataSource { func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { if missionList.isEmpty { diff --git a/NotToDo/NotToDo/Presentation/AchievementScene/Views/SituationStatisticsView.swift b/NotToDo/NotToDo/Presentation/AchievementScene/Views/SituationStatisticsView.swift index 4d9838d..2afd933 100644 --- a/NotToDo/NotToDo/Presentation/AchievementScene/Views/SituationStatisticsView.swift +++ b/NotToDo/NotToDo/Presentation/AchievementScene/Views/SituationStatisticsView.swift @@ -14,7 +14,7 @@ class SituationStatisticsView: UIView { // MARK: - Properties var hiddenSections = Set() - var situationList: [SituationStatistcsResponse] = [] + var situationList: [SituationStatistcsResponseDTO] = [] var isSelected: [Bool] = [] // MARK: - UI Components @@ -27,7 +27,6 @@ class SituationStatisticsView: UIView { override init(frame: CGRect) { super.init(frame: .zero) -// setUI() register() setLayout() } diff --git a/NotToDo/NotToDo/Presentation/AchievementScene/Views/SituationTitleView.swift b/NotToDo/NotToDo/Presentation/AchievementScene/Views/SituationTitleView.swift index 51188dd..05223df 100644 --- a/NotToDo/NotToDo/Presentation/AchievementScene/Views/SituationTitleView.swift +++ b/NotToDo/NotToDo/Presentation/AchievementScene/Views/SituationTitleView.swift @@ -30,7 +30,7 @@ class SituationTitleView: UIView { fatalError("init(coder:) has not been implemented") } } - + // MARK: - Methods extension SituationTitleView { diff --git a/NotToDo/NotToDo/Presentation/AchievementScene/Views/TitleView.swift b/NotToDo/NotToDo/Presentation/AchievementScene/Views/TitleView.swift index 6c64336..ccb0cb0 100644 --- a/NotToDo/NotToDo/Presentation/AchievementScene/Views/TitleView.swift +++ b/NotToDo/NotToDo/Presentation/AchievementScene/Views/TitleView.swift @@ -13,11 +13,11 @@ import Then class TitleView: UIView { // MARK: - UI Components - + private let titleLabel = CustomAchieveLabel(color: .nottodoBlack!, font: .PretendardBold(size: 22.adjusted)) // MARK: - View Life Cycle - + override init(frame: CGRect) { super.init(frame: frame) setUI() @@ -39,7 +39,7 @@ extension TitleView { func setLayout() { addSubview(titleLabel) - + titleLabel.snp.makeConstraints { $0.centerY.equalToSuperview() $0.leading.equalToSuperview().offset(20.adjusted) diff --git a/NotToDo/NotToDo/Presentation/Common/Calendar/MissionCalendarDayCell.swift b/NotToDo/NotToDo/Presentation/Common/Calendar/MissionCalendarDayCell.swift index da51873..ab38e73 100644 --- a/NotToDo/NotToDo/Presentation/Common/Calendar/MissionCalendarDayCell.swift +++ b/NotToDo/NotToDo/Presentation/Common/Calendar/MissionCalendarDayCell.swift @@ -83,5 +83,6 @@ final class MissionCalendarDayCell: FSCalendarCell { extension MissionCalendarDayCell { func configure(_ state: ToDoState) { self.state = state + updateUI() } } diff --git a/NotToDo/NotToDo/Presentation/HomeScene/Cells/HomeCalendarCollectionViewCell.swift b/NotToDo/NotToDo/Presentation/HomeScene/Cells/HomeCalendarCollectionViewCell.swift index e67118e..2003e74 100644 --- a/NotToDo/NotToDo/Presentation/HomeScene/Cells/HomeCalendarCollectionViewCell.swift +++ b/NotToDo/NotToDo/Presentation/HomeScene/Cells/HomeCalendarCollectionViewCell.swift @@ -13,14 +13,10 @@ import Then final class HomeCalendarCollectionViewCell: UICollectionViewCell { - // TODO: 해당 데이터 가지고 셀 각각에 데이터 뿌려주면 될듯 - // 딕셔너리나 배열 적절하게 선택해서 사용하기 -> 배열이 더 익숙하니까 배열 사용하는 것이 더 편할 것임 - // 아마 서버에서 [날짜(String), Int] 값을 배열 형태로 같이 넘겨줄 것 같은데 그거 가지고 사용하면 됨 - var dataSource: [String: Int] = [:] - // MARK: - Properties static let identifier = "HomeCalendarCollectionViewCell" + var dataSource: [String: Int] = [:] // MARK: - UI Components @@ -102,25 +98,8 @@ extension HomeCalendarCollectionViewCell { extension HomeCalendarCollectionViewCell: FSCalendarDataSource { - // 서버에서 넘어온 dateString이랑 이 메서드의 date를 잘 매칭시켜줘야 함 - // date 매칭된 것에 맞게 데이터를 넘겨줘야 함 func calendar(_ calendar: FSCalendar, cellFor date: Date, at position: FSCalendarMonthPosition) -> FSCalendarCell { let cell = calendar.dequeueReusableCell(withIdentifier: String(describing: MissionCalendarDayCell.self), for: date, at: position) as! MissionCalendarDayCell - - // MARK: 서버에서 넘어온 값에 따라 셀 상태 변화시켜주기 - // Date : Int(Enum) - /* - NotToDoCalendarCell에 가보면 Enum이 보일 것임 - 프로젝트 상황에 따라 적절하게 바꿔서 사용하기 - - 현재는 5개의 case가 있음 - - none, step1, step2, step3, bordered - - case에 따라서 backgroundColor 변화시키는 식으로 구현되어 있는데 UI 디테일을 살리고 싶으면 - 그냥 case에 따라 이미지를 넣는 것이 더 쉬움 - */ - - // 캘린더 셀 설정해주는 코드 : CollectionViewCell이랑 동일하게 생각하면 됨 cell.configure(.bordered) return cell } diff --git a/NotToDo/NotToDo/Presentation/RecommendScene/Cell/CustomTabBarCell.swift b/NotToDo/NotToDo/Presentation/RecommendScene/Cell/CustomTabBarCell.swift index 117cc13..0ec68a6 100644 --- a/NotToDo/NotToDo/Presentation/RecommendScene/Cell/CustomTabBarCell.swift +++ b/NotToDo/NotToDo/Presentation/RecommendScene/Cell/CustomTabBarCell.swift @@ -18,7 +18,7 @@ class CustomTabBarCell: UICollectionViewCell { // MARK: - UI Components - private var bgView = UIView() + private var backGroundView = UIView() private var icImage = UIImageView() private var titleLabel = UILabel() @@ -46,10 +46,10 @@ extension CustomTabBarCell { } private func setLayout() { - addSubview(bgView) - bgView.addSubviews(icImage, titleLabel) + addSubview(backGroundView) + backGroundView.addSubviews(icImage, titleLabel) - bgView.snp.makeConstraints { + backGroundView.snp.makeConstraints { $0.height.equalTo(82.adjusted) $0.width.equalTo(69.adjusted) $0.centerX.centerY.equalToSuperview() @@ -74,13 +74,13 @@ extension CustomTabBarCell { titleLabel.textColor = .nottodoGray1 titleLabel.font = .PretendardBold(size: 12.adjusted) icImage.image = UIImage(named: item.activeImage) - bgView.backgroundColor = .yellow_mild + backGroundView.backgroundColor = .yellow_mild } else { titleLabel.text = item.name titleLabel.textColor = .nottodoGray2 titleLabel.font = .PretendardMedium(size: 12.adjusted) icImage.image = UIImage(named: item.image) - bgView.backgroundColor = .clear + backGroundView.backgroundColor = .clear } } } diff --git a/NotToDo/NotToDo/Presentation/RecommendScene/Cell/RecommendCollectionViewCell.swift b/NotToDo/NotToDo/Presentation/RecommendScene/Cell/RecommendCollectionViewCell.swift index 71c426b..4fe6ab9 100644 --- a/NotToDo/NotToDo/Presentation/RecommendScene/Cell/RecommendCollectionViewCell.swift +++ b/NotToDo/NotToDo/Presentation/RecommendScene/Cell/RecommendCollectionViewCell.swift @@ -22,7 +22,7 @@ class RecommendCollectionViewCell: UICollectionViewCell { // MARK: - UI Components lazy var nestedCollectionView = NestedView(frame: .zero) - var item: RecommendElementResponse? + var item: RecommendElementResponseDTO? // MARK: - Life Cycle diff --git a/NotToDo/NotToDo/Presentation/RecommendScene/ViewControllers/RecommendViewController.swift b/NotToDo/NotToDo/Presentation/RecommendScene/ViewControllers/RecommendViewController.swift index 6119b9c..93e8341 100644 --- a/NotToDo/NotToDo/Presentation/RecommendScene/ViewControllers/RecommendViewController.swift +++ b/NotToDo/NotToDo/Presentation/RecommendScene/ViewControllers/RecommendViewController.swift @@ -14,18 +14,16 @@ class RecommendViewController: UIViewController, CustomTabBarDelegate { // MARK: - Properties - var navigationBarView = NavigationBarView(frame: CGRect(), mode: .leftRecommend) - var itemList: [RecommendElementResponse] = [] + var navigationBarView = NavigationBarView(frame: CGRect(), mode: .leftRecommend) + var itemList: [RecommendElementResponseDTO] = [] var selectedIndex: Int = 0 - + typealias Item = AnyHashable enum Section: Int, Hashable { case sub, main } - typealias Item = AnyHashable var dataSource: UICollectionViewDiffableDataSource! = nil - var isClickedClosure: ((_ section: Int, _ index: Int) -> Void)? - + // MARK: - UI Components var navigationMode: NavigationMode? @@ -37,7 +35,7 @@ class RecommendViewController: UIViewController, CustomTabBarDelegate { private lazy var safeArea = self.view.safeAreaLayoutGuide private var nestedView = NestedView() var recommendTextFieldClosure: ((_ result: String) -> Void)? - + // MARK: - Life Cycle override func viewDidLoad() { @@ -60,7 +58,7 @@ extension RecommendViewController { } contentsCollectionView.do { - $0.backgroundColor = .systemGray6 + $0.backgroundColor = .BG $0.showsHorizontalScrollIndicator = false $0.isPagingEnabled = true } @@ -158,7 +156,7 @@ extension RecommendViewController { snapShot.appendItems([], toSection: .main) } - private func updateData(item: [RecommendElementResponse]) { + private func updateData(item: [RecommendElementResponseDTO]) { var snapshot = dataSource.snapshot() snapshot.appendItems(item, toSection: .main) dataSource.apply(snapshot) diff --git a/NotToDo/NotToDo/Presentation/RecommendScene/Views/CustomTabBarView.swift b/NotToDo/NotToDo/Presentation/RecommendScene/Views/CustomTabBarView.swift index 04a79dd..f803428 100644 --- a/NotToDo/NotToDo/Presentation/RecommendScene/Views/CustomTabBarView.swift +++ b/NotToDo/NotToDo/Presentation/RecommendScene/Views/CustomTabBarView.swift @@ -17,7 +17,7 @@ protocol CustomTabBarDelegate: AnyObject { class CustomTabBarView: UIView { // MARK: - Properties - + var defaultIndex: Int = 0 weak var delegate: CustomTabBarDelegate? let titleList: [CustomTabBarItem] = CustomTabBarItem.items @@ -106,10 +106,10 @@ extension CustomTabBarView { private func layout() -> UICollectionViewCompositionalLayout { let item = NSCollectionLayoutItem(layoutSize: .init(widthDimension: .absolute(69), heightDimension: .absolute(82))) - let group = NSCollectionLayoutGroup.horizontal(layoutSize: .init(widthDimension: .absolute(550), heightDimension: .absolute(104)), subitems: [item]) + let group = NSCollectionLayoutGroup.horizontal(layoutSize: .init(widthDimension: .absolute(560), heightDimension: .absolute(104)), subitems: [item]) group.interItemSpacing = .fixed(10) let section = NSCollectionLayoutSection(group: group) - section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 20, bottom: 0, trailing: 0) + section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 20, bottom: 0, trailing: 10) section.orthogonalScrollingBehavior = .continuous let layout = UICollectionViewCompositionalLayout(section: section) return layout diff --git a/NotToDo/NotToDo/Presentation/RecommendScene/Views/NestedView.swift b/NotToDo/NotToDo/Presentation/RecommendScene/Views/NestedView.swift index a7acb1b..11599b9 100644 --- a/NotToDo/NotToDo/Presentation/RecommendScene/Views/NestedView.swift +++ b/NotToDo/NotToDo/Presentation/RecommendScene/Views/NestedView.swift @@ -13,8 +13,8 @@ import Then class NestedView: UIView { // MARK: - Properties - - var item: RecommendElementResponse? + + var item: RecommendElementResponseDTO? var isClickedClosure: ((_ section: Int, _ index: Int) -> Void)? var section: Int? @@ -138,6 +138,5 @@ extension NestedView: UICollectionViewDelegate { if let section = section { isClickedClosure?(section, indexPath.item) } - print("tapped") } }