커뮤니티 댓글, 답글 추가 APi 적용
This commit is contained in:
parent
02764f5fe8
commit
cb3a564a29
|
@ -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 item: GetCommunityPostListResponse
|
||||||
let onClickLike: () -> Void
|
let onClickLike: () -> Void
|
||||||
|
let onClickComment: () -> Void
|
||||||
let onClickWriteComment: (String) -> Void
|
let onClickWriteComment: (String) -> Void
|
||||||
|
|
||||||
@State var isExpandContent = false
|
@State var isExpandContent = false
|
||||||
|
@ -21,10 +22,12 @@ struct CreatorCommunityAllItemView: View {
|
||||||
init(
|
init(
|
||||||
item: GetCommunityPostListResponse,
|
item: GetCommunityPostListResponse,
|
||||||
onClickLike: @escaping () -> Void,
|
onClickLike: @escaping () -> Void,
|
||||||
|
onClickComment: @escaping () -> Void,
|
||||||
onClickWriteComment: @escaping (String) -> Void
|
onClickWriteComment: @escaping (String) -> Void
|
||||||
) {
|
) {
|
||||||
self.item = item
|
self.item = item
|
||||||
self.onClickLike = onClickLike
|
self.onClickLike = onClickLike
|
||||||
|
self.onClickComment = onClickComment
|
||||||
self.onClickWriteComment = onClickWriteComment
|
self.onClickWriteComment = onClickWriteComment
|
||||||
|
|
||||||
self._isLike = State(initialValue: item.isLike)
|
self._isLike = State(initialValue: item.isLike)
|
||||||
|
@ -96,8 +99,14 @@ struct CreatorCommunityAllItemView: View {
|
||||||
commentItem: item.firstComment,
|
commentItem: item.firstComment,
|
||||||
onClickWriteComment: onClickWriteComment
|
onClickWriteComment: onClickWriteComment
|
||||||
)
|
)
|
||||||
|
.onTapGesture {
|
||||||
|
if item.commentCount > 0 {
|
||||||
|
onClickComment()
|
||||||
}
|
}
|
||||||
.padding(6.7)
|
}
|
||||||
|
}
|
||||||
|
.padding(.horizontal, 8)
|
||||||
|
.padding(.vertical, 11)
|
||||||
.background(Color(hex: "222222"))
|
.background(Color(hex: "222222"))
|
||||||
.cornerRadius(5.3)
|
.cornerRadius(5.3)
|
||||||
}
|
}
|
||||||
|
@ -119,6 +128,7 @@ struct CreatorCommunityAllItemView_Previews: PreviewProvider {
|
||||||
firstComment: nil
|
firstComment: nil
|
||||||
),
|
),
|
||||||
onClickLike: {},
|
onClickLike: {},
|
||||||
|
onClickComment: {},
|
||||||
onClickWriteComment: { _ in }
|
onClickWriteComment: { _ in }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ struct CreatorCommunityAllView: View {
|
||||||
|
|
||||||
let creatorId: Int
|
let creatorId: Int
|
||||||
|
|
||||||
@State var isShowingReportView = false
|
@State private var isShowingReportView = false
|
||||||
@StateObject var viewModel = CreatorCommunityAllViewModel()
|
@StateObject var viewModel = CreatorCommunityAllViewModel()
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
@ -28,6 +28,9 @@ struct CreatorCommunityAllView: View {
|
||||||
onClickLike: {
|
onClickLike: {
|
||||||
viewModel.communityPostLike(postId: item.postId)
|
viewModel.communityPostLike(postId: item.postId)
|
||||||
},
|
},
|
||||||
|
onClickComment: {
|
||||||
|
viewModel.postId = item.postId
|
||||||
|
},
|
||||||
onClickWriteComment: { comment in
|
onClickWriteComment: { comment in
|
||||||
viewModel.createCommunityPostComment(
|
viewModel.createCommunityPostComment(
|
||||||
comment: comment,
|
comment: comment,
|
||||||
|
@ -42,10 +45,19 @@ struct CreatorCommunityAllView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 13.3)
|
.padding(5.3)
|
||||||
.padding(.vertical, 5.3)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.sheet(
|
||||||
|
isPresented: $viewModel.isShowCommentListView,
|
||||||
|
content: {
|
||||||
|
CreatorCommunityCommentListView(
|
||||||
|
isPresented: $viewModel.isShowCommentListView,
|
||||||
|
creatorId: creatorId,
|
||||||
|
postId: viewModel.postId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
if isShowingReportView {
|
if isShowingReportView {
|
||||||
CreatorCommunityReportView(isShowing: $isShowingReportView) { _ in
|
CreatorCommunityReportView(isShowing: $isShowingReportView) { _ in
|
||||||
|
|
|
@ -19,6 +19,22 @@ class CreatorCommunityAllViewModel: ObservableObject {
|
||||||
@Published var isShowPopup = false
|
@Published var isShowPopup = false
|
||||||
@Published private(set) var communityPostList = [GetCommunityPostListResponse]()
|
@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 creatorId = 0
|
||||||
|
|
||||||
var page = 1
|
var page = 1
|
||||||
|
|
|
@ -13,6 +13,8 @@ enum CreatorCommunityApi {
|
||||||
case getCommunityPostList(creatorId: Int, page: Int, size: Int)
|
case getCommunityPostList(creatorId: Int, page: Int, size: Int)
|
||||||
case communityPostLike(postId: Int)
|
case communityPostLike(postId: Int)
|
||||||
case createCommunityPostComment(comment: String, postId: Int, parentId: 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 {
|
extension CreatorCommunityApi: TargetType {
|
||||||
|
@ -30,6 +32,12 @@ extension CreatorCommunityApi: TargetType {
|
||||||
|
|
||||||
case .createCommunityPostComment:
|
case .createCommunityPostComment:
|
||||||
return "/creator-community/comment"
|
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:
|
case .createCommunityPost, .communityPostLike, .createCommunityPostComment:
|
||||||
return .post
|
return .post
|
||||||
|
|
||||||
case .getCommunityPostList:
|
case .getCommunityPostList, .getCommunityPostCommentList, .getCommentReplyList:
|
||||||
return .get
|
return .get
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,6 +72,22 @@ extension CreatorCommunityApi: TargetType {
|
||||||
case .createCommunityPostComment(let comment, let postId, let parentId):
|
case .createCommunityPostComment(let comment, let postId, let parentId):
|
||||||
let request = CreateCommunityPostCommentRequest(comment: comment, postId: postId, parentId: parentId)
|
let request = CreateCommunityPostCommentRequest(comment: comment, postId: postId, parentId: parentId)
|
||||||
return .requestJSONEncodable(request)
|
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> {
|
func createCommunityPostComment(comment: String, postId: Int, parentId: Int?) -> AnyPublisher<Response, MoyaError> {
|
||||||
return api.requestPublisher(.createCommunityPostComment(comment: comment, postId: postId, parentId: parentId))
|
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))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue