Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions Projects/Core/Network/Interface/Sources/Endpoint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public enum FeatureTag: String {
case proopPhoto = "ProofPhoto"
case notification = "Notification"
case poke = "Poke"
case stats = "Stats"
case unknown = "Unknown"
}

Expand Down
70 changes: 70 additions & 0 deletions Projects/Domain/Stats/Interface/Sources/DTO/StatsResponseDTO.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//
// StatsResponseDTO.swift
// DomainStats
//
// Created by 정지훈 on 2/25/26.
//

import Foundation

/// 통계 목록 조회 응답을 디코딩하는 DTO입니다.
public struct StatsResponseDTO: Decodable {
let selectedDate: String
let statsGoals: [StatsGoal]

struct StatsGoal: Codable {
let goalId: Int64
let goalName: String
let goalIconType: String
let monthlyTargetCount: Int
let stamp: String
let myStats: Stats
let partnerStats: Stats

struct Stats: Codable {
let nickname: String
let endCount: Int
let stampColors: [String]
}
}
}

extension StatsResponseDTO {
/// 통계 목록 응답 DTO를 도메인 `Stats` 엔티티로 변환합니다.
///
/// ## 사용 예시
/// ```swift
/// let dto: StatsResponseDTO = ...
/// let stats = dto.toEntity(isInProgress: true)
/// ```
public func toEntity(isInProgress: Bool) -> Stats? {
guard let firstStats = statsGoals.first else { return nil }

return Stats(
myNickname: firstStats.myStats.nickname,
partnerNickname: firstStats.partnerStats.nickname,
stats: statsGoals.map {
Stats.StatsItem(
goalId: $0.goalId,
icon: $0.goalIconType,
goalName: $0.goalName,
monthlyCount: $0.monthlyTargetCount,
totalCount: isInProgress ? nil : $0.monthlyTargetCount,
stamp: $0.stamp,
myStamp: .init(
completedCount: $0.myStats.endCount,
stampColors: isInProgress
? $0.myStats.stampColors.compactMap { Stats.StatsItem.StampColor.init(rawValue: $0) }
: []
),
partnerStamp: .init(
completedCount: $0.partnerStats.endCount,
stampColors: isInProgress
? $0.partnerStats.stampColors.compactMap { Stats.StatsItem.StampColor.init(rawValue: $0) }
: []
)
)
}
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//
// StatsEndpoint.swift
// DomainStats
//
// Created by 정지훈 on 2/25/26.
//

import Foundation

import CoreNetworkInterface

/// 통계 목록 조회 API 엔드포인트를 정의합니다.
public enum StatsEndpoint: Endpoint {
case fetchStats(selectedDate: String, status: String)
}

extension StatsEndpoint {
public var path: String {
switch self {
case .fetchStats:
return "/api/v1/stats"
}
}

public var method: HTTPMethod {
switch self {
case .fetchStats:
return .get
}
}

public var headers: [String : String]? {
["Content-Type": "application/json"]
}

public var query: [URLQueryItem]? {
switch self {
case let .fetchStats(date, status):
return [
.init(name: "selectedDate", value: date),
.init(name: "status", value: status),
]
}
}

public var body: (any Encodable)? {
switch self {
case .fetchStats:
return nil
}
}

public var requiresAuth: Bool { true }
public var featureTag: FeatureTag { .stats }
}
54 changes: 34 additions & 20 deletions Projects/Domain/Stats/Interface/Sources/Entity/Stats.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,39 +81,53 @@ public struct Stats: Equatable {
public let goalName: String
public let monthlyCount: Int?
public let totalCount: Int?
public let myCompletedCount: Int
public let partnerCompletedCount: Int
public let stamp: String?
public let myStamp: Stamp
public let partnerStamp: Stamp

/// 단일 목표 통계 항목을 생성합니다.
///
/// ## 사용 예시
/// ```swift
/// let item = Stats.StatsItem(
/// goalId: 1,
/// icon: "ICON_BOOK",
/// goalName: "독서하기",
/// monthlyCount: 12,
/// totalCount: nil,
/// myCompletedCount: 6,
/// partnerCompletedCount: 2
/// )
/// ```
public init(
goalId: Int64,
icon: String,
goalName: String,
monthlyCount: Int?,
totalCount: Int?,
myCompletedCount: Int,
partnerCompletedCount: Int
stamp: String?,
myStamp: Stamp,
partnerStamp: Stamp
) {
self.goalId = goalId
self.icon = icon
self.goalName = goalName
self.monthlyCount = monthlyCount
self.totalCount = totalCount
self.myCompletedCount = myCompletedCount
self.partnerCompletedCount = partnerCompletedCount
self.stamp = stamp
self.myStamp = myStamp
self.partnerStamp = partnerStamp
}

/// 통계 스탬프에서 사용하는 색상 타입입니다.
public enum StampColor: String, Equatable, CaseIterable {
case green400 = "GREEN400"
case blue400 = "BLUE400"
case yellow400 = "YELLOW400"
case pink400 = "PINK400"
case pink300 = "PINK300"
case pink200 = "PINK200"
case orange400 = "ORANGE400"
case purple400 = "PURPLE400"
}

public struct Stamp: Equatable {
public let completedCount: Int
public let stampColors: [StampColor]

public init(
completedCount: Int,
stampColors: [StampColor]
) {
self.completedCount = completedCount
self.stampColors = stampColors
}
}
}
}
Loading