Skip to content

Commit 23f4d36

Browse files
committed
✨ [feat] 계정 가리기, 게시글 가리기 구현
1 parent 3fe2fd6 commit 23f4d36

File tree

7 files changed

+227
-25
lines changed

7 files changed

+227
-25
lines changed

Fitfty/Projects/Coordinator/Sources/Profile/PostCoordinator.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ private extension PostCoordinator {
103103
coordinator.finishDelegate = self
104104
coordinator.parentCoordinator = self
105105
let bottomSheetViewController = BottomSheetViewController(
106-
style: .custom(196),
106+
style: .custom(290),
107107
contentViewController: coordinator.navigationController
108108
)
109109
coordinator.bottomSheetDelegate = bottomSheetViewController

Fitfty/Projects/Coordinator/Sources/Profile/ProfileCoordinator.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ private extension ProfileCoordinator {
9797
coordinator.parentCoordinator = self
9898
let bottomSheetViewController =
9999
BottomSheetViewController(
100-
style: .small,
100+
style: .custom(196),
101101
contentViewController: coordinator.navigationController
102102
)
103103
bottomSheetDelegate = bottomSheetViewController

Fitfty/Projects/Coordinator/Sources/Profile/ReportCoordinator.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import Foundation
1010
import UIKit
1111
import Profile
1212
import Common
13+
import Core
1314

1415
final class ReportCoordinator: Coordinator {
1516

@@ -53,6 +54,13 @@ private extension ReportCoordinator {
5354
func makeReportViewController(reportPresentType: ReportPresentType, userToken: String?, boardToken: String?) -> UIViewController {
5455
let viewController = ReportViewController(
5556
coordinator: self,
57+
viewModel: ReportViewModel(
58+
userManager: DefaultUserManager.shared,
59+
userToken: userToken,
60+
boardToken: boardToken,
61+
reportType: reportPresentType == .userReport ? .userReport : .postReport,
62+
fitftyRepository: DefaultFitftyRepository()
63+
),
5664
reportPresentType: reportPresentType,
5765
userToken: userToken,
5866
boardToken: boardToken
@@ -91,6 +99,15 @@ extension ReportCoordinator: ReportCoordinatorInterface {
9199
self.finishDelegate?.coordinatorDidFinish(childCoordinator: self)
92100
}
93101
}
102+
103+
func popToRoot() {
104+
bottomSheetDelegate?.dismissBottomSheet {
105+
self.navigationController.viewControllers.removeAll()
106+
self.finishDelegate?.coordinatorDidFinish(childCoordinator: self)
107+
self.parentCoordinator?.navigationController.popToRootViewController(animated: true)
108+
}
109+
}
110+
94111
}
95112

96113
extension ReportCoordinator: CoordinatorFinishDelegate {

Fitfty/Projects/Profile/Sources/CoordinatorInterfaces/ReportCoordinatorInterface.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,6 @@ public protocol ReportCoordinatorInterface: AnyObject {
1313

1414
func showDetailReport(_ reportType: ReportType, userToken: String?, boardToken: String?)
1515
func dismiss()
16+
func popToRoot()
1617

1718
}

Fitfty/Projects/Profile/Sources/Post/Views/MyPostBottomSheetView.swift

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,43 +27,76 @@ final class MyPostBottomSheetView: UIStackView {
2727
return button
2828
}()
2929

30-
private lazy var seperatorView: UIView = {
30+
private lazy var thirdButton: UIButton = {
31+
let button = UIButton()
32+
button.setTitleColor(CommonAsset.Colors.gray07.color, for: .normal)
33+
button.titleLabel?.font = FitftyFont.appleSDSemiBold(size: 18).font
34+
button.contentHorizontalAlignment = .left
35+
return button
36+
}()
37+
38+
private lazy var seperatorView1: UIView = {
39+
let view = UIView()
40+
view.backgroundColor = CommonAsset.Colors.gray01.color
41+
return view
42+
}()
43+
44+
private lazy var seperatorView2: UIView = {
3145
let view = UIView()
3246
view.backgroundColor = CommonAsset.Colors.gray01.color
3347
return view
3448
}()
3549

3650
override init(frame: CGRect) {
3751
super.init(frame: frame)
38-
setConstraintsLayout()
52+
setStackView()
3953
}
4054

4155
required init(coder: NSCoder) {
4256
fatalError("init(coder:) has not been implemented")
4357
}
4458

4559
private func setConstraintsLayout() {
60+
addArrangedSubviews(firstButton, seperatorView1, secondButton)
61+
NSLayoutConstraint.activate([
62+
seperatorView1.heightAnchor.constraint(equalToConstant: 1)
63+
])
64+
}
65+
66+
private func setStackView() {
4667
self.axis = .vertical
4768
self.distribution = .fill
4869
self.spacing = 24
49-
addArrangedSubviews(firstButton, seperatorView, secondButton)
50-
NSLayoutConstraint.activate([
51-
seperatorView.heightAnchor.constraint(equalToConstant: 1)
52-
])
5370
}
71+
5472
}
5573

5674
extension MyPostBottomSheetView {
5775

5876
func setUpMyPost() {
5977
firstButton.setTitle("게시글 수정", for: .normal)
6078
secondButton.setTitle("게시글 삭제", for: .normal)
79+
setConstraintsLayout()
6180
}
6281

6382
func setUpUserPost() {
6483
firstButton.setTitleColor(CommonAsset.Colors.error.color, for: .normal)
6584
firstButton.setTitle("계정 신고", for: .normal)
6685
secondButton.setTitle("게시글 신고", for: .normal)
86+
thirdButton.setTitle("이 게시글 가리기", for: .normal)
87+
addArrangedSubviews(firstButton, seperatorView1, secondButton, seperatorView2, thirdButton)
88+
NSLayoutConstraint.activate([
89+
seperatorView1.heightAnchor.constraint(equalToConstant: 1),
90+
seperatorView2.heightAnchor.constraint(equalToConstant: 1)
91+
])
92+
}
93+
94+
func setUpUserProfile() {
95+
firstButton.setTitleColor(CommonAsset.Colors.error.color, for: .normal)
96+
secondButton.setTitleColor(CommonAsset.Colors.gray07.color, for: .normal)
97+
firstButton.setTitle("계정 신고", for: .normal)
98+
secondButton.setTitle("이 계정 가리기", for: .normal)
99+
setConstraintsLayout()
67100
}
68101

69102
func setActionFirstButton(_ target: Any?, action: Selector) {
@@ -74,5 +107,8 @@ extension MyPostBottomSheetView {
74107
secondButton.addTarget(target, action: action, for: .touchUpInside)
75108
}
76109

110+
func setActionThirdButton( _ target: Any?, action: Selector) {
111+
thirdButton.addTarget(target, action: action, for: .touchUpInside)
112+
}
113+
77114
}
78-

Fitfty/Projects/Profile/Sources/Report/ViewControllers/ReportViewController.swift

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,17 @@
88

99
import UIKit
1010
import Common
11+
import Combine
1112

1213
final public class ReportViewController: UIViewController {
1314

14-
let coordinator: ReportCoordinatorInterface
15-
let reportPresentType: ReportPresentType
16-
var userToken: String?
17-
var boardToken: String?
15+
private let coordinator: ReportCoordinatorInterface
16+
private let viewModel: ReportViewModel
17+
private var cancellables: Set<AnyCancellable> = .init()
18+
19+
private let reportPresentType: ReportPresentType
20+
private var userToken: String?
21+
private var boardToken: String?
1822

1923
private lazy var userReportButton: UIButton = {
2024
let button = UIButton()
@@ -36,15 +40,18 @@ final public class ReportViewController: UIViewController {
3640
public override func viewDidLoad() {
3741
super.viewDidLoad()
3842
setUp()
43+
bind()
3944
}
4045

4146
public init(
4247
coordinator: ReportCoordinatorInterface,
48+
viewModel: ReportViewModel,
4349
reportPresentType: ReportPresentType,
4450
userToken: String?,
4551
boardToken: String?
4652
) {
4753
self.coordinator = coordinator
54+
self.viewModel = viewModel
4855
self.reportPresentType = reportPresentType
4956
self.userToken = userToken
5057
self.boardToken = boardToken
@@ -60,25 +67,46 @@ final public class ReportViewController: UIViewController {
6067

6168
}
6269

70+
func bind() {
71+
viewModel.state.compactMap { $0 }
72+
.sinkOnMainThread(receiveValue: { [weak self] state in
73+
switch state {
74+
case .errorMessage(let message):
75+
self?.showAlert(message: message)
76+
77+
case .completed(let isCompleted):
78+
guard isCompleted else {
79+
return
80+
}
81+
let message = self?.reportPresentType == .userReport ? "계정" : "게시글"
82+
let alert = UIAlertController(title: "", message: "\(message) 가리기를 완료했어요.", preferredStyle: .alert)
83+
alert.addAction(UIAlertAction(title: "메인 화면으로 돌아가기", style: .default, handler: { _ in
84+
self?.coordinator.popToRoot()
85+
}))
86+
self?.present(alert, animated: true)
87+
88+
}
89+
}).store(in: &cancellables)
90+
}
91+
6392
private func setConstraintsLayout() {
93+
view.addSubviews(myPostBottomSheetView)
94+
NSLayoutConstraint.activate([
95+
myPostBottomSheetView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
96+
myPostBottomSheetView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
97+
myPostBottomSheetView.topAnchor.constraint(equalTo: view.topAnchor, constant: 40)
98+
])
6499
switch reportPresentType {
65100
case .userReport:
66-
view.addSubviews(userReportButton)
67-
NSLayoutConstraint.activate([
68-
userReportButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
69-
userReportButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 44),
70-
userReportButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20)
71-
])
101+
myPostBottomSheetView.setUpUserProfile()
102+
myPostBottomSheetView.setActionFirstButton(self, action: #selector(didTapUserReportButton))
103+
myPostBottomSheetView.setActionSecondButton(self, action: #selector(didTapBlockButton))
104+
72105
case .postUserReport:
73-
view.addSubviews(myPostBottomSheetView)
74-
NSLayoutConstraint.activate([
75-
myPostBottomSheetView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
76-
myPostBottomSheetView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
77-
myPostBottomSheetView.topAnchor.constraint(equalTo: view.topAnchor, constant: 40)
78-
])
79106
myPostBottomSheetView.setUpUserPost()
80107
myPostBottomSheetView.setActionFirstButton(self, action: #selector(didTapUserReportButton))
81108
myPostBottomSheetView.setActionSecondButton(self, action: #selector(didTapPostReportButton))
109+
myPostBottomSheetView.setActionThirdButton(self, action: #selector(didTapBlockButton))
82110
}
83111

84112
}
@@ -91,4 +119,8 @@ final public class ReportViewController: UIViewController {
91119
coordinator.showDetailReport(.postReport, userToken: userToken, boardToken: boardToken)
92120
}
93121

122+
@objc func didTapBlockButton(_ sender: Any?) {
123+
viewModel.input.didTapBlockButton()
124+
}
125+
94126
}
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
//
2+
// ReportViewModel.swift
3+
// Profile
4+
//
5+
// Created by 임영선 on 2023/02/23.
6+
// Copyright © 2023 Fitfty. All rights reserved.
7+
//
8+
9+
import Foundation
10+
import Common
11+
import Combine
12+
import Core
13+
14+
protocol ReportViewModelInput {
15+
16+
var input: ReportViewModelInput { get }
17+
func didTapBlockButton()
18+
}
19+
20+
public final class ReportViewModel {
21+
22+
private var currentState: CurrentValueSubject<ViewModelState?, Never> = .init(nil)
23+
private var cancellables: Set<AnyCancellable> = .init()
24+
private var userManager: UserManager
25+
private var userToken: String?
26+
private var boardToken: String?
27+
private var reportType: ReportType
28+
private var fitftyRepository: FitftyRepository
29+
30+
public init(
31+
userManager: UserManager,
32+
userToken: String?,
33+
boardToken: String?,
34+
reportType: ReportType,
35+
fitftyRepository: FitftyRepository
36+
) {
37+
self.userManager = userManager
38+
self.userToken = userToken
39+
self.boardToken = boardToken
40+
self.reportType = reportType
41+
self.fitftyRepository = fitftyRepository
42+
}
43+
44+
}
45+
46+
extension ReportViewModel: ReportViewModelInput {
47+
48+
var input: ReportViewModelInput { self }
49+
50+
func didTapBlockButton() {
51+
if userManager.getCurrentGuestState() {
52+
currentState.send(.errorMessage("로그인이 필요합니다."))
53+
} else {
54+
report()
55+
}
56+
}
57+
58+
}
59+
60+
extension ReportViewModel: ViewModelType {
61+
62+
public enum ViewModelState {
63+
case errorMessage(String)
64+
case completed(Bool)
65+
}
66+
67+
public var state: AnyPublisher<ViewModelState, Never> { currentState.compactMap { $0 }.eraseToAnyPublisher() }
68+
69+
}
70+
71+
private extension ReportViewModel {
72+
73+
func report() {
74+
Task { [weak self] in
75+
guard let self = self else {
76+
return
77+
}
78+
do {
79+
switch reportType {
80+
case .postReport:
81+
guard let boardToken = boardToken else {
82+
return
83+
}
84+
let request = PostReportRequest(
85+
reportedBoardToken: boardToken,
86+
type: ["INSULT"]
87+
)
88+
let response = try await self.fitftyRepository.report(request)
89+
guard response.result == "SUCCESS" else {
90+
return
91+
}
92+
self.currentState.send(.completed(true))
93+
94+
case .userReport:
95+
guard let userToken = userToken else {
96+
return
97+
}
98+
let request = UserReportRequest(
99+
reportedUserToken: userToken,
100+
type: ["INSULT"]
101+
)
102+
let response = try await self.fitftyRepository.report(request)
103+
guard response.result == "SUCCESS" else {
104+
return
105+
}
106+
self.currentState.send(.completed(true))
107+
}
108+
109+
} catch {
110+
Logger.debug(error: error, message: "신고하기 실패")
111+
self.currentState.send(.errorMessage("신고에 알 수 없는 에러가 발생했습니다."))
112+
}
113+
}
114+
}
115+
116+
}

0 commit comments

Comments
 (0)