Skip to content

Commit 29a59db

Browse files
committed
[feat] #188 프로필 설정 API 구성
1 parent d1585b6 commit 29a59db

10 files changed

Lines changed: 183 additions & 37 deletions

File tree

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//
2+
// ProfileEditRequest.swift
3+
// CoreKit
4+
//
5+
// Created by 김민호 on 2/25/25.
6+
//
7+
8+
import Foundation
9+
/// 프로필 수정 API Request
10+
public struct ProfileEditRequest: Encodable {
11+
public let profileImageId: Int?
12+
public let nickname: String
13+
14+
public init(profileImageId: Int?, nickname: String) {
15+
self.profileImageId = profileImageId
16+
self.nickname = nickname
17+
}
18+
}
19+
20+
extension ProfileEditRequest {
21+
public func encode(to encoder: Encoder) throws {
22+
var container = encoder.container(keyedBy: CodingKeys.self)
23+
24+
try container.encodeIfPresent(profileImageId, forKey: .profileImageId)
25+
try container.encode(nickname, forKey: .nickname)
26+
27+
if profileImageId == nil {
28+
try container.encodeNil(forKey: .profileImageId)
29+
}
30+
}
31+
32+
private enum CodingKeys: String, CodingKey {
33+
case profileImageId
34+
case nickname
35+
}
36+
}

