Skip to content

Commit

Permalink
Merge pull request #86 from manito-project/feat/#79
Browse files Browse the repository at this point in the history
Feat/#79 - match 하지 않은 채 만료된 방 입장 시 로직 처리
  • Loading branch information
meltsplit authored Nov 2, 2024
2 parents c26af44 + e4a3471 commit 35a2cb4
Show file tree
Hide file tree
Showing 9 changed files with 122 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Foundation
struct RoomStateFactory {
static func create(_ dto: RoomDetailResponse) -> RoomState {
guard dto.deletedByCreatorDate == nil else { return .deleted }
guard dto.expirationDate > Date() else { return .completed }
guard dto.expirationDate > Date() else { return dto.matchingDate == nil ? .expired : .completed }
guard dto.matchingDate != nil else { return .notStarted }
return .inProgress
}
Expand Down
67 changes: 58 additions & 9 deletions SantaManito-iOS/SantaManito-iOS/Data/Entity/Room/RoomDetail.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,45 @@ struct RoomDetail: Hashable {
var expirationDateToString: String {
expirationDate.toDueDateWithoutYear
}

var me: Member {
members.filter { $0.santa.id == UserDefaultsService.shared.userID}.first ?? .init(santa: .stub1, manitto: .stub1)
}

var myMission: Mission? {
mission.filter { $0.id == me.santa.missionId }.first
}

}

extension RoomDetail: Comparable {

/// 1. 방 상태별 정렬 로직
/// 게임 참여중(진행중 > 매칭 대기중) > 게임 참여 불가(종료 > 만료) > 삭제 및 나가기(방장에 의해 삭제된 방)
///
/// 2. 방 상태가 동일한 경우 우선 순위
/// i. 진행중: ’결과 공개 예정일’ 기준 오름차순(’공개 n일 전’의 n이 작을 수록 상위 노출)
/// ii. 매칭 대기중:방장의 방 생성 일자 내림차순(최신 생성 방 상위 노출)
/// iii. 종료(결과 공개): 방 종료 일자 내림차순(최근 종료된 방이 상위 노출)

/// iv. 기한 만료: 방장의 방 생성 일자 내림차순(최신 생성 방 상위 노출)

/// v. 방장에 의해 삭제된 방:방 생성 일자 내림차순(최신 생성 방 상위 노출)
/// vi. 나가기 처리: 비노출
///
/// 결론: 진행중 > 매칭 대기중 > 종료(결과 공개) > 기한 만료 > 방장에 의한 삭제
public static func < (lhs: Self, rhs: Self) -> Bool {
guard lhs.state == rhs.state else { return lhs.state < rhs.state }
switch lhs.state {
case .inProgress: return lhs.expirationDate < rhs.expirationDate
case .notStarted: return lhs.createdAt > rhs.createdAt
case .completed: return lhs.expirationDate < rhs.expirationDate
case .expired: return lhs.createdAt > rhs.createdAt
case .deleted: return lhs.createdAt > rhs.createdAt
}

}
}


extension RoomDetail {

func toMakeRoomInfo() -> MakeRoomInfo {
Expand All @@ -56,7 +93,7 @@ extension RoomDetail {
extension RoomDetail {
static var stub1: Self {
.init(id: "roomID1",
name: "크리스마스 마니또",
name: "",
invitationCode: "초대코드1",
state: .notStarted,
creatorID: User.stub1.id,
Expand All @@ -75,13 +112,16 @@ extension RoomDetail {

static var stub2: Self {
.init(id: "roomID2",
name: "크리스마스 마니또",
name: "두글",
invitationCode: "초대코드2",
state: .inProgress,
creatorID: User.stub1.id,
creatorName: User.stub1.username,
members: .stub2,
mission: [],
mission: [.stub1,
.stub2,
.stub3,
.stub4],
createdAt: Date(),
expirationDate: Date()
)
Expand All @@ -90,13 +130,16 @@ extension RoomDetail {

static var stub3: Self {
.init(id: "roomID3",
name: "크리스마스 마니또",
name: "12345678901234567",
invitationCode: "초대코드3",
state: .inProgress,
state: .expired,
creatorID: User.stub2.id,
creatorName: User.stub2.username,
members: .stub2,
mission: [],
mission: [.stub1,
.stub2,
.stub3,
.stub4],
createdAt: Date(),
expirationDate: Date()
)
Expand All @@ -105,13 +148,16 @@ extension RoomDetail {

static var stub4: Self {
.init(id: "roomID4",
name: "크리스마스 마니또",
name: "크리스마스 마니또크리스마스 마니또",
invitationCode: "초대코드4",
state: .completed,
creatorID: User.stub1.id,
creatorName: User.stub1.username,
members: .stub3,
mission: [],
mission: [.stub1,
.stub2,
.stub3,
.stub4],
createdAt: Date(),
expirationDate: Date()
)
Expand All @@ -126,7 +172,10 @@ extension RoomDetail {
creatorID: User.stub1.id,
creatorName: User.stub1.username,
members: .stub3,
mission: [],
mission: [.stub1,
.stub2,
.stub3,
.stub4],
createdAt: Date(),
expirationDate: Date()
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,14 @@

import Foundation

enum RoomState: Hashable {
case notStarted
enum RoomState: Hashable, Comparable {

// 순서대로
case inProgress
case notStarted
case completed
case expired
case deleted


}
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ extension RoomService: RoomServiceType {
func getEnteredRooms() -> AnyPublisher<[RoomDetail], SMNetworkError> {
requestWithResult(.getEnteredAllRoom, [RoomDetailResponse].self)
.map {
$0.map { $0.toEntity() }
.sorted { $0.expirationDate < $1.expirationDate }
$0.map { $0.toEntity() }.sorted()
}
.eraseToAnyPublisher()
}
Expand Down Expand Up @@ -91,7 +90,7 @@ extension RoomService: RoomServiceType {
struct StubRoomService: RoomServiceType {
// For All
func getEnteredRooms() -> AnyPublisher<[RoomDetail], SMNetworkError> {
Just([.stub1, .stub2, .stub3, .stub4, .stub5]).setFailureType(to: SMNetworkError.self).eraseToAnyPublisher()
Just([.stub1, .stub2, .stub3, .stub4, .stub5].sorted()).setFailureType(to: SMNetworkError.self).eraseToAnyPublisher()
}

func getRoomInfo(with roomID: String) -> AnyPublisher<RoomDetail, SMNetworkError> {
Expand Down
32 changes: 27 additions & 5 deletions SantaManito-iOS/SantaManito-iOS/Feature/Home/HomeView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ fileprivate struct HomeRoomCell: View {


if roomInfo.state != .deleted {
Text(roomInfo.creatorName + "의 산타")
Text((roomInfo.me.manitto?.username ?? "-") + "의 산타")
.font(.medium_14)
.foregroundStyle(.smBlack)
.lineLimit(1)
Expand All @@ -269,7 +269,7 @@ fileprivate struct HomeRoomCell: View {
HomeRoomStateChip(state: roomInfo.state, remainingDays: roomInfo.remainingDays)
.padding(.top, 10)
} else {
Text("해당 방은 방장에 의해 삭제된 방이야")
Text("방장에 의해 삭제되어 더는 참여할 수 없는 방이야")
.font(.medium_14)
.foregroundStyle(.smDarkgray)
Spacer()
Expand All @@ -279,7 +279,7 @@ fileprivate struct HomeRoomCell: View {
Group { // 칩 하단
switch roomInfo.state {
case .inProgress, .completed:
Text(roomInfo.mission.first?.content ?? "")
Text(roomInfo.myMission?.content ?? "")
.font(.medium_14)
.foregroundStyle(.smDarkgray)
.lineLimit(2)
Expand All @@ -300,6 +300,24 @@ fileprivate struct HomeRoomCell: View {
}
.contentShape(Rectangle())
}
case .expired:
VStack {
Spacer()
Button {
viewModel.send(.exitButtonDidTap(roomDetail: roomInfo))
} label : {
Text("방 나가기")
.font(.medium_14)
.foregroundStyle(.smDarkgray)
.padding(.vertical, 6)
.padding(.horizontal, 16)
.overlay(
RoundedRectangle(cornerRadius: 4)
.stroke(Color.smDarkgray, lineWidth: 1)
)
}
.contentShape(Rectangle())
}
case .deleted:
VStack {
Spacer()
Expand Down Expand Up @@ -327,7 +345,7 @@ fileprivate struct HomeRoomCell: View {
}
.frame(width: width)
.frame(height: 240)
.background(roomInfo.state == .deleted
.background(roomInfo.state == .deleted || roomInfo.state == .expired
? .smLightbg
: .smWhite)
.clipShape(RoundedRectangle(cornerRadius: 10))
Expand All @@ -354,7 +372,9 @@ fileprivate struct HomeRoomStateChip: View {
case .inProgress:
"공개 \(remainingDays)일 전"
case .completed:
"결과 발표 완료"
"결과 공개"
case .expired:
"기한 만료"
case .deleted:
"삭제"
}
Expand All @@ -368,6 +388,8 @@ fileprivate struct HomeRoomStateChip: View {
return .smRed
case .completed:
return .smLightgray
case .expired:
return .smLightgray
case .deleted:
return .clear
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ class HomeViewModel: ObservableObject {
navigationRouter.push(to: .matchedRoom(roomInfo: roomDetail))
case .completed:
navigationRouter.push(to: .finish(roomDetail: roomDetail))
case .expired: return
case .deleted: return

}

case .dismissAlert:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class MatchingResultViewModel: ObservableObject {
}

struct State {
fileprivate var roomInfo: RoomDetail = .stub1
fileprivate var roomInfo: RoomDetail

var roomName: String { roomInfo.name }
var description: String {
Expand All @@ -28,31 +28,18 @@ class MatchingResultViewModel: ObservableObject {
"\(roomInfo.expirationDate.toDueDateTime)까지 진행되는 마니또"
}
}
fileprivate var member: Member {
guard let 내가마니또인멤버Index = roomInfo.members.firstIndex(where: { $0.manitto?.id == UserDefaultsService.shared.userID})
else { return .init(santa: .stub1) }
return roomInfo.members[내가마니또인멤버Index]
}

var me: SantaUser {
member.santa
}

var isAnimating: Bool = false

fileprivate var matchedInfo: (User, Mission) = (.stub1, .stub1)

var mannito: User { matchedInfo.0 }
var mission: String { matchedInfo.1.content }
var me: SantaUser { roomInfo.me.santa }
var mannito: User { roomInfo.me.manitto ?? .stub1 }
var mission: String { roomInfo.myMission?.content ?? "미션이 없습니다." }
}

//MARK: Dependency

private var roomService: RoomServiceType
private var navigationRouter: NavigationRoutable

private let roomDetail: RoomDetail

//MARK: Init

init(
Expand All @@ -62,12 +49,12 @@ class MatchingResultViewModel: ObservableObject {
) {
self.roomService = roomService
self.navigationRouter = navigationRouter
self.roomDetail = roomInfo
self.state = State(roomInfo: roomInfo)
}

//MARK: Properties

@Published private(set) var state = State()
@Published private(set) var state: State
private let cancelBag = CancelBag()

//MARK: Methods
Expand All @@ -78,12 +65,13 @@ class MatchingResultViewModel: ObservableObject {

switch action {
case .onAppear:
Just(roomDetail.id)
.flatMap(roomService.getMyInfo)
.assignLoading(to: \.state.isAnimating, on: owner)
.catch { _ in Empty() }
.assign(to: \.state.matchedInfo, on: owner)
.store(in: cancelBag)
return
// Just(state.roomInfo.id)
// .flatMap(roomService.getMyInfo)
// .assignLoading(to: \.state.isAnimating, on: owner)
// .catch { _ in Empty() }
// .assign(to: \.state.matchedInfo, on: owner)
// .store(in: cancelBag)

case .goHomeButtonDidTap:
navigationRouter.popToRootView()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ final class RoomDetailEntityTests: XCTestCase {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}

// 기획서 정렬 로직: 진행중 > 매칭 대기중 > 종료(결과 공개) > 기한 만료 > 방장에 의한 삭제
func test_RoomState_정렬이_잘되는가() {
let expected: [RoomState] = [.inProgress, .notStarted, .completed, .expired, .deleted]

let states1 : [RoomState] = [.completed, .deleted, .expired, .inProgress, .notStarted]
let states2 : [RoomState] = states1.reversed()

XCTAssertEqual(states1.sorted(), expected)
XCTAssertEqual(states2.sorted(), expected)
}



Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ final class RoomStateFactoryTests: XCTestCase {
XCTAssertEqual(state, .deleted)
}

func test_매칭_잔_만료일이_지난_경우_상태가_완료됨으로_변경되는지() {
func test_매칭_전_만료일이_지난_경우_상태가_만료됨으로_변경되는지() {
// Given
let dto = RoomDetailResponse(id: "", roomName: "", invitationCode: "", createdAt: Date().addingTimeInterval(-4),
expirationDate: Date().addingTimeInterval(-3),
Expand All @@ -70,7 +70,7 @@ final class RoomStateFactoryTests: XCTestCase {
let state = sut.create(dto)

// Then
XCTAssertEqual(state, .completed)
XCTAssertEqual(state, .expired)
}

func test_매칭_후_만료일이_지난_경우_상태가_완료됨으로_변경되는지() {
Expand All @@ -89,21 +89,6 @@ final class RoomStateFactoryTests: XCTestCase {
}


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),
Expand Down

0 comments on commit 35a2cb4

Please sign in to comment.