diff --git a/TnT/Projects/DesignSystem/Sources/Components/BottomSheet/AutoSizingBottomSheetModifier.swift b/TnT/Projects/DesignSystem/Sources/Components/BottomSheet/AutoSizingBottomSheetModifier.swift index cedb76e0..ef0a0aa4 100644 --- a/TnT/Projects/DesignSystem/Sources/Components/BottomSheet/AutoSizingBottomSheetModifier.swift +++ b/TnT/Projects/DesignSystem/Sources/Components/BottomSheet/AutoSizingBottomSheetModifier.swift @@ -26,10 +26,10 @@ struct AutoSizingBottomSheetModifier: ViewModifier { GeometryReader { proxy in Color.clear .onAppear { - contentHeight = proxy.size.height + 50 + contentHeight = proxy.size.height + 10 } .onChange(of: proxy.size.height) { _, newHeight in - contentHeight = newHeight + 50 + contentHeight = newHeight + 10 } } ) diff --git a/TnT/Projects/DesignSystem/Sources/Components/Calendar/TCalendarCell.swift b/TnT/Projects/DesignSystem/Sources/Components/Calendar/TCalendarCell.swift index 4bb84927..e777927c 100644 --- a/TnT/Projects/DesignSystem/Sources/Components/Calendar/TCalendarCell.swift +++ b/TnT/Projects/DesignSystem/Sources/Components/Calendar/TCalendarCell.swift @@ -12,7 +12,6 @@ import FSCalendar final class TCalendarCell: FSCalendarCell { // MARK: Properties static let identifier: String = "TCalendarCell" - static let cellSize: CGSize = CGSize(width: 51, height: 54) /// Cell에 표시되는 날짜 private var customDate: Date? @@ -22,8 +21,8 @@ final class TCalendarCell: FSCalendarCell { private var style: Style = .default /// Cell에 표시되는 일정 카운트 private var eventCount: Int = 0 - /// 주간/월간 모드인지 표시 - private var isWeekMode: Bool = false + /// 주간/월간/컴팩트 모드인지 표시 + private var mode: TCalendarType = .month // MARK: UI Elements private let dayLabel: UILabel = UILabel() @@ -100,10 +99,14 @@ final class TCalendarCell: FSCalendarCell { /// 일정 카운트 표시 업데이트 private func updateEventDisplay() { + guard mode != .compactMonth else { + eventStackView.isHidden = true + return + } eventCountLabel.text = "\(eventCount)" let eventExists: Bool = eventCount > 0 eventStackView.isHidden = !eventExists - let presentCount: Bool = !isWeekMode && eventExists + let presentCount: Bool = mode == .month && eventExists eventCountLabel.isHidden = !presentCount } @@ -112,7 +115,7 @@ final class TCalendarCell: FSCalendarCell { // 날짜 및 선택 상태 초기화 customDate = nil isCellSelected = false - isWeekMode = false + mode = .month // 일정 관련 초기화 eventCount = 0 @@ -132,12 +135,12 @@ extension TCalendarCell { with date: Date, isCellSelected: Bool, eventCount: Int = 0, - isWeekMode: Bool = false + mode: TCalendarType = .month ) { self.customDate = date self.isCellSelected = isCellSelected self.eventCount = eventCount - self.isWeekMode = isWeekMode + self.mode = mode // 현재 날짜 및 선택 상태를 반영, Style 설정 if isCellSelected { diff --git a/TnT/Projects/DesignSystem/Sources/Components/Calendar/TCalendarRepresentable.swift b/TnT/Projects/DesignSystem/Sources/Components/Calendar/TCalendarRepresentable.swift index 9d9beddc..8715c777 100644 --- a/TnT/Projects/DesignSystem/Sources/Components/Calendar/TCalendarRepresentable.swift +++ b/TnT/Projects/DesignSystem/Sources/Components/Calendar/TCalendarRepresentable.swift @@ -16,8 +16,8 @@ public struct TCalendarRepresentable: UIViewRepresentable { @Binding private var currentPage: Date /// 캘린더 높이 @Binding var calendarHeight: CGFloat - /// 주간/월간 표시 여부 - private var isWeekMode: Bool + /// 주간/월간/컴팩트 모드인지 표시 + private var mode: TCalendarType = .month /// 캘린더 표시 이벤트 딕셔너리 private var events: [Date: Int] @@ -25,13 +25,13 @@ public struct TCalendarRepresentable: UIViewRepresentable { selectedDate: Binding, currentPage: Binding, calendarHeight: Binding, - isWeekMode: Bool = false, + mode: TCalendarType = .month, events: [Date: Int] = [:] ) { self._selectedDate = selectedDate self._currentPage = currentPage self._calendarHeight = calendarHeight - self.isWeekMode = isWeekMode + self.mode = mode self.events = events } @@ -44,7 +44,7 @@ public struct TCalendarRepresentable: UIViewRepresentable { // Cell 설정 calendar.register(TCalendarCell.self, forCellReuseIdentifier: TCalendarCell.identifier) - calendar.collectionView.contentSize = TCalendarCell.cellSize + calendar.collectionView.contentSize = mode.cellSize // 기본 설정 calendar.delegate = context.coordinator @@ -55,7 +55,7 @@ public struct TCalendarRepresentable: UIViewRepresentable { calendar.placeholderType = .none calendar.headerHeight = 0 calendar.weekdayHeight = 18 - calendar.rowHeight = TCalendarCell.cellSize.height + calendar.rowHeight = mode.cellSize.height calendar.appearance.weekdayTextColor = UIColor(.neutral400) calendar.appearance.weekdayFont = Typography.FontStyle.label2Medium.uiFont calendar.appearance.selectionColor = .clear @@ -77,7 +77,7 @@ public struct TCalendarRepresentable: UIViewRepresentable { } // `isWeekMode` 반영 - let targetScope: FSCalendarScope = isWeekMode ? .week : .month + let targetScope: FSCalendarScope = mode.scope if uiView.scope != targetScope { uiView.scope = targetScope } @@ -137,7 +137,7 @@ public extension TCalendarRepresentable { with: date, isCellSelected: isSelected, eventCount: eventCount, - isWeekMode: parent.isWeekMode + mode: parent.mode ) return cell diff --git a/TnT/Projects/DesignSystem/Sources/Components/Calendar/TCalendarType.swift b/TnT/Projects/DesignSystem/Sources/Components/Calendar/TCalendarType.swift new file mode 100644 index 00000000..86303da9 --- /dev/null +++ b/TnT/Projects/DesignSystem/Sources/Components/Calendar/TCalendarType.swift @@ -0,0 +1,48 @@ +// +// TCalendarType.swift +// DesignSystem +// +// Created by 박민서 on 2/6/25. +// Copyright © 2025 yapp25thTeamTnT. All rights reserved. +// + +import FSCalendar + +/// TCalendar에 사용되는 캘린더 타입입니다 +public enum TCalendarType { + /// 주간 캘린더 - 일정 표시 + case week + /// 월간 캘린더 - 일정 표시 + case month + /// 월간 캘린더 - 날짜와 선택 표시만 + case compactMonth + + var scope: FSCalendarScope { + switch self { + case .week: + return .week + case .month, .compactMonth: + return .month + } + } + + var calendarHeight: CGFloat { + switch self { + case .week: + return 80 + case .month: + return 340 + case .compactMonth: + return 320 + } + } + + var cellSize: CGSize { + switch self { + case .week, .month: + return CGSize(width: 51, height: 54) + case .compactMonth: + return CGSize(width: 51, height: 40) + } + } +} diff --git a/TnT/Projects/DesignSystem/Sources/Components/Calendar/TCalendarView.swift b/TnT/Projects/DesignSystem/Sources/Components/Calendar/TCalendarView.swift index c41c71e8..435992be 100644 --- a/TnT/Projects/DesignSystem/Sources/Components/Calendar/TCalendarView.swift +++ b/TnT/Projects/DesignSystem/Sources/Components/Calendar/TCalendarView.swift @@ -11,11 +11,7 @@ import SwiftUI /// 앱 전반적으로 사용되는 캘린더입니다. /// 주간/월간 표시를 포함합니다. public struct TCalendarView: View { - - /// 주간 캘린더 높이 - static let weeklyCalendarHeight: CGFloat = 80 - /// 월간 캘린더 높이 - static let monthlyCalendarHeight: CGFloat = 340 + /// 선택한 날짜 @Binding var selectedDate: Date /// 현재 페이지 @@ -23,9 +19,9 @@ public struct TCalendarView: View { /// 업데이트 플래그 @State private var forceUpdate: UUID = UUID() /// 캘린더 높이 - @State private var calendarHeight: CGFloat = monthlyCalendarHeight - /// 주간/월간 표시 여부 - private var isWeekMode: Bool + @State private var calendarHeight: CGFloat = TCalendarType.month.calendarHeight + /// 주간/월간/컴팩트 모드인지 표시 + private var mode: TCalendarType = .month /// 캘린더 표시 이벤트 딕셔너리 private var events: [Date: Int] @@ -33,14 +29,14 @@ public struct TCalendarView: View { selectedDate: Binding, currentPage: Binding, forceUpdate: UUID = UUID(), - events: [Date: Int], - isWeekMode: Bool = false + events: [Date: Int] = [:], + mode: TCalendarType = .month ) { self._selectedDate = selectedDate self._currentPage = currentPage self.events = events self.forceUpdate = forceUpdate - self.isWeekMode = isWeekMode + self.mode = mode } public var body: some View { @@ -49,23 +45,19 @@ public struct TCalendarView: View { selectedDate: $selectedDate, currentPage: $currentPage, calendarHeight: $calendarHeight, - isWeekMode: isWeekMode, + mode: mode, events: events ) - .frame(width: proxy.size.width, height: TCalendarView.monthlyCalendarHeight) + .frame(width: proxy.size.width, height: TCalendarType.month.calendarHeight) .id(forceUpdate) .onChange(of: events) { forceUpdate = UUID() } .onAppear { - calendarHeight = isWeekMode - ? TCalendarView.weeklyCalendarHeight - : TCalendarView.monthlyCalendarHeight + calendarHeight = mode.calendarHeight } - .onChange(of: isWeekMode) { - calendarHeight = isWeekMode - ? TCalendarView.weeklyCalendarHeight - : TCalendarView.monthlyCalendarHeight + .onChange(of: mode) { + calendarHeight = mode.calendarHeight } } .frame(height: calendarHeight) diff --git a/TnT/Projects/DesignSystem/Sources/Components/DatePickerView/TDatePickerView.swift b/TnT/Projects/DesignSystem/Sources/Components/DatePickerView/TDatePickerView.swift index e8cd5a25..e89b6a9e 100644 --- a/TnT/Projects/DesignSystem/Sources/Components/DatePickerView/TDatePickerView.swift +++ b/TnT/Projects/DesignSystem/Sources/Components/DatePickerView/TDatePickerView.swift @@ -15,8 +15,14 @@ public struct TDatePickerView: View { private let title: String /// 버튼 실행 action private let buttonAction: (Date) -> Void + /// 헤더 formatter + private let monthFormatter: (Date) -> String /// 선택 날짜 @State private var selectedDate: Date = .now + /// 표시 날짜 + @State private var currentDate: Date = .now + + @Environment(\.dismiss) var dismiss /// `TDatePickerView` 생성자 /// - Parameters: @@ -26,33 +32,55 @@ public struct TDatePickerView: View { public init( selectedDate: Date = .now, title: String, + monthFormatter: @escaping (Date) -> String, buttonAction: @escaping (Date) -> Void ) { self.selectedDate = selectedDate self.title = title + self.monthFormatter = monthFormatter self.buttonAction = buttonAction } public var body: some View { - VStack { - DatePicker( - title, - selection: $selectedDate, - displayedComponents: [.date] + VStack(spacing: 12) { + HStack { + Text(title) + .typographyStyle(.heading3, with: .neutral900) + Spacer() + Button(action: { + dismiss() + }, label: { + Image(.icnDelete) + .renderingMode(.template) + .resizable() + .tint(.neutral400) + .frame(width: 32, height: 32) + }) + } + .padding(20) + + TCalendarHeader( + currentPage: $currentDate, + formatter: monthFormatter + ) + .padding(.top, 20) + + TCalendarView( + selectedDate: $selectedDate, + currentPage: $currentDate, + mode: .compactMonth ) - .tint(Color.red500) - .datePickerStyle(.graphical) - .labelsHidden() - .padding() + .padding(.horizontal, 16) - TBottomButton( - title: "완료", - isEnable: true, + TButton( + title: "확인", + config: .large, + state: .default(.primary(isEnabled: true)), action: { buttonAction(selectedDate) } ) - .ignoresSafeArea(.all, edges: .bottom) + .padding(20) } } } diff --git a/TnT/Projects/DesignSystem/Sources/Components/TimePicker/FlatPickerColumn.swift b/TnT/Projects/DesignSystem/Sources/Components/TimePicker/FlatPickerColumn.swift new file mode 100644 index 00000000..fc776ce7 --- /dev/null +++ b/TnT/Projects/DesignSystem/Sources/Components/TimePicker/FlatPickerColumn.swift @@ -0,0 +1,126 @@ +// +// TPickerColumn.swift +// DesignSystem +// +// Created by 박민서 on 2/6/25. +// Copyright © 2025 yapp25thTeamTnT. All rights reserved. +// + +import SwiftUI + +/// 주어진 문자열 배열(items)을 반복하여 무한 스크롤을 표시하거나, 그대로 표시하는 열 뷰 +struct FlatPickerColumn: View { + /// 원본 배열 + let items: [String] + /// 각 행의 높이 + let rowHeight: CGFloat + /// 한 화면에 보일 행의 수 (중앙 행이 선택됨) + let visibleCount: Int + /// 일반 텍스트 폰트 + let normalFont: Font + /// 중앙(선택) 텍스트 폰트 + let selectedFont: Font + /// 일반 텍스트 색상 + let normalColor: Color + /// 중앙(선택) 텍스트 색상 + let selectedColor: Color + /// 무한 스크롤 여부: true이면 원본 데이터를 반복하여 보여줌, false이면 원본 배열 그대로 표시 + let infiniteScroll: Bool + + /// 반복 횟수 (무한 스크롤일 때만 사용) + let repetition: Int = 100 + var totalCount: Int { infiniteScroll ? items.count * repetition : items.count } + + /// 원본 배열의 선택된 인덱스 (예: 0 ~ items.count-1) + @Binding var selected: Int + + // 스크롤 스냅 예약 작업 관리 + @State private var pendingScrollTask: DispatchWorkItem? = nil + + var body: some View { + GeometryReader { geo in + let containerCenterY = geo.size.height / 2 + ScrollViewReader { scrollProxy in + ScrollView(.vertical, showsIndicators: false) { + LazyVStack(spacing: 0) { + ForEach(0.. items.count / 2 { + candidate -= items.count + } else if currentIndex - candidate > items.count / 2 { + candidate += items.count + } + targetIndex = candidate + } else { + // 유한 스크롤인 경우: 그냥 newSelection (0 ~ items.count-1) + targetIndex = newSelection + } + + let task = DispatchWorkItem { + withAnimation { + scrollProxy.scrollTo(targetIndex, anchor: .center) + } + } + pendingScrollTask = task + DispatchQueue.main.asyncAfter(deadline: .now() + 0.2, execute: task) + } + } + .onAppear { + let initialIndex: Int + if infiniteScroll { + // 중앙 블록의 시작점: totalCount / 2를 items.count로 나눈 나머지를 제거한 값 + let midBlock = (totalCount / 2) - ((totalCount / 2) % items.count) + // 그 중앙 블록에서 selected 값만큼 오프셋 적용 + initialIndex = midBlock + selected + } else { + // 유한 스크롤일 경우, 선택값에 맞춰 중앙에 오도록 + initialIndex = selected + } + DispatchQueue.main.async { + scrollProxy.scrollTo(initialIndex, anchor: .center) + } + } + } + } + .frame(height: rowHeight * CGFloat(visibleCount)) + } +} diff --git a/TnT/Projects/DesignSystem/Sources/Components/TimePicker/RowPreference.swift b/TnT/Projects/DesignSystem/Sources/Components/TimePicker/RowPreference.swift new file mode 100644 index 00000000..96a0a635 --- /dev/null +++ b/TnT/Projects/DesignSystem/Sources/Components/TimePicker/RowPreference.swift @@ -0,0 +1,23 @@ +// +// RowPreference.swift +// DesignSystem +// +// Created by 박민서 on 2/6/25. +// Copyright © 2025 yapp25thTeamTnT. All rights reserved. +// + +import SwiftUI + +/// 각 행의 인덱스와 해당 행의 중앙 Y 좌표를 저장 +struct RowPreferenceData: Equatable { + let index: Int + let midY: CGFloat +} + +/// 자식 뷰(행)에서 전달한 RowPreferenceData 배열을 모으는 PreferenceKey +struct RowPreferenceKey: PreferenceKey { + static var defaultValue: [RowPreferenceData] = [] + static func reduce(value: inout [RowPreferenceData], nextValue: () -> [RowPreferenceData]) { + value.append(contentsOf: nextValue()) + } +} diff --git a/TnT/Projects/DesignSystem/Sources/Components/TimePicker/TTimePicker.swift b/TnT/Projects/DesignSystem/Sources/Components/TimePicker/TTimePicker.swift new file mode 100644 index 00000000..65bb00d7 --- /dev/null +++ b/TnT/Projects/DesignSystem/Sources/Components/TimePicker/TTimePicker.swift @@ -0,0 +1,143 @@ +// +// TTimePicker.swift +// DesignSystem +// +// Created by 박민서 on 2/6/25. +// Copyright © 2025 yapp25thTeamTnT. All rights reserved. +// + +import SwiftUI + +/// 시간, 분, 오전/오후 세 열을 나란히 배치하는 커스텀 타임 피커 +public struct TTimePicker: View { + /// 선택된 시간이 종합되는 date + @Binding private var date: Date + /// 0 ~ 11 (표시 시에는 +1 해서 1~12) + @State private var selectedHour: Int + /// 분 선택은 내부적으로 분 배열의 인덱스로 저장 (예, minuteStep이 5면 0~11) + @State private var selectedMinuteIndex: Int + /// 0: AM, 1: PM + @State private var selectedPeriod: Int + + /// 셀 높이 + let rowHeight: CGFloat = 35 + /// 피커에 표시되는 셀 개수 + let visibleCount: Int = 5 + /// 선택되지 않은 시간 텍스트 폰트 + let normalFont: Font = Typography.FontStyle.heading4.font + /// 선택된 시간 텍스트 폰트 + let selectedFont: Font = Typography.FontStyle.heading3.font + /// 선택되지 않은 시간 텍스트 컬러 + let normalColor: Color = .neutral400 + /// 선택된 시간 텍스트 컬러 + let selectedColor: Color = .neutral900 + /// 분 단위 설정 + let minuteStep: Int + // 무한 스크롤 사용 여부 - false로 설정하면 유한 스크롤 + let infiniteScroll: Bool = true + /// 실제 분 값을 계산 + /// ex - minuteStep이 5이면 내부 저장값 7 -> 35분 + public var selectedMinute: Int { + selectedMinuteIndex * minuteStep + } + + public init(selectedDate: Binding, minuteStep: Int = 1) { + _date = selectedDate + + let hour24 = Calendar.current.component(.hour, from: selectedDate.wrappedValue) + let hour12 = hour24 % 12 == 0 ? 12 : hour24 % 12 + let hour = hour12 - 1 + _selectedHour = State(initialValue: hour) + + let minute = Calendar.current.component(.minute, from: selectedDate.wrappedValue) + _selectedMinuteIndex = State(initialValue: minute / minuteStep) + + _selectedPeriod = State(initialValue: hour24 < 12 ? 0 : 1) + self.minuteStep = minuteStep + } + + public var body: some View { + ZStack { + RoundedRectangle(cornerRadius: 8) + .fill(Color.neutral100) + .frame(height: rowHeight) + + HStack(spacing: 0) { + // 시간 열: "1" ~ "12" + FlatPickerColumn( + items: (1...12).map { "\($0)" }, + rowHeight: rowHeight, + visibleCount: visibleCount, + normalFont: normalFont, + selectedFont: selectedFont, + normalColor: normalColor, + selectedColor: selectedColor, + infiniteScroll: infiniteScroll, + selected: Binding(get: { + selectedHour + }, set: { + selectedHour = $0 + updateDate() + }) + ) + Text(":") + .typographyStyle(.heading4, with: .neutral900) + // 분 열: 생성 시 minuteStep에 따라 아이템 생성 (예, minuteStep 5 → ["00","05",..., "55"]) + FlatPickerColumn( + items: stride(from: 0, to: 60, by: minuteStep) + .map { String(format: "%02d", $0) }, + rowHeight: rowHeight, + visibleCount: visibleCount, + normalFont: normalFont, + selectedFont: selectedFont, + normalColor: normalColor, + selectedColor: selectedColor, + infiniteScroll: infiniteScroll, + selected: Binding( + get: { selectedMinuteIndex }, + set: { newValue in + selectedMinuteIndex = newValue + updateDate() + } + ) + ) + Text(":") + .typographyStyle(.heading4, with: .clear) + // 오전/오후 열: "오전", "오후" + FlatPickerColumn( + items: ["오전", "오후"], + rowHeight: rowHeight, + visibleCount: visibleCount, + normalFont: normalFont, + selectedFont: selectedFont, + normalColor: normalColor, + selectedColor: selectedColor, + infiniteScroll: false, + selected: Binding( + get: { selectedPeriod }, + set: { newValue in + selectedPeriod = newValue + updateDate() + } + ) + ) + } + } + } + + private func updateDate() { + var calendar: Calendar = Calendar.current + calendar.timeZone = TimeZone(secondsFromGMT: 0) ?? .current // UTC로 설정 + var components: DateComponents = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: date) + + // 24시간대로 시간 포맷 설정 + let hour24: Int = (selectedHour + 1) % 12 + (selectedPeriod == 1 ? 12 : 0) + + components.hour = hour24 + components.minute = selectedMinute + + if let newDate = calendar.date(from: components) { + date = newDate + } + } +} diff --git a/TnT/Projects/Presentation/Sources/Home/Trainee/TraineeHomeView.swift b/TnT/Projects/Presentation/Sources/Home/Trainee/TraineeHomeView.swift index 9ebbf554..961c9ccb 100644 --- a/TnT/Projects/Presentation/Sources/Home/Trainee/TraineeHomeView.swift +++ b/TnT/Projects/Presentation/Sources/Home/Trainee/TraineeHomeView.swift @@ -92,7 +92,7 @@ public struct TraineeHomeView: View { selectedDate: $store.selectedDate, currentPage: $store.view_currentPage, events: store.events, - isWeekMode: true + mode: .week ) .padding(.horizontal, 20) diff --git a/TnT/Projects/Presentation/Sources/Home/Trainer/TrainerHomeView.swift b/TnT/Projects/Presentation/Sources/Home/Trainer/TrainerHomeView.swift index 35c2f89f..e8b9bfd9 100644 --- a/TnT/Projects/Presentation/Sources/Home/Trainer/TrainerHomeView.swift +++ b/TnT/Projects/Presentation/Sources/Home/Trainer/TrainerHomeView.swift @@ -60,8 +60,7 @@ public struct TrainerHomeView: View { TCalendarView( selectedDate: $store.selectedDate, currentPage: $store.view_currentPage, - events: store.events, - isWeekMode: false + events: store.events ) .padding(.horizontal, 20) } diff --git a/TnT/Projects/Presentation/Sources/Onboarding/Trainee/TraineeBasicInfoInput/TraineeBasicInfoInputView.swift b/TnT/Projects/Presentation/Sources/Onboarding/Trainee/TraineeBasicInfoInput/TraineeBasicInfoInputView.swift index a4a4247d..51baaeba 100644 --- a/TnT/Projects/Presentation/Sources/Onboarding/Trainee/TraineeBasicInfoInput/TraineeBasicInfoInputView.swift +++ b/TnT/Projects/Presentation/Sources/Onboarding/Trainee/TraineeBasicInfoInput/TraineeBasicInfoInputView.swift @@ -54,10 +54,15 @@ public struct TraineeBasicInfoInputView: View { } } .sheet(isPresented: $store.view_isDatePickerPresented) { - TDatePickerView(title: "생년월일") { date in + TDatePickerView( + title: "생년월일", + monthFormatter: { + TDateFormatUtility.formatter(for: .yyyy년_MM월).string(from: $0) + } + ) { date in send(.tapBirthDatePickerDoneButton(date)) } - .presentationDetents([.medium]) + .autoSizingBottomSheet(presentationDragIndicator: .hidden) .interactiveDismissDisabled(true) } .onChange(of: focusedField) { oldValue, newValue in diff --git a/TnT/Projects/Presentation/Sources/Onboarding/Trainee/TraineeTrainingInfoInput/TraineeTrainingInfoInputView.swift b/TnT/Projects/Presentation/Sources/Onboarding/Trainee/TraineeTrainingInfoInput/TraineeTrainingInfoInputView.swift index 432f44ba..e95d0ca8 100644 --- a/TnT/Projects/Presentation/Sources/Onboarding/Trainee/TraineeTrainingInfoInput/TraineeTrainingInfoInputView.swift +++ b/TnT/Projects/Presentation/Sources/Onboarding/Trainee/TraineeTrainingInfoInput/TraineeTrainingInfoInputView.swift @@ -56,10 +56,15 @@ public struct TraineeTrainingInfoInputView: View { } } .sheet(isPresented: $store.view_isDatePickerPresented) { - TDatePickerView(title: "PT 시작일") { date in + TDatePickerView( + title: "PT 시작일", + monthFormatter: { + TDateFormatUtility.formatter(for: .yyyy년_MM월).string(from: $0) + } + ) { date in send(.tapStartDatePickerDoneButton(date)) } - .presentationDetents([.medium]) + .autoSizingBottomSheet(presentationDragIndicator: .hidden) .interactiveDismissDisabled(true) } .onChange(of: focusedField) { oldValue, newValue in