Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
25c7ecd
[BOOK-499] feat: “내 기록 모음” 부분 텍스트 색상 수정
doyeonk429 Feb 8, 2026
f198b07
[BOOK-499] feat: 도서 상세 헤더 간격 수정
doyeonk429 Feb 8, 2026
c348d2e
[BOOK-499] feat: “내 기록 모음” 상단 간격 수정
doyeonk429 Feb 8, 2026
1009109
[BOOK-499] feat: BookDetailItem page -> Int?로 변경
doyeonk429 Feb 8, 2026
e89a389
[BOOK-499] feat: BookDetailViewCell 디자인 수정
doyeonk429 Feb 8, 2026
f6c138d
[BOOK-499] feat: Colorsystem 수정사항 반영
doyeonk429 Feb 8, 2026
91c05ae
[BOOK-499] feat: SeedGraphView(progress bar) 개발
doyeonk429 Feb 9, 2026
c9fe268
[BOOK-499] feat: SeedItemView 개발
doyeonk429 Feb 9, 2026
fbd54e3
[BOOK-499] feat: SeedReportView 내부 뷰 수정
doyeonk429 Feb 9, 2026
3aaa798
[BOOK-499] feat: add api-v2 base url
doyeonk429 Feb 9, 2026
d26e95c
[BOOK-499] feat: etc emotion case 추가
doyeonk429 Feb 9, 2026
8ef8f5e
[BOOK-499] feat: api-v2 적용하는 케이스만 따로 분류
doyeonk429 Feb 9, 2026
f27f584
[BOOK-499] feat: fetch, seed v2 responseDTO 추가
doyeonk429 Feb 9, 2026
38d0ce3
[BOOK-499] feat: fetch in RecordRepo 수정 및 RecordFetchResult Entity 생성
doyeonk429 Feb 9, 2026
7644789
[BOOK-499] feat: FetchRecordsUseCase 수정
doyeonk429 Feb 9, 2026
124cf2a
[BOOK-499] feat: 대표감정 api 연결
doyeonk429 Feb 9, 2026
ad31bd2
[BOOK-499] fix: Emotion 추가 케이스 관련한 예외 처리
doyeonk429 Feb 9, 2026
79bf7a9
[BOOK-499] fix: 불필요한 출력문 제거
doyeonk429 Feb 9, 2026
415d021
[BOOK-499] feat: 설명 텍스트 EmotionSeed case에 따라 분리
doyeonk429 Feb 9, 2026
ca5ce5d
[BOOK-499] fix: codeRabbit review 반영
doyeonk429 Feb 9, 2026
131c1ac
[BOOK-499] fix: peer Review 반영
doyeonk429 Feb 14, 2026
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
10 changes: 10 additions & 0 deletions src/Projects/BKCore/Sources/Extension/Optional.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright © 2026 Booket. All rights reserved

import UIKit

public extension Optional where Wrapped == Int {
/// Int? 값을 "123p" 또는 값이 없을 경우 "-p" 문자열로 반환합니다.
var toPageString: String {
return self.map { "\($0)p" } ?? "-p"
}
}
7 changes: 6 additions & 1 deletion src/Projects/BKData/Sources/API/RecordAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@ enum RecordAPI {

extension RecordAPI: RequestTarget {
var baseURL: String {
return "\(APIConfig.baseURL)/reading-records"
switch self {
case .fetch, .seed:
return "\(APIConfig.baseV2URL)/reading-records"
default:
return "\(APIConfig.baseURL)/reading-records"
}
}

var path: String {
Expand Down
7 changes: 7 additions & 0 deletions src/Projects/BKData/Sources/Constant/APIConfig.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,11 @@ enum APIConfig {
}
return value
}()

static let baseV2URL: String = {
guard let value = bundle.object(forInfoDictionaryKey: "BASE_API_V2_URL") as? String else {
fatalError("Can't load environment: BKData.BASE_API_V2_URL")
}
return value
}()
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,39 @@ extension DetailRecordResponseDTO {
)
}
}

