커뮤니티 댓글, 팬토크, 콘텐츠 댓글
- 프로필 이미지 터치시 차단, 신고가 가능한 유저 프로필 표시
This commit is contained in:
		| @@ -17,6 +17,7 @@ struct AudioContentCommentItemView: View { | |||||||
|      |      | ||||||
|     let modifyComment: (Int, String) -> Void |     let modifyComment: (Int, String) -> Void | ||||||
|     let onClickDelete: (Int) -> Void |     let onClickDelete: (Int) -> Void | ||||||
|  |     let onClickProfile: (Int) -> Void | ||||||
|      |      | ||||||
|     @State var isShowPopupMenu: Bool = false |     @State var isShowPopupMenu: Bool = false | ||||||
|     @State var isModeModify: Bool = false |     @State var isModeModify: Bool = false | ||||||
| @@ -30,6 +31,11 @@ struct AudioContentCommentItemView: View { | |||||||
|                         .resizable() |                         .resizable() | ||||||
|                         .frame(width: 40, height: 40) |                         .frame(width: 40, height: 40) | ||||||
|                         .clipShape(Circle()) |                         .clipShape(Circle()) | ||||||
|  |                         .onTapGesture { | ||||||
|  |                             if UserDefaults.int(forKey: .userId) != commentItem.writerId { | ||||||
|  |                                 onClickProfile(commentItem.writerId) | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|                      |                      | ||||||
|                     VStack(alignment: .leading, spacing: 0) { |                     VStack(alignment: .leading, spacing: 0) { | ||||||
|                         HStack(spacing: 6.7) { |                         HStack(spacing: 6.7) { | ||||||
| @@ -95,8 +101,8 @@ struct AudioContentCommentItemView: View { | |||||||
|                                 .autocapitalization(.none) |                                 .autocapitalization(.none) | ||||||
|                                 .disableAutocorrection(true) |                                 .disableAutocorrection(true) | ||||||
|                                 .font(.custom(Font.medium.rawValue, size: 13.3)) |                                 .font(.custom(Font.medium.rawValue, size: 13.3)) | ||||||
|                                 .foregroundColor(Color(hex: "eeeeee")) |                                 .foregroundColor(Color.grayee) | ||||||
|                                 .accentColor(Color(hex: "3bb9f1")) |                                 .accentColor(Color.button) | ||||||
|                                 .keyboardType(.default) |                                 .keyboardType(.default) | ||||||
|                                 .padding(.horizontal, 13.3) |                                 .padding(.horizontal, 13.3) | ||||||
|                              |                              | ||||||
| @@ -114,7 +120,7 @@ struct AudioContentCommentItemView: View { | |||||||
|                                     isModeModify = false |                                     isModeModify = false | ||||||
|                                 } |                                 } | ||||||
|                         } |                         } | ||||||
|                         .background(Color(hex: "232323")) |                         .background(Color.gray23) | ||||||
|                         .cornerRadius(10) |                         .cornerRadius(10) | ||||||
|                         .overlay( |                         .overlay( | ||||||
|                             RoundedRectangle(cornerRadius: 10) |                             RoundedRectangle(cornerRadius: 10) | ||||||
| @@ -151,7 +157,7 @@ struct AudioContentCommentItemView: View { | |||||||
|                 .padding(.leading, 46.7) |                 .padding(.leading, 46.7) | ||||||
|                  |                  | ||||||
|                 Rectangle() |                 Rectangle() | ||||||
|                     .foregroundColor(Color(hex: "595959")) |                     .foregroundColor(Color.gray59) | ||||||
|                     .frame(height: 0.5) |                     .frame(height: 0.5) | ||||||
|                     .padding(.top, 16.7) |                     .padding(.top, 16.7) | ||||||
|             } |             } | ||||||
| @@ -161,7 +167,7 @@ struct AudioContentCommentItemView: View { | |||||||
|                     if commentItem.writerId == UserDefaults.int(forKey: .userId) { |                     if commentItem.writerId == UserDefaults.int(forKey: .userId) { | ||||||
|                         Text("수정") |                         Text("수정") | ||||||
|                             .font(.custom(Font.medium.rawValue, size: 14)) |                             .font(.custom(Font.medium.rawValue, size: 14)) | ||||||
|                             .foregroundColor(Color(hex: "777777")) |                             .foregroundColor(Color.gray77) | ||||||
|                             .onTapGesture { |                             .onTapGesture { | ||||||
|                                 isModeModify = true |                                 isModeModify = true | ||||||
|                                 isShowPopupMenu = false |                                 isShowPopupMenu = false | ||||||
| @@ -173,7 +179,7 @@ struct AudioContentCommentItemView: View { | |||||||
|                     { |                     { | ||||||
|                         Text("삭제") |                         Text("삭제") | ||||||
|                             .font(.custom(Font.medium.rawValue, size: 14)) |                             .font(.custom(Font.medium.rawValue, size: 14)) | ||||||
|                             .foregroundColor(Color(hex: "777777")) |                             .foregroundColor(Color.gray77) | ||||||
|                             .onTapGesture { |                             .onTapGesture { | ||||||
|                                 onClickDelete(commentItem.id) |                                 onClickDelete(commentItem.id) | ||||||
|                                 isShowPopupMenu = false |                                 isShowPopupMenu = false | ||||||
| @@ -181,7 +187,7 @@ struct AudioContentCommentItemView: View { | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 .padding(10) |                 .padding(10) | ||||||
|                 .background(Color(hex: "222222")) |                 .background(Color.gray22) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         .onAppear { comment = commentItem.comment } |         .onAppear { comment = commentItem.comment } | ||||||
|   | |||||||
| @@ -21,6 +21,9 @@ struct AudioContentCommentListView: View { | |||||||
|     @State private var commentId: Int = 0 |     @State private var commentId: Int = 0 | ||||||
|     @State private var isShowDeletePopup: Bool = false |     @State private var isShowDeletePopup: Bool = false | ||||||
|      |      | ||||||
|  |     @State private var memberId: Int = 0 | ||||||
|  |     @State private var isShowMemberProfilePopup: Bool = false | ||||||
|  |      | ||||||
|     var body: some View { |     var body: some View { | ||||||
|         NavigationView { |         NavigationView { | ||||||
|             ZStack { |             ZStack { | ||||||
| @@ -137,6 +140,10 @@ struct AudioContentCommentListView: View { | |||||||
|                                         onClickDelete: { |                                         onClickDelete: { | ||||||
|                                             commentId = $0 |                                             commentId = $0 | ||||||
|                                             isShowDeletePopup = true |                                             isShowDeletePopup = true | ||||||
|  |                                         }, | ||||||
|  |                                         onClickProfile: { | ||||||
|  |                                             memberId = $0 | ||||||
|  |                                             isShowMemberProfilePopup = true | ||||||
|                                         } |                                         } | ||||||
|                                     ) |                                     ) | ||||||
|                                     .padding(.horizontal, 26.7) |                                     .padding(.horizontal, 26.7) | ||||||
| @@ -169,6 +176,10 @@ struct AudioContentCommentListView: View { | |||||||
|                     ) |                     ) | ||||||
|                 } |                 } | ||||||
|                  |                  | ||||||
|  |                 if isShowMemberProfilePopup { | ||||||
|  |                     MemberProfileDialog(isShowing: $isShowMemberProfilePopup, memberId: memberId) | ||||||
|  |                 } | ||||||
|  |                  | ||||||
|                 if viewModel.isLoading { |                 if viewModel.isLoading { | ||||||
|                     LoadingView() |                     LoadingView() | ||||||
|                 } |                 } | ||||||
|   | |||||||
| @@ -20,6 +20,9 @@ struct AudioContentListReplyView: View { | |||||||
|     @State private var commentId: Int = 0 |     @State private var commentId: Int = 0 | ||||||
|     @State private var isShowDeletePopup: Bool = false |     @State private var isShowDeletePopup: Bool = false | ||||||
|      |      | ||||||
|  |     @State private var memberId: Int = 0 | ||||||
|  |     @State private var isShowMemberProfilePopup: Bool = false | ||||||
|  |      | ||||||
|     var body: some View { |     var body: some View { | ||||||
|         ZStack { |         ZStack { | ||||||
|             VStack(spacing: 0) { |             VStack(spacing: 0) { | ||||||
| @@ -98,7 +101,11 @@ struct AudioContentListReplyView: View { | |||||||
|                     isReplyComment: true, |                     isReplyComment: true, | ||||||
|                     isShowPopupMenuButton: false, |                     isShowPopupMenuButton: false, | ||||||
|                     modifyComment: { _, _ in }, |                     modifyComment: { _, _ in }, | ||||||
|                     onClickDelete: { _ in } |                     onClickDelete: { _ in }, | ||||||
|  |                     onClickProfile: { | ||||||
|  |                         memberId = $0 | ||||||
|  |                         isShowMemberProfilePopup = true | ||||||
|  |                     } | ||||||
|                 ) |                 ) | ||||||
|                     .padding(.horizontal, 26.7) |                     .padding(.horizontal, 26.7) | ||||||
|                     .padding(.bottom, 13.3) |                     .padding(.bottom, 13.3) | ||||||
| @@ -120,6 +127,10 @@ struct AudioContentListReplyView: View { | |||||||
|                                 onClickDelete: { |                                 onClickDelete: { | ||||||
|                                     commentId = $0 |                                     commentId = $0 | ||||||
|                                     isShowDeletePopup = true |                                     isShowDeletePopup = true | ||||||
|  |                                 }, | ||||||
|  |                                 onClickProfile: { | ||||||
|  |                                     memberId = $0 | ||||||
|  |                                     isShowMemberProfilePopup = true | ||||||
|                                 } |                                 } | ||||||
|                             ) |                             ) | ||||||
|                                 .padding(.horizontal, 40) |                                 .padding(.horizontal, 40) | ||||||
| @@ -153,6 +164,10 @@ struct AudioContentListReplyView: View { | |||||||
|                 ) |                 ) | ||||||
|             } |             } | ||||||
|              |              | ||||||
|  |             if isShowMemberProfilePopup { | ||||||
|  |                 MemberProfileDialog(isShowing: $isShowMemberProfilePopup, memberId: memberId) | ||||||
|  |             } | ||||||
|  |              | ||||||
|             if viewModel.isLoading { |             if viewModel.isLoading { | ||||||
|                 LoadingView() |                 LoadingView() | ||||||
|             } |             } | ||||||
|   | |||||||
							
								
								
									
										174
									
								
								SodaLive/Sources/Dialog/MemberProfileDialog.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								SodaLive/Sources/Dialog/MemberProfileDialog.swift
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,174 @@ | |||||||
|  | // | ||||||
|  | //  MemberProfileDialog.swift | ||||||
|  | //  SodaLive | ||||||
|  | // | ||||||
|  | //  Created by klaus on 9/7/24. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | import SwiftUI | ||||||
|  | import Kingfisher | ||||||
|  |  | ||||||
|  | struct MemberProfileDialog: View { | ||||||
|  |      | ||||||
|  |     @StateObject var viewModel = UserViewModel() | ||||||
|  |      | ||||||
|  |     @Binding var isShowing: Bool | ||||||
|  |     let memberId: Int | ||||||
|  |      | ||||||
|  |     var body: some View { | ||||||
|  |         ZStack { | ||||||
|  |             Color.black.opacity(0.7).ignoresSafeArea() | ||||||
|  |                 .onTapGesture { | ||||||
|  |                     isShowing = false | ||||||
|  |                 } | ||||||
|  |              | ||||||
|  |             VStack(alignment: .leading, spacing: 21) { | ||||||
|  |                 HStack(spacing: 0) { | ||||||
|  |                     Text("프로필") | ||||||
|  |                         .font(.custom(Font.bold.rawValue, size: 15)) | ||||||
|  |                         .foregroundColor(Color.grayee) | ||||||
|  |                      | ||||||
|  |                     Spacer() | ||||||
|  |                      | ||||||
|  |                     Image("ic_close_white") | ||||||
|  |                         .onTapGesture { | ||||||
|  |                             isShowing = false | ||||||
|  |                         } | ||||||
|  |                 } | ||||||
|  |                  | ||||||
|  |                 if let profile = viewModel.memberProfile { | ||||||
|  |                     Text(profile.nickname) | ||||||
|  |                         .font(.custom(Font.bold.rawValue, size: 18.3)) | ||||||
|  |                         .foregroundColor(Color.grayee) | ||||||
|  |                      | ||||||
|  |                     KFImage(URL(string: profile.profileImageUrl)) | ||||||
|  |                         .resizable() | ||||||
|  |                         .frame(maxWidth: screenSize().width - 66.7, maxHeight: screenSize().width - 66.7) | ||||||
|  |                         .aspectRatio(CGSize(width: 1, height: 1), contentMode: .fit) | ||||||
|  |                         .cornerRadius(8) | ||||||
|  |                      | ||||||
|  |                     HStack(spacing: 8) { | ||||||
|  |                         Text(profile.isBlocked ? "차단 해제" : "차단") | ||||||
|  |                             .font(.custom(Font.bold.rawValue, size: 15)) | ||||||
|  |                             .foregroundColor(Color.button) | ||||||
|  |                             .frame(maxWidth: .infinity) | ||||||
|  |                             .padding(.vertical, 13) | ||||||
|  |                             .cornerRadius(8) | ||||||
|  |                             .contentShape(Rectangle()) | ||||||
|  |                             .overlay( | ||||||
|  |                                 RoundedRectangle(cornerRadius: 8) | ||||||
|  |                                     .strokeBorder(lineWidth: 1) | ||||||
|  |                                     .foregroundColor(Color.button) | ||||||
|  |                             ) | ||||||
|  |                             .onTapGesture { | ||||||
|  |                                 if profile.isBlocked { | ||||||
|  |                                     viewModel.memberUnBlock() | ||||||
|  |                                 } else { | ||||||
|  |                                     viewModel.isShowUesrBlockConfirm = true | ||||||
|  |                                 } | ||||||
|  |                             } | ||||||
|  |                          | ||||||
|  |                         Text("사용자 신고") | ||||||
|  |                             .font(.custom(Font.bold.rawValue, size: 15)) | ||||||
|  |                             .foregroundColor(Color.button) | ||||||
|  |                             .frame(maxWidth: .infinity) | ||||||
|  |                             .padding(.vertical, 13) | ||||||
|  |                             .cornerRadius(8) | ||||||
|  |                             .contentShape(Rectangle()) | ||||||
|  |                             .overlay( | ||||||
|  |                                 RoundedRectangle(cornerRadius: 8) | ||||||
|  |                                     .strokeBorder(lineWidth: 1) | ||||||
|  |                                     .foregroundColor(Color.button) | ||||||
|  |                             ) | ||||||
|  |                             .onTapGesture { viewModel.isShowUesrReportView = true } | ||||||
|  |                          | ||||||
|  |                         Text("프로필 신고") | ||||||
|  |                             .font(.custom(Font.bold.rawValue, size: 15)) | ||||||
|  |                             .foregroundColor(Color.button) | ||||||
|  |                             .frame(maxWidth: .infinity) | ||||||
|  |                             .padding(.vertical, 13) | ||||||
|  |                             .cornerRadius(8) | ||||||
|  |                             .contentShape(Rectangle()) | ||||||
|  |                             .overlay( | ||||||
|  |                                 RoundedRectangle(cornerRadius: 8) | ||||||
|  |                                     .strokeBorder(lineWidth: 1) | ||||||
|  |                                     .foregroundColor(Color.button) | ||||||
|  |                             ) | ||||||
|  |                             .onTapGesture { viewModel.isShowProfileReportConfirm = true } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             .padding(.horizontal, 13.3) | ||||||
|  |             .padding(.top, 13.3) | ||||||
|  |             .padding(.bottom, 20) | ||||||
|  |             .background(Color.gray22) | ||||||
|  |             .cornerRadius(8) | ||||||
|  |             .padding(.horizontal, 13.3) | ||||||
|  |             .frame(maxWidth: screenSize().width - 33.3) | ||||||
|  |             .onAppear { | ||||||
|  |                 if memberId <= 1 { | ||||||
|  |                     viewModel.errorMessage = "잘못된 요청입니다." | ||||||
|  |                     viewModel.isShowPopup = true | ||||||
|  |                 } else { | ||||||
|  |                     viewModel.getMemberProfile(memberId: memberId) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             .popup(isPresented: $viewModel.isShowPopup, type: .toast, position: .bottom, autohideIn: 2) { | ||||||
|  |                 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.button) | ||||||
|  |                         .foregroundColor(Color.white) | ||||||
|  |                         .multilineTextAlignment(.leading) | ||||||
|  |                         .cornerRadius(20) | ||||||
|  |                         .padding(.bottom, 66.7) | ||||||
|  |                     Spacer() | ||||||
|  |                 } | ||||||
|  |                 .onDisappear { | ||||||
|  |                     if viewModel.dismissDialog { | ||||||
|  |                         isShowing = false | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             if viewModel.isShowUesrBlockConfirm { | ||||||
|  |                 UserBlockConfirmDialogView( | ||||||
|  |                     isShowing: $viewModel.isShowUesrBlockConfirm, | ||||||
|  |                     nickname: viewModel.nickname, | ||||||
|  |                     confirmAction: { | ||||||
|  |                         viewModel.memberBlock() | ||||||
|  |                     } | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             if viewModel.isShowUesrReportView { | ||||||
|  |                 UserReportDialogView( | ||||||
|  |                     isShowing: $viewModel.isShowUesrReportView, | ||||||
|  |                     confirmAction: { reason in | ||||||
|  |                         viewModel.report(type: .USER, reason: reason) | ||||||
|  |                     } | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             if viewModel.isShowProfileReportConfirm { | ||||||
|  |                 ProfileReportDialogView( | ||||||
|  |                     isShowing: $viewModel.isShowProfileReportConfirm, | ||||||
|  |                     confirmAction: { | ||||||
|  |                         viewModel.report(type: .PROFILE) | ||||||
|  |                     } | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             if viewModel.isLoading { | ||||||
|  |                 LoadingView() | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #Preview { | ||||||
|  |     MemberProfileDialog(isShowing: .constant(true), memberId: 1) | ||||||
|  | } | ||||||
| @@ -17,6 +17,7 @@ struct CreatorCommunityCommentItemView: View { | |||||||
|      |      | ||||||
|     let modifyComment: (Int, String) -> Void |     let modifyComment: (Int, String) -> Void | ||||||
|     let onClickDelete: (Int) -> Void |     let onClickDelete: (Int) -> Void | ||||||
|  |     let onClickProfile: (Int) -> Void | ||||||
|      |      | ||||||
|     @State var isShowPopupMenu: Bool = false |     @State var isShowPopupMenu: Bool = false | ||||||
|     @State var isModeModify: Bool = false |     @State var isModeModify: Bool = false | ||||||
| @@ -30,6 +31,11 @@ struct CreatorCommunityCommentItemView: View { | |||||||
|                         .resizable() |                         .resizable() | ||||||
|                         .frame(width: 40, height: 40) |                         .frame(width: 40, height: 40) | ||||||
|                         .clipShape(Circle()) |                         .clipShape(Circle()) | ||||||
|  |                         .onTapGesture { | ||||||
|  |                             if UserDefaults.int(forKey: .userId) != commentItem.writerId { | ||||||
|  |                                 onClickProfile(commentItem.writerId) | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|                      |                      | ||||||
|                     VStack(alignment: .leading, spacing: 0) { |                     VStack(alignment: .leading, spacing: 0) { | ||||||
|                         Text(commentItem.nickname) |                         Text(commentItem.nickname) | ||||||
| @@ -38,7 +44,7 @@ struct CreatorCommunityCommentItemView: View { | |||||||
|                          |                          | ||||||
|                         Text(commentItem.date) |                         Text(commentItem.date) | ||||||
|                             .font(.custom(Font.medium.rawValue, size: 10.3)) |                             .font(.custom(Font.medium.rawValue, size: 10.3)) | ||||||
|                             .foregroundColor(Color(hex: "525252")) |                             .foregroundColor(Color.gray52) | ||||||
|                             .padding(.top, 4) |                             .padding(.top, 4) | ||||||
|                     } |                     } | ||||||
|                      |                      | ||||||
| @@ -57,8 +63,8 @@ struct CreatorCommunityCommentItemView: View { | |||||||
|                                 .autocapitalization(.none) |                                 .autocapitalization(.none) | ||||||
|                                 .disableAutocorrection(true) |                                 .disableAutocorrection(true) | ||||||
|                                 .font(.custom(Font.medium.rawValue, size: 13.3)) |                                 .font(.custom(Font.medium.rawValue, size: 13.3)) | ||||||
|                                 .foregroundColor(Color(hex: "eeeeee")) |                                 .foregroundColor(Color.grayee) | ||||||
|                                 .accentColor(Color(hex: "3bb9f1")) |                                 .accentColor(Color.button) | ||||||
|                                 .keyboardType(.default) |                                 .keyboardType(.default) | ||||||
|                                 .padding(.horizontal, 13.3) |                                 .padding(.horizontal, 13.3) | ||||||
|                              |                              | ||||||
|   | |||||||
| @@ -17,6 +17,10 @@ struct CreatorCommunityCommentListView: View { | |||||||
|      |      | ||||||
|     @State private var commentId: Int = 0 |     @State private var commentId: Int = 0 | ||||||
|     @State private var isShowDeletePopup: Bool = false |     @State private var isShowDeletePopup: Bool = false | ||||||
|  |      | ||||||
|  |     @State private var memberId: Int = 0 | ||||||
|  |     @State private var isShowMemberProfilePopup: Bool = false | ||||||
|  |      | ||||||
|     @StateObject var viewModel = CreatorCommunityCommentListViewModel() |     @StateObject var viewModel = CreatorCommunityCommentListViewModel() | ||||||
|      |      | ||||||
|     var body: some View { |     var body: some View { | ||||||
| @@ -115,6 +119,10 @@ struct CreatorCommunityCommentListView: View { | |||||||
|                                         onClickDelete: { |                                         onClickDelete: { | ||||||
|                                             commentId = $0 |                                             commentId = $0 | ||||||
|                                             isShowDeletePopup = true |                                             isShowDeletePopup = true | ||||||
|  |                                         }, | ||||||
|  |                                         onClickProfile: { | ||||||
|  |                                             memberId = $0 | ||||||
|  |                                             isShowMemberProfilePopup = true | ||||||
|                                         } |                                         } | ||||||
|                                     ) |                                     ) | ||||||
|                                     .padding(.horizontal, 26.7) |                                     .padding(.horizontal, 26.7) | ||||||
| @@ -147,6 +155,10 @@ struct CreatorCommunityCommentListView: View { | |||||||
|                     ) |                     ) | ||||||
|                 } |                 } | ||||||
|                  |                  | ||||||
|  |                 if isShowMemberProfilePopup { | ||||||
|  |                     MemberProfileDialog(isShowing: $isShowMemberProfilePopup, memberId: memberId) | ||||||
|  |                 } | ||||||
|  |                  | ||||||
|                 if viewModel.isLoading { |                 if viewModel.isLoading { | ||||||
|                     LoadingView() |                     LoadingView() | ||||||
|                 } |                 } | ||||||
|   | |||||||
| @@ -20,6 +20,9 @@ struct CreatorCommunityCommentReplyView: View { | |||||||
|     @State private var commentId: Int = 0 |     @State private var commentId: Int = 0 | ||||||
|     @State private var isShowDeletePopup: Bool = false |     @State private var isShowDeletePopup: Bool = false | ||||||
|      |      | ||||||
|  |     @State private var memberId: Int = 0 | ||||||
|  |     @State private var isShowMemberProfilePopup: Bool = false | ||||||
|  |      | ||||||
|     var body: some View { |     var body: some View { | ||||||
|         ZStack { |         ZStack { | ||||||
|             VStack(spacing: 0) { |             VStack(spacing: 0) { | ||||||
| @@ -98,7 +101,11 @@ struct CreatorCommunityCommentReplyView: View { | |||||||
|                     isReplyComment: true, |                     isReplyComment: true, | ||||||
|                     isShowPopupMenuButton: false, |                     isShowPopupMenuButton: false, | ||||||
|                     modifyComment: { _, _ in }, |                     modifyComment: { _, _ in }, | ||||||
|                     onClickDelete: { _ in } |                     onClickDelete: { _ in }, | ||||||
|  |                     onClickProfile: { | ||||||
|  |                         memberId = $0 | ||||||
|  |                         isShowMemberProfilePopup = true | ||||||
|  |                     } | ||||||
|                 ) |                 ) | ||||||
|                 .padding(.horizontal, 26.7) |                 .padding(.horizontal, 26.7) | ||||||
|                 .padding(.bottom, 13.3) |                 .padding(.bottom, 13.3) | ||||||
| @@ -120,6 +127,10 @@ struct CreatorCommunityCommentReplyView: View { | |||||||
|                                 onClickDelete: { |                                 onClickDelete: { | ||||||
|                                     commentId = $0 |                                     commentId = $0 | ||||||
|                                     isShowDeletePopup = true |                                     isShowDeletePopup = true | ||||||
|  |                                 }, | ||||||
|  |                                 onClickProfile: { | ||||||
|  |                                     memberId = $0 | ||||||
|  |                                     isShowMemberProfilePopup = true | ||||||
|                                 } |                                 } | ||||||
|                             ) |                             ) | ||||||
|                             .padding(.horizontal, 26.7) |                             .padding(.horizontal, 26.7) | ||||||
| @@ -154,6 +165,10 @@ struct CreatorCommunityCommentReplyView: View { | |||||||
|                 ) |                 ) | ||||||
|             } |             } | ||||||
|              |              | ||||||
|  |             if isShowMemberProfilePopup { | ||||||
|  |                 MemberProfileDialog(isShowing: $isShowMemberProfilePopup, memberId: memberId) | ||||||
|  |             } | ||||||
|  |              | ||||||
|             if viewModel.isLoading { |             if viewModel.isLoading { | ||||||
|                 LoadingView() |                 LoadingView() | ||||||
|             } |             } | ||||||
|   | |||||||
| @@ -16,6 +16,9 @@ struct UserProfileFanTalkAllView: View { | |||||||
|     @State private var cheersContent: String = "" |     @State private var cheersContent: String = "" | ||||||
|     @State private var cheersId: Int = 0 |     @State private var cheersId: Int = 0 | ||||||
|      |      | ||||||
|  |     @State private var memberId: Int = 0 | ||||||
|  |     @State private var isShowMemberProfilePopup: Bool = false | ||||||
|  |      | ||||||
|     var body: some View { |     var body: some View { | ||||||
|         GeometryReader { proxy in |         GeometryReader { proxy in | ||||||
|             BaseView(isLoading: $viewModel.isLoading) { |             BaseView(isLoading: $viewModel.isLoading) { | ||||||
| @@ -26,17 +29,17 @@ struct UserProfileFanTalkAllView: View { | |||||||
|                         HStack(spacing: 6.7) { |                         HStack(spacing: 6.7) { | ||||||
|                             Text("응원") |                             Text("응원") | ||||||
|                                 .font(.custom(Font.medium.rawValue, size: 14.7)) |                                 .font(.custom(Font.medium.rawValue, size: 14.7)) | ||||||
|                                 .foregroundColor(Color(hex: "eeeeee")) |                                 .foregroundColor(Color.grayee) | ||||||
|                              |                              | ||||||
|                             Text("\(viewModel.cheersTotalCount)") |                             Text("\(viewModel.cheersTotalCount)") | ||||||
|                                 .font(.custom(Font.medium.rawValue, size: 12)) |                                 .font(.custom(Font.medium.rawValue, size: 12)) | ||||||
|                                 .foregroundColor(Color(hex: "777777")) |                                 .foregroundColor(Color.gray77) | ||||||
|                         } |                         } | ||||||
|                         .padding(.top, 20) |                         .padding(.top, 20) | ||||||
|                          |                          | ||||||
|                         Rectangle() |                         Rectangle() | ||||||
|                             .frame(height: 1) |                             .frame(height: 1) | ||||||
|                             .foregroundColor(Color(hex: "909090").opacity(0.5)) |                             .foregroundColor(Color.gray90.opacity(0.5)) | ||||||
|                             .padding(.top, 13.3) |                             .padding(.top, 13.3) | ||||||
|                          |                          | ||||||
|                         HStack(spacing: 0) { |                         HStack(spacing: 0) { | ||||||
| @@ -44,8 +47,8 @@ struct UserProfileFanTalkAllView: View { | |||||||
|                                 .autocapitalization(.none) |                                 .autocapitalization(.none) | ||||||
|                                 .disableAutocorrection(true) |                                 .disableAutocorrection(true) | ||||||
|                                 .font(.custom(Font.medium.rawValue, size: 13.3)) |                                 .font(.custom(Font.medium.rawValue, size: 13.3)) | ||||||
|                                 .foregroundColor(Color(hex: "eeeeee")) |                                 .foregroundColor(Color.grayee) | ||||||
|                                 .accentColor(Color(hex: "3bb9f1")) |                                 .accentColor(Color.button) | ||||||
|                                 .keyboardType(.default) |                                 .keyboardType(.default) | ||||||
|                                 .padding(.horizontal, 13.3) |                                 .padding(.horizontal, 13.3) | ||||||
|                              |                              | ||||||
| @@ -61,18 +64,18 @@ struct UserProfileFanTalkAllView: View { | |||||||
|                                     cheersContent = "" |                                     cheersContent = "" | ||||||
|                                 } |                                 } | ||||||
|                         } |                         } | ||||||
|                         .background(Color(hex: "232323")) |                         .background(Color.gray23) | ||||||
|                         .cornerRadius(10) |                         .cornerRadius(10) | ||||||
|                         .overlay( |                         .overlay( | ||||||
|                             RoundedRectangle(cornerRadius: 10) |                             RoundedRectangle(cornerRadius: 10) | ||||||
|                                 .strokeBorder(lineWidth: 1) |                                 .strokeBorder(lineWidth: 1) | ||||||
|                                 .foregroundColor(Color(hex: "3bb9f1")) |                                 .foregroundColor(Color.button) | ||||||
|                         ) |                         ) | ||||||
|                         .padding(.top, 13.3) |                         .padding(.top, 13.3) | ||||||
|                          |                          | ||||||
|                         Rectangle() |                         Rectangle() | ||||||
|                             .frame(height: 1) |                             .frame(height: 1) | ||||||
|                             .foregroundColor(Color(hex: "909090").opacity(0.5)) |                             .foregroundColor(Color.gray90.opacity(0.5)) | ||||||
|                             .padding(.top, 13.3) |                             .padding(.top, 13.3) | ||||||
|                          |                          | ||||||
|                         ScrollView(.vertical, showsIndicators: false) { |                         ScrollView(.vertical, showsIndicators: false) { | ||||||
| @@ -96,6 +99,10 @@ struct UserProfileFanTalkAllView: View { | |||||||
|                                             onClickDelete: { cheersId in |                                             onClickDelete: { cheersId in | ||||||
|                                                 self.cheersId = cheersId |                                                 self.cheersId = cheersId | ||||||
|                                                 viewModel.isShowCheersDeleteView = true |                                                 viewModel.isShowCheersDeleteView = true | ||||||
|  |                                             }, | ||||||
|  |                                             onClickProfile: { | ||||||
|  |                                                 self.memberId = $0 | ||||||
|  |                                                 self.isShowMemberProfilePopup = true | ||||||
|                                             } |                                             } | ||||||
|                                         ) |                                         ) | ||||||
|                                         .onAppear { |                                         .onAppear { | ||||||
| @@ -110,7 +117,7 @@ struct UserProfileFanTalkAllView: View { | |||||||
|                                 } else { |                                 } else { | ||||||
|                                     Text("응원이 없습니다.\n\n처음으로 응원을 해보세요!") |                                     Text("응원이 없습니다.\n\n처음으로 응원을 해보세요!") | ||||||
|                                         .font(.custom(Font.light.rawValue, size: 13.3)) |                                         .font(.custom(Font.light.rawValue, size: 13.3)) | ||||||
|                                         .foregroundColor(Color(hex: "bbbbbb")) |                                         .foregroundColor(Color.graybb) | ||||||
|                                         .multilineTextAlignment(.center) |                                         .multilineTextAlignment(.center) | ||||||
|                                         .fixedSize(horizontal: false, vertical: true) |                                         .fixedSize(horizontal: false, vertical: true) | ||||||
|                                         .padding(.vertical, 60) |                                         .padding(.vertical, 60) | ||||||
| @@ -136,7 +143,7 @@ struct UserProfileFanTalkAllView: View { | |||||||
|                             .padding(.vertical, 13.3) |                             .padding(.vertical, 13.3) | ||||||
|                             .frame(width: screenSize().width - 66.7, alignment: .center) |                             .frame(width: screenSize().width - 66.7, alignment: .center) | ||||||
|                             .font(.custom(Font.medium.rawValue, size: 12)) |                             .font(.custom(Font.medium.rawValue, size: 12)) | ||||||
|                             .background(Color(hex: "9970ff")) |                             .background(Color.button) | ||||||
|                             .foregroundColor(Color.white) |                             .foregroundColor(Color.white) | ||||||
|                             .multilineTextAlignment(.leading) |                             .multilineTextAlignment(.leading) | ||||||
|                             .cornerRadius(20) |                             .cornerRadius(20) | ||||||
| @@ -171,6 +178,10 @@ struct UserProfileFanTalkAllView: View { | |||||||
|                             ) |                             ) | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|  |                      | ||||||
|  |                     if isShowMemberProfilePopup { | ||||||
|  |                         MemberProfileDialog(isShowing: $isShowMemberProfilePopup, memberId: memberId) | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -16,6 +16,7 @@ struct UserProfileFanTalkCheersItemView: View { | |||||||
|     let modifyCheer: (Int, String) -> Void |     let modifyCheer: (Int, String) -> Void | ||||||
|     let reportPopup: (Int) -> Void |     let reportPopup: (Int) -> Void | ||||||
|     let onClickDelete: (Int) -> Void |     let onClickDelete: (Int) -> Void | ||||||
|  |     let onClickProfile: (Int) -> Void | ||||||
|      |      | ||||||
|     @State var replyContent: String = "" |     @State var replyContent: String = "" | ||||||
|     @State var isShowInputReply = false |     @State var isShowInputReply = false | ||||||
| @@ -34,6 +35,11 @@ struct UserProfileFanTalkCheersItemView: View { | |||||||
|                         .resizable() |                         .resizable() | ||||||
|                         .frame(width: 33.3, height: 33.3) |                         .frame(width: 33.3, height: 33.3) | ||||||
|                         .clipShape(Circle()) |                         .clipShape(Circle()) | ||||||
|  |                         .onTapGesture { | ||||||
|  |                             if UserDefaults.int(forKey: .userId) != cheersItem.memberId { | ||||||
|  |                                 onClickProfile(cheersItem.memberId) | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|                      |                      | ||||||
|                     VStack(alignment: .leading, spacing: 0) { |                     VStack(alignment: .leading, spacing: 0) { | ||||||
|                         Text("\(cheersItem.nickname)") |                         Text("\(cheersItem.nickname)") | ||||||
| @@ -51,10 +57,10 @@ struct UserProfileFanTalkCheersItemView: View { | |||||||
|                                     .autocapitalization(.none) |                                     .autocapitalization(.none) | ||||||
|                                     .disableAutocorrection(true) |                                     .disableAutocorrection(true) | ||||||
|                                     .font(.custom(Font.medium.rawValue, size: 13.3)) |                                     .font(.custom(Font.medium.rawValue, size: 13.3)) | ||||||
|                                     .foregroundColor(Color(hex: "eeeeee")) |                                     .foregroundColor(Color.grayee) | ||||||
|                                     .padding(13.3) |                                     .padding(13.3) | ||||||
|                                     .background(Color(hex: "232323")) |                                     .background(Color.gray23) | ||||||
|                                     .accentColor(Color(hex: "3bb9f1")) |                                     .accentColor(Color.button) | ||||||
|                                     .keyboardType(.default) |                                     .keyboardType(.default) | ||||||
|                                     .cornerRadius(10) |                                     .cornerRadius(10) | ||||||
|                                     .overlay( |                                     .overlay( | ||||||
| @@ -65,7 +71,7 @@ struct UserProfileFanTalkCheersItemView: View { | |||||||
|                                  |                                  | ||||||
|                                 Text("수정") |                                 Text("수정") | ||||||
|                                     .font(.custom(Font.bold.rawValue, size: 13.3)) |                                     .font(.custom(Font.bold.rawValue, size: 13.3)) | ||||||
|                                     .foregroundColor(Color(hex: "ffffff")) |                                     .foregroundColor(Color.white) | ||||||
|                                     .padding(13.3) |                                     .padding(13.3) | ||||||
|                                     .background(Color.button) |                                     .background(Color.button) | ||||||
|                                     .cornerRadius(6.7) |                                     .cornerRadius(6.7) | ||||||
| @@ -78,7 +84,7 @@ struct UserProfileFanTalkCheersItemView: View { | |||||||
|                                     .font(.custom(Font.bold.rawValue, size: 13.3)) |                                     .font(.custom(Font.bold.rawValue, size: 13.3)) | ||||||
|                                     .foregroundColor(Color.button) |                                     .foregroundColor(Color.button) | ||||||
|                                     .padding(13.3) |                                     .padding(13.3) | ||||||
|                                     .background(Color(hex: "222222")) |                                     .background(Color.gray22) | ||||||
|                                     .cornerRadius(6.7) |                                     .cornerRadius(6.7) | ||||||
|                                     .onTapGesture { |                                     .onTapGesture { | ||||||
|                                         isModeModify = false |                                         isModeModify = false | ||||||
| @@ -100,23 +106,23 @@ struct UserProfileFanTalkCheersItemView: View { | |||||||
|                                     .autocapitalization(.none) |                                     .autocapitalization(.none) | ||||||
|                                     .disableAutocorrection(true) |                                     .disableAutocorrection(true) | ||||||
|                                     .font(.custom(Font.medium.rawValue, size: 13.3)) |                                     .font(.custom(Font.medium.rawValue, size: 13.3)) | ||||||
|                                     .foregroundColor(Color(hex: "eeeeee")) |                                     .foregroundColor(Color.grayee) | ||||||
|                                     .padding(13.3) |                                     .padding(13.3) | ||||||
|                                     .background(Color(hex: "232323")) |                                     .background(Color.gray23) | ||||||
|                                     .accentColor(Color(hex: "3bb9f1")) |                                     .accentColor(Color.button) | ||||||
|                                     .keyboardType(.default) |                                     .keyboardType(.default) | ||||||
|                                     .cornerRadius(10) |                                     .cornerRadius(10) | ||||||
|                                     .overlay( |                                     .overlay( | ||||||
|                                         RoundedRectangle(cornerRadius: 10) |                                         RoundedRectangle(cornerRadius: 10) | ||||||
|                                             .strokeBorder(lineWidth: 1) |                                             .strokeBorder(lineWidth: 1) | ||||||
|                                             .foregroundColor(Color(hex: "3bb9f1")) |                                             .foregroundColor(Color.button) | ||||||
|                                     ) |                                     ) | ||||||
|                                  |                                  | ||||||
|                                 Text("등록") |                                 Text("등록") | ||||||
|                                     .font(.custom(Font.bold.rawValue, size: 13.3)) |                                     .font(.custom(Font.bold.rawValue, size: 13.3)) | ||||||
|                                     .foregroundColor(Color(hex: "ffffff")) |                                     .foregroundColor(Color.white) | ||||||
|                                     .padding(13.3) |                                     .padding(13.3) | ||||||
|                                     .background(Color(hex: "3bb9f1")) |                                     .background(Color.button) | ||||||
|                                     .cornerRadius(6.7) |                                     .cornerRadius(6.7) | ||||||
|                                     .onTapGesture { |                                     .onTapGesture { | ||||||
|                                         if cheersItem.replyList.count > 0 { |                                         if cheersItem.replyList.count > 0 { | ||||||
| @@ -182,7 +188,7 @@ struct UserProfileFanTalkCheersItemView: View { | |||||||
|                  |                  | ||||||
|                 Rectangle() |                 Rectangle() | ||||||
|                     .frame(height: 1) |                     .frame(height: 1) | ||||||
|                     .foregroundColor(Color(hex: "909090").opacity(0.5)) |                     .foregroundColor(Color.gray90.opacity(0.5)) | ||||||
|                     .padding(.top, 13.3) |                     .padding(.top, 13.3) | ||||||
|             } |             } | ||||||
|             .frame(width: screenSize().width - 26.7) |             .frame(width: screenSize().width - 26.7) | ||||||
| @@ -192,7 +198,7 @@ struct UserProfileFanTalkCheersItemView: View { | |||||||
|                     if cheersItem.memberId != UserDefaults.int(forKey: .userId) { |                     if cheersItem.memberId != UserDefaults.int(forKey: .userId) { | ||||||
|                         Text("신고하기") |                         Text("신고하기") | ||||||
|                             .font(.custom(Font.medium.rawValue, size: 14)) |                             .font(.custom(Font.medium.rawValue, size: 14)) | ||||||
|                             .foregroundColor(Color(hex: "777777")) |                             .foregroundColor(Color.gray77) | ||||||
|                             .onTapGesture { |                             .onTapGesture { | ||||||
|                                 reportPopup(cheersItem.cheersId) |                                 reportPopup(cheersItem.cheersId) | ||||||
|                                 isShowPopupMenu = false |                                 isShowPopupMenu = false | ||||||
| @@ -202,7 +208,7 @@ struct UserProfileFanTalkCheersItemView: View { | |||||||
|                     if cheersItem.memberId == UserDefaults.int(forKey: .userId) { |                     if cheersItem.memberId == UserDefaults.int(forKey: .userId) { | ||||||
|                         Text("수정") |                         Text("수정") | ||||||
|                             .font(.custom(Font.medium.rawValue, size: 14)) |                             .font(.custom(Font.medium.rawValue, size: 14)) | ||||||
|                             .foregroundColor(Color(hex: "777777")) |                             .foregroundColor(Color.gray77) | ||||||
|                             .onTapGesture { |                             .onTapGesture { | ||||||
|                                 isModeModify = true |                                 isModeModify = true | ||||||
|                                 isShowPopupMenu = false |                                 isShowPopupMenu = false | ||||||
| @@ -215,7 +221,7 @@ struct UserProfileFanTalkCheersItemView: View { | |||||||
|                     { |                     { | ||||||
|                         Text("삭제") |                         Text("삭제") | ||||||
|                             .font(.custom(Font.medium.rawValue, size: 14)) |                             .font(.custom(Font.medium.rawValue, size: 14)) | ||||||
|                             .foregroundColor(Color(hex: "777777")) |                             .foregroundColor(Color.gray77) | ||||||
|                             .onTapGesture { |                             .onTapGesture { | ||||||
|                                 onClickDelete(cheersItem.cheersId) |                                 onClickDelete(cheersItem.cheersId) | ||||||
|                                 isShowPopupMenu = false |                                 isShowPopupMenu = false | ||||||
| @@ -223,7 +229,7 @@ struct UserProfileFanTalkCheersItemView: View { | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 .padding(10) |                 .padding(10) | ||||||
|                 .background(Color(hex: "222222")) |                 .background(Color.gray22) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         .contentShape(Rectangle()) |         .contentShape(Rectangle()) | ||||||
|   | |||||||
| @@ -17,6 +17,7 @@ struct UserProfileFanTalkView: View { | |||||||
|     let errorPopup: (String) -> Void |     let errorPopup: (String) -> Void | ||||||
|     let reportPopup: (Int) -> Void |     let reportPopup: (Int) -> Void | ||||||
|     let deletePopup: (Int) -> Void |     let deletePopup: (Int) -> Void | ||||||
|  |     let profilePopup: (Int) -> Void | ||||||
|      |      | ||||||
|     @Binding var isLoading: Bool |     @Binding var isLoading: Bool | ||||||
|     @State private var cheersContent: String = "" |     @State private var cheersContent: String = "" | ||||||
| @@ -26,13 +27,13 @@ struct UserProfileFanTalkView: View { | |||||||
|             HStack(spacing: 0) { |             HStack(spacing: 0) { | ||||||
|                 Text("팬 Talk") |                 Text("팬 Talk") | ||||||
|                     .font(.custom(Font.bold.rawValue, size: 16.7)) |                     .font(.custom(Font.bold.rawValue, size: 16.7)) | ||||||
|                     .foregroundColor(Color(hex: "eeeeee")) |                     .foregroundColor(Color.grayee) | ||||||
|                  |                  | ||||||
|                 Spacer() |                 Spacer() | ||||||
|                  |                  | ||||||
|                 Text("전체보기") |                 Text("전체보기") | ||||||
|                     .font(.custom(Font.light.rawValue, size: 11.3)) |                     .font(.custom(Font.light.rawValue, size: 11.3)) | ||||||
|                     .foregroundColor(Color(hex: "bbbbbb")) |                     .foregroundColor(Color.graybb) | ||||||
|                     .onTapGesture { |                     .onTapGesture { | ||||||
|                         AppState.shared.setAppStep(step: .userProfileFanTalkAll(userId: userId)) |                         AppState.shared.setAppStep(step: .userProfileFanTalkAll(userId: userId)) | ||||||
|                     } |                     } | ||||||
| @@ -43,17 +44,17 @@ struct UserProfileFanTalkView: View { | |||||||
|                 HStack(spacing: 6.7) { |                 HStack(spacing: 6.7) { | ||||||
|                     Text("응원") |                     Text("응원") | ||||||
|                         .font(.custom(Font.medium.rawValue, size: 14.7)) |                         .font(.custom(Font.medium.rawValue, size: 14.7)) | ||||||
|                         .foregroundColor(Color(hex: "eeeeee")) |                         .foregroundColor(Color.grayee) | ||||||
|                      |                      | ||||||
|                     Text("\(cheers.totalCount)") |                     Text("\(cheers.totalCount)") | ||||||
|                         .font(.custom(Font.medium.rawValue, size: 12)) |                         .font(.custom(Font.medium.rawValue, size: 12)) | ||||||
|                         .foregroundColor(Color(hex: "777777")) |                         .foregroundColor(Color.gray77) | ||||||
|                 } |                 } | ||||||
|                 .padding(.top, 20) |                 .padding(.top, 20) | ||||||
|                  |                  | ||||||
|                 Rectangle() |                 Rectangle() | ||||||
|                     .frame(height: 1) |                     .frame(height: 1) | ||||||
|                     .foregroundColor(Color(hex: "909090").opacity(0.5)) |                     .foregroundColor(Color.gray90.opacity(0.5)) | ||||||
|                     .padding(.top, 13.3) |                     .padding(.top, 13.3) | ||||||
|                  |                  | ||||||
|                 HStack(spacing: 0) { |                 HStack(spacing: 0) { | ||||||
| @@ -61,8 +62,8 @@ struct UserProfileFanTalkView: View { | |||||||
|                         .autocapitalization(.none) |                         .autocapitalization(.none) | ||||||
|                         .disableAutocorrection(true) |                         .disableAutocorrection(true) | ||||||
|                         .font(.custom(Font.medium.rawValue, size: 13.3)) |                         .font(.custom(Font.medium.rawValue, size: 13.3)) | ||||||
|                         .foregroundColor(Color(hex: "eeeeee")) |                         .foregroundColor(Color.grayee) | ||||||
|                         .accentColor(Color(hex: "3bb9f1")) |                         .accentColor(Color.button) | ||||||
|                         .keyboardType(.default) |                         .keyboardType(.default) | ||||||
|                         .padding(.horizontal, 13.3) |                         .padding(.horizontal, 13.3) | ||||||
|                      |                      | ||||||
| @@ -78,18 +79,18 @@ struct UserProfileFanTalkView: View { | |||||||
|                             cheersContent = "" |                             cheersContent = "" | ||||||
|                         } |                         } | ||||||
|                 } |                 } | ||||||
|                 .background(Color(hex: "232323")) |                 .background(Color.gray23) | ||||||
|                 .cornerRadius(10) |                 .cornerRadius(10) | ||||||
|                 .overlay( |                 .overlay( | ||||||
|                     RoundedRectangle(cornerRadius: 10) |                     RoundedRectangle(cornerRadius: 10) | ||||||
|                         .strokeBorder(lineWidth: 1) |                         .strokeBorder(lineWidth: 1) | ||||||
|                         .foregroundColor(Color(hex: "9970ff")) |                         .foregroundColor(Color.button) | ||||||
|                 ) |                 ) | ||||||
|                 .padding(.top, 13.3) |                 .padding(.top, 13.3) | ||||||
|                  |                  | ||||||
|                 Rectangle() |                 Rectangle() | ||||||
|                     .frame(height: 1) |                     .frame(height: 1) | ||||||
|                     .foregroundColor(Color(hex: "909090").opacity(0.5)) |                     .foregroundColor(Color.gray90.opacity(0.5)) | ||||||
|                     .padding(.top, 13.3) |                     .padding(.top, 13.3) | ||||||
|                  |                  | ||||||
|                 VStack(spacing: 20) { |                 VStack(spacing: 20) { | ||||||
| @@ -110,6 +111,9 @@ struct UserProfileFanTalkView: View { | |||||||
|                                 }, |                                 }, | ||||||
|                                 onClickDelete: { cheersId in |                                 onClickDelete: { cheersId in | ||||||
|                                     deletePopup(cheersId) |                                     deletePopup(cheersId) | ||||||
|  |                                 }, | ||||||
|  |                                 onClickProfile: { | ||||||
|  |                                     profilePopup($0) | ||||||
|                                 } |                                 } | ||||||
|                             ) |                             ) | ||||||
|                             .onTapGesture { |                             .onTapGesture { | ||||||
| @@ -119,7 +123,7 @@ struct UserProfileFanTalkView: View { | |||||||
|                     } else { |                     } else { | ||||||
|                         Text("응원이 없습니다.\n\n처음으로 응원을 해보세요!") |                         Text("응원이 없습니다.\n\n처음으로 응원을 해보세요!") | ||||||
|                             .font(.custom(Font.light.rawValue, size: 13.3)) |                             .font(.custom(Font.light.rawValue, size: 13.3)) | ||||||
|                             .foregroundColor(Color(hex: "bbbbbb")) |                             .foregroundColor(Color.graybb) | ||||||
|                             .multilineTextAlignment(.center) |                             .multilineTextAlignment(.center) | ||||||
|                             .fixedSize(horizontal: false, vertical: true) |                             .fixedSize(horizontal: false, vertical: true) | ||||||
|                             .padding(.vertical, 60) |                             .padding(.vertical, 60) | ||||||
|   | |||||||
| @@ -12,6 +12,9 @@ struct UserProfileView: View { | |||||||
|     let userId: Int |     let userId: Int | ||||||
|     @StateObject var viewModel = UserProfileViewModel() |     @StateObject var viewModel = UserProfileViewModel() | ||||||
|      |      | ||||||
|  |     @State private var memberId: Int = 0 | ||||||
|  |     @State private var isShowMemberProfilePopup: Bool = false | ||||||
|  |      | ||||||
|     var body: some View { |     var body: some View { | ||||||
|         GeometryReader { proxy in |         GeometryReader { proxy in | ||||||
|             BaseView(isLoading: $viewModel.isLoading) { |             BaseView(isLoading: $viewModel.isLoading) { | ||||||
| @@ -196,6 +199,10 @@ struct UserProfileView: View { | |||||||
|                                         viewModel.cheersId = cheerId |                                         viewModel.cheersId = cheerId | ||||||
|                                         viewModel.isShowCheersDeleteView = true |                                         viewModel.isShowCheersDeleteView = true | ||||||
|                                     }, |                                     }, | ||||||
|  |                                     profilePopup: { | ||||||
|  |                                         self.memberId = $0 | ||||||
|  |                                         self.isShowMemberProfilePopup = true | ||||||
|  |                                     }, | ||||||
|                                     isLoading: $viewModel.isLoading |                                     isLoading: $viewModel.isLoading | ||||||
|                                 ) |                                 ) | ||||||
|                                 .padding(.top, 26.7) |                                 .padding(.top, 26.7) | ||||||
| @@ -311,6 +318,10 @@ struct UserProfileView: View { | |||||||
|                             } |                             } | ||||||
|                         ) |                         ) | ||||||
|                     } |                     } | ||||||
|  |                      | ||||||
|  |                     if isShowMemberProfilePopup { | ||||||
|  |                         MemberProfileDialog(isShowing: $isShowMemberProfilePopup, memberId: memberId) | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             .sheet( |             .sheet( | ||||||
|   | |||||||
							
								
								
									
										13
									
								
								SodaLive/Sources/User/GetMemberProfileResponse.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								SodaLive/Sources/User/GetMemberProfileResponse.swift
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | // | ||||||
|  | //  GetMemberProfileResponse.swift | ||||||
|  | //  SodaLive | ||||||
|  | // | ||||||
|  | //  Created by klaus on 9/7/24. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | struct GetMemberProfileResponse: Decodable { | ||||||
|  |     let memberId: Int | ||||||
|  |     let nickname: String | ||||||
|  |     let profileImageUrl: String | ||||||
|  |     let isBlocked: Bool | ||||||
|  | } | ||||||
| @@ -33,6 +33,7 @@ enum UserApi { | |||||||
|     case checkNickname(nickname: String) |     case checkNickname(nickname: String) | ||||||
|     case changeNickname(request: ProfileUpdateRequest) |     case changeNickname(request: ProfileUpdateRequest) | ||||||
|     case updateIdfa(request: IdfaUpdateRequest) |     case updateIdfa(request: IdfaUpdateRequest) | ||||||
|  |     case getMemberProfile(memberId: Int) | ||||||
| } | } | ||||||
|  |  | ||||||
| extension UserApi: TargetType { | extension UserApi: TargetType { | ||||||
| @@ -80,10 +81,10 @@ extension UserApi: TargetType { | |||||||
|              |              | ||||||
|         case .creatorUnFollow: |         case .creatorUnFollow: | ||||||
|             return "/member/creator/unfollow" |             return "/member/creator/unfollow" | ||||||
|          |              | ||||||
|         case .getBlockedMemberIdList: |         case .getBlockedMemberIdList: | ||||||
|             return "/member/block/id" |             return "/member/block/id" | ||||||
|          |              | ||||||
|         case .getBlockedMemberList, .memberBlock: |         case .getBlockedMemberList, .memberBlock: | ||||||
|             return "/member/block" |             return "/member/block" | ||||||
|              |              | ||||||
| @@ -107,6 +108,9 @@ extension UserApi: TargetType { | |||||||
|              |              | ||||||
|         case .updateIdfa: |         case .updateIdfa: | ||||||
|             return "/member/adid/update" |             return "/member/adid/update" | ||||||
|  |              | ||||||
|  |         case .getMemberProfile(let memberId): | ||||||
|  |             return "/member/profile/\(memberId)" | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|      |      | ||||||
| @@ -116,7 +120,7 @@ extension UserApi: TargetType { | |||||||
|                 .profileImageUpdate: |                 .profileImageUpdate: | ||||||
|             return .post |             return .post | ||||||
|              |              | ||||||
|         case .searchUser, .getMypage, .getMemberInfo, .getMyProfile, .getChangeNicknamePrice, .checkNickname, .getBlockedMemberList, .getBlockedMemberIdList: |         case .searchUser, .getMypage, .getMemberInfo, .getMyProfile, .getChangeNicknamePrice, .checkNickname, .getBlockedMemberList, .getBlockedMemberIdList, .getMemberProfile: | ||||||
|             return .get |             return .get | ||||||
|              |              | ||||||
|         case .updatePushToken, .profileUpdate, .changeNickname, .updateIdfa: |         case .updatePushToken, .profileUpdate, .changeNickname, .updateIdfa: | ||||||
| @@ -141,7 +145,7 @@ extension UserApi: TargetType { | |||||||
|         case .getMypage, .getMyProfile, .getMemberInfo: |         case .getMypage, .getMyProfile, .getMemberInfo: | ||||||
|             return .requestParameters(parameters: ["container" : "ios"], encoding: URLEncoding.queryString) |             return .requestParameters(parameters: ["container" : "ios"], encoding: URLEncoding.queryString) | ||||||
|              |              | ||||||
|         case .logout, .logoutAllDevice, .getChangeNicknamePrice, .getBlockedMemberIdList: |         case .logout, .logoutAllDevice, .getChangeNicknamePrice, .getBlockedMemberIdList, .getMemberProfile: | ||||||
|             return .requestPlain |             return .requestPlain | ||||||
|              |              | ||||||
|         case .notification(let request): |         case .notification(let request): | ||||||
|   | |||||||
| @@ -120,4 +120,8 @@ final class UserRepository { | |||||||
|     func updateIdfa(request: IdfaUpdateRequest) -> AnyPublisher<Response, MoyaError> { |     func updateIdfa(request: IdfaUpdateRequest) -> AnyPublisher<Response, MoyaError> { | ||||||
|         return api.requestPublisher(.updateIdfa(request: request)) |         return api.requestPublisher(.updateIdfa(request: request)) | ||||||
|     } |     } | ||||||
|  |      | ||||||
|  |     func getMemberProfile(memberId: Int) -> AnyPublisher<Response, MoyaError> { | ||||||
|  |         return api.requestPublisher(.getMemberProfile(memberId: memberId)) | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										192
									
								
								SodaLive/Sources/User/UserViewModel.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								SodaLive/Sources/User/UserViewModel.swift
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,192 @@ | |||||||
|  | // | ||||||
|  | //  UserViewModel.swift | ||||||
|  | //  SodaLive | ||||||
|  | // | ||||||
|  | //  Created by klaus on 9/7/24. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | import Foundation | ||||||
|  | import Moya | ||||||
|  | import Combine | ||||||
|  |  | ||||||
|  | final class UserViewModel: ObservableObject { | ||||||
|  |     private let repository = UserRepository() | ||||||
|  |     private let reportRepository = ReportRepository() | ||||||
|  |     private var subscription = Set<AnyCancellable>() | ||||||
|  |      | ||||||
|  |     @Published var isLoading = false | ||||||
|  |     @Published var errorMessage = "" | ||||||
|  |     @Published var isShowPopup = false | ||||||
|  |      | ||||||
|  |     @Published var memberId = 0 | ||||||
|  |     @Published var nickname = "" | ||||||
|  |     @Published var dismissDialog = false | ||||||
|  |      | ||||||
|  |     @Published var isShowUesrBlockConfirm = false | ||||||
|  |     @Published var isShowUesrReportView = false | ||||||
|  |     @Published var isShowProfileReportConfirm = false | ||||||
|  |      | ||||||
|  |     @Published var memberProfile: GetMemberProfileResponse? | ||||||
|  |      | ||||||
|  |     func getMemberProfile(memberId: Int) { | ||||||
|  |         isLoading = true | ||||||
|  |          | ||||||
|  |         repository.getMemberProfile(memberId: memberId) | ||||||
|  |             .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<GetMemberProfileResponse>.self, from: responseData) | ||||||
|  |                      | ||||||
|  |                     if let data = decoded.data, decoded.success { | ||||||
|  |                         self.memberProfile = data | ||||||
|  |                         self.memberId = data.memberId | ||||||
|  |                         self.nickname = data.nickname | ||||||
|  |                     } 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 memberBlock() { | ||||||
|  |         isLoading = true | ||||||
|  |         repository.memberBlock(userId: memberId) | ||||||
|  |             .sink { result in | ||||||
|  |                 switch result { | ||||||
|  |                 case .finished: | ||||||
|  |                     DEBUG_LOG("finish") | ||||||
|  |                 case .failure(let error): | ||||||
|  |                     ERROR_LOG(error.localizedDescription) | ||||||
|  |                 } | ||||||
|  |             } receiveValue: { [unowned self] response in | ||||||
|  |                 self.isLoading = false | ||||||
|  |                 let responseData = response.data | ||||||
|  |                  | ||||||
|  |                 do { | ||||||
|  |                     let jsonDecoder = JSONDecoder() | ||||||
|  |                     let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: responseData) | ||||||
|  |                      | ||||||
|  |                     if decoded.success { | ||||||
|  |                         self.errorMessage = "차단하였습니다." | ||||||
|  |                         self.dismissDialog = true | ||||||
|  |                          | ||||||
|  |                         self.memberId = 0 | ||||||
|  |                         self.nickname = "" | ||||||
|  |                     } 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) | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     func memberUnBlock() { | ||||||
|  |         isLoading = true | ||||||
|  |         repository.memberUnBlock(userId: memberId) | ||||||
|  |             .sink { result in | ||||||
|  |                 switch result { | ||||||
|  |                 case .finished: | ||||||
|  |                     DEBUG_LOG("finish") | ||||||
|  |                 case .failure(let error): | ||||||
|  |                     ERROR_LOG(error.localizedDescription) | ||||||
|  |                 } | ||||||
|  |             } receiveValue: { [unowned self] response in | ||||||
|  |                 self.isLoading = false | ||||||
|  |                 let responseData = response.data | ||||||
|  |                  | ||||||
|  |                 do { | ||||||
|  |                     let jsonDecoder = JSONDecoder() | ||||||
|  |                     let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: responseData) | ||||||
|  |                      | ||||||
|  |                     if decoded.success { | ||||||
|  |                         self.errorMessage = "차단이 해제 되었습니다." | ||||||
|  |                         self.dismissDialog = true | ||||||
|  |                          | ||||||
|  |                         self.memberId = 0 | ||||||
|  |                         self.nickname = "" | ||||||
|  |                     } 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) | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     func report(type: ReportType, reason: String = "프로필 신고") { | ||||||
|  |         isLoading = true | ||||||
|  |          | ||||||
|  |         let request = ReportRequest(type: type, reason: reason, reportedMemberId: memberId, cheersId: nil, audioContentId: nil) | ||||||
|  |         reportRepository.report(request: request) | ||||||
|  |             .sink { result in | ||||||
|  |                 switch result { | ||||||
|  |                 case .finished: | ||||||
|  |                     DEBUG_LOG("finish") | ||||||
|  |                 case .failure(let error): | ||||||
|  |                     ERROR_LOG(error.localizedDescription) | ||||||
|  |                 } | ||||||
|  |             } receiveValue: { [unowned self] response in | ||||||
|  |                 self.isLoading = false | ||||||
|  |                 let responseData = response.data | ||||||
|  |                  | ||||||
|  |                 self.memberId = 0 | ||||||
|  |                 self.nickname = "" | ||||||
|  |                 self.dismissDialog = true | ||||||
|  |                  | ||||||
|  |                 do { | ||||||
|  |                     let jsonDecoder = JSONDecoder() | ||||||
|  |                     let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: responseData) | ||||||
|  |                      | ||||||
|  |                     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) | ||||||
|  |     } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	 Yu Sung
					Yu Sung