diff --git a/SantaManito-iOS/SantaManito-iOS.xcodeproj/project.pbxproj b/SantaManito-iOS/SantaManito-iOS.xcodeproj/project.pbxproj index f78a4a6..f2889c9 100644 --- a/SantaManito-iOS/SantaManito-iOS.xcodeproj/project.pbxproj +++ b/SantaManito-iOS/SantaManito-iOS.xcodeproj/project.pbxproj @@ -113,7 +113,6 @@ D28568AC2CAD031C0044C231 /* RequestHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28568AB2CAD031C0044C231 /* RequestHandler.swift */; }; D28568AE2CAD033C0044C231 /* ErrorHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28568AD2CAD033C0044C231 /* ErrorHandler.swift */; }; D28568B22CAD21800044C231 /* Config.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28568B12CAD21800044C231 /* Config.swift */; }; - D2A8F60E2C9D18FF00810BCF /* EditRoomService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A8F60D2C9D18FF00810BCF /* EditRoomService.swift */; }; D2A8F6122C9D1A4F00810BCF /* MakeRoomInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A8F6112C9D1A4F00810BCF /* MakeRoomInfo.swift */; }; D2A8F6192CA1168B00810BCF /* MatchingResultViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A8F6182CA1168B00810BCF /* MatchingResultViewModel.swift */; }; D2A8F61B2CA116BD00810BCF /* MatchingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A8F61A2CA116BD00810BCF /* MatchingViewModel.swift */; }; @@ -121,7 +120,6 @@ D2A8F61F2CA1170B00810BCF /* MatchingResultView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A8F61E2CA1170B00810BCF /* MatchingResultView.swift */; }; D2A8F6212CA1172100810BCF /* FinishView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A8F6202CA1172100810BCF /* FinishView.swift */; }; D2A8F6232CA1173600810BCF /* FinishViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A8F6222CA1173600810BCF /* FinishViewModel.swift */; }; - D2A8F6252CA118EA00810BCF /* MatchRoomService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A8F6242CA118E900810BCF /* MatchRoomService.swift */; }; D2BC1A8C2C8EBCF500CB32B8 /* SMColoredTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2BC1A8B2C8EBCF500CB32B8 /* SMColoredTextView.swift */; }; D2BC1A902C8F4C6400CB32B8 /* Date+.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2BC1A8F2C8F4C6400CB32B8 /* Date+.swift */; }; D2BC1A922C90101E00CB32B8 /* EditMissionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2BC1A912C90101E00CB32B8 /* EditMissionView.swift */; }; @@ -255,7 +253,6 @@ D28568AB2CAD031C0044C231 /* RequestHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestHandler.swift; sourceTree = ""; }; D28568AD2CAD033C0044C231 /* ErrorHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorHandler.swift; sourceTree = ""; }; D28568B12CAD21800044C231 /* Config.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Config.swift; sourceTree = ""; }; - D2A8F60D2C9D18FF00810BCF /* EditRoomService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditRoomService.swift; sourceTree = ""; }; D2A8F6112C9D1A4F00810BCF /* MakeRoomInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MakeRoomInfo.swift; sourceTree = ""; }; D2A8F6182CA1168B00810BCF /* MatchingResultViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatchingResultViewModel.swift; sourceTree = ""; }; D2A8F61A2CA116BD00810BCF /* MatchingViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatchingViewModel.swift; sourceTree = ""; }; @@ -263,7 +260,6 @@ D2A8F61E2CA1170B00810BCF /* MatchingResultView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatchingResultView.swift; sourceTree = ""; }; D2A8F6202CA1172100810BCF /* FinishView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FinishView.swift; sourceTree = ""; }; D2A8F6222CA1173600810BCF /* FinishViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FinishViewModel.swift; sourceTree = ""; }; - D2A8F6242CA118E900810BCF /* MatchRoomService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatchRoomService.swift; sourceTree = ""; }; D2BC1A8B2C8EBCF500CB32B8 /* SMColoredTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SMColoredTextView.swift; sourceTree = ""; }; D2BC1A8F2C8F4C6400CB32B8 /* Date+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+.swift"; sourceTree = ""; }; D2BC1A912C90101E00CB32B8 /* EditMissionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditMissionView.swift; sourceTree = ""; }; @@ -360,15 +356,6 @@ path = User; sourceTree = ""; }; - 8779D81B2CB8DD8B00B61DEA /* Deprecated */ = { - isa = PBXGroup; - children = ( - D2A8F6242CA118E900810BCF /* MatchRoomService.swift */, - D2A8F60D2C9D18FF00810BCF /* EditRoomService.swift */, - ); - path = Deprecated; - sourceTree = ""; - }; 877CA06B2C8AA1AD00D23193 /* Component */ = { isa = PBXGroup; children = ( @@ -858,7 +845,6 @@ D2A8F60C2C9D18E700810BCF /* Room */ = { isa = PBXGroup; children = ( - 8779D81B2CB8DD8B00B61DEA /* Deprecated */, D268793C2CAA7F8A0025A611 /* RoomAPI.swift */, 879829062C98284B00A863EC /* RoomService.swift */, ); @@ -1084,7 +1070,6 @@ 874017CB2CA7E6970096E847 /* SMPasteBoard.swift in Sources */, 874017B02CA29C820096E847 /* MyPageViewModel.swift in Sources */, 877EA2412C88ABA00073FFBD /* PushNotificationService.swift in Sources */, - D2A8F6252CA118EA00810BCF /* MatchRoomService.swift in Sources */, D268793F2CAA80580025A611 /* BaseAPI.swift in Sources */, D25570E92C8E858A00CCC226 /* EditRoomInfoView.swift in Sources */, D26BFA802C91692700C5CF86 /* SMInfoView.swift in Sources */, @@ -1114,7 +1099,6 @@ 879829072C98284B00A863EC /* RoomService.swift in Sources */, 87873BDC2CAC29E900E368BF /* AppDelegate.swift in Sources */, D2A8F61B2CA116BD00810BCF /* MatchingViewModel.swift in Sources */, - D2A8F60E2C9D18FF00810BCF /* EditRoomService.swift in Sources */, D2A8F61D2CA116F800810BCF /* MatchingView.swift in Sources */, 879829052C9827B200A863EC /* HomeViewModel.swift in Sources */, D26BFA912C919D0000C5CF86 /* ManitoWaitingRoomView.swift in Sources */, diff --git a/SantaManito-iOS/SantaManito-iOS/Data/DTO/Room/CreateRoomDTO.swift b/SantaManito-iOS/SantaManito-iOS/Data/DTO/Room/CreateRoomDTO.swift index 4f94626..44a3dd1 100644 --- a/SantaManito-iOS/SantaManito-iOS/Data/DTO/Room/CreateRoomDTO.swift +++ b/SantaManito-iOS/SantaManito-iOS/Data/DTO/Room/CreateRoomDTO.swift @@ -9,14 +9,14 @@ import Foundation struct CreateRoomRequest: Encodable { var roomName: String - var expirationDate: String + var expirationDate: Date var missionContents: [String] } extension CreateRoomRequest { init(_ room: MakeRoomInfo, _ mission: [Mission]) { self.roomName = room.name - self.expirationDate = room.expirationDate.ISO8601Format() //TODO: DateFormat 어떤식으로 Request보낼지에 따라 결정 + self.expirationDate = room.expirationDate self.missionContents = mission.map { $0.content } // TODO: 미션로직 수정필요하다면 } } diff --git a/SantaManito-iOS/SantaManito-iOS/Data/DTO/Room/RoomDetailDTO.swift b/SantaManito-iOS/SantaManito-iOS/Data/DTO/Room/RoomDetailDTO.swift index 9545996..780e97b 100644 --- a/SantaManito-iOS/SantaManito-iOS/Data/DTO/Room/RoomDetailDTO.swift +++ b/SantaManito-iOS/SantaManito-iOS/Data/DTO/Room/RoomDetailDTO.swift @@ -12,10 +12,10 @@ struct RoomDetailResponse: Decodable { let id: String let roomName: String let invitationCode: String - let createdAt: String //TODO: 서버 확정 후 Date로 변경 - let expirationDate: String //TODO: 서버 확정 후 Date로 변경 - let matchingDate: String? //TODO: 서버 확정 후 Date로 변경 - let deletedByCreatorDate: String? //TODO: 서버 확정 후 Date로 변경 + let createdAt: Date + let expirationDate: Date + let matchingDate: Date? + let deletedByCreatorDate: Date? let creator: UserResponse let missions: [MissionResponse] let members: [MemberResponse] @@ -44,8 +44,8 @@ extension RoomDetailResponse { creatorName: self.creator.username, members: members.map { $0.toEntity()}, mission: missions.map { $0.toEntity()} , - createdAt: Date().addingTimeInterval(-5 * 24 * 60 * 60), // TODO: 위 주석 해제하면 createdAt에 연결해야함. - expirationDate: Date().addingTimeInterval(-3 * 12 * 60 * 60) + createdAt: self.createdAt, + expirationDate: self.expirationDate ) } } diff --git a/SantaManito-iOS/SantaManito-iOS/Data/DTO/Room/RoomStateFactory.swift b/SantaManito-iOS/SantaManito-iOS/Data/DTO/Room/RoomStateFactory.swift index fe3b85e..25b2dc5 100644 --- a/SantaManito-iOS/SantaManito-iOS/Data/DTO/Room/RoomStateFactory.swift +++ b/SantaManito-iOS/SantaManito-iOS/Data/DTO/Room/RoomStateFactory.swift @@ -9,9 +9,8 @@ import Foundation struct RoomStateFactory { static func create(_ dto: RoomDetailResponse) -> RoomState { - return .notStarted guard dto.deletedByCreatorDate == nil else { return .deleted } -// guard dto.expirationDate > Date() else { return .completed } //TODO: 서버 DTO. Date 형식 정해지면 주석 해제 + guard dto.expirationDate > Date() else { return .completed } guard dto.matchingDate != nil else { return .notStarted } return .inProgress } diff --git a/SantaManito-iOS/SantaManito-iOS/Data/Entity/Room/RoomDetail.swift b/SantaManito-iOS/SantaManito-iOS/Data/Entity/Room/RoomDetail.swift index 7c1ff86..2bb83de 100644 --- a/SantaManito-iOS/SantaManito-iOS/Data/Entity/Room/RoomDetail.swift +++ b/SantaManito-iOS/SantaManito-iOS/Data/Entity/Room/RoomDetail.swift @@ -21,7 +21,7 @@ struct RoomDetail: Hashable { var isHost: Bool { - UserDefaultsService.userID == creatorID + UserDefaultsService.shared.userID == creatorID } // 오늘부터 만료일까지 (한국 날짜 기준) diff --git a/SantaManito-iOS/SantaManito-iOS/Data/Service/Room/Deprecated/EditRoomService.swift b/SantaManito-iOS/SantaManito-iOS/Data/Service/Room/Deprecated/EditRoomService.swift deleted file mode 100644 index 6e0729c..0000000 --- a/SantaManito-iOS/SantaManito-iOS/Data/Service/Room/Deprecated/EditRoomService.swift +++ /dev/null @@ -1,126 +0,0 @@ -// -// EditRoomService.swift -// SantaManito-iOS -// -// Created by 류희재 on 9/20/24. -// - -import Foundation -import Combine - -protocol EditRoomServiceType { -// func getRoomInfo(with roomID: String) -> AnyPublisher - func editRoomInfo(with roomID: String, request: EditRoomRequest) -> AnyPublisher - func createRoom(_ request: CreateRoomRequest) -> AnyPublisher - -// func getRoomMyInfo(with roomID: String) -> AnyPublisher - func deleteRoom(with roomID: String) -> AnyPublisher - func deleteHistoryRoom(with roomID: String) -> AnyPublisher - - func enterRoom(inviteCode: String) -> AnyPublisher - func exitRoom(roomID: String) -> AnyPublisher -} - -//extension EditRoomService: EditRoomServiceType { -// //TODO: 참여 방 조회하기면 홈에서 넘어오기 때문에 연결을 안해도 될거 같은데 -//// func getRoomInfo(with roomID: String) -> AnyPublisher { -//// return Just( -//// MakeRoomInfo( -//// name: "마니또 방 이름", -//// remainingDays: 10, -//// dueDate: Date().adjustDays(remainingDays: 10) -//// ) -//// ).setFailureType(to: SMNetworkError.self).eraseToAnyPublisher() -//// } -// -// func editRoomInfo(with roomID: String, request: EditRoomRequest) -> AnyPublisher { -// requestWithNoResult(.editRoomInfo(roomID: roomID, request: request)) -// } -// -// func createRoom(_ request: CreateRoomRequest) -> AnyPublisher { -// requestWithResult(.createRoom(request: request), CreateRoomResult.self) -// .map { result in result.invitationCode } -// .eraseToAnyPublisher() -// } -// -// func getRoomMyInfo(with roomID: String) -> AnyPublisher { -// requestWithResult(.getMyInfo(roomID: roomID), RoomMyInfoResult.self) -// } -// -// func deleteRoom(with roomID: String) -> AnyPublisher { -// requestWithNoResult(.deleteRoom(roomID: roomID)) -// } -// -// func deleteHistoryRoom(with roomID: String) -> AnyPublisher { -// requestWithNoResult(.deleteHistoryRoom(roomID: roomID)) -// } -// -// func enterRoom(inviteCode: String) -> AnyPublisher { -// requestWithResult( -// .enterRoom(request: EnterRoomRequest(inviteCode: inviteCode)), -// EnterRoomResult.self -// ) -// //TODO: 여기 수정하기 -// .mapError { smError -> EnterError in -// switch smError { -// case .invalidResponse(let responseError): -// if case let .invalidStatusCode(code, _) = responseError { -// return EnterError.error(with: code) -// } -// return .unknown -// -// default: -// return .unknown -// } -// } -// .map { result in result.roomId } -// .eraseToAnyPublisher() -// } -// -// func exitRoom(roomID: String) -> AnyPublisher { -// requestWithNoResult(.exitRoom(roomID: roomID)) -// } -//} -// -//struct StubEditRoomService: EditRoomServiceType { -// func getRoomMyInfo(with roomID: String) -> AnyPublisher { -// return Just(RoomMyInfoResult(manitto: .stub1, mission: Mission(content: "asdf", id: UUID()))) -// .setFailureType(to: SMNetworkError.self) -// .eraseToAnyPublisher() -// } -// -// func editRoomInfo(with roomID: String, request: EditRoomRequest) -> AnyPublisher { -// return Just(()).setFailureType(to: SMNetworkError.self).eraseToAnyPublisher() -// } -// -//// func getRoomInfo(with roomID: String) -> AnyPublisher { -//// return Just( -//// MakeRoomInfo( -//// name: "마니또 방 이름", -//// remainingDays: 10, -//// dueDate: Date().adjustDays(remainingDays: 10) -//// ) -//// ).setFailureType(to: SMNetworkError.self).eraseToAnyPublisher() -//// } -// -// func createRoom(_ request: CreateRoomRequest) -> AnyPublisher { -// return Just("asdkf12").setFailureType(to: SMNetworkError.self).eraseToAnyPublisher() -// } -// -// func deleteRoom(with roomID: String) -> AnyPublisher { -// return Just(()).setFailureType(to: SMNetworkError.self).eraseToAnyPublisher() -// } -// -// func deleteHistoryRoom(with roomID: String) -> AnyPublisher { -// return Just(()).setFailureType(to: SMNetworkError.self).eraseToAnyPublisher() -// } -// -// func enterRoom(inviteCode: String) -> AnyPublisher { -// return Just("roomId").setFailureType(to: EnterError.self).eraseToAnyPublisher() -// } -// -// func exitRoom(roomID: String) -> AnyPublisher { -// return Just(()).setFailureType(to: SMNetworkError.self).eraseToAnyPublisher() -// } -//} -// diff --git a/SantaManito-iOS/SantaManito-iOS/Data/Service/Room/Deprecated/MatchRoomService.swift b/SantaManito-iOS/SantaManito-iOS/Data/Service/Room/Deprecated/MatchRoomService.swift deleted file mode 100644 index a60710e..0000000 --- a/SantaManito-iOS/SantaManito-iOS/Data/Service/Room/Deprecated/MatchRoomService.swift +++ /dev/null @@ -1,115 +0,0 @@ -// -// MatchRoomService.swift -// SantaManito-iOS -// -// Created by 류희재 on 9/23/24. -// - -import Foundation -import Combine - -struct MatchingFinishData : Codable, Hashable { - let userID, santaUserID, manittoUserID: Int - let myMission, missionToMe: MissionToMe - let santaUsername, manittoUsername: String - - enum CodingKeys: String, CodingKey { - case userID = "UserId" - case santaUserID = "SantaUserId" - case manittoUserID = "ManittoUserId" - case myMission = "MyMission" - case missionToMe = "MissionToMe" - case santaUsername = "SantaUsername" - case manittoUsername = "ManittoUsername" - } -} - -// MARK: - MissionToMe -struct MissionToMe: Codable, Hashable { - let content: String -} - -extension MatchingFinishData { - static var stub1: MatchingFinishData { - .init( - userID: 1, - santaUserID: 2, - manittoUserID: 1, - myMission: MissionToMe(content: "5천원 이하의 선물과 함께 카톡으로 수고했다고 말하기 카톡으로 수고했다고 말하기"), - missionToMe: MissionToMe(content: "5천원 이하의 선물과 함께 카톡으로 수고했다고 말하기 카톡으로 수고했다고 말하기"), - santaUsername: "류희재", - manittoUsername: "장석우" - ) - } - - static var stub2: MatchingFinishData { - .init( - userID: 1, - santaUserID: 2, - manittoUserID: 1, - myMission: MissionToMe(content: "뭐시기뭐시기뭐시기뭐시기"), - missionToMe: MissionToMe(content: "뭐시기뭐시기뭐시기뭐시기"), - santaUsername: "류희재", - manittoUsername: "장석우" - ) - } - - static var stub3: MatchingFinishData { - .init( - userID: 1, - santaUserID: 2, - manittoUserID: 1, - myMission: MissionToMe(content: "뭐시기뭐시기뭐시기뭐시기"), - missionToMe: MissionToMe(content: "뭐시기뭐시기뭐시기뭐시기"), - santaUsername: "류희재", - manittoUsername: "장석우" - ) - } - - static var stub4: MatchingFinishData { - .init( - userID: 1, - santaUserID: 2, - manittoUserID: 1, - myMission: MissionToMe(content: "5천원 이하의 선물과 함께 카톡으로 수고했다고 말하기"), - missionToMe: MissionToMe(content: "5천원 이하의 선물과 함께 카톡으로 수고했다고 말하기"), - santaUsername: "류희재", - manittoUsername: "장석우" - ) - } - - static var stubList: [MatchingFinishData] { - return [.stub1, .stub2, .stub3, .stub4, .stub1, .stub2, .stub3, .stub4] - } -} - - -// -//protocol MatchRoomServiceType { -// func matchPlayer() -> AnyPublisher -// func getManito(_ userID: String) -> AnyPublisher -// func getManitoResult(_ roomID: String) -> AnyPublisher<[MatchingFinishData], Error> -// func deleteRoom(_ roomID: String) -> AnyPublisher -//} -// -//struct StubMatchRoomService: MatchRoomServiceType { -// -// func matchPlayer() -> AnyPublisher { -// return Just(()).setFailureType(to: Error.self).eraseToAnyPublisher() -// } -// -// func getManito(_ userID: String) -> AnyPublisher { -// return Just(.stub1).setFailureType(to: Error.self).eraseToAnyPublisher() -// } -// -// func getManitoResult(_ roomID: String) -> AnyPublisher<[MatchingFinishData], Error> { -// return Just(MatchingFinishData.stubList).setFailureType(to: Error.self).eraseToAnyPublisher() -// } -// -// func deleteRoom(_ roomID: String) -> AnyPublisher { -// return Just(()).setFailureType(to: Error.self).eraseToAnyPublisher() -// } -//} -// -// -// diff --git a/SantaManito-iOS/SantaManito-iOS/Data/Service/UserDefaultsService.swift b/SantaManito-iOS/SantaManito-iOS/Data/Service/UserDefaultsService.swift index 4242743..b7b2925 100644 --- a/SantaManito-iOS/SantaManito-iOS/Data/Service/UserDefaultsService.swift +++ b/SantaManito-iOS/SantaManito-iOS/Data/Service/UserDefaultsService.swift @@ -13,26 +13,32 @@ enum UserDefaultKey: String, CaseIterable { } protocol UserDefaultsServiceType { - static var userID: String { get set } - static var accessToken: String { get set } -} - -struct UserDefaultsService: UserDefaultsServiceType { - @UserDefault(key: .userID, defaultValue: "") static var userID: String - @UserDefault(key: .accessToken, defaultValue: "") static var accessToken: String -} - - -struct StubUserDefaultsService: UserDefaultsServiceType { - static var userID: String = "" - static var accessToken: String = "" + var userID: String { get set } + var accessToken: String { get set } + func removeAll() } extension UserDefaultsServiceType { - static func reset() { + func removeAll() { UserDefaultKey.allCases .forEach { UserDefaults.standard.removeObject(forKey: $0.rawValue) } } } + + +struct UserDefaultsService: UserDefaultsServiceType { + static var shared = UserDefaultsService() + private init() { } + + @UserDefault(key: .userID, defaultValue: "") var userID: String + @UserDefault(key: .accessToken, defaultValue: "") var accessToken: String +} + + +struct StubUserDefaultsService: UserDefaultsServiceType { + var userID: String = "" + var accessToken: String = "" +} + diff --git a/SantaManito-iOS/SantaManito-iOS/Feature/EnterRoom/ViewModel/EnterRoomViewModel.swift b/SantaManito-iOS/SantaManito-iOS/Feature/EnterRoom/ViewModel/EnterRoomViewModel.swift index 6a7c7c0..cb74e44 100644 --- a/SantaManito-iOS/SantaManito-iOS/Feature/EnterRoom/ViewModel/EnterRoomViewModel.swift +++ b/SantaManito-iOS/SantaManito-iOS/Feature/EnterRoom/ViewModel/EnterRoomViewModel.swift @@ -57,6 +57,7 @@ class EnterRoomViewModel: ObservableObject { switch action { case .enterButtonDidTap: roomService.enterRoom(at: inviteCode) + .receive(on: RunLoop.main) .mapError { [weak self] error in self?.state.enterFailMessage = (true, error.description) return error @@ -67,6 +68,7 @@ class EnterRoomViewModel: ObservableObject { .catch { _ in Empty() } .eraseToAnyPublisher() } + .receive(on: RunLoop.main) .sink(receiveCompletion: { _ in }, receiveValue: { [weak self] roomDetail in diff --git a/SantaManito-iOS/SantaManito-iOS/Feature/EnterRoom/ViewModel/ManitoWaitingRoomViewModel.swift b/SantaManito-iOS/SantaManito-iOS/Feature/EnterRoom/ViewModel/ManitoWaitingRoomViewModel.swift index 4a313d5..eca8511 100644 --- a/SantaManito-iOS/SantaManito-iOS/Feature/EnterRoom/ViewModel/ManitoWaitingRoomViewModel.swift +++ b/SantaManito-iOS/SantaManito-iOS/Feature/EnterRoom/ViewModel/ManitoWaitingRoomViewModel.swift @@ -59,7 +59,7 @@ class ManitoWaitingRoomViewModel: ObservableObject { case .refreshButtonDidTap: roomService.getRoomInfo(with: state.roomDetail.id) - .receive(on: DispatchQueue.main) + .receive(on: RunLoop.main) .assignLoading(to: \.state.isLoading, on: owner) .catch { _ in Empty() } .assign(to: \.state.roomDetail, on: owner) diff --git a/SantaManito-iOS/SantaManito-iOS/Feature/Home/HomeView.swift b/SantaManito-iOS/SantaManito-iOS/Feature/Home/HomeView.swift index 16fd9ed..27bb938 100644 --- a/SantaManito-iOS/SantaManito-iOS/Feature/Home/HomeView.swift +++ b/SantaManito-iOS/SantaManito-iOS/Feature/Home/HomeView.swift @@ -109,6 +109,28 @@ struct HomeView: View { .onAppear { viewModel.send(.onAppear) } + .smAlert( + isPresented: viewModel.state.guestExitAlert.isPresented, + title: viewModel.state.guestExitAlert.detail.name + "\n이 방을 나가는 거 맞지?", + primaryButton: ( + "방 나가기", + { + viewModel.send(.dismissAlert) + viewModel.send(.guestExitButtonDidTap(roomDetail: viewModel.state.guestExitAlert.detail))} + ), + secondaryButton: ("방에 머물기", { viewModel.send(.dismissAlert) }) + ) + .smAlert( + isPresented: viewModel.state.creatorExitAlert.isPresented, + title: "방장이 나가면 재입장할 수 없고,\n친구들도 더 이상 방에 접속할 수 없어!", + primaryButton: ( + "방 나가기", + { + viewModel.send(.dismissAlert) + viewModel.send(.creatorExitButtonDidTap(roomDetail: viewModel.state.creatorExitAlert.detail))} + ), + secondaryButton: ("방에 머물기", { viewModel.send(.dismissAlert) }) + ) } } @@ -155,6 +177,8 @@ struct HomeView: View { } } .padding(.top, 20) + + } } @@ -265,7 +289,7 @@ fileprivate struct HomeRoomCell: View { VStack { Spacer() Button { - viewModel.send(.exitButtonDidTap(roomID: roomInfo.id)) + viewModel.send(.exitButtonDidTap(roomDetail: roomInfo)) } label : { Text("방 나가기") .font(.medium_14) @@ -314,6 +338,7 @@ fileprivate struct HomeRoomCell: View { .padding(.vertical, 1) + } } diff --git a/SantaManito-iOS/SantaManito-iOS/Feature/Home/HomeViewModel.swift b/SantaManito-iOS/SantaManito-iOS/Feature/Home/HomeViewModel.swift index 00eddeb..a3cee75 100644 --- a/SantaManito-iOS/SantaManito-iOS/Feature/Home/HomeViewModel.swift +++ b/SantaManito-iOS/SantaManito-iOS/Feature/Home/HomeViewModel.swift @@ -20,13 +20,19 @@ class HomeViewModel: ObservableObject { case makeRoomButtonDidTap case enterRoomButtonDidTap case roomCellDidTap(roomDetail: RoomDetail) - case exitButtonDidTap(roomID: String) + case exitButtonDidTap(roomDetail: RoomDetail) // 확인용 이벤트 + case creatorExitButtonDidTap(roomDetail: RoomDetail) // 실제 나가기 + case guestExitButtonDidTap(roomDetail: RoomDetail) // 실제 나가기 + case dismissAlert case deleteHistoryButtonDidTap(roomID: String) + } struct State { var rooms: [RoomDetail] = [] + var creatorExitAlert = (isPresented: false, detail: RoomDetail.stub1) + var guestExitAlert = (isPresented: false, detail: RoomDetail.stub1) var isLoading = false } @@ -63,7 +69,7 @@ class HomeViewModel: ObservableObject { case .onAppear, .refreshButtonDidTap: roomService.getEnteredRooms() - .receive(on: DispatchQueue.main) + .receive(on: RunLoop.main) .assignLoading(to: \.state.isLoading, on: owner) .catch { _ in Empty() } .assign(to: \.state.rooms, on: owner) @@ -89,14 +95,35 @@ class HomeViewModel: ObservableObject { case .deleted: return } + case .dismissAlert: + state.creatorExitAlert.isPresented = false + state.guestExitAlert.isPresented = false - case let .exitButtonDidTap(roomID): - roomService.exitRoom(with: roomID) - .receive(on: DispatchQueue.main) + case let .exitButtonDidTap(roomDetail): + if roomDetail.isHost { + state.creatorExitAlert = (true,roomDetail) + } else { + state.guestExitAlert = (true, roomDetail) + } + case let .creatorExitButtonDidTap(roomDetail): + roomService.deleteRoom(with: roomDetail.id) + .receive(on: RunLoop.main) .assignLoading(to: \.state.isLoading, on: owner) .catch { _ in Empty()} .sink { - guard let removedIndex = owner.state.rooms.firstIndex(where: { $0.id == roomID }) + guard let removedIndex = owner.state.rooms.firstIndex(where: { $0.id == roomDetail.id }) + else { return } + owner.state.rooms.remove(at: removedIndex) + } + .store(in: cancelBag) + + case let .guestExitButtonDidTap(roomDetail): + roomService.exitRoom(with: roomDetail.id) + .receive(on: RunLoop.main) + .assignLoading(to: \.state.isLoading, on: owner) + .catch { _ in Empty()} + .sink { + guard let removedIndex = owner.state.rooms.firstIndex(where: { $0.id == roomDetail.id }) else { return } owner.state.rooms.remove(at: removedIndex) } @@ -104,7 +131,7 @@ class HomeViewModel: ObservableObject { case let .deleteHistoryButtonDidTap(roomID): roomService.deleteHistoryRoom(with: roomID) - .receive(on: DispatchQueue.main) + .receive(on: RunLoop.main) .assignLoading(to: \.state.isLoading, on: owner) .catch { _ in Empty()} .sink { diff --git a/SantaManito-iOS/SantaManito-iOS/Feature/MakeRoom/View/CheckRoomInfoView.swift b/SantaManito-iOS/SantaManito-iOS/Feature/MakeRoom/View/CheckRoomInfoView.swift index bf69d79..53c27fc 100644 --- a/SantaManito-iOS/SantaManito-iOS/Feature/MakeRoom/View/CheckRoomInfoView.swift +++ b/SantaManito-iOS/SantaManito-iOS/Feature/MakeRoom/View/CheckRoomInfoView.swift @@ -35,6 +35,7 @@ struct CheckRoomInfoView: View { } .padding(.horizontal, 16) }) + .loading(viewModel.state.isLoading) .smAlertWithInviteCode( isPresented: viewModel.state.isPresented, title: "초대 코드를 복사해서\n친구들에게 공유해 주자!", diff --git a/SantaManito-iOS/SantaManito-iOS/Feature/MakeRoom/ViewModel/CheckRoomInfoViewModel.swift b/SantaManito-iOS/SantaManito-iOS/Feature/MakeRoom/ViewModel/CheckRoomInfoViewModel.swift index 7b63538..b4f9a80 100644 --- a/SantaManito-iOS/SantaManito-iOS/Feature/MakeRoom/ViewModel/CheckRoomInfoViewModel.swift +++ b/SantaManito-iOS/SantaManito-iOS/Feature/MakeRoom/ViewModel/CheckRoomInfoViewModel.swift @@ -20,6 +20,7 @@ class CheckRoomInfoViewModel: ObservableObject { struct State { var isPresented: Bool = false + var isLoading: Bool = false } //MARK: - Dependency @@ -66,6 +67,8 @@ class CheckRoomInfoViewModel: ObservableObject { let request = CreateRoomRequest(roomInfo, missionList) // TODO: 미션 로직 수정 roomService.createRoom(request: request) .catch { _ in Empty() } + .receive(on: RunLoop.main) + .assignLoading(to: \.state.isLoading, on: self) .sink { inviteCode in owner.inviteCode = inviteCode owner.state.isPresented = true diff --git a/SantaManito-iOS/SantaManito-iOS/Feature/MakeRoom/ViewModel/EditRoomInfoViewModel.swift b/SantaManito-iOS/SantaManito-iOS/Feature/MakeRoom/ViewModel/EditRoomInfoViewModel.swift index 91d222f..fb5b2fb 100644 --- a/SantaManito-iOS/SantaManito-iOS/Feature/MakeRoom/ViewModel/EditRoomInfoViewModel.swift +++ b/SantaManito-iOS/SantaManito-iOS/Feature/MakeRoom/ViewModel/EditRoomInfoViewModel.swift @@ -8,8 +8,6 @@ import Foundation import Combine -//TODO: 서버통신 되기 전에 description 어떻게 설정할지 고민 - final class EditRoomInfoViewModel: ObservableObject { //MARK: Action, State @@ -136,7 +134,8 @@ final class EditRoomInfoViewModel: ObservableObject { case .editButtonDidTap: guard let roomID = viewType.roomID else { return } - roomService.editRoomInfo(with: roomID, info: roomInfo) //TODO: + roomService.editRoomInfo(with: roomID, info: roomInfo) + .receive(on: RunLoop.main) .catch { _ in Empty() } .sink { [weak self] _ in self?.navigationRouter.pop() diff --git a/SantaManito-iOS/SantaManito-iOS/Feature/MatchRoom/ViewModel/FinishViewModel.swift b/SantaManito-iOS/SantaManito-iOS/Feature/MatchRoom/ViewModel/FinishViewModel.swift index 6ece3e1..3e2c8b8 100644 --- a/SantaManito-iOS/SantaManito-iOS/Feature/MatchRoom/ViewModel/FinishViewModel.swift +++ b/SantaManito-iOS/SantaManito-iOS/Feature/MatchRoom/ViewModel/FinishViewModel.swift @@ -54,7 +54,7 @@ class FinishViewModel: ObservableObject { var members: [Member] { roomInfo.members } var member: Member { - guard let 내가마니또인멤버Index = roomInfo.members.firstIndex(where: { $0.manitto?.id == UserDefaultsService.userID}) + guard let 내가마니또인멤버Index = roomInfo.members.firstIndex(where: { $0.manitto?.id == UserDefaultsService.shared.userID}) else { return .init(santa: .stub1) } return roomInfo.members[내가마니또인멤버Index] } @@ -70,8 +70,8 @@ class FinishViewModel: ObservableObject { //MARK: Dependency - private var roomService: RoomServiceType - private var navigationRouter: NavigationRoutableType + private let roomService: RoomServiceType + private let navigationRouter: NavigationRoutableType //MARK: Init @@ -103,6 +103,7 @@ class FinishViewModel: ObservableObject { case .deleteRoomButtonDidTap: roomService.exitRoom(with: state.roomInfo.id) .catch { _ in Empty() } + .receive(on: RunLoop.main) .sink(receiveValue: { [weak self] _ in self?.navigationRouter.popToRootView() }) diff --git a/SantaManito-iOS/SantaManito-iOS/Feature/MatchRoom/ViewModel/MatchingResultViewModel.swift b/SantaManito-iOS/SantaManito-iOS/Feature/MatchRoom/ViewModel/MatchingResultViewModel.swift index 74e4147..f14ee05 100644 --- a/SantaManito-iOS/SantaManito-iOS/Feature/MatchRoom/ViewModel/MatchingResultViewModel.swift +++ b/SantaManito-iOS/SantaManito-iOS/Feature/MatchRoom/ViewModel/MatchingResultViewModel.swift @@ -29,7 +29,7 @@ class MatchingResultViewModel: ObservableObject { } } fileprivate var member: Member { - guard let 내가마니또인멤버Index = roomInfo.members.firstIndex(where: { $0.manitto?.id == UserDefaultsService.userID}) + guard let 내가마니또인멤버Index = roomInfo.members.firstIndex(where: { $0.manitto?.id == UserDefaultsService.shared.userID}) else { return .init(santa: .stub1) } return roomInfo.members[내가마니또인멤버Index] } diff --git a/SantaManito-iOS/SantaManito-iOS/Feature/MatchRoom/ViewModel/MatchingViewModel.swift b/SantaManito-iOS/SantaManito-iOS/Feature/MatchRoom/ViewModel/MatchingViewModel.swift index f77e29e..0901bdd 100644 --- a/SantaManito-iOS/SantaManito-iOS/Feature/MatchRoom/ViewModel/MatchingViewModel.swift +++ b/SantaManito-iOS/SantaManito-iOS/Feature/MatchRoom/ViewModel/MatchingViewModel.swift @@ -58,6 +58,7 @@ class MatchingViewModel: ObservableObject { .flatMap(roomService.matchRoom) .map { owner.roomID } .flatMap(roomService.getRoomInfo) + .receive(on: RunLoop.main) .assignLoading(to: \.state.isAnimating, on: owner) .catch { _ in Empty() } .sink { roomDetail in diff --git a/SantaManito-iOS/SantaManito-iOS/Feature/MyPage/EditUsername/EditUsernameView.swift b/SantaManito-iOS/SantaManito-iOS/Feature/MyPage/EditUsername/EditUsernameView.swift index e68dbf3..70b6421 100644 --- a/SantaManito-iOS/SantaManito-iOS/Feature/MyPage/EditUsername/EditUsernameView.swift +++ b/SantaManito-iOS/SantaManito-iOS/Feature/MyPage/EditUsername/EditUsernameView.swift @@ -103,6 +103,7 @@ struct EditUsernameView: View { viewModel.send(.deleteAccountButtonDidTap) } label: { Text("회원탈퇴") + .font(.medium_16) .foregroundStyle(.smLightgray) .underline() } @@ -126,6 +127,10 @@ struct EditUsernameView: View { viewModel.send(.onAppear) } .loading(viewModel.state.isLoading) + .smAlert(isPresented: viewModel.state.isDeleteAccountAlertPresented, + title: "탈퇴하면 소중한 추억이 담긴 마니또 내역을\n다시 확인할 수 없어. 그래도 괜찮아?", + primaryButton: ("탈퇴하기", {viewModel.send(.alertDeleteButtonDidTap)}), + secondaryButton: ("머무르기", { viewModel.send(.alertDismissDidTap)})) } diff --git a/SantaManito-iOS/SantaManito-iOS/Feature/MyPage/EditUsername/EditUsernameViewModel.swift b/SantaManito-iOS/SantaManito-iOS/Feature/MyPage/EditUsername/EditUsernameViewModel.swift index c3f4f26..4913430 100644 --- a/SantaManito-iOS/SantaManito-iOS/Feature/MyPage/EditUsername/EditUsernameViewModel.swift +++ b/SantaManito-iOS/SantaManito-iOS/Feature/MyPage/EditUsername/EditUsernameViewModel.swift @@ -14,11 +14,14 @@ final class EditUsernameViewModel: ObservableObject { case onAppear case doneButtonDidTap case deleteAccountButtonDidTap + case alertDeleteButtonDidTap + case alertDismissDidTap } struct State { var isLoading = false var doneButtonDisabled = true + var isDeleteAccountAlertPresented = false } //MARK: - Dependency @@ -26,7 +29,7 @@ final class EditUsernameViewModel: ObservableObject { private let navigationRouter: NavigationRoutableType private let windowRouter: WindowRoutableType private let userService: UserServiceType - private let userDefaultsService: UserDefaultsServiceType.Type + private let userDefaultsService: UserDefaultsServiceType @Published private(set) var state = State() @Published var username: String = "" @@ -37,7 +40,7 @@ final class EditUsernameViewModel: ObservableObject { //MARK: - Init init(userService: UserServiceType, - userDefaultsService: UserDefaultsServiceType.Type = UserDefaultsService.self, + userDefaultsService: UserDefaultsServiceType = UserDefaultsService.shared, navigationRouter: NavigationRoutableType, windowRouter: WindowRoutableType ) { @@ -58,7 +61,7 @@ final class EditUsernameViewModel: ObservableObject { switch action { case .onAppear: userService.getUser(with: userDefaultsService.userID) - .receive(on: DispatchQueue.main) + .receive(on: RunLoop.main) .assignLoading(to: \.state.isLoading, on: owner) .map { $0.username } .catch { _ in Empty() } @@ -70,22 +73,26 @@ final class EditUsernameViewModel: ObservableObject { case .doneButtonDidTap: userService.editUsername(with: username) - .receive(on: DispatchQueue.main) + .receive(on: RunLoop.main) .assignLoading(to: \.state.isLoading, on: owner) .catch { _ in Empty() } .sink { [weak self] username in self?.navigationRouter.popToRootView() } .store(in: cancelBag) - case .deleteAccountButtonDidTap: + state.isDeleteAccountAlertPresented = true + case .alertDismissDidTap: + state.isDeleteAccountAlertPresented = false + case .alertDeleteButtonDidTap: + state.isDeleteAccountAlertPresented = false userService.deleteAccount() - .receive(on: DispatchQueue.main) + .receive(on: RunLoop.main) .assignLoading(to: \.state.isLoading, on: owner) .catch { _ in Empty() } - .receive(on: DispatchQueue.main) + .receive(on: RunLoop.main) .sink { _ in - owner.userDefaultsService.reset() + owner.userDefaultsService.removeAll() owner.windowRouter.switch(to: .splash) owner.navigationRouter.popToRootView() } diff --git a/SantaManito-iOS/SantaManito-iOS/Feature/Onboarding/OnboardingViewModel.swift b/SantaManito-iOS/SantaManito-iOS/Feature/Onboarding/OnboardingViewModel.swift index 5c31f4a..8eb23a4 100644 --- a/SantaManito-iOS/SantaManito-iOS/Feature/Onboarding/OnboardingViewModel.swift +++ b/SantaManito-iOS/SantaManito-iOS/Feature/Onboarding/OnboardingViewModel.swift @@ -60,7 +60,7 @@ final class OnboardingViewModel: ObservableObject { private let appService: AppServiceType private let authService: AuthenticationServiceType - private let userDefaultsService: UserDefaultsServiceType.Type + private var userDefaultsService: UserDefaultsServiceType private var windowRouter: WindowRoutableType //MARK: - Properties @@ -75,7 +75,7 @@ final class OnboardingViewModel: ObservableObject { init( appService: AppServiceType, authService: AuthenticationServiceType, - userDefaultsService: UserDefaultsServiceType.Type = UserDefaultsService.self, + userDefaultsService: UserDefaultsServiceType = UserDefaultsService.shared, windowRouter: WindowRoutableType ) { self.appService = appService @@ -113,7 +113,7 @@ final class OnboardingViewModel: ObservableObject { .sink { auth in owner.userDefaultsService.userID = auth.userID owner.userDefaultsService.accessToken = auth.accessToken - owner.windowRouter.switch(to: .main) + owner.windowRouter.switch(to: .main) } .store(in: cancelBag) } diff --git a/SantaManito-iOS/SantaManito-iOS/Feature/Splash/SplashViewModel.swift b/SantaManito-iOS/SantaManito-iOS/Feature/Splash/SplashViewModel.swift index 007c279..d7c2001 100644 --- a/SantaManito-iOS/SantaManito-iOS/Feature/Splash/SplashViewModel.swift +++ b/SantaManito-iOS/SantaManito-iOS/Feature/Splash/SplashViewModel.swift @@ -26,7 +26,7 @@ class SplashViewModel: ObservableObject { private let appService: AppServiceType private let authService: AuthenticationServiceType - private let userDefaultsService: UserDefaultsServiceType.Type + private var userDefaultsService: UserDefaultsServiceType private let remoteConfigService: RemoteConfigServiceType private(set) var windowRouter: WindowRoutableType @@ -41,7 +41,7 @@ class SplashViewModel: ObservableObject { appService: AppServiceType, remoteConfigService: RemoteConfigServiceType, authService: AuthenticationServiceType, - userDefaultsService: UserDefaultsServiceType.Type = UserDefaultsService.self, + userDefaultsService: UserDefaultsServiceType = UserDefaultsService.shared, windowRouter: WindowRoutableType ) { self.appService = appService @@ -60,7 +60,7 @@ class SplashViewModel: ObservableObject { case .onAppear: appService.isLatestVersion() - .receive(on: DispatchQueue.main) + .receive(on: RunLoop.main) .sink { isLatestVersion in guard isLatestVersion else { @@ -69,10 +69,9 @@ class SplashViewModel: ObservableObject { } Just(owner.appService.getDeviceIdentifier() ?? "" ) - .receive(on: DispatchQueue.main) .filter { !$0.isEmpty } .flatMap(owner.authService.signIn) - .receive(on: DispatchQueue.main) + .receive(on: RunLoop.main) .map { owner.userDefaultsService.userID = $0.userID owner.userDefaultsService.accessToken = $0.accessToken @@ -85,11 +84,10 @@ class SplashViewModel: ObservableObject { .store(in: owner.cancelBag) owner.remoteConfigService.getServerCheck() - .receive(on: DispatchQueue.main) .filter { $0 } .map { _ in } .flatMap(owner.remoteConfigService.getServerCheckMessage) - .receive(on: DispatchQueue.main) + .receive(on: RunLoop.main) .catch { _ in Empty() } .map { (true, $0 ) } .assign(to: \.state.serverCheckAlert, on: owner) diff --git a/SantaManito-iOS/SantaManito-iOS/Networks/Foundation/APIConstants.swift b/SantaManito-iOS/SantaManito-iOS/Networks/Foundation/APIConstants.swift index 5b5b7d9..903d9b9 100644 --- a/SantaManito-iOS/SantaManito-iOS/Networks/Foundation/APIConstants.swift +++ b/SantaManito-iOS/SantaManito-iOS/Networks/Foundation/APIConstants.swift @@ -30,7 +30,7 @@ extension APIConstants{ static var hasTokenHeader: Dictionary { return [ contentType: applicationJSON, - auth : "Bearer " + UserDefaultsService.accessToken + auth : "Bearer " + UserDefaultsService.shared.accessToken ] } } diff --git a/SantaManito-iOS/SantaManito-iOS/Networks/Foundation/BaseService.swift b/SantaManito-iOS/SantaManito-iOS/Networks/Foundation/BaseService.swift index ac37bbd..6f142b9 100644 --- a/SantaManito-iOS/SantaManito-iOS/Networks/Foundation/BaseService.swift +++ b/SantaManito-iOS/SantaManito-iOS/Networks/Foundation/BaseService.swift @@ -68,10 +68,10 @@ extension BaseService { .mapError { _ in SMNetworkError.invalidResponse(.invalidStatusCode(code: response.response.statusCode)) } .flatMap { response in Fail(error: SMNetworkError.invalidResponse(.invalidStatusCode( - code: response.statusCode, - data: response.data - ) - ) + code: response.statusCode, + data: response.data + ) + ) ).eraseToAnyPublisher() } .eraseToAnyPublisher() @@ -83,13 +83,8 @@ extension BaseService { private func decode(data: Data, target: API) -> AnyPublisher { let decoder = JSONDecoder() let formatter = DateFormatter() - formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss" - formatter.timeZone = TimeZone(secondsFromGMT: -1 * 9 * 60 * 60) // 한국 시간 (KST) UTC+9로 설정 - // - 를 한 이유는 서버엔 UTC+9기준으로 저장되지만 - // iOS에서 Date는 UTC 기준으로 설정되기에 - // 서버의 UTC + 9 를 UTC 기준으로 변환 후 - // iOS 내 모든 Date는 UTC 타임을 기준으로 설정하게 한다. - // 단, Date의 timeZone은 Asia/Seoul로 설정하여 유저에겐 UTC +9 시간을 보여준다. + formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSz" + formatter.timeZone = TimeZone(secondsFromGMT: 0) // UTC기준으로 디코딩 decoder.dateDecodingStrategy = .formatted(formatter) return Just(data) diff --git a/SantaManito-iOS/SantaManito-iOS/Networks/Foundation/ParameterEncoding.swift b/SantaManito-iOS/SantaManito-iOS/Networks/Foundation/ParameterEncoding.swift index 2737d93..9b6e1fc 100644 --- a/SantaManito-iOS/SantaManito-iOS/Networks/Foundation/ParameterEncoding.swift +++ b/SantaManito-iOS/SantaManito-iOS/Networks/Foundation/ParameterEncoding.swift @@ -30,11 +30,11 @@ extension ParameterEncodable { guard let parameters else { return Fail(error: .emptyParameters).eraseToAnyPublisher() } guard let url else { return Fail(error: .missingURL).eraseToAnyPublisher() } -// TODO: 2024.10.09 수정. 확인 했다면 주석 지워도됨. to 히디 from 석우 -// let data = try JSONSerialization.data(withJSONObject: parameters) -// guard JSONSerialization.isValidJSONObject(parameters) else { -// return Fail(error: .invalidJSON).eraseToAnyPublisher() -// } + // TODO: 2024.10.09 수정. 확인 했다면 주석 지워도됨. to 히디 from 석우 + // let data = try JSONSerialization.data(withJSONObject: parameters) + // guard JSONSerialization.isValidJSONObject(parameters) else { + // return Fail(error: .invalidJSON).eraseToAnyPublisher() + // } return Just((parameters, url)) .setFailureType(to: SMNetworkError.ParameterEncoding.self) @@ -65,11 +65,19 @@ public struct URLEncoding: ParameterEncodable { public struct JSONEncoding: ParameterEncodable { func encode(_ request: URLRequest, with parameters: Encodable?) -> AnyPublisher { var request = request + let encoder = JSONEncoder() + let formatter = DateFormatter() + formatter.dateFormat = "yyyy-MM-dd HH:mm:ss" + formatter.timeZone = TimeZone(secondsFromGMT: 0) // UTC 기준으로 인코딩 + encoder.dateEncodingStrategy = .formatted(formatter) + return checkValidURLData(parameters, request.url) .tryMap { parameters, _ -> URLRequest in do { - let data = try JSONEncoder().encode(parameters) + let data = try encoder.encode(parameters) request.httpBody = data +// let s = try JSONSerialization.jsonObject(with: data) +// print(s) return request } catch { throw SMNetworkError.invalidRequest(.parameterEncodingFailed(.jsonEncodingFailed)) diff --git a/SantaManito-iOS/SantaManitoUnitTests/DateExtensionTests.swift b/SantaManito-iOS/SantaManitoUnitTests/DateExtensionTests.swift index a34c1d4..550d02f 100644 --- a/SantaManito-iOS/SantaManitoUnitTests/DateExtensionTests.swift +++ b/SantaManito-iOS/SantaManitoUnitTests/DateExtensionTests.swift @@ -21,10 +21,9 @@ final class DateParsingTests: XCTestCase { func test_iso형식이_맞는가() { // Given - let dateString = "2000-04-15T11:13:00Z" + let dateString = "2000-04-15T11:13:00.111Z" let formatter = ISO8601DateFormatter() - - + formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds] // When let date = formatter.date(from: dateString) @@ -33,21 +32,54 @@ final class DateParsingTests: XCTestCase { XCTAssertTrue(date != nil) } - func test_custom형식으로_iso형식을_파싱이_가능한가() { - + func test_서버Response의_dateformat을_정상적으로_파싱이_가능한가() { // Given - let dateString = "2000-04-15T11:13:00Z" + let stringFromServer = "2000-04-15T11:13:00.111Z" let formatter = DateFormatter() - formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssz" - + formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSz" // When - let date = formatter.date(from: dateString) + let date = formatter.date(from: stringFromServer) //Then XCTAssertTrue(date != nil) } + func test_서버Request로_보낼_Date를_정상적으로_인코딩하는가() throws { + // Given + struct Request: Codable { + let date: Date + } + let currentDate = Date() + let request = Request(date: Date()) + + let encoder = JSONEncoder() + let formatter = DateFormatter() + formatter.dateFormat = "yyyy-MM-dd HH:mm:ss" + encoder.dateEncodingStrategy = .formatted(formatter) + + // When + guard let data = try? encoder.encode(request) else { + XCTFail("Encoding failed") + return + } + + // Then + // data를 JSON 형식의 String으로 변환하여 확인 + if let jsonString = String(data: data, encoding: .utf8) { + print("Encoded JSON:", jsonString) + + // date를 포맷에 맞게 String으로 변환 + let expectedDateString = formatter.string(from: currentDate) + + // 실제 JSON에 포함된 date 값이 예상하는 포맷과 일치하는지 확인 + XCTAssertTrue(jsonString.contains(expectedDateString), "Encoded date does not match the expected format") + } else { + XCTFail("Failed to convert data to string") + } + } + + //MARK: - UTC +9 기준 func test_between함수는_UTC_9날짜를_한국날짜_기준으로_1일후를_반환하는가() { diff --git a/SantaManito-iOS/SantaManitoUnitTests/RoomEntityTests/RoomStateFactoryTests.swift b/SantaManito-iOS/SantaManitoUnitTests/RoomEntityTests/RoomStateFactoryTests.swift index 146d4c6..d9780bd 100644 --- a/SantaManito-iOS/SantaManitoUnitTests/RoomEntityTests/RoomStateFactoryTests.swift +++ b/SantaManito-iOS/SantaManitoUnitTests/RoomEntityTests/RoomStateFactoryTests.swift @@ -12,125 +12,133 @@ // // let sut = RoomStateFactory.self // -// override func setUp() { -// // Put setup code here. This method is called before the invocation of each test method in the class. -// } -// -// override func tearDown() { -// // Put teardown code here. This method is called after the invocation of each test method in the class. -// } -// -// func test_매칭_전_방장이_삭제한_경우_상태가_삭제됨으로_변경되는지() { -// // Given -// let dto = RoomDetailResponse(id: "", roomName: "", invitationCode: "", -// expirationDate: Date().addingTimeInterval(-3), -// matchingDate: nil, -// deletedByCreatorDate: Date().addingTimeInterval(-1), -// creator: .init(id: "", username: ""), missions: [], members: []) -// -// // When -// let state = sut.create(dto) -// -// // Then -// XCTAssertEqual(state, .deleted) -// } -// -// func test_매칭_이후_방장이_삭제한_경우_상태가_삭제됨으로_변경되는지() { -// // Given -// let dto = RoomDetailResponse(id: "", roomName: "", invitationCode: "", -// expirationDate: Date().addingTimeInterval(-3), -// matchingDate: Date().addingTimeInterval(-2), -// deletedByCreatorDate: Date().addingTimeInterval(-1), -// creator: .init(id: "", username: ""), missions: [], members: []) -// -// // When -// let state = sut.create(dto) -// -// // Then -// XCTAssertEqual(state, .deleted) -// } -// -// func test_매칭_잔_만료일이_지난_경우_상태가_완료됨으로_변경되는지() { -// // Given -// let dto = RoomDetailResponse(id: "", roomName: "", invitationCode: "", -// expirationDate: Date().addingTimeInterval(-3), -// matchingDate: nil, -// deletedByCreatorDate: nil, -// creator: .init(id: "", username: ""), missions: [], members: []) -// -// // When -// let state = sut.create(dto) -// -// // Then -// XCTAssertEqual(state, .completed) -// } -// -// func test_매칭_후_만료일이_지난_경우_상태가_완료됨으로_변경되는지() { -// // Given -// let dto = RoomDetailResponse(id: "", roomName: "", invitationCode: "", -// expirationDate: Date().addingTimeInterval(-3), -// matchingDate: Date().addingTimeInterval(-2), -// deletedByCreatorDate: nil, -// creator: .init(id: "", username: ""), missions: [], members: []) -// -// // When -// let state = sut.create(dto) -// -// // Then -// XCTAssertEqual(state, .completed) -// } -// -// -// func test_매칭_전_만료일이_지난_경우_상태가_완료됨으로_변경되는지() { -// // Given -// let dto = RoomDetailResponse(id: "", roomName: "", invitationCode: "", -// expirationDate: Date().addingTimeInterval(-3), -// matchingDate: nil, -// deletedByCreatorDate: nil, -// creator: .init(id: "", username: ""), missions: [], members: []) -// -// // When -// let state = sut.create(dto) -// -// // Then -// XCTAssertEqual(state, .completed) -// } -// -// func test_만료일이_남은_경우_매칭_전이면_상태가_시작전으로_변경되는지() { -// // Given -// let dto = RoomDetailResponse(id: "", roomName: "", invitationCode: "", -// expirationDate: Date().addingTimeInterval(+3), -// matchingDate: nil, -// deletedByCreatorDate: nil, -// creator: .init(id: "", username: ""), missions: [], members: []) -// -// // When -// let state = sut.create(dto) -// -// // Then -// XCTAssertEqual(state, .notStarted) -// } -// -// -// func test_만료일이_남은_경우_매칭_후면_상태가_진행_중으로_변경되는지() { -// // Given -// let dto = RoomDetailResponse(id: "", roomName: "", invitationCode: "", -// expirationDate: Date().addingTimeInterval(+3), -// matchingDate: Date().addingTimeInterval(-1), -// deletedByCreatorDate: nil, -// creator: .init(id: "", username: ""), missions: [], members: []) -// -// // When -// let state = sut.create(dto) -// -// // Then -// XCTAssertEqual(state, .inProgress) -// } -// -// -// -// -// -// -// -//} + +import XCTest +@testable import SantaManito_iOS + +final class RoomStateFactoryTests: XCTestCase { + + let sut = RoomStateFactory.self + + override func setUp() { + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func test_매칭_전_방장이_삭제한_경우_상태가_삭제됨으로_변경되는지() { + // Given + let dto = RoomDetailResponse(id: "", roomName: "", invitationCode: "", createdAt: Date().addingTimeInterval(-4), + expirationDate: Date().addingTimeInterval(-3), + matchingDate: nil, + deletedByCreatorDate: Date().addingTimeInterval(-1), + creator: .init(id: "", username: ""), missions: [], members: []) + + // When + let state = sut.create(dto) + + // Then + XCTAssertEqual(state, .deleted) + } + + func test_매칭_이후_방장이_삭제한_경우_상태가_삭제됨으로_변경되는지() { + // Given + let dto = RoomDetailResponse(id: "", roomName: "", invitationCode: "",createdAt: Date().addingTimeInterval(-4), + expirationDate: Date().addingTimeInterval(-3), + matchingDate: Date().addingTimeInterval(-2), + deletedByCreatorDate: Date().addingTimeInterval(-1), + creator: .init(id: "", username: ""), missions: [], members: []) + + // When + let state = sut.create(dto) + + // Then + XCTAssertEqual(state, .deleted) + } + + func test_매칭_잔_만료일이_지난_경우_상태가_완료됨으로_변경되는지() { + // Given + let dto = RoomDetailResponse(id: "", roomName: "", invitationCode: "", createdAt: Date().addingTimeInterval(-4), + expirationDate: Date().addingTimeInterval(-3), + matchingDate: nil, + deletedByCreatorDate: nil, + creator: .init(id: "", username: ""), missions: [], members: []) + + // When + let state = sut.create(dto) + + // Then + XCTAssertEqual(state, .completed) + } + + func test_매칭_후_만료일이_지난_경우_상태가_완료됨으로_변경되는지() { + // Given + let dto = RoomDetailResponse(id: "", roomName: "", invitationCode: "", createdAt: Date().addingTimeInterval(-4), + expirationDate: Date().addingTimeInterval(-3), + matchingDate: Date().addingTimeInterval(-2), + deletedByCreatorDate: nil, + creator: .init(id: "", username: ""), missions: [], members: []) + + // When + let state = sut.create(dto) + + // Then + XCTAssertEqual(state, .completed) + } + + + func test_매칭_전_만료일이_지난_경우_상태가_완료됨으로_변경되는지() { + // Given + let dto = RoomDetailResponse(id: "", roomName: "", invitationCode: "", createdAt: Date().addingTimeInterval(-4), + expirationDate: Date().addingTimeInterval(-3), + matchingDate: nil, + deletedByCreatorDate: nil, + creator: .init(id: "", username: ""), missions: [], members: []) + + // When + let state = sut.create(dto) + + // Then + XCTAssertEqual(state, .completed) + } + + func test_만료일이_남은_경우_매칭_전이면_상태가_시작전으로_변경되는지() { + // Given + let dto = RoomDetailResponse(id: "", roomName: "", invitationCode: "", createdAt: Date().addingTimeInterval(-4), + expirationDate: Date().addingTimeInterval(+3), + matchingDate: nil, + deletedByCreatorDate: nil, + creator: .init(id: "", username: ""), missions: [], members: []) + + // When + let state = sut.create(dto) + + // Then + XCTAssertEqual(state, .notStarted) + } + + + func test_만료일이_남은_경우_매칭_후면_상태가_진행_중으로_변경되는지() { + // Given + let dto = RoomDetailResponse(id: "", roomName: "", invitationCode: "", createdAt: Date().addingTimeInterval(-4), + expirationDate: Date().addingTimeInterval(+3), + matchingDate: Date().addingTimeInterval(-1), + deletedByCreatorDate: nil, + creator: .init(id: "", username: ""), missions: [], members: []) + + // When + let state = sut.create(dto) + + // Then + XCTAssertEqual(state, .inProgress) + } + + + + + + + +} diff --git a/SantaManito-iOS/SantaManitoUnitTests/RoomServiceServerTests.swift b/SantaManito-iOS/SantaManitoUnitTests/RoomServiceServerTests.swift index 4a5bcb9..025d73a 100644 --- a/SantaManito-iOS/SantaManitoUnitTests/RoomServiceServerTests.swift +++ b/SantaManito-iOS/SantaManitoUnitTests/RoomServiceServerTests.swift @@ -18,7 +18,7 @@ final class RoomServiceServerTests: XCTestCase { cancelBag = CancelBag() sut = RoomService() - UserDefaultsService.accessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImFlYjg0Yzg3LWNkZmEtNDBhMS1hNGY3LTI1YTQwOTNjMDcyMCIsImlhdCI6MTcyODYyMTcxMywiZXhwIjoxNzM2Mzk3NzEzfQ.7kdOdP5YxtkIzXa2TMYgifcUWjoQI7it71u8KM-Paok" + UserDefaultsService.shared.accessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImFlYjg0Yzg3LWNkZmEtNDBhMS1hNGY3LTI1YTQwOTNjMDcyMCIsImlhdCI6MTcyODYyMTcxMywiZXhwIjoxNzM2Mzk3NzEzfQ.7kdOdP5YxtkIzXa2TMYgifcUWjoQI7it71u8KM-Paok" } override func tearDown() {