// api-v2
public struct DetailRecordV2ResponseDTO: Decodable {
public let id: String
public let userBookId: String
public let pageNumber: Int
public let quote: String
public let review: String?
public let primaryEmotion: PrimaryEmotionResponseDTO
public let detailEmotions: [DetailEmotionResponseDTO?]
public let createdAt: String
public let updatedAt: String
public let bookTitle: String
public let bookPublisher: String
public let bookCoverImageUrl: URL
public let author: String
}

extension DetailRecordV2ResponseDTO {
func toRecordInfo() -> RecordInfo {
return RecordInfo(
recordId: id,
bookId: userBookId,
pageNumber: pageNumber,
quote: quote,
review: review,
emotionTags: [primaryEmotion.displayName],
createdAt: DateParser.parseISO8601(createdAt) ?? .distantPast,
updatedAt: DateParser.parseISO8601(updatedAt),
bookTitle: bookTitle,
bookPublisher: bookPublisher,
bookCoverImageUrl: bookCoverImageUrl,
author: author
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
import BKDomain

struct FetchRecordResponseDTO: Decodable {
let readingRecords: [DetailRecordResponseDTO]
let readingRecords: [DetailRecordV2ResponseDTO]
let lastPage: Bool
let totalResults: Int
let representativeEmotion: PrimaryEmotionResponseDTO?
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright © 2026 Booket. All rights reserved

import BKDomain

public struct PrimaryEmotionResponseDTO: Decodable {
let code: String
let displayName: Emotion
}

public struct DetailEmotionResponseDTO: Decodable {
let id: String
let name: String
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public final class DefaultRecordRepository: RecordRepository {
bookId: String,
sortType: LibrarySortType,
page: Int
) -> AnyPublisher<(infos: [RecordInfo], hasMore: Bool, totalCount: Int), DomainError> {
) -> AnyPublisher<RecordFetchResult, DomainError> {
networkProvider.request(
target: RecordAPI.fetch(
userBookId: bookId,
Expand All @@ -46,7 +46,14 @@ public final class DefaultRecordRepository: RecordRepository {
)
.mapError { $0.toDomainError() }
.debugError(logger: AppLogger.network)
.map { ($0.readingRecords.map { $0.toRecordInfo() }, !$0.lastPage, $0.totalResults) }
.map {
RecordFetchResult(
infos: $0.readingRecords.map { $0.toRecordInfo() },
hasMore: !$0.lastPage,
totalCount: $0.totalResults,
mainEmotion: $0.representativeEmotion?.displayName
)
}
.eraseToAnyPublisher()
}

Expand Down
13 changes: 13 additions & 0 deletions src/Projects/BKDesign/Sources/Extensions/UIColor+.swift
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,19 @@ public extension UIColor {
}
}

static func bkEmotionGraphTintColor(
_ semanticColor: BKSemanticColor.EmotionGraphTint
) -> UIColor {
return UIColor { traitCollection in
switch traitCollection.userInterfaceStyle {
case .dark:
return semanticColor.resolve(for: .light)
default:
return semanticColor.resolve(for: .light)
}
}
}

static func bkShadowColor(
_ semanticColor: BKSemanticColor.Shadow
) -> UIColor {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,16 +89,50 @@ public enum BKAtomicColor {

// Blue Palette
public enum Blue: String {
case b50 = "#e3f4ff"
case b100 = "#bbe2ff"
case b200 = "#8dd0ff"
case b300 = "#56bdff"
case b400 = "#1dadff"
case b500 = "#009eff"
case b600 = "#008fff"
case b700 = "#007bff"
case b800 = "#1269ec"
case b900 = "#1f47cd"
case b50 = "#EBF3FF"
case b100 = "#C0D8FF"
case b200 = "#94BDFF"
case b300 = "#68A3FF"
case b400 = "#3C88FF"
case b500 = "#2A74E9"
case b600 = "#195CC7"
case b700 = "#0B47A5"
case b800 = "#013383"
case b900 = "#002661"

public var color: UIColor {
return UIColor(hex: self.rawValue)
}
}

public enum Orange: String {
case o50 = "#FFF1EB"
case o100 = "#FFD2BE"
case o200 = "#FFB392"
case o300 = "#FF9365"
case o400 = "#EF6D35"
case o500 = "#CD5622"
case o600 = "#AB4114"
case o700 = "#892F08"
case o800 = "#672001"
case o900 = "#451500"

public var color: UIColor {
return UIColor(hex: self.rawValue)
}
}

public enum Violet: String {
case v50 = "#F7F0FF"
case v100 = "#E6CEFF"
case v200 = "#D4ADFF"
case v300 = "#C38CFF"
case v400 = "#B26AFF"
case v500 = "#9A55E4"
case v600 = "#7F40C2"
case v700 = "#652EA0"
case v800 = "#4C1E7E"
case v900 = "#36125C"

public var color: UIColor {
return UIColor(hex: self.rawValue)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,22 +129,24 @@ public enum BKSemanticColor {
case joy
case insight
case sadness
case etc

public func resolve(for mode: BKColorMode) -> UIColor {
switch mode {
case .light:
switch self {
case .warmth: return UIColor(hex: "#E3931B")
case .joy: return UIColor(hex: "#EE6B33")
case .insight: return UIColor(hex: "#9A55E4")
case .sadness: return UIColor(hex: "#2872E9")
case .warmth: return BKAtomicColor.Yellow.y700.color
case .joy: return BKAtomicColor.Orange.o400.color
case .insight: return BKAtomicColor.Violet.v500.color
case .sadness: return BKAtomicColor.Blue.b500.color
case .etc: return .bkContentColor(.secondary)
}
// case .dark:
// switch self { /* dark mode colors */ }
}
}
}

public enum EmotionBase {
case warmth
case joy
Expand All @@ -166,6 +168,29 @@ public enum BKSemanticColor {
}
}

public enum EmotionGraphTint {
case warmth
case joy
case insight
case sadness
case etc

public func resolve(for mode: BKColorMode) -> UIColor {
switch mode {
case .light:
switch self {
case .warmth: return BKAtomicColor.Yellow.y300.color
case .joy: return BKAtomicColor.Orange.o300.color
case .insight: return BKAtomicColor.Violet.v300.color
case .sadness: return BKAtomicColor.Blue.b300.color
case .etc: return BKAtomicColor.Neutral.n300.color
}
// case .dark:
// switch self { /* dark mode colors */ }
}
}
}

public enum Shadow {
case primary

Expand Down
1 change: 1 addition & 0 deletions src/Projects/BKDomain/Sources/Entity/Emotion.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ public enum Emotion: String, CaseIterable, Decodable {
case joy = "즐거움"
case sad = "슬픔"
case insight = "깨달음"
case etc = "기타"
}
22 changes: 22 additions & 0 deletions src/Projects/BKDomain/Sources/Entity/RecordFetchResult.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright © 2026 Booket. All rights reserved

import Foundation

public struct RecordFetchResult {
public let infos: [RecordInfo]
public let hasMore: Bool
public let totalCount: Int
public let mainEmotion: Emotion?

public init(
infos: [RecordInfo],
hasMore: Bool,
totalCount: Int,
mainEmotion: Emotion?
) {
self.infos = infos
self.hasMore = hasMore
self.totalCount = totalCount
self.mainEmotion = mainEmotion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public protocol RecordRepository {
bookId: String,
sortType: LibrarySortType,
page: Int
) -> AnyPublisher<(infos: [RecordInfo], hasMore: Bool, totalCount: Int), DomainError>
) -> AnyPublisher<RecordFetchResult, DomainError>

func findBy(
id recordId: String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ public protocol FetchRecordsUseCase {
func execute(
id: String,
page: Int
) -> AnyPublisher<(infos: [RecordInfo], hasMore: Bool, totalCount: Int), DomainError>
) -> AnyPublisher<RecordFetchResult, DomainError>
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public struct DefaultFetchRecordsUseCase: FetchRecordsUseCase {
public func execute(
id: String,
page: Int
) -> AnyPublisher<(infos: [RecordInfo], hasMore: Bool, totalCount: Int), DomainError> {
) -> AnyPublisher<RecordFetchResult, DomainError> {
repository.fetch(
bookId: id,
sortType: .pageNumberDesc,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ struct BookDetailItem: Hashable {
/// 감정
let emotion: EmotionSeed?
let createdAt: Date
let page: Int
let page: Int?
let bookTitle: String

static func from(recordInfo: RecordInfo) -> Self {
Expand Down
Loading