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/NST-51] #25 Schedule picker 컴포넌트 작성 #29

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

oyslucy
Copy link
Collaborator

@oyslucy oyslucy commented Jan 12, 2025

🔥 Issue

close #25


🔥 변경된 내용

NSTDateUtility 파일에 스케쥴피커에 필요한 케이스 및 함수 추가했습니다.


🔥 PR Point

  1. dateList와 timeList 함수로 스케쥴 표를 생성하기 위한 배열을 생성합니다.
let dateHeaders: [String] = dateList(mockDateList)
let timeHeaders: [String] = timeList(mockStartTime, mockEndTime)
  1. Schedule Picker를 생성 후 dataSource에서 표의 가로, 세로 헤더에 내용을 채운 후 (readMode의 경우) 참가자 수에 따른 cell background를 조정하는 구조입니당
private lazy var schedulePicker = SchedulePicker(timeHeaders: timeHeaders, dateHeaders: dateHeaders, mode: .readMode)

cell.configureHeader(for: indexPath, dateHeaders: dateHeaders, timeHeaders: timeHeaders)
self.schedulePicker.configureCellBackground(cell, for: indexPath, participants: participants)

🔥 ScreenShot

  • read mode
  • edit mode

@oyslucy oyslucy added the Feat 새로운 기능 구현 label Jan 12, 2025
@oyslucy oyslucy self-assigned this Jan 12, 2025
Copy link
Collaborator

@FpRaArNkK FpRaArNkK left a comment

Choose a reason for hiding this comment

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

고생많으셨습니다! 여러모로 고민한 흔적이 보여서 좋네요 👍👍👍 다만 전체적으로 코드의 흐름을 반응형으로 바꿔주세요!

컴포넌트에서 관리되는 데이터를 상태로 두고, 해당 상태를 UI에 반영하거나 인터랙션을 통해 설정할 수 있게 해주세요.

컴포넌트이니, Input과 Output을 명확히 명시하는 것이 좋을 것 같아요. 해당 컴포넌트를 사용해야 하는 개발자가 어떻게 데이터를 주입하고 가져올 수 있을지 고민해주시면 좋을 것 같습니다!

이대로만 가시죠 🔥

Comment on lines 23 to 34
init(timeHeaders: [String], dateHeaders: [String], mode: Mode) {
self.timeHeaders = timeHeaders
self.dateHeaders = dateHeaders
self.mode = mode
super.init(frame: .zero, collectionViewLayout: layout)
self.layout.configure(totalRows: timeHeaders.count + 1, totalColumns: dateHeaders.count + 1)
self.register(SchedulePickerCell.self, forCellWithReuseIdentifier: SchedulePickerCell.identifier)
self.cellAvailability = calculateCellAvailability(totalRows: timeHeaders.count + 1,
totalColumns: dateHeaders.count + 1,
//Fix: mockMemberStartTime 변경 필요
startTimes: mockMemberStartTime)
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

캬 야무지네요 다만 init 아래의 내용은 팀 코드 컨벤션대로 따로 셋업 함수에서 처리해주세요!

}

