Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat] 모임 상세 화면 삭제(나가기) 기능 및 바뀐 API 명세 반영하기 #329

Merged
merged 7 commits into from
Aug 24, 2024

Conversation

JinUng41
Copy link
Contributor

🔗 연결된 이슈

📄 작업 내용

  • 모임 삭제(나가기) 기능 구현
  • 바뀐 API 명세 반영하기 (MeetingPromisesModel의 time 변경)
  • 내가 포함된 약속 / 모임 전체 약속은 이 작업 이후에 진행할 예정입니다.
구현 내용 IPhone 13 mini
API 명세를 반영한 화면
모임 나가기

💻 주요 코드 설명

View 영역에서 사용될 Model, MeetingInfoPromiseModel

  • 서버의 API 명세가 변경됨에 따라 (time을 "yyyy-MM-dd HH:mm:ss"로 일괄적으로 전송)
  • DTO인 MeetingPromisesModel의 MeetingPromises가 변경이 필요했습니다.
  • 또한 View에서는 time이 분리된 형태로 보여줘야 하기 때문에 추가적인 로직이 필요했습니다.
  • 따라서 DTO와는 다른 View에서 사용되는 모델을 정의하고 이를 ViewModel에서 변환하였습니다.
MeetingInfoViewModel.swift
private extension MeetingInfoViewModel {
    func convertToMeetingInfoPromiseModels(from promises: [MeetingPromise]) -> [MeetingInfoPromiseModel] {
        let inputDateFormatter = DateFormatter()
        inputDateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        
        let outputDateFormatter = DateFormatter().then {
            $0.locale = Locale(identifier: "ko_KR")
            $0.timeZone = TimeZone(identifier: "Asia/Seoul")
            $0.dateFormat = "yyyy.MM.dd a h:mm"
            $0.amSymbol = "AM"
            $0.pmSymbol = "PM"
        }
        
        return promises.compactMap { promise in
            guard let date = inputDateFormatter.date(from: promise.time) else { return nil }
            let formattedDate = outputDateFormatter.string(from: date)
            let (dateString, timeString) = splitDateAndTime(from: formattedDate)
            let (dDayString, state) = configure(dDay: promise.dDay)
            
            return MeetingInfoPromiseModel(
                state: state,
                promiseID: promise.promiseID,
                name: promise.name,
                dDayText: dDayString,
                dateText: dateString,
                timeText: timeString,
                placeName: promise.placeName
            )
        }
    }
    
    func splitDateAndTime(from formattedDate: String) -> (String, String) {
        let components = formattedDate.split(separator: " ").map { "\($0)" }
        guard components.count >= 3 else { return ("", "") }
        let dateString = components[0]
        let timeString = "\(components[1]) \(components[2])"
        return (dateString, timeString)
    }
    
    func configure(dDay: Int) -> (dDayText: String, state: MeetingPromiseCell.State) {
        if 0 < dDay {
            return ("+\(dDay)", .past)
        } else if 0 == dDay {
            return ("-Day", .today)
        } else {
            return ("\(dDay)", .future)
        }
    }
}

RxMoya 사용

  • RxMoya를 아주 얕게나마 사용하였습니다.
  • 확실히 컴플리션 핸들러나, Task 구문 등에 대응할 필요없이 일반적인 메서드 형태로 사용할 수 있다는 것이 매우 크게 다가왔습니다.
  • 현재의 기능은 크게 없어 매우 간단한 형태로 사용되었습니다.
  • 서버 에러 (500번) 또는 디코딩 에러 등에는 크게 대응하지 않고 있습니다.
  • 디코딩 된 후 발생할 수 있는 에러는 일괄적으로 토스트 메세지를 띄우는 것으로 구현하였습니다. (ResponsBodyDTO 내 success)
MeetingService.swift
// extension MeetingService: MeetingInfoServiceProtocol에서
func exitMeeting(with meetingID: Int) -> Single<ResponseBodyDTO<EmptyModel>> {
    return provider.rx.request(.exitMeeting(meetingID: meetingID))
        .filterSuccessfulStatusCodes() // 200번대 코드 필터링
        .map(ResponseBodyDTO<EmptyModel>.self) // 해당되는 모델로 디코딩
        .catch { error in
            print("에러 발생: \(error.localizedDescription)")
            throw error
        }
}

@JinUng41 JinUng41 added ✨ feat 기능 구현시 사용 💙 JinUng 걸스 토크에 미쳐보고 싶다면 labels Aug 24, 2024
@JinUng41 JinUng41 self-assigned this Aug 24, 2024
@JinUng41 JinUng41 linked an issue Aug 24, 2024 that may be closed by this pull request
2 tasks
Copy link
Member

@hooni0918 hooni0918 left a comment

Choose a reason for hiding this comment

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

좋은코드 잘 구경하고갑니다
RxMoya도입이 기대되네요

Copy link
Member

@youz2me youz2me left a comment

Choose a reason for hiding this comment

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

고생하셨습니다. 나중에 저도 Rx를 도입하게 된다면 꼭 참고해보도록 할게요.

Member(
memberID: 1,
name: "김진웅",
profileImageURL: "https://reqres.in/img/faces/\(Int.random(in: 1...10))-image.jpg"
Copy link
Member

Choose a reason for hiding this comment

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

오? 이런게 있군요

Comment on lines +143 to +153
func convertToMeetingInfoPromiseModels(from promises: [MeetingPromise]) -> [MeetingInfoPromiseModel] {
let inputDateFormatter = DateFormatter()
inputDateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"

let outputDateFormatter = DateFormatter().then {
$0.locale = Locale(identifier: "ko_KR")
$0.timeZone = TimeZone(identifier: "Asia/Seoul")
$0.dateFormat = "yyyy.MM.dd a h:mm"
$0.amSymbol = "AM"
$0.pmSymbol = "PM"
}
Copy link
Member

Choose a reason for hiding this comment

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

저도 잘 써먹도록 하겠습니다. 감사합니다.

Copy link
Member

Choose a reason for hiding this comment

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

저도 용이하게 사용하겠습니다. 혹시 셋 모두가 필요한 함수라면 공통 메서드로 사용할 수 있게 하는 건 어떨까요?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

그것도 괜찮은 방법이네요.
뭐 예를 들어, DateFormatter의 익스텐션 메서드를 둔다던지.. 등

Copy link
Member

@mmaybei mmaybei left a comment

Choose a reason for hiding this comment

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

수고하셨습니다!

Comment on lines +110 to +116
func configure(model: MeetingInfoPromiseModel) {
dDayLabel.setText("D\(model.dDayText)", style: .body05, color: model.state.dDayTextColor)
nameLabel.setText(model.name, style: .body03, color: model.state.nameTextColor)
dateLabel.setText(model.dateText, style: .body06, color: model.state.otherTextColor)
timeLabel.setText(model.timeText, style: .body06, color: model.state.otherTextColor)
placeLabel.setText(model.placeName, style: .body06, color: model.state.otherTextColor)
}
Copy link
Member

Choose a reason for hiding this comment

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

👍

Comment on lines +143 to +153
func convertToMeetingInfoPromiseModels(from promises: [MeetingPromise]) -> [MeetingInfoPromiseModel] {
let inputDateFormatter = DateFormatter()
inputDateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"

let outputDateFormatter = DateFormatter().then {
$0.locale = Locale(identifier: "ko_KR")
$0.timeZone = TimeZone(identifier: "Asia/Seoul")
$0.dateFormat = "yyyy.MM.dd a h:mm"
$0.amSymbol = "AM"
$0.pmSymbol = "PM"
}
Copy link
Member

Choose a reason for hiding this comment

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

저도 용이하게 사용하겠습니다. 혹시 셋 모두가 필요한 함수라면 공통 메서드로 사용할 수 있게 하는 건 어떨까요?

@JinUng41 JinUng41 merged commit a2a9717 into suyeon Aug 24, 2024
@JinUng41 JinUng41 deleted the feat/#322-meeting-info-delete branch August 24, 2024 13:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
✨ feat 기능 구현시 사용 💙 JinUng 걸스 토크에 미쳐보고 싶다면
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[feat] 모임 상세 화면 삭제 기능 및 바뀐 API 명세 반영하기
4 participants