|
6 | 6 | // Copyright Β© 2025 yapp25thTeamTnT. All rights reserved. |
7 | 7 | // |
8 | 8 |
|
9 | | -import Foundation |
| 9 | +import SwiftUI |
| 10 | +import ComposableArchitecture |
| 11 | + |
| 12 | +import Domain |
| 13 | +import DesignSystem |
| 14 | + |
| 15 | +/// νΈλ μ΄λμ λ©μΈ ν λ·°μ
λλ€ |
| 16 | +public struct TraineeHomeView: View { |
| 17 | + |
| 18 | + // MARK: μμ State |
| 19 | + @State var ispresented: Bool = false |
| 20 | + @State var selectedDate: Date = Date() |
| 21 | + @State var currentPage: Date = Date() |
| 22 | + @State var events: [Date: Int] = [:] |
| 23 | + @State var todaysSessionInfo: WorkoutListItemEntity? = .init(currentCount: 8, startDate: .now, endDate: .now, trainerProfileImageUrl: nil, trainerName: "κΉλ―Όμ", hasRecord: true) |
| 24 | + @State var records: [RecordListItemEntity] = [ |
| 25 | + .init(type: .meal(type: .lunch), date: .now, title: "μκ³ μΆλ€", hasFeedBack: true, imageUrl: nil), |
| 26 | + .init(type: .meal(type: .dinner), date: .now, title: "μκ³ μΆλ€", hasFeedBack: false, imageUrl: "https://images.genius.com/8e0b15e4847f8e59db7dfda22b4db4ec.1000x1000x1.png"), |
| 27 | + .init(type: .meal(type: .morning), date: .now, title: "μκ³ μΆλ€", hasFeedBack: true, imageUrl: nil) |
| 28 | + ] |
| 29 | + @State var toggleMode: Bool = true |
| 30 | + |
| 31 | + |
| 32 | + public init() {} |
| 33 | + |
| 34 | + public var body: some View { |
| 35 | + ScrollView { |
| 36 | + VStack(spacing: 0) { |
| 37 | + CalendarSection() |
| 38 | + |
| 39 | + RecordListSection() |
| 40 | + .background(Color.neutral100) |
| 41 | + |
| 42 | + Spacer() |
| 43 | + } |
| 44 | + } |
| 45 | + .overlay(alignment: .bottomTrailing) { |
| 46 | + Button(action: { |
| 47 | + // TODO: STORE |
| 48 | + ispresented = true |
| 49 | + }, label: { |
| 50 | + Image(.icnPlus) |
| 51 | + .renderingMode(.template) |
| 52 | + .resizable() |
| 53 | + .tint(Color.common0) |
| 54 | + .frame(width: 24, height: 24) |
| 55 | + .padding(16) |
| 56 | + .background(Color.neutral900) |
| 57 | + .clipShape(.rect(cornerRadius: 16)) |
| 58 | + }) |
| 59 | + .padding(.bottom, 20) |
| 60 | + .padding(.trailing, 12) |
| 61 | + } |
| 62 | + .navigationBarBackButtonHidden() |
| 63 | + .sheet(isPresented: $ispresented) { |
| 64 | + TraineeRecordStartView(itemContents: [ |
| 65 | + ("ππ»ββοΈ", "κ°μΈ μ΄λ", { |
| 66 | + // TODO: Store μ°κ²° |
| 67 | + print("pop") |
| 68 | + }), |
| 69 | + ("π₯", "μλ¨", { |
| 70 | + // TODO: Store μ°κ²° |
| 71 | + print("pop") |
| 72 | + }) |
| 73 | + ]) |
| 74 | + .autoSizingBottomSheet() |
| 75 | + } |
| 76 | + } |
| 77 | + |
| 78 | + // MARK: - Sections |
| 79 | + @ViewBuilder |
| 80 | + private func CalendarSection() -> some View { |
| 81 | + VStack(spacing: 16) { |
| 82 | + TCalendarHeader( |
| 83 | + currentPage: $currentPage, |
| 84 | + formatter: { TDateFormatUtility.formatter(for: .yyyyλ
_MMμ).string(from: $0) }, |
| 85 | + rightView: { |
| 86 | + Button(action: { |
| 87 | + // TODO: Store μ°κ²° |
| 88 | + print("pop") |
| 89 | + toggleMode.toggle() |
| 90 | + }, label: { |
| 91 | + Image(.icnAlarm) |
| 92 | + .resizable() |
| 93 | + .scaledToFit() |
| 94 | + .frame(width: 24, height: 24) |
| 95 | + }) |
| 96 | + } |
| 97 | + ) |
| 98 | + |
| 99 | + // Calendar + κΈμΌ μμ
μΉ΄λ |
| 100 | + VStack(spacing: 12) { |
| 101 | + TCalendarView( |
| 102 | + selectedDate: $selectedDate, |
| 103 | + currentPage: $currentPage, |
| 104 | + events: events, |
| 105 | + isWeekMode: toggleMode |
| 106 | + ) |
| 107 | + .padding(.horizontal, 20) |
| 108 | + |
| 109 | + if let todaysSessionInfo { |
| 110 | + TWorkoutCard( |
| 111 | + chipUIInfo: RecordType.session(count: todaysSessionInfo.currentCount).chipInfo, |
| 112 | + timeText: "\(TDateFormatUtility.formatter(for: .a_HHmm).string(from: todaysSessionInfo.startDate)) ~ \(TDateFormatUtility.formatter(for: .a_HHmm).string(from: todaysSessionInfo.endDate))", |
| 113 | + title: "\(todaysSessionInfo.trainerName) νΈλ μ΄λ", |
| 114 | + imgURL: .init(string: todaysSessionInfo.trainerProfileImageUrl ?? ""), |
| 115 | + hasRecord: todaysSessionInfo.hasRecord, |
| 116 | + footerTapAction: { |
| 117 | + // TODO: STORe |
| 118 | + print("μγ
μ") |
| 119 | + } |
| 120 | + ) |
| 121 | + .padding(.horizontal, 20) |
| 122 | + .padding(.bottom, 16) |
| 123 | + } else { |
| 124 | + SessionEmptyView() |
| 125 | + .padding(.horizontal, 20) |
| 126 | + .padding(.vertical, 16) |
| 127 | + } |
| 128 | + } |
| 129 | + |
| 130 | + } |
| 131 | + .padding(.vertical, 12) |
| 132 | + |
| 133 | + } |
| 134 | + |
| 135 | + @ViewBuilder |
| 136 | + private func RecordListSection() -> some View { |
| 137 | + VStack(alignment: .leading, spacing: 0) { |
| 138 | + Text(TDateFormatUtility.formatter(for: .MMμ_ddμΌ_EEEE).string(from: selectedDate)) |
| 139 | + .typographyStyle(.heading3, with: .neutral800) |
| 140 | + .padding(20) |
| 141 | + |
| 142 | + VStack(spacing: 12) { |
| 143 | + ForEach(records.indices, id: \.self) { index in |
| 144 | + let item = records[index] |
| 145 | + TRecordCard( |
| 146 | + chipUIInfo: item.type.chipInfo, |
| 147 | + timeText: TDateFormatUtility.formatter(for: .a_HHmm).string(from: item.date), |
| 148 | + title: "μκ³ μΆμ΄μ μ§μ§λ‘ γ΄γ
γ
γΉγ
γ΄γ
λγ
£γ
γ
γ
γ
γ
γ·;γ
γ
γ
γ
γ
γ
γ·λγ
;γ
γ
γ
γ·γΉγ
;γ
γ
γ
γ
γ·γΉγ
γ
", |
| 149 | + imgURL: URL(string: item.imageUrl ?? ""), |
| 150 | + hasFeedback: item.hasFeedBack, |
| 151 | + footerTapAction: { |
| 152 | + // TODO: STORE |
| 153 | + print("pop\(index)") |
| 154 | + } |
| 155 | + ) |
| 156 | + } |
| 157 | + } |
| 158 | + .padding(.horizontal, 16) |
| 159 | + } |
| 160 | + } |
| 161 | +} |
| 162 | + |
| 163 | +private extension TraineeHomeView { |
| 164 | + /// μμ λ μμ
μ΄ μμ΄μ |
| 165 | + struct SessionEmptyView: View { |
| 166 | + var body: some View { |
| 167 | + Text("μμ λ μμ
μ΄ μμ΄μ") |
| 168 | + .typographyStyle(.label1Medium, with: .neutral400) |
| 169 | + .frame(maxWidth: .infinity) |
| 170 | + .padding(.vertical, 12) |
| 171 | + } |
| 172 | + } |
| 173 | + |
| 174 | + /// μμ§ κΈ°λ‘μ΄ μμ΄μ |
| 175 | + struct RecordEmptyView: View { |
| 176 | + var body: some View { |
| 177 | + VStack(spacing: 4) { |
| 178 | + Text("μΆκ° λ²νΌμ λλ¬ μμ¬μ μ΄λμ κΈ°λ‘ν΄λ³΄μΈμ") |
| 179 | + .typographyStyle(.body2Bold, with: .neutral600) |
| 180 | + .frame(maxWidth: .infinity) |
| 181 | + |
| 182 | + Text("μΆκ° λ²νΌμ λλ¬ μμ¬μ μ΄λμ κΈ°λ‘ν΄λ³΄μΈμ") |
| 183 | + .typographyStyle(.label1Medium, with: .neutral400) |
| 184 | + .frame(maxWidth: .infinity) |
| 185 | + } |
| 186 | + } |
| 187 | + } |
| 188 | +} |
0 commit comments