func addSelectedCell(at indexPath: IndexPath) {
guard mode == .editMode else { return }
Copy link
Collaborator

Choose a reason for hiding this comment

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

예외 처리 뭐죠 너 오연서 아니지


func addSelectedCell(at indexPath: IndexPath) {
guard mode == .editMode else { return }
if let cell = cellForItem(at: indexPath) as? SchedulePickerCell {
Copy link
Collaborator

Choose a reason for hiding this comment

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

위에서 guard문으로 체크하는 김에 같이 작성해서
editMode && SchedulePickerCell
조건일때만 아래로 넘기겠다의 문맥이면 더 좋을 것 같네요!

self.register(SchedulePickerCell.self, forCellWithReuseIdentifier: SchedulePickerCell.identifier)
self.cellAvailability = calculateCellAvailability(totalRows: timeHeaders.count + 1,
totalColumns: dateHeaders.count + 1,
//Fix: mockMemberStartTime 변경 필요
Copy link
Collaborator

Choose a reason for hiding this comment

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

해당 TODO or FIX 사항은 해결된건가요??

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

아뇹 ㅋㅋ 이부분은 화면 만들면서 다시 바꿔볼 예정입니다 ..

Copy link
Collaborator

Choose a reason for hiding this comment

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

아뇨 지금 해주세요

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Comment on lines 43 to 48
cell.isSelectedCell.toggle()
if cell.isSelectedCell {
selectedCells.insert(indexPath)
} else {
selectedCells.remove(indexPath)
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

너무 절차형같아요 반응형으로 리팩토링하는 고민을 해보는건 어떨까요?

현재 코드

  1. CV에서 Cell의 내용을 토글
  2. CV에서 Cell의 내용을 참조해서 CV의 내용을 수정

반응형이라면

  1. CV와 Cell의 데이터가 바인딩
  2. cell or cv에서 변경되면 나머지도 같이 변경

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

모르게쒀요... 이부분 말고도 전체적인 흐름을 반응형으로 바꾸기 위해서 selectedCells와 cellAvailability를 behaviorRelay로 변경하는게 나을까요
반응형으로 리팩토링해야한다면 변경해야하는 부분은 이 토글부분 말고는 안보이기는 하는데 . . .

Comment on lines +15 to +19
var isSelectedCell: Bool = false {
didSet {
backgroundColor = isSelectedCell ? .appBlue400 : .appWhite
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

rx 말고 didSet 사용한 이유가 있을까요?
전 일단 해당 코드에 동의해요! :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

굳이 rx로 안해도될거같아서 .... didSet을 사용했는데 딱히 이유는 없어요 😅😅
동의하신 이유를 알려주시죠 ㅋ.

Copy link
Collaborator

Choose a reason for hiding this comment

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

ㅋㅋ 똑같습니다 굳이 rx로 안해도 돼서라고 생각해요!
내-외부에서 구독해야하는 스트림과 일련의 비즈니스 로직이 존재하는 것도 아니고,
오히려 Rx를 위해 Cell 별 DisposeBag과 RxCocoa를 통한 subscribe 로직이 필요할테니까요.
Cell이 특히나 많이 생성될 여지가 있는 부분에서 didSet으로 역할을 간소화시킨건 좋다고 생각해요.

self.layer.borderColor = UIColor.appGray200.cgColor
}

func configureHeader(for indexPath: IndexPath, dateHeaders: [String], timeHeaders: [String]) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

코드의 역할이 너무 많은것 같아요! 세부적으로 기능을 쪼개면 더 읽기 편하고 명료한 코드가 될 것 같습니다.
추가로 if 케이스 처리가 여러개라면 Switch를 통해 가독성을 높이는 방법도 고려해보세요!


import UIKit

final class SchedulePickerLayout: UICollectionViewFlowLayout {
Copy link
Collaborator

Choose a reason for hiding this comment

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

야무지네여 야무져 다만 해당 레이아웃은 SchedulePicker에만 해당되는 레이아웃이니 SchedulePicker extension으로 선언해서 프로퍼티임을 강조하는게 어떨까요?

func configure(totalRows: Int = 0, totalColumns: Int = 0) {
self.totalRows = totalRows
self.totalColumns = totalColumns
invalidateLayout()
Copy link
Collaborator

Choose a reason for hiding this comment

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

이 코드는 어떤 코드인가요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

레이아웃이 말을 안들어서 추가해놨었는데 빼도 될거같음다

Comment on lines 90 to 127
func dateList(_ dateStrings: [String]) -> [String] {
let formatter = NSTDateUtility(format: .yyyyMMddTHHmmss) // ISO 8601 형식
let displayFormatter = NSTDateUtility(format: .MMddEE) // 출력 형식

return dateStrings.compactMap { dateString in
switch formatter.date(from: dateString) {
case .success(let date):
return displayFormatter.string(from: date)
case .failure(let error):
print("Failed to parse date \(dateString): \(error.localizedDescription)")
return nil
}
}
}

func timeList(_ startTime: String, _ endTime: String) -> [String] {
let formatter = NSTDateUtility(format: .yyyyMMddTHHmmss) // ISO 8601 형식
var result: [String] = []

switch (formatter.date(from: startTime), formatter.date(from: endTime)) {
case (.success(let start), .success(let end)):
let calendar = Calendar.current
var current = start

while current <= end {
result.append(NSTDateUtility(format: .HH).string(from: current)) // 출력 형식
if let nextHour = calendar.date(byAdding: .hour, value: 1, to: current) {
current = nextHour
} else {
break
}
}
default:
print("Failed to parse start or end time.")
return []
}
return result
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

해당 함수들은 NSTDateUtility 내용에 포함되면서 self로도 사용 가능하니 NSTDateUtility extension으로 두는게 어떨까요!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

NSTDateUtility 파일 내에 extension으로 따로 빼라는 말인거죠?

Copy link
Collaborator

Choose a reason for hiding this comment

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

맞습니다!

Copy link
Collaborator

@FpRaArNkK FpRaArNkK left a comment

Choose a reason for hiding this comment

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

좋습니다! 컴포넌트 외부에서 사용하는 입장에서 어떻게 데이터 가져오는지만 작성해주시고 진행해주세요! 고생하셨슴다

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feat 새로운 기능 구현
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Feat/NST-51] SchedulePicker component
2 participants