Projects/CoreKit/Sources/Data/Network/User/UserClient+LiveKey.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ extension UserClient: DependencyKey {
1515
let provider = MoyaProvider<UserEndpoint>.build()
1616

1717
return Self(
18+
프로필_수정: { model in
19+
try await provider.request(.프로필_수정(model: model))
20+
},
1821
닉네임_수정: { model in
1922
try await provider.request(.닉네임_수정(model: model))
2023
},

Projects/CoreKit/Sources/Data/Network/User/UserClient+TestKey.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import Dependencies
1212
extension UserClient: TestDependencyKey {
1313
public static let previewValue: Self = {
1414
Self(
15+
프로필_수정: { _ in .mock },
1516
닉네임_수정: { _ in .mock },
1617
회원등록: { _ in .mock },
1718
닉네임_중복_체크: { _ in .mock },

Projects/CoreKit/Sources/Data/Network/User/UserClient.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import DependenciesMacros
99

1010
@DependencyClient
1111
public struct UserClient {
12+
public var 프로필_수정: @Sendable (_ model: ProfileEditRequest) async throws -> BaseUserResponse
1213
public var 닉네임_수정: @Sendable (_ model: NicknameEditRequest) async throws -> BaseUserResponse
1314
public var 회원등록: @Sendable (_ model: SignupRequest) async throws -> BaseUserResponse
1415
public var 닉네임_중복_체크: @Sendable (_ nickname: String) async throws -> NicknameCheckResponse

Projects/CoreKit/Sources/Data/Network/User/UserEndpoint.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import Util
1111
import Moya
1212
/// 컨텐츠 전용 Endpont
1313
public enum UserEndpoint {
14+
case 프로필_수정(model: ProfileEditRequest)
1415
case 닉네임_수정(model: NicknameEditRequest)
1516
case 회원등록(model: SignupRequest)
1617
case 닉네임_중복_체크(nickname: String)
@@ -27,6 +28,8 @@ extension UserEndpoint: TargetType {
2728

2829
public var path: String {
2930
switch self {
31+
case .프로필_수정:
32+
return ""
3033
case .닉네임_수정, .닉네임_조회:
3134
return "/nickname"
3235
case .회원등록:
@@ -44,7 +47,7 @@ extension UserEndpoint: TargetType {
4447

4548
public var method: Moya.Method {
4649
switch self {
47-
case .닉네임_수정:
50+
case .프로필_수정, .닉네임_수정:
4851
return .put
4952

5053
case .회원등록,
@@ -61,6 +64,8 @@ extension UserEndpoint: TargetType {
6164

6265
public var task: Moya.Task {
6366
switch self {
67+
case let .프로필_수정(model):
68+
return .requestJSONEncodable(model)
6469
case let .닉네임_수정(model):
6570
return .requestJSONEncodable(model)
6671
case let .회원등록(model):

Projects/Domain/Sources/DTO/User/BaseUserResponse+Extension.swift

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,9 @@ public extension BaseUserResponse {
1515
id: self.id,
1616
email: self.email,
1717
nickname: self.nickname,
18-
profile: BaseProfile(
19-
id: self.profileImage?.id ?? 0,
20-
url: self.profileImage?.url ?? ""
21-
)
18+
profile: self.profileImage == nil
19+
? nil
20+
: BaseProfile(id: self.profileImage?.id ?? 0, url: self.profileImage?.url ?? "")
2221
)
2322
}
2423
}

Projects/Domain/Sources/NicknameSetting/NicknameSetting.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,23 @@ public struct NicknameSetting: Equatable {
1313
public var user: BaseUser? = nil
1414
/// 닉네임 중복 여부
1515
public var isDuplicate: Bool
16+
/// 유저 선택 프로필
17+
public var selectedProfile: BaseCategoryImage?
18+
/// 프로필에 설정할 수 있는 이미지
19+
public var imageList: [BaseCategoryImage]
1620

1721
// - MARK: Request
1822
/// 등록할 닉네임
1923
public var nickname: String
2024

2125
public init(
2226
isDuplicate: Bool = false,
23-
nickname: String = ""
27+
nickname: String = "",
28+
selectedProfile: BaseCategoryImage?
2429
) {
30+
self.imageList = []
2531
self.isDuplicate = isDuplicate
2632
self.nickname = nickname
33+
self.selectedProfile = selectedProfile
2734
}
2835
}

Projects/Feature/FeatureSetting/Sources/Setting/NickNameSetting/NickNameSettingFeature.swift

Lines changed: 80 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,27 @@
55
// Created by 김민호 on 7/22/24.
66

77
import ComposableArchitecture
8-
import Domain
8+
99
import CoreKit
10+
import Domain
1011
import DSKit
1112
import Util
1213

1314
@Reducer
1415
public struct NickNameSettingFeature {
1516
/// - Dependency
16-
@Dependency(\.dismiss) var dismiss
17-
@Dependency(\.mainQueue) var mainQueue
18-
@Dependency(UserClient.self) var userClient
17+
@Dependency(\.dismiss)
18+
var dismiss
19+
@Dependency(\.mainQueue)
20+
var mainQueue
21+
@Dependency(UserClient.self)
22+
var userClient
23+
@Dependency(CategoryClient.self)
24+
var categoryClient
1925
/// - State
2026
@ObservableState
2127
public struct State: Equatable {
22-
fileprivate var domain = NicknameSetting()
28+
fileprivate var domain: NicknameSetting
2329
var text: String {
2430
get { self.domain.nickname }
2531
set { self.domain.nickname = newValue }
@@ -28,10 +34,32 @@ public struct NickNameSettingFeature {
2834
get { domain.user }
2935
}
3036

37+
var selectedProfile: BaseCategoryImage? {
38+
get { domain.selectedProfile }
39+
set { domain.selectedProfile = newValue }
40+
}
41+
42+
var profileImages: [BaseCategoryImage] {
43+
get { domain.imageList }
44+
}
45+
3146
var textfieldState: PokitInputStyle.State = .default
3247
var buttonState: PokitButtonStyle.State = .disable
48+
var isProfileSheetPresented: Bool = false
3349

34-
public init() {}
50+
public init(user: BaseUser?) {
51+
if let user,
52+
let profile = user.profile {
53+
self.domain = .init(
54+
selectedProfile: BaseCategoryImage(
55+
imageId: profile.id,
56+
imageURL: profile.url
57+
)
58+
)
59+
} else {
60+
self.domain = .init(selectedProfile: nil)
61+
}
62+
}
3563
}
3664

3765
/// - Action
@@ -46,23 +74,29 @@ public struct NickNameSettingFeature {
4674
public enum View: BindableAction, Equatable {
4775
case binding(BindingAction<State>)
4876
case dismiss
77+
4978
case 저장_버튼_눌렀을때
5079
case 뷰가_나타났을때
5180
case 닉네임지우기_버튼_눌렀을때
81+
case 프로필_설정_버튼_눌렀을때
5282
}
5383

5484
public enum InnerAction: Equatable {
5585
case 닉네임_텍스트_변경되었을때
5686
case 닉네임_중복_확인_API_반영(Bool)
5787
case 닉네임_조회_API_반영(BaseUser)
88+
case 프로필_목록_조회_API_반영(images: [BaseCategoryImage])
5889
}
5990

6091
public enum AsyncAction: Equatable {
6192
case 닉네임_중복_확인_API
6293
case 닉네임_조회_API
94+
case 프로필_목록_조회_API
6395
}
6496

65-
public enum ScopeAction: Equatable { case 없음 }
97+
public enum ScopeAction {
98+
case profile(PokitProfileBottomSheet<BaseCategoryImage>.Delegate)
99+
}
66100

67101
public enum DelegateAction: Equatable { case 없음 }
68102
}
@@ -124,17 +158,30 @@ private extension NickNameSettingFeature {
124158
return .run { _ in await dismiss() }
125159

126160
case .저장_버튼_눌렀을때:
127-
return .run { [nickName = state.text] send in
128-
let request = NicknameEditRequest(nickname: nickName)
129-
let _ = try await userClient.닉네임_수정(request)
161+
return .run { [nickName = state.text, selectedImage = state.selectedProfile] send in
162+
if let selectedImage {
163+
let request = ProfileEditRequest(profileImageId: selectedImage.id, nickname: nickName)
164+
let _ = try await userClient.프로필_수정(model: request)
165+
} else {
166+
let request = ProfileEditRequest(profileImageId: nil, nickname: nickName)
167+
let _ = try await userClient.프로필_수정(model: request)
168+
}
130169
await dismiss()
131170
}
132171

133172
case .뷰가_나타났을때:
134-
return .send(.async(.닉네임_조회_API))
173+
return .merge(
174+
.send(.async(.프로필_목록_조회_API)),
175+
.send(.async(.닉네임_조회_API))
176+
)
177+
135178
case .닉네임지우기_버튼_눌렀을때:
136179
state.domain.nickname = ""
137180
return .none
181+
182+
case .프로필_설정_버튼_눌렀을때:
183+
state.isProfileSheetPresented.toggle()
184+
return .none
138185
}
139186
}
140187

@@ -176,6 +223,15 @@ private extension NickNameSettingFeature {
176223
case let .닉네임_조회_API_반영(user):
177224
state.domain.user = user
178225
state.domain.nickname = user.nickname
226+
if let profile = user.profile {
227+
state.selectedProfile = BaseCategoryImage(imageId: profile.id, imageURL: profile.url)
228+
} else {
229+
state.selectedProfile = nil
230+
}
231+
return .none
232+
233+
case let .프로필_목록_조회_API_반영(images):
234+
state.domain.imageList = images
179235
return .none
180236
}
181237
}
@@ -194,12 +250,24 @@ private extension NickNameSettingFeature {
194250
let user = try await userClient.닉네임_조회().toDomain()
195251
await send(.inner(.닉네임_조회_API_반영(user)), animation: .easeInOut)
196252
}
253+
254+
case .프로필_목록_조회_API:
255+
return .run { send in
256+
let response = try await categoryClient.카테고리_프로필_목록_조회()
257+
let images = response.map { $0.toDomain() }
258+
await send(.inner(.프로필_목록_조회_API_반영(images: images)))
259+
}
197260
}
198261
}
199262

200263
/// - Scope Effect
201264
func handleScopeAction(_ action: Action.ScopeAction, state: inout State) -> Effect<Action> {
202-
return .none
265+
switch action {
266+
case .profile(.이미지_선택했을때(let imageInfo)):
267+
state.isProfileSheetPresented = false
268+
state.selectedProfile = imageInfo
269+
return .none
270+
}
203271
}
204272

205273
/// - Delegate Effect

0 commit comments

Comments
 (0)