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

[TNT-254] QA 반영 #98

Open
wants to merge 32 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
89a931c
[Fix] 탭바 store init 에러 처리
syss220211 Feb 15, 2025
ab0299a
[Refactor] 버전 조정, 회원 목록 모달 padding 수정
syss220211 Feb 15, 2025
02ed948
[Fix] Gesture Nav Back - DragDismiss 충돌 에러 해결
FpRaArNkK Feb 15, 2025
d3d35fe
[Feat] 네트워크 에러 표시 처리 추가
FpRaArNkK Feb 15, 2025
b90168e
[Fix] AddDiet, AddPTSession 라우팅 처리 수정
FpRaArNkK Feb 15, 2025
21f5ff7
[Fix] AddDiet 메모 유효검사처리
FpRaArNkK Feb 15, 2025
0fb5947
[Fix] AddDiet 유효성 검사 로직 수정, 데이터 전달 추가
FpRaArNkK Feb 15, 2025
569305b
[Feat] AddPTSession 데이터 전달 추가
FpRaArNkK Feb 15, 2025
951af1d
[Fix] 서버 반출 UI 표시 에러 처리 추가
FpRaArNkK Feb 15, 2025
ef29344
[Feat] UINavigationController 제스처 컨트롤 추가
FpRaArNkK Feb 16, 2025
3aa3c30
[Feat] Nav Gesture 비활성 상태를 Int로 관리 -> gestureDisableCount 추가
FpRaArNkK Feb 16, 2025
1cbaf98
[Feat] 제스처 컨트롤 필요화면 전체 적용
FpRaArNkK Feb 16, 2025
ffbd356
[Feat] 트레이너/트레이니 연결 여부 반영
FpRaArNkK Feb 16, 2025
659f68b
[Fix] 식단 추가 유효 검사 로직 수정
FpRaArNkK Feb 16, 2025
edcf1d4
[Feat] 홈 진입시 세션 체크 추가
FpRaArNkK Feb 16, 2025
2fca0ac
[Feat] PhotoPicker Wrapper 작성
FpRaArNkK Feb 16, 2025
c0bd3f3
[Feat] 사진 관련 info.plist 작성
FpRaArNkK Feb 16, 2025
85de89d
[Feat] TraineeAddDietRecord PhotoPickerView 로직 적용
FpRaArNkK Feb 16, 2025
47fef38
[Feat] CreateProfile PhotoPickerView 로직 적용
FpRaArNkK Feb 16, 2025
61d0f18
[Fix] 식단 기록 작성 후 nav back 시 로직 수정
FpRaArNkK Feb 16, 2025
5b7df5c
[Feat] 유저 이름 관련 정책 수정
FpRaArNkK Feb 16, 2025
c6ca366
[Feat] 탭바 관련 UI 수정
FpRaArNkK Feb 16, 2025
061015b
[Feat] 바텀 시트 상단 패딩 조절
FpRaArNkK Feb 16, 2025
7be6d97
[Fix] 폰트, TButton intrinsic 높이 관련 수정
FpRaArNkK Feb 16, 2025
49b7183
[Fix] TrainerHome 수업카드 UI 수정
FpRaArNkK Feb 16, 2025
37b90ff
[Fix] 피드백,회원목록 UI 수정
FpRaArNkK Feb 17, 2025
45672b7
[Feat] 가입시 FCM 토큰 등록 로직 수정
FpRaArNkK Feb 17, 2025
42dfbbe
[Feat] 권한 관련 문구 수정
FpRaArNkK Feb 18, 2025
2681716
[Fix] FCM 토큰 관련 로직 수정
FpRaArNkK Feb 18, 2025
57af9bb
[Fix] AddDietRecord 팝업 로직 수정
FpRaArNkK Feb 22, 2025
403148f
[Fix] AddPTSession 버튼 수정
FpRaArNkK Feb 22, 2025
fbe3af4
[chore] TraineeHome 화면 캐싱 비활성화
FpRaArNkK Feb 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions TnT/Projects/Data/Sources/Network/Foundation/NetworkError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ enum NetworkError: Error {
case unauthorized(message: String?) // 401
case forbidden(message: String?) // 403
case notFound(message: String?) // 404
case conflict(message: String?) // 409

// MARK: - Server Errors (500 ~ 599)
case serverError(statusCode: Int, message: String?)
Expand Down Expand Up @@ -47,6 +48,8 @@ extension NetworkError: LocalizedError {
return "[403] \(message ?? "권한이 없습니다.")"
case .notFound(let message):
return "[404] \(message ?? "요청한 리소스를 찾을 수 없습니다.")"
case .conflict(let message):
return "[409] \(message ?? "요청이 충돌되었습니다.")"
case .timeout:
return "요청 시간이 초과되었습니다."
case .noInternet:
Expand All @@ -57,4 +60,14 @@ extension NetworkError: LocalizedError {
return "[\(statusCode ?? 0)] \(message ?? "알 수 없는 오류 발생")"
}
}

/// UI 표시 여부
var isUIToastError: Bool {
switch self {
case .notFound, .conflict:
return true
default:
return false
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

import Foundation

import Domain

struct ResponseValidatorInterceptor: Interceptor {
let priority: InterceptorPriority = .normal

Expand All @@ -17,11 +19,18 @@ struct ResponseValidatorInterceptor: Interceptor {
}

let statusCode: Int = httpResponse.statusCode
let responseBody: String = String(data: data, encoding: .utf8) ?? "No Response"

switch statusCode {
case 200..<300:
return
default:
try throwError(with: data, statusCode: statusCode)
}
}

private func throwError(with data: Data, statusCode: Int) throws {
let responseBody: String = try JSONDecoder().decode(ErrorResponse.self, from: data).message

switch statusCode {
case 400:
throw NetworkError.badRequest(message: responseBody)

Expand All @@ -33,6 +42,9 @@ struct ResponseValidatorInterceptor: Interceptor {

case 404:
throw NetworkError.notFound(message: responseBody)

case 409:
throw NetworkError.conflict(message: responseBody)

case 405..<500:
throw NetworkError.clientError(statusCode: statusCode, message: responseBody)
Expand Down
2 changes: 2 additions & 0 deletions TnT/Projects/Data/Sources/Network/NetworkService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ public final class NetworkService {
switch error {
case .unauthorized:
NotificationCenter.default.postSessionExpired()
case .notFound(let message), .conflict(let message):
NotificationCenter.default.post(toast: .init(presentType: .text("⚠"), message: message ?? ""))
default:
NotificationCenter.default.post(toast: .init(presentType: .text("⚠"), message: "서버 요청에 실패했어요"))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import AuthenticationServices
import KakaoSDKCommon
import KakaoSDKAuth
import KakaoSDKUser
import FirebaseMessaging

import Domain

Expand Down Expand Up @@ -172,3 +173,20 @@ extension SNSLoginManager {
)
}
}

// MARK: FCM 토큰
extension SNSLoginManager {
public func getFCMToken() async throws -> String {
return try await withCheckedThrowingContinuation { continuation in
Messaging.messaging().token { token, error in
if let error = error {
continuation.resume(throwing: error)
} else if let token = token {
continuation.resume(returning: token)
} else {
continuation.resume(throwing: LoginError.fcmError)
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public enum LoginError: Error {
case networkFailure
case kakaoError
case appleError
case fcmError
case unknown(message: String)
}

Expand All @@ -34,4 +35,8 @@ public struct SocialLogInRepositoryImpl: SocialLoginRepository {
public func kakaoLogin() async -> KakaoLoginInfo? {
return await loginManager.kakaoLogin()
}

public func getFCMToken() async throws -> String {
return try await loginManager.getFCMToken()
}
}
17 changes: 8 additions & 9 deletions TnT/Projects/DesignSystem/Sources/Button/TButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,9 @@ public struct TButton: View {

// 제목 추가
Text(title)
.typographyStyle(config.font, with: textColor)
.frame(maxWidth: .infinity, alignment: .center)
.typographyStyle(config.font, with: textColor)
.frame(maxWidth: .infinity, alignment: .center)
.frame(minHeight: config.font.lineHeight)

// 오른쪽 이미지 추가
if let rightImage = image, rightImage.type == .right || rightImage.type == .both {
Expand All @@ -79,15 +80,13 @@ public struct TButton: View {
.frame(width: rightImage.size, height: rightImage.size)
}
}
.padding(.vertical, config.verticalSize)
.padding(.horizontal, config.horizontalSize)
.background(backgroundColor)
.clipShape(RoundedRectangle(cornerRadius: config.radius))
.overlay {
.padding(.vertical, config.verticalSize + 0.5)
.padding(.horizontal, config.horizontalSize + 0.5)
.background(
RoundedRectangle(cornerRadius: config.radius)
.fill(backgroundColor)
.stroke(borderColor, lineWidth: 1.5)
}
.contentShape(Rectangle())
)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,15 @@ struct AutoSizingBottomSheetModifier: ViewModifier {

func body(content: Content) -> some View {
content
.padding(.top, 24)
.background(
GeometryReader { proxy in
Color.clear
.onAppear {
contentHeight = proxy.size.height + 10
contentHeight = proxy.size.height
}
.onChange(of: proxy.size.height) { _, newHeight in
contentHeight = newHeight + 10
contentHeight = newHeight
}
}
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public struct TPopUpAlertView: View {
Text(alertState.title)
.typographyStyle(.heading3, with: .neutral900)
.multilineTextAlignment(.center)
.fixedSize(horizontal: false, vertical: true)
}

if let message = alertState.message {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,40 +49,40 @@ public struct Typography {
/// - size: 폰트 크기
/// - lineHeightMultiplier: 줄 높이 배율 (CGFloat)
/// - letterSpacing: 자간 (CGFloat)
init(_ weight: Pretendard.Weight, size: CGFloat, lineHeightMultiplier: CGFloat, letterSpacing: CGFloat) {
init(_ weight: Pretendard.Weight, size: CGFloat, lineHeightMultiplier: CGFloat, letterSpacingRate: CGFloat) {
self.font = weight.fontConvertible.swiftUIFont(size: size)
self.uiFont = weight.fontConvertible.font(size: size)
self.size = size
self.lineHeight = size * lineHeightMultiplier
self.lineSpacing = (size * lineHeightMultiplier) - size
self.letterSpacing = letterSpacing
self.letterSpacing = size * letterSpacingRate
}
}
}

/// 앱에서 사용할 기본적인 폰트 스타일을 정의합니다.
public extension Typography.FontStyle {
// Heading Styles
static let heading1: Typography.FontStyle = Typography.FontStyle(.bold, size: 28, lineHeightMultiplier: 1.4, letterSpacing: -0.02)
static let heading2: Typography.FontStyle = Typography.FontStyle(.bold, size: 24, lineHeightMultiplier: 1.5, letterSpacing: -0.02)
static let heading3: Typography.FontStyle = Typography.FontStyle(.bold, size: 20, lineHeightMultiplier: 1.5, letterSpacing: -0.02)
static let heading4: Typography.FontStyle = Typography.FontStyle(.bold, size: 18, lineHeightMultiplier: 1.5, letterSpacing: -0.02)
static let heading1: Typography.FontStyle = Typography.FontStyle(.bold, size: 28, lineHeightMultiplier: 1.4, letterSpacingRate: -0.02)
static let heading2: Typography.FontStyle = Typography.FontStyle(.bold, size: 24, lineHeightMultiplier: 1.5, letterSpacingRate: -0.02)
static let heading3: Typography.FontStyle = Typography.FontStyle(.bold, size: 20, lineHeightMultiplier: 1.5, letterSpacingRate: -0.02)
static let heading4: Typography.FontStyle = Typography.FontStyle(.bold, size: 18, lineHeightMultiplier: 1.5, letterSpacingRate: -0.02)

// Body Styles
static let body1Bold: Typography.FontStyle = Typography.FontStyle(.bold, size: 16, lineHeightMultiplier: 1.5, letterSpacing: -0.02)
static let body1Semibold: Typography.FontStyle = Typography.FontStyle(.semibold, size: 16, lineHeightMultiplier: 1.5, letterSpacing: -0.02)
static let body1Medium: Typography.FontStyle = Typography.FontStyle(.medium, size: 16, lineHeightMultiplier: 1.6, letterSpacing: -0.02)
static let body2Bold: Typography.FontStyle = Typography.FontStyle(.bold, size: 15, lineHeightMultiplier: 1.5, letterSpacing: -0.02)
static let body2Medium: Typography.FontStyle = Typography.FontStyle(.medium, size: 15, lineHeightMultiplier: 1.5, letterSpacing: -0.02)
static let body1Bold: Typography.FontStyle = Typography.FontStyle(.bold, size: 16, lineHeightMultiplier: 1.5, letterSpacingRate: -0.02)
static let body1Semibold: Typography.FontStyle = Typography.FontStyle(.semibold, size: 16, lineHeightMultiplier: 1.5, letterSpacingRate: -0.02)
static let body1Medium: Typography.FontStyle = Typography.FontStyle(.medium, size: 16, lineHeightMultiplier: 1.6, letterSpacingRate: -0.02)
static let body2Bold: Typography.FontStyle = Typography.FontStyle(.bold, size: 15, lineHeightMultiplier: 1.5, letterSpacingRate: -0.02)
static let body2Medium: Typography.FontStyle = Typography.FontStyle(.medium, size: 15, lineHeightMultiplier: 1.5, letterSpacingRate: -0.02)

// Label Styles
static let label1Bold: Typography.FontStyle = Typography.FontStyle(.bold, size: 13, lineHeightMultiplier: 1.3, letterSpacing: -0.02)
static let label1Medium: Typography.FontStyle = Typography.FontStyle(.medium, size: 13, lineHeightMultiplier: 1.5, letterSpacing: -0.02)
static let label2Bold: Typography.FontStyle = Typography.FontStyle(.bold, size: 12, lineHeightMultiplier: 1.5, letterSpacing: -0.02)
static let label2Medium: Typography.FontStyle = Typography.FontStyle(.medium, size: 12, lineHeightMultiplier: 1.5, letterSpacing: -0.02)
static let label1Bold: Typography.FontStyle = Typography.FontStyle(.bold, size: 13, lineHeightMultiplier: 1.3, letterSpacingRate: -0.02)
static let label1Medium: Typography.FontStyle = Typography.FontStyle(.medium, size: 13, lineHeightMultiplier: 1.5, letterSpacingRate: -0.02)
static let label2Bold: Typography.FontStyle = Typography.FontStyle(.bold, size: 12, lineHeightMultiplier: 1.5, letterSpacingRate: -0.02)
static let label2Medium: Typography.FontStyle = Typography.FontStyle(.medium, size: 12, lineHeightMultiplier: 1.5, letterSpacingRate: -0.02)

// Caption Styles
static let caption1: Typography.FontStyle = Typography.FontStyle(.medium, size: 11, lineHeightMultiplier: 1.3, letterSpacing: -0.02)
static let caption1: Typography.FontStyle = Typography.FontStyle(.medium, size: 11, lineHeightMultiplier: 1.3, letterSpacingRate: -0.02)
}

/// 텍스트에 Typography 스타일과 색상을 적용하는 ViewModifier입니다.
Expand All @@ -91,13 +91,31 @@ public extension Typography.FontStyle {
struct TypographyModifier: ViewModifier {
let style: Typography.FontStyle
let color: Color

func body(content: Content) -> some View {
content
.font(style.font)
.lineSpacing(style.lineSpacing)
.kerning(style.letterSpacing)
.foregroundStyle(color)
.background(
GeometryReader { proxy in
Color.clear
.onAppear {
if proxy.size.height < style.lineHeight {
applySingleLineFix(content: content)
}
}
}
)
}

/// 한 줄짜리 텍스트에 대한 lineHeight 적용
@ViewBuilder
private func applySingleLineFix(content: Content) -> some View {
content
.frame(height: style.lineHeight)
.baselineOffset((style.lineHeight - style.size) / 2)
}
}

Expand Down
4 changes: 4 additions & 0 deletions TnT/Projects/Domain/Sources/DTO/EmptyResponse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,7 @@ import Foundation
public struct EmptyResponse: Decodable {
public init() {}
}

public struct ErrorResponse: Decodable {
public let message: String
}
12 changes: 6 additions & 6 deletions TnT/Projects/Domain/Sources/Entity/SocailLoginEntity.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,21 @@

import Foundation

public enum SocialType: String {
public enum SocialType: String, Sendable {
case kakao = "KAKAO"
case apple = "APPLE"
}

/// 소셜 로그인 요청 DTO
public struct PostSocialEntity: Equatable {
public struct PostSocialEntity: Equatable, Sendable {
/// 소셜 로그인 타입 (KAKAO, APPLE)
let socialType: SocialType
public let socialType: SocialType
/// FCM 토큰
let fcmToken: String
public var fcmToken: String
/// 소셜 액세스 토큰
let socialAccessToken: String?
public let socialAccessToken: String?
/// 애플 ID 토큰 (Apple z로그인 시 필요)
let idToken: String?
public let idToken: String?

public init(
socialType: SocialType,
Expand Down
2 changes: 1 addition & 1 deletion TnT/Projects/Domain/Sources/Policy/UserPolicy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ struct UserPolicy {

/// 사용자 이름 검증 - 한글/영어/공백만 허용 (특수문자 불가)
static let userNameInput: PolicyInputInfo = .init(
textValidation: { TextValidator.isValidInput($0, maxLength: maxNameLength, regexPattern: "^[ㄱ-ㅎㅏ-ㅣ가-힣a-zA-Z ]*$") },
textValidation: { TextValidator.isValidInput($0, maxLength: maxNameLength, regexPattern: "^(?!\\s*$)[ㄱ-ㅎㅏ-ㅣ가-힣a-zA-Z ]*$") },
isRequired: true
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ public protocol SocialLoginRepository {
func appleLogin() async -> AppleLoginInfo?
/// 카카오 로그인을 수행합니다
func kakaoLogin() async -> KakaoLoginInfo?
/// FCM 토큰을 가져옵니다
func getFCMToken() async throws -> String
}
4 changes: 4 additions & 0 deletions TnT/Projects/Domain/Sources/UseCase/SocialLoginUseCase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,8 @@ public struct SocialLoginUseCase {
public func kakaoLogin() async -> KakaoLoginInfo? {
return await socialLoginRepository.kakaoLogin()
}

public func getFCMToken() async throws -> String {
return try await socialLoginRepository.getFCMToken()
}
}
Loading