커뮤니티 댓글, 답글 추가 APi 적용
This commit is contained in:
		| @@ -0,0 +1,150 @@ | ||||
| // | ||||
| //  CreatorCommunityCommentItemView.swift | ||||
| //  SodaLive | ||||
| // | ||||
| //  Created by klaus on 2023/12/20. | ||||
| // | ||||
|  | ||||
| import SwiftUI | ||||
| import Kingfisher | ||||
|  | ||||
| struct CreatorCommunityCommentItemView: View { | ||||
|     let creatorId: Int | ||||
|     let postId: Int | ||||
|     let commentItem: GetCommunityPostCommentListItem | ||||
|     let isReplyComment: Bool | ||||
|     let isShowPopupMenuButton: Bool | ||||
|      | ||||
|     let modifyComment: (Int, String) -> Void | ||||
|     let onClickDelete: (Int) -> Void | ||||
|      | ||||
|     @State var isShowPopupMenu: Bool = false | ||||
|     @State var isModeModify: Bool = false | ||||
|     @State var comment: String = "" | ||||
|      | ||||
|     var body: some View { | ||||
|         ZStack(alignment: .topTrailing) { | ||||
|             VStack(alignment: .leading, spacing: 0) { | ||||
|                 HStack(spacing: 6.7) { | ||||
|                     KFImage(URL(string: commentItem.profileUrl)) | ||||
|                         .resizable() | ||||
|                         .frame(width: 40, height: 40) | ||||
|                         .clipShape(Circle()) | ||||
|                      | ||||
|                     VStack(alignment: .leading, spacing: 0) { | ||||
|                         Text(commentItem.nickname) | ||||
|                             .font(.custom(Font.medium.rawValue, size: 13.3)) | ||||
|                             .foregroundColor(Color(hex: "eeeeee")) | ||||
|                          | ||||
|                         Text(commentItem.date) | ||||
|                             .font(.custom(Font.medium.rawValue, size: 10.3)) | ||||
|                             .foregroundColor(Color(hex: "525252")) | ||||
|                             .padding(.top, 4) | ||||
|                     } | ||||
|                      | ||||
|                     Spacer() | ||||
|                      | ||||
|                     if isShowPopupMenuButton && (creatorId == UserDefaults.int(forKey: .userId) || commentItem.writerId == UserDefaults.int(forKey: .userId)) { | ||||
|                         Image("ic_seemore_vertical") | ||||
|                             .onTapGesture { isShowPopupMenu.toggle() } | ||||
|                     } | ||||
|                 } | ||||
|                  | ||||
|                 HStack(spacing: 0) { | ||||
|                     if isModeModify { | ||||
|                         HStack(spacing: 0) { | ||||
|                             TextField("댓글을 입력해 보세요.", text: $comment) | ||||
|                                 .autocapitalization(.none) | ||||
|                                 .disableAutocorrection(true) | ||||
|                                 .font(.custom(Font.medium.rawValue, size: 13.3)) | ||||
|                                 .foregroundColor(Color(hex: "eeeeee")) | ||||
|                                 .accentColor(Color(hex: "3bb9f1")) | ||||
|                                 .keyboardType(.default) | ||||
|                                 .padding(.horizontal, 13.3) | ||||
|                              | ||||
|                             Spacer() | ||||
|                              | ||||
|                             Image("btn_message_send") | ||||
|                                 .resizable() | ||||
|                                 .frame(width: 35, height: 35) | ||||
|                                 .padding(6.7) | ||||
|                                 .onTapGesture { | ||||
|                                     hideKeyboard() | ||||
|                                     if commentItem.comment != comment { | ||||
|                                         modifyComment(commentItem.id, comment) | ||||
|                                     } | ||||
|                                     isModeModify = false | ||||
|                                 } | ||||
|                         } | ||||
|                         .background(Color(hex: "232323")) | ||||
|                         .cornerRadius(10) | ||||
|                         .overlay( | ||||
|                             RoundedRectangle(cornerRadius: 10) | ||||
|                                 .strokeBorder(lineWidth: 1) | ||||
|                                 .foregroundColor(Color(hex: "3bb9f1")) | ||||
|                         ) | ||||
|                     } else { | ||||
|                         VStack(alignment: .leading, spacing: 13.3) { | ||||
|                             Text(commentItem.comment) | ||||
|                                 .font(.custom(Font.medium.rawValue, size: 12)) | ||||
|                                 .foregroundColor(Color(hex: "777777")) | ||||
|                                 .fixedSize(horizontal: false, vertical: true) | ||||
|                                 .padding(.top, 13.3) | ||||
|                              | ||||
|                             if !isReplyComment { | ||||
|                                 NavigationLink( | ||||
|                                     destination: CreatorCommunityCommentReplyView( | ||||
|                                         creatorId: creatorId, | ||||
|                                         postId: postId, | ||||
|                                         parentComment: commentItem | ||||
|                                     ) | ||||
|                                 ) { | ||||
|                                     Text(commentItem.replyCount > 0 ? "답글 \(commentItem.replyCount)개" : "답글 쓰기") | ||||
|                                         .font(.custom(Font.medium.rawValue, size: 13.3)) | ||||
|                                         .foregroundColor(Color(hex: "9970ff")) | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                      | ||||
|                     Spacer() | ||||
|                 } | ||||
|                 .padding(.leading, 46.7) | ||||
|                  | ||||
|                 Rectangle() | ||||
|                     .foregroundColor(Color(hex: "595959")) | ||||
|                     .frame(height: 0.5) | ||||
|                     .padding(.top, 16.7) | ||||
|             } | ||||
|              | ||||
|             if isShowPopupMenu { | ||||
|                 VStack(spacing: 10) { | ||||
|                     if commentItem.writerId == UserDefaults.int(forKey: .userId) { | ||||
|                         Text("수정") | ||||
|                             .font(.custom(Font.medium.rawValue, size: 14)) | ||||
|                             .foregroundColor(Color(hex: "777777")) | ||||
|                             .onTapGesture { | ||||
|                                 isModeModify = true | ||||
|                                 isShowPopupMenu = false | ||||
|                             } | ||||
|                     } | ||||
|                      | ||||
|                     if creatorId == UserDefaults.int(forKey: .userId) || | ||||
|                         commentItem.writerId == UserDefaults.int(forKey: .userId) | ||||
|                     { | ||||
|                         Text("삭제") | ||||
|                             .font(.custom(Font.medium.rawValue, size: 14)) | ||||
|                             .foregroundColor(Color(hex: "777777")) | ||||
|                             .onTapGesture { | ||||
|                                 onClickDelete(commentItem.id) | ||||
|                                 isShowPopupMenu = false | ||||
|                             } | ||||
|                     } | ||||
|                 } | ||||
|                 .padding(10) | ||||
|                 .background(Color(hex: "222222")) | ||||
|             } | ||||
|         } | ||||
|         .onAppear { comment = commentItem.comment } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,185 @@ | ||||
| // | ||||
| //  CreatorCommunityCommentListView.swift | ||||
| //  SodaLive | ||||
| // | ||||
| //  Created by klaus on 2023/12/20. | ||||
| // | ||||
|  | ||||
| import SwiftUI | ||||
| import Kingfisher | ||||
|  | ||||
| struct CreatorCommunityCommentListView: View { | ||||
|      | ||||
|     @Binding var isPresented: Bool | ||||
|      | ||||
|     let creatorId: Int | ||||
|     let postId: Int | ||||
|      | ||||
|     @State private var commentId: Int = 0 | ||||
|     @State private var isShowDeletePopup: Bool = false | ||||
|     @StateObject var viewModel = CreatorCommunityCommentListViewModel() | ||||
|      | ||||
|     var body: some View { | ||||
|         NavigationView { | ||||
|             ZStack { | ||||
|                 VStack(spacing: 0) { | ||||
|                     HStack(spacing: 0) { | ||||
|                         Text("댓글") | ||||
|                             .font(.custom(Font.medium.rawValue, size: 14.7)) | ||||
|                             .foregroundColor(.white) | ||||
|                             .padding(.leading, 13.3) | ||||
|                          | ||||
|                         Text("\(viewModel.totalCommentCount)") | ||||
|                             .font(.custom(Font.medium.rawValue, size: 12)) | ||||
|                             .foregroundColor(Color(hex: "909090")) | ||||
|                             .padding(.leading, 6.7) | ||||
|                          | ||||
|                         Spacer() | ||||
|                          | ||||
|                         Image("ic_close_white") | ||||
|                             .onTapGesture { isPresented = false} | ||||
|                     } | ||||
|                     .padding(.horizontal, 13.3) | ||||
|                     .padding(.top, 12) | ||||
|                      | ||||
|                     Rectangle() | ||||
|                         .foregroundColor(Color(hex: "595959")) | ||||
|                         .frame(height: 0.5) | ||||
|                         .padding(.top, 12) | ||||
|                         .padding(.bottom, 13.3) | ||||
|                         .padding(.horizontal, 13.3) | ||||
|                      | ||||
|                     HStack(spacing: 8) { | ||||
|                         KFImage(URL(string: UserDefaults.string(forKey: .profileImage))) | ||||
|                             .cancelOnDisappear(true) | ||||
|                             .downsampling(size: CGSize(width: 33.3, height: 33.3)) | ||||
|                             .resizable() | ||||
|                             .frame(width: 33.3, height: 33.3) | ||||
|                             .clipShape(Circle()) | ||||
|                          | ||||
|                         HStack(spacing: 0) { | ||||
|                             TextField("댓글을 입력해 보세요.", text: $viewModel.comment) | ||||
|                                 .autocapitalization(.none) | ||||
|                                 .disableAutocorrection(true) | ||||
|                                 .font(.custom(Font.medium.rawValue, size: 13.3)) | ||||
|                                 .foregroundColor(Color(hex: "eeeeee")) | ||||
|                                 .accentColor(Color(hex: "3bb9f1")) | ||||
|                                 .keyboardType(.default) | ||||
|                                 .padding(.horizontal, 13.3) | ||||
|                              | ||||
|                             Spacer() | ||||
|                              | ||||
|                             Image("btn_message_send") | ||||
|                                 .resizable() | ||||
|                                 .frame(width: 35, height: 35) | ||||
|                                 .padding(6.7) | ||||
|                                 .onTapGesture { | ||||
|                                     hideKeyboard() | ||||
|                                     viewModel.createCommunityPostComment() | ||||
|                                 } | ||||
|                         } | ||||
|                         .background(Color(hex: "232323")) | ||||
|                         .cornerRadius(10) | ||||
|                         .overlay( | ||||
|                             RoundedRectangle(cornerRadius: 10) | ||||
|                                 .strokeBorder(lineWidth: 1) | ||||
|                                 .foregroundColor(Color(hex: "3bb9f1")) | ||||
|                         ) | ||||
|                          | ||||
|                         Spacer() | ||||
|                     } | ||||
|                     .padding(.horizontal, 13.3) | ||||
|                      | ||||
|                     Rectangle() | ||||
|                         .foregroundColor(Color(hex: "595959")) | ||||
|                         .frame(height: 0.5) | ||||
|                         .padding(.top, 12) | ||||
|                         .padding(.bottom, 13.3) | ||||
|                         .padding(.horizontal, 13.3) | ||||
|                      | ||||
|                     ScrollView(.vertical, showsIndicators: false) { | ||||
|                         LazyVStack(spacing: 13.3) { | ||||
|                             ForEach(0..<viewModel.commentList.count, id: \.self) { index in | ||||
|                                 let comment = viewModel.commentList[index] | ||||
|                                 VStack { | ||||
|                                     CreatorCommunityCommentItemView( | ||||
|                                         creatorId: creatorId, | ||||
|                                         postId: postId, | ||||
|                                         commentItem: comment, | ||||
|                                         isReplyComment: false, | ||||
|                                         isShowPopupMenuButton: true, | ||||
|                                         modifyComment: { commentId, comment in | ||||
|                                             hideKeyboard() | ||||
|                                         }, | ||||
|                                         onClickDelete: { | ||||
|                                             commentId = $0 | ||||
|                                             isShowDeletePopup = true | ||||
|                                         } | ||||
|                                     ) | ||||
|                                     .padding(.horizontal, 26.7) | ||||
|                                     .onAppear { | ||||
|                                         if index == viewModel.commentList.count - 1 { | ||||
|                                             viewModel.getCommentList() | ||||
|                                         } | ||||
|                                     } | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                  | ||||
|                 if isShowDeletePopup && commentId > 0 { | ||||
|                     SodaDialog( | ||||
|                         title: "댓글 삭제", | ||||
|                         desc: "삭제하시겠습니까?", | ||||
|                         confirmButtonTitle: "삭제", | ||||
|                         confirmButtonAction: { | ||||
|                             commentId = 0 | ||||
|                             isShowDeletePopup = false | ||||
|                         }, | ||||
|                         cancelButtonTitle: "취소", | ||||
|                         cancelButtonAction: { | ||||
|                             commentId = 0 | ||||
|                             isShowDeletePopup = false | ||||
|                         } | ||||
|                     ) | ||||
|                 } | ||||
|                  | ||||
|                 if viewModel.isLoading { | ||||
|                     LoadingView() | ||||
|                 } | ||||
|             } | ||||
|             .onAppear { | ||||
|                 viewModel.postId = postId | ||||
|                 viewModel.getCommentList() | ||||
|             } | ||||
|             .popup(isPresented: $viewModel.isShowPopup, type: .toast, position: .top, autohideIn: 2) { | ||||
|                 GeometryReader { geo in | ||||
|                     HStack { | ||||
|                         Spacer() | ||||
|                         Text(viewModel.errorMessage) | ||||
|                             .padding(.vertical, 13.3) | ||||
|                             .frame(width: screenSize().width - 66.7, alignment: .center) | ||||
|                             .font(.custom(Font.medium.rawValue, size: 12)) | ||||
|                             .background(Color(hex: "9970ff")) | ||||
|                             .foregroundColor(Color.white) | ||||
|                             .multilineTextAlignment(.center) | ||||
|                             .cornerRadius(20) | ||||
|                             .padding(.top, 66.7) | ||||
|                         Spacer() | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| struct CreatorCommunityCommentListView_Previews: PreviewProvider { | ||||
|     static var previews: some View { | ||||
|         CreatorCommunityCommentListView( | ||||
|             isPresented: .constant(true), | ||||
|             creatorId: 0, | ||||
|             postId: 0 | ||||
|         ) | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,122 @@ | ||||
| // | ||||
| //  CreatorCommunityCommentListViewModel.swift | ||||
| //  SodaLive | ||||
| // | ||||
| //  Created by klaus on 2023/12/20. | ||||
| // | ||||
|  | ||||
| import Foundation | ||||
| import Combine | ||||
|  | ||||
| final class CreatorCommunityCommentListViewModel: ObservableObject { | ||||
|     private let repository = CreatorCommunityRepository() | ||||
|     private var subscription = Set<AnyCancellable>() | ||||
|      | ||||
|     @Published var isLoading = false | ||||
|     @Published var errorMessage = "" | ||||
|     @Published var isShowPopup = false | ||||
|      | ||||
|     @Published var comment = "" | ||||
|     @Published var totalCommentCount = 0 | ||||
|     @Published var commentList = [GetCommunityPostCommentListItem]() | ||||
|      | ||||
|     var postId = 0 | ||||
|     var page = 1 | ||||
|     var isLast = false | ||||
|     private let pageSize = 10 | ||||
|      | ||||
|     func getCommentList() { | ||||
|         if (!isLast && !isLoading) { | ||||
|             repository | ||||
|                 .getCommunityPostCommentList(postId: postId, page: page, size: pageSize) | ||||
|                 .sink { result in | ||||
|                     switch result { | ||||
|                     case .finished: | ||||
|                         DEBUG_LOG("finish") | ||||
|                     case .failure(let error): | ||||
|                         ERROR_LOG(error.localizedDescription) | ||||
|                     } | ||||
|                 } receiveValue: { [unowned self] response in | ||||
|                     let responseData = response.data | ||||
|                      | ||||
|                     do { | ||||
|                         let jsonDecoder = JSONDecoder() | ||||
|                         let decoded = try jsonDecoder.decode(ApiResponse<GetCommunityPostCommentListResponse>.self, from: responseData) | ||||
|                          | ||||
|                         if let data = decoded.data, decoded.success { | ||||
|                             if page == 1 { | ||||
|                                 commentList.removeAll() | ||||
|                             } | ||||
|                              | ||||
|                             if !data.items.isEmpty { | ||||
|                                 page += 1 | ||||
|                                 self.totalCommentCount = data.totalCount | ||||
|                                 self.commentList.append(contentsOf: data.items) | ||||
|                             } else { | ||||
|                                 isLast = true | ||||
|                             } | ||||
|                         } else { | ||||
|                             if let message = decoded.message { | ||||
|                                 self.errorMessage = message | ||||
|                             } else { | ||||
|                                 self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." | ||||
|                             } | ||||
|                              | ||||
|                             self.isShowPopup = true | ||||
|                         } | ||||
|                     } catch { | ||||
|                         self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." | ||||
|                         self.isShowPopup = true | ||||
|                     } | ||||
|                      | ||||
|                     self.isLoading = false | ||||
|                 } | ||||
|                 .store(in: &subscription) | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     func createCommunityPostComment(parentId: Int? = nil) { | ||||
|         if !isLoading { | ||||
|             isLoading = true | ||||
|              | ||||
|             repository.createCommunityPostComment(comment: comment, postId: postId, parentId: parentId) | ||||
|                 .sink { result in | ||||
|                     switch result { | ||||
|                     case .finished: | ||||
|                         DEBUG_LOG("finish") | ||||
|                     case .failure(let error): | ||||
|                         ERROR_LOG(error.localizedDescription) | ||||
|                     } | ||||
|                 } receiveValue: { [unowned self] response in | ||||
|                     let responseData = response.data | ||||
|                     self.isLoading = false | ||||
|                      | ||||
|                     do { | ||||
|                         let jsonDecoder = JSONDecoder() | ||||
|                         let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: responseData) | ||||
|                          | ||||
|                         if decoded.success { | ||||
|                             DispatchQueue.main.async { | ||||
|                                 self.comment = "" | ||||
|                                 self.page = 1 | ||||
|                                 self.isLast = false | ||||
|                                 self.getCommentList() | ||||
|                             } | ||||
|                         } else { | ||||
|                             if let message = decoded.message { | ||||
|                                 self.errorMessage = message | ||||
|                             } else { | ||||
|                                 self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." | ||||
|                             } | ||||
|                              | ||||
|                             self.isShowPopup = true | ||||
|                         } | ||||
|                     } catch { | ||||
|                         self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." | ||||
|                         self.isShowPopup = true | ||||
|                     } | ||||
|                 } | ||||
|                 .store(in: &subscription) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,182 @@ | ||||
| // | ||||
| //  CreatorCommunityCommentReplyView.swift | ||||
| //  SodaLive | ||||
| // | ||||
| //  Created by klaus on 2023/12/20. | ||||
| // | ||||
|  | ||||
| import SwiftUI | ||||
| import Kingfisher | ||||
|  | ||||
| struct CreatorCommunityCommentReplyView: View { | ||||
|      | ||||
|     let creatorId: Int | ||||
|     let postId: Int | ||||
|     let parentComment: GetCommunityPostCommentListItem | ||||
|      | ||||
|     @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode> | ||||
|     @StateObject var viewModel = CreatorCommunityCommentReplyViewModel() | ||||
|      | ||||
|     @State private var commentId: Int = 0 | ||||
|     @State private var isShowDeletePopup: Bool = false | ||||
|      | ||||
|     var body: some View { | ||||
|         ZStack { | ||||
|             VStack(spacing: 0) { | ||||
|                 HStack(spacing: 6.7) { | ||||
|                     Image("ic_back") | ||||
|                      | ||||
|                     Text("답글") | ||||
|                         .font(.custom(Font.medium.rawValue, size: 14.7)) | ||||
|                         .foregroundColor(.white) | ||||
|                      | ||||
|                     Spacer() | ||||
|                 } | ||||
|                 .padding(.horizontal, 13.3) | ||||
|                 .padding(.top, 12) | ||||
|                 .onTapGesture { presentationMode.wrappedValue.dismiss() } | ||||
|                  | ||||
|                 Rectangle() | ||||
|                     .foregroundColor(Color(hex: "595959")) | ||||
|                     .frame(height: 0.5) | ||||
|                     .padding(.top, 12) | ||||
|                     .padding(.bottom, 13.3) | ||||
|                     .padding(.horizontal, 13.3) | ||||
|                  | ||||
|                 HStack(spacing: 8) { | ||||
|                     KFImage(URL(string: UserDefaults.string(forKey: .profileImage))) | ||||
|                         .cancelOnDisappear(true) | ||||
|                         .downsampling(size: CGSize(width: 33.3, height: 33.3)) | ||||
|                         .resizable() | ||||
|                         .frame(width: 33.3, height: 33.3) | ||||
|                         .clipShape(Circle()) | ||||
|                      | ||||
|                     HStack(spacing: 0) { | ||||
|                         TextField("댓글을 입력해 보세요.", text: $viewModel.comment) | ||||
|                             .autocapitalization(.none) | ||||
|                             .disableAutocorrection(true) | ||||
|                             .font(.custom(Font.medium.rawValue, size: 13.3)) | ||||
|                             .foregroundColor(Color(hex: "eeeeee")) | ||||
|                             .accentColor(Color(hex: "3bb9f1")) | ||||
|                             .keyboardType(.default) | ||||
|                             .padding(.horizontal, 13.3) | ||||
|                          | ||||
|                         Spacer() | ||||
|                          | ||||
|                         Image("btn_message_send") | ||||
|                             .resizable() | ||||
|                             .frame(width: 35, height: 35) | ||||
|                             .padding(6.7) | ||||
|                             .onTapGesture { | ||||
|                                 hideKeyboard() | ||||
|                                 viewModel.createCommunityPostComment(parentId: parentComment.id) | ||||
|                             } | ||||
|                     } | ||||
|                     .background(Color(hex: "232323")) | ||||
|                     .cornerRadius(10) | ||||
|                     .overlay( | ||||
|                         RoundedRectangle(cornerRadius: 10) | ||||
|                             .strokeBorder(lineWidth: 1) | ||||
|                             .foregroundColor(Color(hex: "3bb9f1")) | ||||
|                     ) | ||||
|                      | ||||
|                     Spacer() | ||||
|                 } | ||||
|                 .padding(.horizontal, 13.3) | ||||
|                  | ||||
|                 Rectangle() | ||||
|                     .foregroundColor(Color(hex: "595959")) | ||||
|                     .frame(height: 0.5) | ||||
|                     .padding(.top, 12) | ||||
|                     .padding(.bottom, 13.3) | ||||
|                     .padding(.horizontal, 13.3) | ||||
|                  | ||||
|                 CreatorCommunityCommentItemView( | ||||
|                     creatorId: creatorId, | ||||
|                     postId: postId, | ||||
|                     commentItem: parentComment, | ||||
|                     isReplyComment: true, | ||||
|                     isShowPopupMenuButton: false, | ||||
|                     modifyComment: { _, _ in }, | ||||
|                     onClickDelete: { _ in } | ||||
|                 ) | ||||
|                 .padding(.horizontal, 26.7) | ||||
|                 .padding(.bottom, 13.3) | ||||
|                  | ||||
|                 ScrollView(.vertical, showsIndicators: false) { | ||||
|                     LazyVStack(spacing: 13.3) { | ||||
|                         ForEach(0..<viewModel.commentList.count, id: \.self) { index in | ||||
|                             let comment = viewModel.commentList[index] | ||||
|                             CreatorCommunityCommentItemView( | ||||
|                                 creatorId: creatorId, | ||||
|                                 postId: postId, | ||||
|                                 commentItem: comment, | ||||
|                                 isReplyComment: true, | ||||
|                                 isShowPopupMenuButton: true, | ||||
|                                 modifyComment: { commentId, comment in | ||||
|                                     hideKeyboard() | ||||
|                                 }, | ||||
|                                 onClickDelete: { | ||||
|                                     commentId = $0 | ||||
|                                     isShowDeletePopup = true | ||||
|                                 } | ||||
|                             ) | ||||
|                             .padding(.horizontal, 26.7) | ||||
|                             .onAppear { | ||||
|                                 if index == viewModel.commentList.count - 1 { | ||||
|                                     viewModel.getCommentList() | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             .navigationTitle("") | ||||
|             .navigationBarBackButtonHidden() | ||||
|              | ||||
|             if isShowDeletePopup && commentId > 0 { | ||||
|                 SodaDialog( | ||||
|                     title: "댓글 삭제", | ||||
|                     desc: "삭제하시겠습니까?", | ||||
|                     confirmButtonTitle: "삭제", | ||||
|                     confirmButtonAction: { | ||||
|                         commentId = 0 | ||||
|                         isShowDeletePopup = false | ||||
|                     }, | ||||
|                     cancelButtonTitle: "취소", | ||||
|                     cancelButtonAction: { | ||||
|                         commentId = 0 | ||||
|                         isShowDeletePopup = false | ||||
|                     } | ||||
|                 ) | ||||
|             } | ||||
|              | ||||
|             if viewModel.isLoading { | ||||
|                 LoadingView() | ||||
|             } | ||||
|         } | ||||
|         .onAppear { | ||||
|             viewModel.postId = postId | ||||
|             viewModel.commentId = parentComment.id | ||||
|             viewModel.getCommentList() | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| struct CreatorCommunityCommentReplyView_Previews: PreviewProvider { | ||||
|     static var previews: some View { | ||||
|         CreatorCommunityCommentReplyView( | ||||
|             creatorId: 0, | ||||
|             postId: 0, | ||||
|             parentComment: GetCommunityPostCommentListItem( | ||||
|                 id: 0, | ||||
|                 writerId: 0, | ||||
|                 nickname: "댓글", | ||||
|                 profileUrl: "", | ||||
|                 comment: "부모 댓글입니다.", | ||||
|                 date: "1시간전", | ||||
|                 replyCount: 1 | ||||
|             ) | ||||
|         ) | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,124 @@ | ||||
| // | ||||
| //  CreatorCommunityCommentReplyViewModel.swift | ||||
| //  SodaLive | ||||
| // | ||||
| //  Created by klaus on 2023/12/20. | ||||
| // | ||||
|  | ||||
| import Foundation | ||||
| import Combine | ||||
|  | ||||
| final class CreatorCommunityCommentReplyViewModel: ObservableObject { | ||||
|      | ||||
|     private let repository = CreatorCommunityRepository() | ||||
|     private var subscription = Set<AnyCancellable>() | ||||
|      | ||||
|     @Published var isLoading = false | ||||
|     @Published var errorMessage = "" | ||||
|     @Published var isShowPopup = false | ||||
|      | ||||
|     @Published var comment = "" | ||||
|     @Published var totalCommentCount = 0 | ||||
|     @Published var commentList = [GetCommunityPostCommentListItem]() | ||||
|      | ||||
|     var postId = 0 | ||||
|     var commentId = 0 | ||||
|     var page = 1 | ||||
|     var isLast = false | ||||
|     private let pageSize = 10 | ||||
|      | ||||
|     func getCommentList() { | ||||
|         if (!isLast && !isLoading) { | ||||
|             repository | ||||
|                 .getCommentReplyList(commentId: commentId, page: page, size: pageSize) | ||||
|                 .sink { result in | ||||
|                     switch result { | ||||
|                     case .finished: | ||||
|                         DEBUG_LOG("finish") | ||||
|                     case .failure(let error): | ||||
|                         ERROR_LOG(error.localizedDescription) | ||||
|                     } | ||||
|                 } receiveValue: { [unowned self] response in | ||||
|                     let responseData = response.data | ||||
|                      | ||||
|                     do { | ||||
|                         let jsonDecoder = JSONDecoder() | ||||
|                         let decoded = try jsonDecoder.decode(ApiResponse<GetCommunityPostCommentListResponse>.self, from: responseData) | ||||
|                          | ||||
|                         if let data = decoded.data, decoded.success { | ||||
|                             if page == 1 { | ||||
|                                 commentList.removeAll() | ||||
|                             } | ||||
|                              | ||||
|                             if !data.items.isEmpty { | ||||
|                                 page += 1 | ||||
|                                 self.totalCommentCount = data.totalCount | ||||
|                                 self.commentList.append(contentsOf: data.items) | ||||
|                             } else { | ||||
|                                 isLast = true | ||||
|                             } | ||||
|                         } else { | ||||
|                             if let message = decoded.message { | ||||
|                                 self.errorMessage = message | ||||
|                             } else { | ||||
|                                 self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." | ||||
|                             } | ||||
|                              | ||||
|                             self.isShowPopup = true | ||||
|                         } | ||||
|                     } catch { | ||||
|                         self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." | ||||
|                         self.isShowPopup = true | ||||
|                     } | ||||
|                      | ||||
|                     self.isLoading = false | ||||
|                 } | ||||
|                 .store(in: &subscription) | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     func createCommunityPostComment(parentId: Int? = nil) { | ||||
|         if !isLoading { | ||||
|             isLoading = true | ||||
|              | ||||
|             repository.createCommunityPostComment(comment: comment, postId: postId, parentId: parentId) | ||||
|                 .sink { result in | ||||
|                     switch result { | ||||
|                     case .finished: | ||||
|                         DEBUG_LOG("finish") | ||||
|                     case .failure(let error): | ||||
|                         ERROR_LOG(error.localizedDescription) | ||||
|                     } | ||||
|                 } receiveValue: { [unowned self] response in | ||||
|                     let responseData = response.data | ||||
|                     self.isLoading = false | ||||
|                      | ||||
|                     do { | ||||
|                         let jsonDecoder = JSONDecoder() | ||||
|                         let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: responseData) | ||||
|                          | ||||
|                         if decoded.success { | ||||
|                             DispatchQueue.main.async { | ||||
|                                 self.comment = "" | ||||
|                                 self.page = 1 | ||||
|                                 self.isLast = false | ||||
|                                 self.getCommentList() | ||||
|                             } | ||||
|                         } else { | ||||
|                             if let message = decoded.message { | ||||
|                                 self.errorMessage = message | ||||
|                             } else { | ||||
|                                 self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." | ||||
|                             } | ||||
|                              | ||||
|                             self.isShowPopup = true | ||||
|                         } | ||||
|                     } catch { | ||||
|                         self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." | ||||
|                         self.isShowPopup = true | ||||
|                     } | ||||
|                 } | ||||
|                 .store(in: &subscription) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -12,6 +12,7 @@ struct CreatorCommunityAllItemView: View { | ||||
|      | ||||
|     let item: GetCommunityPostListResponse | ||||
|     let onClickLike: () -> Void | ||||
|     let onClickComment: () -> Void | ||||
|     let onClickWriteComment: (String) -> Void | ||||
|      | ||||
|     @State var isExpandContent = false | ||||
| @@ -21,10 +22,12 @@ struct CreatorCommunityAllItemView: View { | ||||
|     init( | ||||
|         item: GetCommunityPostListResponse, | ||||
|         onClickLike: @escaping () -> Void, | ||||
|         onClickComment: @escaping () -> Void, | ||||
|         onClickWriteComment: @escaping (String) -> Void | ||||
|     ) { | ||||
|         self.item = item | ||||
|         self.onClickLike = onClickLike | ||||
|         self.onClickComment = onClickComment | ||||
|         self.onClickWriteComment = onClickWriteComment | ||||
|          | ||||
|         self._isLike = State(initialValue: item.isLike) | ||||
| @@ -96,8 +99,14 @@ struct CreatorCommunityAllItemView: View { | ||||
|                 commentItem: item.firstComment, | ||||
|                 onClickWriteComment: onClickWriteComment | ||||
|             ) | ||||
|             .onTapGesture { | ||||
|                 if item.commentCount > 0 { | ||||
|                     onClickComment() | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         .padding(6.7) | ||||
|         .padding(.horizontal, 8) | ||||
|         .padding(.vertical, 11) | ||||
|         .background(Color(hex: "222222")) | ||||
|         .cornerRadius(5.3) | ||||
|     } | ||||
| @@ -119,6 +128,7 @@ struct CreatorCommunityAllItemView_Previews: PreviewProvider { | ||||
|                 firstComment: nil | ||||
|             ), | ||||
|             onClickLike: {}, | ||||
|             onClickComment: {}, | ||||
|             onClickWriteComment: { _ in } | ||||
|         ) | ||||
|     } | ||||
|   | ||||
| @@ -11,7 +11,7 @@ struct CreatorCommunityAllView: View { | ||||
|      | ||||
|     let creatorId: Int | ||||
|      | ||||
|     @State var isShowingReportView = false | ||||
|     @State private var isShowingReportView = false | ||||
|     @StateObject var viewModel = CreatorCommunityAllViewModel() | ||||
|      | ||||
|     var body: some View { | ||||
| @@ -28,6 +28,9 @@ struct CreatorCommunityAllView: View { | ||||
|                                 onClickLike: { | ||||
|                                     viewModel.communityPostLike(postId: item.postId) | ||||
|                                 }, | ||||
|                                 onClickComment: { | ||||
|                                     viewModel.postId = item.postId | ||||
|                                 }, | ||||
|                                 onClickWriteComment: { comment in | ||||
|                                     viewModel.createCommunityPostComment( | ||||
|                                         comment: comment, | ||||
| @@ -42,10 +45,19 @@ struct CreatorCommunityAllView: View { | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     .padding(.horizontal, 13.3) | ||||
|                     .padding(.vertical, 5.3) | ||||
|                     .padding(5.3) | ||||
|                 } | ||||
|             } | ||||
|             .sheet( | ||||
|                 isPresented: $viewModel.isShowCommentListView, | ||||
|                 content: { | ||||
|                     CreatorCommunityCommentListView( | ||||
|                         isPresented: $viewModel.isShowCommentListView, | ||||
|                         creatorId: creatorId, | ||||
|                         postId: viewModel.postId | ||||
|                     ) | ||||
|                 } | ||||
|             ) | ||||
|              | ||||
|             if isShowingReportView { | ||||
|                 CreatorCommunityReportView(isShowing: $isShowingReportView) { _ in | ||||
|   | ||||
| @@ -19,6 +19,22 @@ class CreatorCommunityAllViewModel: ObservableObject { | ||||
|     @Published var isShowPopup = false | ||||
|     @Published private(set) var communityPostList = [GetCommunityPostListResponse]() | ||||
|      | ||||
|     @Published var postId = 0 { | ||||
|         didSet { | ||||
|             if postId > 0 { | ||||
|                 isShowCommentListView = true | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     @Published var isShowCommentListView = false { | ||||
|         didSet { | ||||
|             if !isShowCommentListView { | ||||
|                 postId = 0 | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     var creatorId = 0 | ||||
|      | ||||
|     var page = 1 | ||||
|   | ||||
| @@ -13,6 +13,8 @@ enum CreatorCommunityApi { | ||||
|     case getCommunityPostList(creatorId: Int, page: Int, size: Int) | ||||
|     case communityPostLike(postId: Int) | ||||
|     case createCommunityPostComment(comment: String, postId: Int, parentId: Int?) | ||||
|     case getCommunityPostCommentList(postId: Int, page: Int, size: Int) | ||||
|     case getCommentReplyList(commentId: Int, page: Int, size: Int) | ||||
| } | ||||
|  | ||||
| extension CreatorCommunityApi: TargetType { | ||||
| @@ -30,6 +32,12 @@ extension CreatorCommunityApi: TargetType { | ||||
|              | ||||
|         case .createCommunityPostComment: | ||||
|             return "/creator-community/comment" | ||||
|              | ||||
|         case .getCommunityPostCommentList(let postId, _, _): | ||||
|             return "/creator-community/\(postId)/comment" | ||||
|              | ||||
|         case .getCommentReplyList(let commentId, _, _): | ||||
|             return "/creator-community/comment/\(commentId)" | ||||
|         } | ||||
|     } | ||||
|      | ||||
| @@ -38,7 +46,7 @@ extension CreatorCommunityApi: TargetType { | ||||
|         case .createCommunityPost, .communityPostLike, .createCommunityPostComment: | ||||
|             return .post | ||||
|              | ||||
|         case .getCommunityPostList: | ||||
|         case .getCommunityPostList, .getCommunityPostCommentList, .getCommentReplyList: | ||||
|             return .get | ||||
|         } | ||||
|     } | ||||
| @@ -64,6 +72,22 @@ extension CreatorCommunityApi: TargetType { | ||||
|         case .createCommunityPostComment(let comment, let postId, let parentId): | ||||
|             let request = CreateCommunityPostCommentRequest(comment: comment, postId: postId, parentId: parentId) | ||||
|             return .requestJSONEncodable(request) | ||||
|              | ||||
|         case .getCommunityPostCommentList(_, let page, let size): | ||||
|             let parameters = [ | ||||
|                 "page": page - 1, | ||||
|                 "size": size, | ||||
|                 "timezone": TimeZone.current.identifier | ||||
|             ] as [String: Any] | ||||
|             return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString) | ||||
|              | ||||
|         case .getCommentReplyList(_, let page, let size): | ||||
|             let parameters = [ | ||||
|                 "page": page - 1, | ||||
|                 "size": size, | ||||
|                 "timezone": TimeZone.current.identifier | ||||
|             ] as [String: Any] | ||||
|             return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString) | ||||
|         } | ||||
|     } | ||||
|      | ||||
|   | ||||
| @@ -28,4 +28,12 @@ class CreatorCommunityRepository { | ||||
|     func createCommunityPostComment(comment: String, postId: Int, parentId: Int?) -> AnyPublisher<Response, MoyaError> { | ||||
|         return api.requestPublisher(.createCommunityPostComment(comment: comment, postId: postId, parentId: parentId)) | ||||
|     } | ||||
|      | ||||
|     func getCommunityPostCommentList(postId: Int, page: Int, size: Int) -> AnyPublisher<Response, MoyaError> { | ||||
|         return api.requestPublisher(.getCommunityPostCommentList(postId: postId, page: page, size: size)) | ||||
|     } | ||||
|      | ||||
|     func getCommentReplyList(commentId: Int, page: Int, size: Int) -> AnyPublisher<Response, MoyaError> { | ||||
|         return api.requestPublisher(.getCommentReplyList(commentId: commentId, page: page, size: size)) | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Yu Sung
					Yu Sung