-
Notifications
You must be signed in to change notification settings - Fork 0
fix: 콜밴팟 QA #381
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
base: develop
Are you sure you want to change the base?
fix: 콜밴팟 QA #381
Changes from all commits
1998bc4
f2c8841
50e1cd6
44f74b2
8ccb8f6
c424bb7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,14 +11,12 @@ import Then | |
| final class KoinPickerDropDownViewDateDelegate { | ||
|
|
||
| // MARK: - Properties | ||
| let columnWidths: [CGFloat] = [53, 31, 31] | ||
| private var dates: [Int: [Int: [Int]]] = [:] | ||
| private let columnWidths: [CGFloat] = [53, 31, 31] | ||
|
|
||
| private let inputFormatter = DateFormatter().then { | ||
| $0.dateFormat = "yyyy-MM-dd" | ||
| } | ||
|
|
||
| private let outputFormatter = DateFormatter().then { | ||
| $0.dateFormat = "yyyy년*M월*d일" | ||
| // MARK: - Initialzier | ||
| init(range: Range<Int>) { | ||
| resetDates(range: range) | ||
|
Comment on lines
+14
to
+19
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Refresh the cached dates when the picker resets.
💡 Suggested fix final class KoinPickerDropDownViewDateDelegate {
// MARK: - Properties
private var dates: [Int: [Int: [Int]]] = [:]
private let columnWidths: [CGFloat] = [53, 31, 31]
+ private let range: Range<Int>
// MARK: - Initialzier
init(range: Range<Int>) {
+ self.range = range
resetDates(range: range)
}
}
extension KoinPickerDropDownViewDateDelegate: KoinPickerDropDownViewDelegate {
@@
func reset(koinPicker: KoinPickerDropDownView, initialDate: Date) {
+ resetDates(range: range)
let year = initialDate.year
let month = initialDate.month
let day = initialDate.dayAlso applies to: 29-37, 72-93 🤖 Prompt for AI Agents |
||
| } | ||
| } | ||
|
|
||
|
|
@@ -29,68 +27,90 @@ extension KoinPickerDropDownViewDateDelegate: KoinPickerDropDownViewDelegate { | |
| } | ||
|
|
||
| func reset(koinPicker: KoinPickerDropDownView, initialDate: Date) { | ||
| let year = initialDate.year | ||
| let month = initialDate.month | ||
| let day = initialDate.day | ||
|
|
||
| let selectedItem = outputFormatter.string(from: initialDate).components(separatedBy: "*") | ||
| let items = getItems(selectedItem: selectedItem) | ||
| let items = getItems(year: year, month: month) | ||
| let selectedItem: [String] = ["\(year)년", "\(month)월", "\(day)일"] | ||
|
|
||
| koinPicker.reset(items: items, selectedItem: selectedItem, columnWidths: [53, 31, 31]) | ||
| koinPicker.reset(items: items, selectedItem: selectedItem, columnWidths: columnWidths) | ||
| } | ||
|
|
||
| func selectedItemUpdated(koinPicker: KoinPickerDropDownView, selectedItem: [String]) { | ||
|
|
||
| guard let yearInt = Int(selectedItem[0].filter { $0.isNumber }), | ||
| let monthInt = Int(selectedItem[1].filter { $0.isNumber }), | ||
| var dayInt = Int(selectedItem[2].filter { $0.isNumber }) else { | ||
| guard let selectedYear = Int(selectedItem[0].filter { $0.isNumber }), | ||
| var selectedMonth = Int(selectedItem[1].filter { $0.isNumber }), | ||
| var selectedDay = Int(selectedItem[2].filter { $0.isNumber }) else { | ||
| assert(false) | ||
| return | ||
| } | ||
| let maxDay = getAllDays(year: yearInt, month: monthInt).count | ||
| if dayInt > maxDay { | ||
| dayInt = maxDay | ||
| let items = getItems(year: selectedYear, month: selectedMonth) | ||
| guard let minMonthString = items[1].first?.filter({ $0.isNumber}), | ||
| let minMonth = Int(minMonthString), | ||
| let maxMonthString = items[1].last?.filter({ $0.isNumber}), | ||
| let maxMonth = Int(maxMonthString) else { | ||
| assert(false) | ||
| return | ||
| } | ||
| guard let validDate = inputFormatter.date(from: String(format: "%d-%d-%d", yearInt, monthInt, dayInt)) else { | ||
| guard let minDayString = items[2].first?.filter({ $0.isNumber }), | ||
| let minDay = Int(minDayString), | ||
| let maxDayString = items[2].last?.filter({ $0.isNumber }), | ||
| let maxDay = Int(maxDayString) else { | ||
| assert(false) | ||
| return | ||
| } | ||
| reset(koinPicker: koinPicker, initialDate: validDate) | ||
| selectedMonth = min(max(selectedMonth, minMonth), maxMonth) | ||
| selectedDay = min(max(selectedDay, minDay), maxDay) | ||
| let selectedItem: [String] = ["\(selectedYear)년", "\(selectedMonth)월", "\(selectedDay)일"] | ||
| koinPicker.reset(items: items, selectedItem: selectedItem, columnWidths: columnWidths) | ||
| } | ||
| } | ||
|
|
||
| extension KoinPickerDropDownViewDateDelegate { | ||
|
|
||
| private func getItems(selectedItem: [String]) -> [[String]] { | ||
|
|
||
| guard let selectedYearInt = Int(selectedItem[0].filter { $0.isNumber }), | ||
| let selectedMonthInt = Int(selectedItem[1].filter { $0.isNumber }) else { | ||
| assert(false) | ||
| return [[],[],[]] | ||
| private func resetDates(range: Range<Int>) { | ||
| let calendar = Calendar.current | ||
| let startDay = calendar.startOfDay(for: Date()) | ||
| let availableDates = range.compactMap { | ||
| calendar.date(byAdding: .day, value: $0, to: startDay) | ||
| } | ||
|
|
||
| let years: [String] = { | ||
| let thisYearInt = Date().year | ||
| let lowestYearInt = min(selectedYearInt, thisYearInt) | ||
| let heighestYearInt = thisYearInt + 1 | ||
| return Range(lowestYearInt...heighestYearInt).map { String($0)+"년" } | ||
| }() | ||
| let months: [String] = Range(1...12).map { String($0)+"월" } | ||
| let days: [String] = getAllDays(year: selectedYearInt, month: selectedMonthInt) | ||
| var dates: [Int: [Int: [Int]]] = [:] | ||
|
|
||
| return [years, months, days] | ||
| for date in availableDates { | ||
| if dates[date.year] == nil { | ||
| dates[date.year] = [:] | ||
| } | ||
|
|
||
| if dates[date.year]?[date.month] == nil { | ||
| dates[date.year]?[date.month] = [] | ||
| } | ||
|
|
||
| dates[date.year]?[date.month]?.append(date.day) | ||
| } | ||
|
|
||
| self.dates = dates | ||
| } | ||
|
|
||
| func getAllDays(year: Int, month: Int) -> [String] { | ||
|
|
||
| let calendar = Calendar.current | ||
| var components = DateComponents() | ||
| components.year = year | ||
| components.month = month | ||
| private func getItems(year: Int, month: Int) -> [[String]] { | ||
| guard let minYear: Int = dates.keys.sorted().first, | ||
| let maxYear: Int = dates.keys.sorted().last else { | ||
| assert(false) | ||
| return [[],[],[]] | ||
| } | ||
| let year = min(max(minYear, year), maxYear) | ||
|
|
||
| guard let date = calendar.date(from: components), | ||
| let dayRange = calendar.range(of: .day, in: .month, for: date) else { | ||
| guard let minMonth: Int = dates[year]?.keys.sorted().first, | ||
| let maxMonth: Int = dates[year]?.keys.sorted().last else { | ||
| assert(false) | ||
| return [] | ||
| return [[],[],[]] | ||
| } | ||
| let month = min(max(minMonth, month), maxMonth) | ||
|
|
||
| return dayRange.map { String($0) + "일" } | ||
| let years: [String] = dates.keys.sorted().map { "\($0)년" } | ||
| let months: [String] = dates[year]!.keys.sorted().map { "\($0)월" } | ||
| let days: [String] = dates[year]![month]!.sorted().compactMap { "\($0)일" } | ||
| return [years, months, days] | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -37,7 +37,7 @@ final class CallVanPostViewModel: ViewModelProtocol { | |
| } | ||
| private(set) var request = CallVanPostRequest() { | ||
| didSet { | ||
| validateRequest() | ||
| validate() | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -98,13 +98,42 @@ extension CallVanPostViewModel { | |
| outputSubject.send(.updateArrival(request.arrivalType, request.arrivalCustomName)) | ||
| } | ||
|
|
||
| private func validateRequest() { | ||
| let validation = request.departureType != nil | ||
| && request.arrivalType != nil | ||
| && request.departureDate != nil | ||
| && request.departureTime != nil | ||
| private func validate() { | ||
| var isValid = true | ||
|
|
||
| outputSubject.send(.enablePostButton(validation)) | ||
| let formatter = DateFormatter() | ||
| formatter.dateFormat = "yyyy-MM-dd HH:mm" | ||
| let tenMinutes: TimeInterval = 1 * 60 * 10 | ||
|
|
||
| /// 빈 값이 있는지 확인 | ||
| if request.departureType == nil | ||
| || request.arrivalType == nil | ||
| || request.departureDate?.isEmpty == true | ||
| || request.departureTime?.isEmpty == true { | ||
| isValid = false | ||
| } | ||
|
|
||
| /// 출발지와 도착지가 다른지 확인 | ||
| switch (request.departureType, request.arrivalType) { | ||
| case (.custom, .custom): | ||
| if request.departureCustomName == request.arrivalCustomName { | ||
| isValid = false | ||
| } | ||
| default: | ||
| if request.departureType == request.arrivalType { | ||
| isValid = false | ||
| } | ||
| } | ||
|
|
||
| /// 현재 시각으로부터 최소 10분 이후 일정인지 확인 | ||
| let date = request.departureDate ?? "" | ||
| let time = request.departureTime ?? "" | ||
| if let requestDate = formatter.date(from: "\(date) \(time)"), | ||
| requestDate.timeIntervalSince(Date()) < tenMinutes { | ||
| isValid = false | ||
| } | ||
|
|
||
| outputSubject.send(.enablePostButton(isValid)) | ||
|
Comment on lines
+101
to
+136
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
💡 Suggested fix private func validate() {
var isValid = true
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm"
- let tenMinutes: TimeInterval = 1 * 60 * 10
+ let tenMinutes: TimeInterval = 10 * 60
- /// 빈 값이 있는지 확인
- if request.departureType == nil
- || request.arrivalType == nil
- || request.departureDate?.isEmpty == true
- || request.departureTime?.isEmpty == true {
- isValid = false
- }
+ guard request.departureType != nil,
+ request.arrivalType != nil,
+ let date = request.departureDate, !date.isEmpty,
+ let time = request.departureTime, !time.isEmpty,
+ let requestDate = formatter.date(from: "\(date) \(time)") else {
+ outputSubject.send(.enablePostButton(false))
+ return
+ }
/// 출발지와 도착지가 다른지 확인
switch (request.departureType, request.arrivalType) {
case (.custom, .custom):
if request.departureCustomName == request.arrivalCustomName {
isValid = false
}
default:
if request.departureType == request.arrivalType {
isValid = false
}
}
/// 현재 시각으로부터 최소 10분 이후 일정인지 확인
- let date = request.departureDate ?? ""
- let time = request.departureTime ?? ""
- if let requestDate = formatter.date(from: "\(date) \(time)"),
- requestDate.timeIntervalSince(Date()) < tenMinutes {
+ if requestDate.timeIntervalSince(Date()) < tenMinutes {
isValid = false
}
outputSubject.send(.enablePostButton(isValid))
}🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| private func postData() { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Initialize the hidden offset after the sheet has a real height.
contentView.bounds.heightis often still0here because the injected view has not completed an Auto Layout pass yet. In that case the sheet starts on-screen and the firstpresent()animation becomes a no-op. Use an off-screen offset derived after layout, or from the container height instead.🤖 Prompt for AI Agents