From 3a1d4b6e71b445d44d9da295730e041d30011036 Mon Sep 17 00:00:00 2001 From: mint3382 Date: Tue, 25 Feb 2025 19:10:09 +0900 Subject: [PATCH 01/12] =?UTF-8?q?=E2=9C=A8(feat)=20SignOutReasonViewContro?= =?UTF-8?q?ller=20=ED=99=94=EB=A9=B4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- echog/echog.xcodeproj/project.pbxproj | 12 ++ echog/echog/Data/Model/SignOutReason.swift | 35 +++++ .../Cell/SignOutReasonCell.swift | 74 +++++++++ .../MyPage/SignOutReasonViewController.swift | 145 ++++++++++++++++++ 4 files changed, 266 insertions(+) create mode 100644 echog/echog/Data/Model/SignOutReason.swift create mode 100644 echog/echog/Design System/Cell/SignOutReasonCell.swift create mode 100644 echog/echog/Presentation/MyPage/SignOutReasonViewController.swift diff --git a/echog/echog.xcodeproj/project.pbxproj b/echog/echog.xcodeproj/project.pbxproj index 3539c34..865ce68 100644 --- a/echog/echog.xcodeproj/project.pbxproj +++ b/echog/echog.xcodeproj/project.pbxproj @@ -23,6 +23,9 @@ 920470AB2C9D47BC00D547FB /* PopUpProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 920470AA2C9D47BC00D547FB /* PopUpProtocol.swift */; }; 92325B642D661C0300F5CCE9 /* NetworkKit in Frameworks */ = {isa = PBXBuildFile; productRef = 92325B632D661C0300F5CCE9 /* NetworkKit */; }; 92325B662D661C0700F5CCE9 /* NetworkFeatureKit in Frameworks */ = {isa = PBXBuildFile; productRef = 92325B652D661C0700F5CCE9 /* NetworkFeatureKit */; }; + 92325FD32D6CB26B00F5CCE9 /* SignOutReasonViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92325FD22D6CB25500F5CCE9 /* SignOutReasonViewController.swift */; }; + 92325FD52D6DC1FE00F5CCE9 /* SignOutReasonCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92325FD42D6DC1F900F5CCE9 /* SignOutReasonCell.swift */; }; + 92325FD92D6DCE1300F5CCE9 /* SignOutReason.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92325FD82D6DCE0C00F5CCE9 /* SignOutReason.swift */; }; 92365B5F2D06B108001D4A71 /* Pretendard-SemiBold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 9204707E2C9A760300D547FB /* Pretendard-SemiBold.otf */; }; 92365B602D06B121001D4A71 /* Pretendard-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = 920470872C9A7A7300D547FB /* Pretendard-Regular.otf */; }; 92365B612D06B127001D4A71 /* Pretendard-Medium.otf in Resources */ = {isa = PBXBuildFile; fileRef = 9204707F2C9A760F00D547FB /* Pretendard-Medium.otf */; }; @@ -139,6 +142,9 @@ 920470A42C9BBC6B00D547FB /* UIImage+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+.swift"; sourceTree = ""; }; 920470A82C9BC45B00D547FB /* PopUpView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PopUpView.swift; sourceTree = ""; }; 920470AA2C9D47BC00D547FB /* PopUpProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PopUpProtocol.swift; sourceTree = ""; }; + 92325FD22D6CB25500F5CCE9 /* SignOutReasonViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignOutReasonViewController.swift; sourceTree = ""; }; + 92325FD42D6DC1F900F5CCE9 /* SignOutReasonCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignOutReasonCell.swift; sourceTree = ""; }; + 92325FD82D6DCE0C00F5CCE9 /* SignOutReason.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignOutReason.swift; sourceTree = ""; }; 92365B572D05D96D001D4A71 /* InformationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InformationViewController.swift; sourceTree = ""; }; 92365B592D05DEC3001D4A71 /* TextFieldView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldView.swift; sourceTree = ""; }; 92365B5B2D06A066001D4A71 /* UIControl+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIControl+.swift"; sourceTree = ""; }; @@ -397,6 +403,7 @@ 92365BBE2D1BC1F5001D4A71 /* Cell */ = { isa = PBXGroup; children = ( + 92325FD42D6DC1F900F5CCE9 /* SignOutReasonCell.swift */, 92E697342D5CDF150059D3AE /* VoteCell.swift */, 92365BFE2D2EC565001D4A71 /* MyVoteCell.swift */, 92365BC12D1C16A0001D4A71 /* HeaderView.swift */, @@ -408,6 +415,7 @@ 92365BDF2D1D737A001D4A71 /* MyPage */ = { isa = PBXGroup; children = ( + 92325FD22D6CB25500F5CCE9 /* SignOutReasonViewController.swift */, 92365BE02D1D7387001D4A71 /* MyVoteListViewController.swift */, 92365BDB2D1D043A001D4A71 /* MyPageViewController.swift */, ); @@ -424,6 +432,7 @@ 92DD8F4B2CEC9979001197D0 /* Model */ = { isa = PBXGroup; children = ( + 92325FD82D6DCE0C00F5CCE9 /* SignOutReason.swift */, 92E697322D5CDA5E0059D3AE /* VoteDTO.swift */, 92365BDD2D1D72B7001D4A71 /* MyPage.swift */, ); @@ -690,6 +699,7 @@ 92365BC02D1BC201001D4A71 /* DiaryCell.swift in Sources */, 92365B9B2D0833DA001D4A71 /* DiaryHomeViewController.swift in Sources */, 92E697332D5CDA7C0059D3AE /* VoteDTO.swift in Sources */, + 92325FD92D6DCE1300F5CCE9 /* SignOutReason.swift in Sources */, 92DFD3F62D3236C8008CFE95 /* UIView+.swift in Sources */, 92365BC22D1C16A4001D4A71 /* HeaderView.swift in Sources */, 92E697462D5DA8A80059D3AE /* VoteSelectLineView.swift in Sources */, @@ -723,9 +733,11 @@ 92365BFF2D2EC56E001D4A71 /* MyVoteCell.swift in Sources */, 92E6975A2D5E05CE0059D3AE /* PasswordCompleteViewController.swift in Sources */, 92E697542D5DFA650059D3AE /* LogInCoordinator.swift in Sources */, + 92325FD52D6DC1FE00F5CCE9 /* SignOutReasonCell.swift in Sources */, 92E697412D5D9D440059D3AE /* ChipLabel.swift in Sources */, 92DFD4C92D532197008CFE95 /* OnBoardingStore.swift in Sources */, 92656BF32D62C7E600FE4337 /* DiaryReducer.swift in Sources */, + 92325FD32D6CB26B00F5CCE9 /* SignOutReasonViewController.swift in Sources */, 92E6976B2D5F23D20059D3AE /* VoteCreationViewController.swift in Sources */, 920470852C9A76F700D547FB /* UIFontMetrics+.swift in Sources */, 92E697442D5DA38C0059D3AE /* VoteView.swift in Sources */, diff --git a/echog/echog/Data/Model/SignOutReason.swift b/echog/echog/Data/Model/SignOutReason.swift new file mode 100644 index 0000000..f520654 --- /dev/null +++ b/echog/echog/Data/Model/SignOutReason.swift @@ -0,0 +1,35 @@ +// +// SignOutReason.swift +// echog +// +// Created by minsong kim on 2/25/25. +// + +enum SignOutReason: CaseIterable { + case uncomfortableService + case uncomfortableDiary + case contentsNotSatisfying + case moveToAnotherService + case personalReason + case burdenPrice + case etc + + var title: String { + switch self { + case .uncomfortableService: + "서비스 이용이 불편함" + case .uncomfortableDiary: + "일기 작성 기능이 부족하거나 불편함" + case .contentsNotSatisfying: + "콘텐츠(투표, 커뮤니티)에 대한 불만" + case .moveToAnotherService: + "다른 일기/투표 서비스로 이동 예정" + case .personalReason: + "개인적인 이유로 더 이상 이용하지 않음" + case .burdenPrice: + "광고 또는 유료 결제 정책이 부담됨" + case .etc: + "기타 (직접 입력 가능)" + } + } +} diff --git a/echog/echog/Design System/Cell/SignOutReasonCell.swift b/echog/echog/Design System/Cell/SignOutReasonCell.swift new file mode 100644 index 0000000..471a70a --- /dev/null +++ b/echog/echog/Design System/Cell/SignOutReasonCell.swift @@ -0,0 +1,74 @@ +// +// SignOutReasonCell.swift +// echog +// +// Created by minsong kim on 2/25/25. +// + +import UIKit +import SnapKit + +class SignOutReasonCell: UITableViewCell { + static let identifier = "SignOutReasonCell" + + private let titleLabel: UILabel = { + let label = UILabel() + label.font = .regularTitle15 + label.textColor = .slate800 + + return label + }() + + private let checkButton = SelectionButton(isSelected: false) + + let reasonTextView: UITextView = { + let textView = UITextView() + textView.font = .regularTitle15 + textView.layer.borderWidth = 1 + textView.layer.borderColor = UIColor.slate100.cgColor + textView.layer.cornerRadius = 8 + textView.backgroundColor = .slate25 + textView.text = "탈퇴사유를 입력해 주세요." + textView.textColor = .textDisabled + + return textView + }() + + private func configureLabels() { + self.addSubview(titleLabel) + self.addSubview(checkButton) + + checkButton.snp.makeConstraints { make in + make.leading.equalToSuperview().inset(16) + make.top.equalToSuperview().inset(20) + make.width.height.equalTo(16) + } + + titleLabel.snp.makeConstraints { make in + make.leading.equalTo(checkButton.snp.trailing).offset(8) + make.centerY.equalTo(checkButton) + make.height.equalTo(22) + } + } + + private func configureTextView() { + self.addSubview(reasonTextView) + + reasonTextView.snp.makeConstraints { make in + make.top.equalTo(titleLabel.snp.bottom).offset(16) + make.leading.equalTo(titleLabel) + make.trailing.equalToSuperview().inset(16) + make.height.equalTo(100) + } + } + + func configureCells(title: String, isTextView: Bool = false) { + titleLabel.text = title + + configureLabels() + + if isTextView { + configureTextView() + } + } +} diff --git a/echog/echog/Presentation/MyPage/SignOutReasonViewController.swift b/echog/echog/Presentation/MyPage/SignOutReasonViewController.swift new file mode 100644 index 0000000..5b274ba --- /dev/null +++ b/echog/echog/Presentation/MyPage/SignOutReasonViewController.swift @@ -0,0 +1,145 @@ +// +// SignOutReasonViewController.swift +// echog +// +// Created by minsong kim on 2/24/25. +// + +import Combine +import UIKit +import SnapKit + +class SignOutReasonViewController: UIViewController { + private let titleLabel: UILabel = { + let label = UILabel() + label.font = .semiboldLargetitle17 + label.textColor = .black + label.text = "회원탈퇴" + + return label + }() + + private let backButton: UIButton = { + var configuration = UIButton.Configuration.plain() + configuration.image = UIImage(systemName: "arrow.backward") + configuration.baseForegroundColor = .slate800 + + let button = UIButton(configuration: configuration) + + return button + }() + + private let tableView: UITableView = { + let table = UITableView() + table.backgroundColor = .clear + table.separatorStyle = .none + + return table + }() + + private let nextButton = MainButton(title: "다음") + + override func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = .systemBackground + + configureBar() + configureTableView() + configureButton() + } + + private func configureBar() { + view.addSubview(titleLabel) + view.addSubview(backButton) + + backButton.snp.makeConstraints { make in + make.top.equalTo(view.safeAreaLayoutGuide) + make.leading.equalToSuperview().inset(8) + } + + titleLabel.snp.makeConstraints { make in + make.leading.equalTo(backButton.snp.trailing).inset(8) + make.centerY.equalTo(backButton.snp.centerY) + } + } + + private func configureTableView() { + tableView.dataSource = self + tableView.delegate = self + tableView.register(SignOutReasonCell.self, forCellReuseIdentifier: SignOutReasonCell.identifier) + tableView.separatorStyle = .singleLine + tableView.separatorInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) + tableView.separatorColor = .slate100 + + view.addSubview(tableView) + + tableView.snp.makeConstraints { make in + make.top.equalTo(titleLabel.snp.bottom).offset(16) + make.leading.trailing.equalToSuperview() + make.bottom.equalToSuperview() + } + } + + private func configureButton() { + view.addSubview(nextButton) + + nextButton.snp.makeConstraints { make in + make.leading.trailing.equalToSuperview().inset(20) + make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom).offset(-20) + make.height.equalTo(50) + } + } +} + +extension SignOutReasonViewController: UITableViewDelegate, UITableViewDataSource { + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + SignOutReason.allCases.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + guard let cell = tableView.dequeueReusableCell(withIdentifier: SignOutReasonCell.identifier, for: indexPath) as? SignOutReasonCell else { + return UITableViewCell() + } + + if indexPath.item == SignOutReason.allCases.count - 1 { + cell.configureCells(title: SignOutReason.allCases[indexPath.item].title, isTextView: true) + cell.reasonTextView.delegate = self + } else { + cell.configureCells(title: SignOutReason.allCases[indexPath.item].title) + } + + return cell + } + + func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + let line = UIView(frame: CGRect(x: 0, y:0, width: tableView.frame.width, height: 0.5)) + line.backgroundColor = .slate100 + + return line + } + + func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + 0.5 + } + + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + if indexPath.item == SignOutReason.allCases.count - 1 { + 172 + } else { + 56 + } + } +} + +extension SignOutReasonViewController: UITextViewDelegate { + func textViewDidBeginEditing(_ textView: UITextView) { + textView.text = nil + textView.textColor = .slate800 + } +} + +#Preview { + let vc = SignOutReasonViewController() + + return vc +} From 804691a58cccd21a8d61d4d786ae70df37d2890a Mon Sep 17 00:00:00 2001 From: mint3382 Date: Tue, 25 Feb 2025 20:09:47 +0900 Subject: [PATCH 02/12] =?UTF-8?q?=E2=9C=A8(feat)=20SignOutConfirmViewContr?= =?UTF-8?q?oller=20=ED=99=94=EB=A9=B4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- echog/echog.xcodeproj/project.pbxproj | 4 + .../MyPage/SignOutConfirmViewController.swift | 189 ++++++++++++++++++ 2 files changed, 193 insertions(+) create mode 100644 echog/echog/Presentation/MyPage/SignOutConfirmViewController.swift diff --git a/echog/echog.xcodeproj/project.pbxproj b/echog/echog.xcodeproj/project.pbxproj index 865ce68..c3ef9e8 100644 --- a/echog/echog.xcodeproj/project.pbxproj +++ b/echog/echog.xcodeproj/project.pbxproj @@ -25,6 +25,7 @@ 92325B662D661C0700F5CCE9 /* NetworkFeatureKit in Frameworks */ = {isa = PBXBuildFile; productRef = 92325B652D661C0700F5CCE9 /* NetworkFeatureKit */; }; 92325FD32D6CB26B00F5CCE9 /* SignOutReasonViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92325FD22D6CB25500F5CCE9 /* SignOutReasonViewController.swift */; }; 92325FD52D6DC1FE00F5CCE9 /* SignOutReasonCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92325FD42D6DC1F900F5CCE9 /* SignOutReasonCell.swift */; }; + 92325FD72D6DCDEB00F5CCE9 /* SignOutConfirmViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92325FD62D6DCDE100F5CCE9 /* SignOutConfirmViewController.swift */; }; 92325FD92D6DCE1300F5CCE9 /* SignOutReason.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92325FD82D6DCE0C00F5CCE9 /* SignOutReason.swift */; }; 92365B5F2D06B108001D4A71 /* Pretendard-SemiBold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 9204707E2C9A760300D547FB /* Pretendard-SemiBold.otf */; }; 92365B602D06B121001D4A71 /* Pretendard-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = 920470872C9A7A7300D547FB /* Pretendard-Regular.otf */; }; @@ -144,6 +145,7 @@ 920470AA2C9D47BC00D547FB /* PopUpProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PopUpProtocol.swift; sourceTree = ""; }; 92325FD22D6CB25500F5CCE9 /* SignOutReasonViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignOutReasonViewController.swift; sourceTree = ""; }; 92325FD42D6DC1F900F5CCE9 /* SignOutReasonCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignOutReasonCell.swift; sourceTree = ""; }; + 92325FD62D6DCDE100F5CCE9 /* SignOutConfirmViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignOutConfirmViewController.swift; sourceTree = ""; }; 92325FD82D6DCE0C00F5CCE9 /* SignOutReason.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignOutReason.swift; sourceTree = ""; }; 92365B572D05D96D001D4A71 /* InformationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InformationViewController.swift; sourceTree = ""; }; 92365B592D05DEC3001D4A71 /* TextFieldView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldView.swift; sourceTree = ""; }; @@ -416,6 +418,7 @@ isa = PBXGroup; children = ( 92325FD22D6CB25500F5CCE9 /* SignOutReasonViewController.swift */, + 92325FD62D6DCDE100F5CCE9 /* SignOutConfirmViewController.swift */, 92365BE02D1D7387001D4A71 /* MyVoteListViewController.swift */, 92365BDB2D1D043A001D4A71 /* MyPageViewController.swift */, ); @@ -752,6 +755,7 @@ 92DFD4832D450C71008CFE95 /* UILabel+.swift in Sources */, 920470A52C9BBC6B00D547FB /* UIImage+.swift in Sources */, 920470A92C9BC45B00D547FB /* PopUpView.swift in Sources */, + 92325FD72D6DCDEB00F5CCE9 /* SignOutConfirmViewController.swift in Sources */, 92E6976D2D5F5D0C0059D3AE /* SelectionButton.swift in Sources */, 92DFD3FF2D335198008CFE95 /* Coordinator.swift in Sources */, 92656BF52D62C7F100FE4337 /* DiaryStore.swift in Sources */, diff --git a/echog/echog/Presentation/MyPage/SignOutConfirmViewController.swift b/echog/echog/Presentation/MyPage/SignOutConfirmViewController.swift new file mode 100644 index 0000000..3685e5b --- /dev/null +++ b/echog/echog/Presentation/MyPage/SignOutConfirmViewController.swift @@ -0,0 +1,189 @@ +// +// SignOutConfirmViewController.swift +// echog +// +// Created by minsong kim on 2/25/25. +// + +import UIKit +import SnapKit + +class SignOutConfirmViewController: UIViewController { + private let titleLabel: UILabel = { + let label = UILabel() + label.font = .semiboldLargetitle17 + label.textColor = .black + label.text = "회원탈퇴" + + return label + }() + + private let backButton: UIButton = { + var configuration = UIButton.Configuration.plain() + configuration.image = UIImage(systemName: "arrow.backward") + configuration.baseForegroundColor = .slate800 + + let button = UIButton(configuration: configuration) + + return button + }() + + private let separatorLine: UIView = { + let view = UIView() + view.backgroundColor = .slate100 + + return view + }() + + private let separatorSecondLine: UIView = { + let view = UIView() + view.backgroundColor = .slate100 + + return view + }() + + private let guideTitleLabel: UILabel = { + let label = UILabel() + label.font = .semiboldTitle13 + label.text = "탈퇴 안내" + label.textColor = .slate600 + + return label + }() + + private let guideLabel: UILabel = { + let label = UILabel() + label.font = .regularTitle15 + label.textColor = .slate600 + label.numberOfLines = 2 + label.setTextWithLineSpacing("탈퇴 후에는 내 일기를 더 이상 보관하거나 볼 수 없어요. \n회원 탈퇴를 신청하려면 아래 문장을 입력해주세요.", font: .regularTitle15, lineSpacing: 12, alinment: .left, color: .slate600) + + return label + }() + + private let textTitleLabel: UILabel = { + let label = UILabel() + label.font = .semiboldTitle13 + label.text = "문구" + label.textColor = .slate600 + + return label + }() + + private let confirmTextLabel: UILabel = { + let label = UILabel() + label.font = .regularTitle15 + label.textColor = .slate600 + label.numberOfLines = 2 + label.setTextWithLineSpacing("탈퇴를 신청하며 더 이상 내 일기를 작성하거나\n투표에 참여할 수 없음을 확인했습니다.", font: .mediumTitle15, lineSpacing: 12, alinment: .left, color: .countBlue) + + return label + }() + + private let signOutTextView: UITextView = { + let textView = UITextView() + textView.font = .regularTitle15 + textView.layer.borderWidth = 1 + textView.layer.borderColor = UIColor.slate100.cgColor + textView.layer.cornerRadius = 8 + textView.text = "탈퇴를 신청하며 더 이상 내 일기를 작성하거나 투표에 참여할 수 없음을 확인했습니다." + textView.textColor = .textDisabled + + return textView + }() + + private let signOutButton = MainButton(title: "탈퇴하기") + + override func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = .systemBackground + + configureBar() + configureGuideLabel() + configureConfirmLabel() + configureButton() + } + + private func configureBar() { + view.addSubview(titleLabel) + view.addSubview(backButton) + + backButton.snp.makeConstraints { make in + make.top.equalTo(view.safeAreaLayoutGuide) + make.leading.equalToSuperview().inset(8) + } + + titleLabel.snp.makeConstraints { make in + make.leading.equalTo(backButton.snp.trailing).inset(8) + make.centerY.equalTo(backButton.snp.centerY) + } + } + + private func configureGuideLabel() { + view.addSubview(separatorLine) + view.addSubview(guideTitleLabel) + view.addSubview(guideLabel) + + separatorLine.snp.makeConstraints { make in + make.leading.trailing.equalToSuperview() + make.height.equalTo(0.5) + make.top.equalTo(titleLabel.snp.bottom).offset(16) + } + + guideTitleLabel.snp.makeConstraints { make in + make.top.equalTo(separatorLine.snp.bottom).offset(16) + make.leading.equalToSuperview().inset(20) + } + + guideLabel.snp.makeConstraints { make in + make.top.equalTo(guideTitleLabel.snp.bottom).offset(16) + make.leading.equalTo(guideTitleLabel) + } + } + + private func configureConfirmLabel() { + view.addSubview(separatorSecondLine) + view.addSubview(textTitleLabel) + view.addSubview(confirmTextLabel) + view.addSubview(signOutTextView) + + separatorSecondLine.snp.makeConstraints { make in + make.leading.trailing.equalToSuperview() + make.height.equalTo(0.5) + make.top.equalTo(guideLabel.snp.bottom).offset(16) + } + + textTitleLabel.snp.makeConstraints { make in + make.top.equalTo(separatorSecondLine.snp.bottom).offset(16) + make.leading.equalToSuperview().inset(20) + } + + confirmTextLabel.snp.makeConstraints { make in + make.top.equalTo(textTitleLabel.snp.bottom).offset(16) + make.leading.equalTo(guideTitleLabel) + } + + signOutTextView.snp.makeConstraints { make in + make.top.equalTo(confirmTextLabel.snp.bottom).offset(16) + make.leading.equalTo(confirmTextLabel) + make.trailing.equalToSuperview().inset(20) + make.height.equalTo(60) + } + } + + private func configureButton() { + view.addSubview(signOutButton) + + signOutButton.snp.makeConstraints { make in + make.leading.trailing.equalToSuperview().inset(20) + make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom).offset(-20) + make.height.equalTo(50) + } + } +} + +#Preview { + let vc = SignOutConfirmViewController() + + return vc +} From aa64e4e217be5ea8254520c16f45fa9406b0e5f6 Mon Sep 17 00:00:00 2001 From: mint3382 Date: Fri, 28 Feb 2025 14:27:52 +0900 Subject: [PATCH 03/12] =?UTF-8?q?=E2=9C=A8(feat)=20UserDeleteNetwork=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - UserDeleteNetworkBuilder - signOut() --- .../Builder/UserDeleteNetworkBuilder.swift | 22 +++++++++++++++++++ .../NetworkFeatureKit/User/UserNetwork.swift | 5 +++++ 2 files changed, 27 insertions(+) create mode 100644 echog/NetworkFeatureKit/Sources/NetworkFeatureKit/User/Builder/UserDeleteNetworkBuilder.swift diff --git a/echog/NetworkFeatureKit/Sources/NetworkFeatureKit/User/Builder/UserDeleteNetworkBuilder.swift b/echog/NetworkFeatureKit/Sources/NetworkFeatureKit/User/Builder/UserDeleteNetworkBuilder.swift new file mode 100644 index 0000000..6366141 --- /dev/null +++ b/echog/NetworkFeatureKit/Sources/NetworkFeatureKit/User/Builder/UserDeleteNetworkBuilder.swift @@ -0,0 +1,22 @@ +// +// UserDeleteNetworkBuilder.swift +// NetworkFeatureKit +// +// Created by minsong kim on 2/27/25. +// + +import Foundation +import NetworkKit + +struct UserDeleteNetworkBuilder: NetworkBuilderProtocol { + typealias Response = DefalutDTO + + var baseURL: BaseURLType { .api } + var path: String { "/api/users/delete" } + var queries: [URLQueryItem]? + var method: HTTPMethod { .post } + var parameters: [String : Any] = [:] + var deserializer: any NetworkDeserializable = JSONNetworkDeserializer(decoder: JSONDecoder()) + + var useAuthorization: Bool = true +} diff --git a/echog/NetworkFeatureKit/Sources/NetworkFeatureKit/User/UserNetwork.swift b/echog/NetworkFeatureKit/Sources/NetworkFeatureKit/User/UserNetwork.swift index 0a29d49..a0111c7 100644 --- a/echog/NetworkFeatureKit/Sources/NetworkFeatureKit/User/UserNetwork.swift +++ b/echog/NetworkFeatureKit/Sources/NetworkFeatureKit/User/UserNetwork.swift @@ -38,4 +38,9 @@ public final class UserNetwork: @unchecked Sendable { let builder = UserLogInNetworkBuilder(parameters: ["loginId": email, "password": password]) return try await networkManager.fetchData(builder) } + + public func signOut() async throws -> DefalutDTO { + let builder = UserDeleteNetworkBuilder() + return try await networkManager.fetchData(builder) + } } From de3b6c7cd693d664899a2e93b18bb42c86ecc547 Mon Sep 17 00:00:00 2001 From: mint3382 Date: Fri, 28 Feb 2025 14:28:09 +0900 Subject: [PATCH 04/12] =?UTF-8?q?=E2=9C=A8(feat)=20LaunchScreen=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../echog/Base.lproj/LaunchScreen.storyboard | 35 ++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/echog/echog/Base.lproj/LaunchScreen.storyboard b/echog/echog/Base.lproj/LaunchScreen.storyboard index 865e932..7d90bb1 100644 --- a/echog/echog/Base.lproj/LaunchScreen.storyboard +++ b/echog/echog/Base.lproj/LaunchScreen.storyboard @@ -1,8 +1,10 @@ - - + + + - + + @@ -11,10 +13,26 @@ - + - + + + + + + + + + + + + + + + + + @@ -22,4 +40,11 @@ + + + + + + + From 82b786c93cc38c46fc3e3c015077b5cf55131a9f Mon Sep 17 00:00:00 2001 From: mint3382 Date: Fri, 28 Feb 2025 14:28:46 +0900 Subject: [PATCH 05/12] =?UTF-8?q?=E2=9C=A8(feat)=20MyPage=20=EA=B0=9C?= =?UTF-8?q?=EC=9D=B8=EC=A0=95=EB=B3=B4=20=EC=B2=98=EB=A6=AC=EB=B0=A9?= =?UTF-8?q?=EC=B9=A8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- echog/echog/Data/Model/MyPage.swift | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/echog/echog/Data/Model/MyPage.swift b/echog/echog/Data/Model/MyPage.swift index 4318fd0..1bbc56a 100644 --- a/echog/echog/Data/Model/MyPage.swift +++ b/echog/echog/Data/Model/MyPage.swift @@ -21,14 +21,17 @@ enum MyPageList: CaseIterable { } } -enum MyPageSignOut: CaseIterable { - case logOut +enum MyPageSignOut: Int, CaseIterable { + case logOut = 0 + case checkTerms case signOut var title: String { switch self { case .logOut: "로그아웃" + case .checkTerms: + "개인정보 처리방침" case .signOut: "회원탈퇴" } @@ -37,9 +40,11 @@ enum MyPageSignOut: CaseIterable { var color: UIColor { switch self { case .logOut: - .black + .slate800 + case .checkTerms: + .slate800 case .signOut: - .red + .red500 } } } From f341ff54387a4d04b3bb83131eaa4c3e38e6986f Mon Sep 17 00:00:00 2001 From: mint3382 Date: Fri, 28 Feb 2025 14:29:34 +0900 Subject: [PATCH 06/12] =?UTF-8?q?=E2=9C=A8(feat)=20MyPageCoordinator=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Coordinator/AppCoordinator.swift | 6 +- .../Coordinator/MyPageCoordinator.swift | 67 +++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 echog/echog/Presentation/Coordinator/MyPageCoordinator.swift diff --git a/echog/echog/Presentation/Coordinator/AppCoordinator.swift b/echog/echog/Presentation/Coordinator/AppCoordinator.swift index 3ad1d1f..5b5e9a1 100644 --- a/echog/echog/Presentation/Coordinator/AppCoordinator.swift +++ b/echog/echog/Presentation/Coordinator/AppCoordinator.swift @@ -80,6 +80,10 @@ class AppCoordinator: Coordinator { } func startMyPageCoordinator() { - + let myPageCoordinator = MyPageCoordinator(navigationController: navigationController) + children.removeAll() + myPageCoordinator.parentCoordinator = self + children.append(myPageCoordinator) + myPageCoordinator.start() } } diff --git a/echog/echog/Presentation/Coordinator/MyPageCoordinator.swift b/echog/echog/Presentation/Coordinator/MyPageCoordinator.swift new file mode 100644 index 0000000..6d41d8e --- /dev/null +++ b/echog/echog/Presentation/Coordinator/MyPageCoordinator.swift @@ -0,0 +1,67 @@ +// +// MyPageCoordinator.swift +// echog +// +// Created by minsong kim on 2/20/25. +// + +import UIKit + +protocol MyPageNavigation: AnyObject { + func goToDiaryViewController() +} + +class MyPageCoordinator: Coordinator { + var parentCoordinator: Coordinator? + var children: [Coordinator] = [] + var navigationController: UINavigationController + private var reducer = MyPageReducer() + private lazy var store = MyPageStore(reducer: reducer) + + init(navigationController: UINavigationController) { + self.navigationController = navigationController + reducer.delegate = self + } + + func start() { + pushMyPageViewController() + } +} + +extension MyPageCoordinator: MyPageNavigation { + func pushMyPageViewController() { + let myPageViewController = MyPageViewController(store: store) + navigationController.pushViewController(myPageViewController, animated: false) + } + + func pushSignOutReasonViewController() { + let signOutResonViewController = SignOutReasonViewController(store: store) + navigationController.pushViewController(signOutResonViewController, animated: true) + } + + func pushSignOutConfirmViewController() { + let signOutConfirmViewController = SignOutConfirmViewController(store: store) + navigationController.pushViewController(signOutConfirmViewController, animated: true) + } + + func pushTermsViewController() { + let termsViewController = TermsCheckViewController(store: store) + navigationController.pushViewController(termsViewController, animated: false) + } + + func goToDiaryViewController() { + let appCoordinator = parentCoordinator as? AppCoordinator + appCoordinator?.startDiaryCoordinator() + appCoordinator?.childDidFinish(self) + } + + func goToLogInViewController() { + let appCoordinator = parentCoordinator as? AppCoordinator + appCoordinator?.startLoginCoordinator() + appCoordinator?.childDidFinish(self) + } + + func popViewController() { + navigationController.popViewController(animated: false) + } +} From d1fc08526b475f01a1a59b3c9f3b661b6870c263 Mon Sep 17 00:00:00 2001 From: mint3382 Date: Fri, 28 Feb 2025 14:30:22 +0900 Subject: [PATCH 07/12] =?UTF-8?q?=E2=9C=A8(feat)=20MyPageReducer,=20Store?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- echog/echog.xcodeproj/project.pbxproj | 12 +++ .../Presentation/MyPage/MyPageReducer.swift | 83 +++++++++++++++++++ .../Presentation/MyPage/MyPageStore.swift | 35 ++++++++ 3 files changed, 130 insertions(+) create mode 100644 echog/echog/Presentation/MyPage/MyPageReducer.swift create mode 100644 echog/echog/Presentation/MyPage/MyPageStore.swift diff --git a/echog/echog.xcodeproj/project.pbxproj b/echog/echog.xcodeproj/project.pbxproj index c3ef9e8..d167701 100644 --- a/echog/echog.xcodeproj/project.pbxproj +++ b/echog/echog.xcodeproj/project.pbxproj @@ -23,6 +23,9 @@ 920470AB2C9D47BC00D547FB /* PopUpProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 920470AA2C9D47BC00D547FB /* PopUpProtocol.swift */; }; 92325B642D661C0300F5CCE9 /* NetworkKit in Frameworks */ = {isa = PBXBuildFile; productRef = 92325B632D661C0300F5CCE9 /* NetworkKit */; }; 92325B662D661C0700F5CCE9 /* NetworkFeatureKit in Frameworks */ = {isa = PBXBuildFile; productRef = 92325B652D661C0700F5CCE9 /* NetworkFeatureKit */; }; + 92325BA02D6741B000F5CCE9 /* MyPageReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92325B9F2D6741A800F5CCE9 /* MyPageReducer.swift */; }; + 92325BA22D6741B900F5CCE9 /* MyPageStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92325BA12D6741B500F5CCE9 /* MyPageStore.swift */; }; + 92325BA42D67425700F5CCE9 /* MyPageCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92325BA32D67425100F5CCE9 /* MyPageCoordinator.swift */; }; 92325FD32D6CB26B00F5CCE9 /* SignOutReasonViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92325FD22D6CB25500F5CCE9 /* SignOutReasonViewController.swift */; }; 92325FD52D6DC1FE00F5CCE9 /* SignOutReasonCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92325FD42D6DC1F900F5CCE9 /* SignOutReasonCell.swift */; }; 92325FD72D6DCDEB00F5CCE9 /* SignOutConfirmViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92325FD62D6DCDE100F5CCE9 /* SignOutConfirmViewController.swift */; }; @@ -143,6 +146,9 @@ 920470A42C9BBC6B00D547FB /* UIImage+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+.swift"; sourceTree = ""; }; 920470A82C9BC45B00D547FB /* PopUpView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PopUpView.swift; sourceTree = ""; }; 920470AA2C9D47BC00D547FB /* PopUpProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PopUpProtocol.swift; sourceTree = ""; }; + 92325B9F2D6741A800F5CCE9 /* MyPageReducer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageReducer.swift; sourceTree = ""; }; + 92325BA12D6741B500F5CCE9 /* MyPageStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageStore.swift; sourceTree = ""; }; + 92325BA32D67425100F5CCE9 /* MyPageCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageCoordinator.swift; sourceTree = ""; }; 92325FD22D6CB25500F5CCE9 /* SignOutReasonViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignOutReasonViewController.swift; sourceTree = ""; }; 92325FD42D6DC1F900F5CCE9 /* SignOutReasonCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignOutReasonCell.swift; sourceTree = ""; }; 92325FD62D6DCDE100F5CCE9 /* SignOutConfirmViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignOutConfirmViewController.swift; sourceTree = ""; }; @@ -417,6 +423,8 @@ 92365BDF2D1D737A001D4A71 /* MyPage */ = { isa = PBXGroup; children = ( + 92325BA12D6741B500F5CCE9 /* MyPageStore.swift */, + 92325B9F2D6741A800F5CCE9 /* MyPageReducer.swift */, 92325FD22D6CB25500F5CCE9 /* SignOutReasonViewController.swift */, 92325FD62D6DCDE100F5CCE9 /* SignOutConfirmViewController.swift */, 92365BE02D1D7387001D4A71 /* MyVoteListViewController.swift */, @@ -489,6 +497,7 @@ 92DFD4022D335448008CFE95 /* Coordinator */ = { isa = PBXGroup; children = ( + 92325BA32D67425100F5CCE9 /* MyPageCoordinator.swift */, 92656BF82D62D10500FE4337 /* PasswordCoordinator.swift */, 92E697532D5DFA5F0059D3AE /* LogInCoordinator.swift */, 92DFD4652D4350D4008CFE95 /* DiaryHomeCoordinator.swift */, @@ -702,6 +711,7 @@ 92365BC02D1BC201001D4A71 /* DiaryCell.swift in Sources */, 92365B9B2D0833DA001D4A71 /* DiaryHomeViewController.swift in Sources */, 92E697332D5CDA7C0059D3AE /* VoteDTO.swift in Sources */, + 92325BA22D6741B900F5CCE9 /* MyPageStore.swift in Sources */, 92325FD92D6DCE1300F5CCE9 /* SignOutReason.swift in Sources */, 92DFD3F62D3236C8008CFE95 /* UIView+.swift in Sources */, 92365BC22D1C16A4001D4A71 /* HeaderView.swift in Sources */, @@ -735,6 +745,7 @@ 92365BE12D1D7390001D4A71 /* MyVoteListViewController.swift in Sources */, 92365BFF2D2EC56E001D4A71 /* MyVoteCell.swift in Sources */, 92E6975A2D5E05CE0059D3AE /* PasswordCompleteViewController.swift in Sources */, + 92325BA42D67425700F5CCE9 /* MyPageCoordinator.swift in Sources */, 92E697542D5DFA650059D3AE /* LogInCoordinator.swift in Sources */, 92325FD52D6DC1FE00F5CCE9 /* SignOutReasonCell.swift in Sources */, 92E697412D5D9D440059D3AE /* ChipLabel.swift in Sources */, @@ -750,6 +761,7 @@ 92656BF92D62D10C00FE4337 /* PasswordCoordinator.swift in Sources */, 92DFD4662D4350DC008CFE95 /* DiaryHomeCoordinator.swift in Sources */, 92DFD3F82D327653008CFE95 /* InformationLoadingViewController.swift in Sources */, + 92325BA02D6741B000F5CCE9 /* MyPageReducer.swift in Sources */, 92DFD4BD2D52E243008CFE95 /* InformationStore.swift in Sources */, 92DFD3F42D323391008CFE95 /* UIGestureRecognizer+.swift in Sources */, 92DFD4832D450C71008CFE95 /* UILabel+.swift in Sources */, diff --git a/echog/echog/Presentation/MyPage/MyPageReducer.swift b/echog/echog/Presentation/MyPage/MyPageReducer.swift new file mode 100644 index 0000000..f7eeafa --- /dev/null +++ b/echog/echog/Presentation/MyPage/MyPageReducer.swift @@ -0,0 +1,83 @@ +// +// MyPageReducer.swift +// echog +// +// Created by minsong kim on 2/20/25. +// + +import Combine +import Foundation +import NetworkFeatureKit +import KeyChainModule + +struct MyPageReducer: ReducerProtocol { + + enum Intent { + case selectMyPage(IndexPath) + case goToNextSignOutPage + case popPage + case signOut + } + + enum Mutation { + case signOutFailure + } + + struct State { + var isSignOutSuccess: TryState = .notYet + } + + var initialState = State() + + weak var delegate: MyPageCoordinator? + + func mutate(action: Intent) -> AnyPublisher? { + switch action { + case .selectMyPage(let indexPath): + let page = MyPageSignOut(rawValue: indexPath.row) + + if page == .logOut { + KeyChain.delete(key: .accessToken) + KeyChain.delete(key: .refreshToken) + delegate?.goToLogInViewController() + } else if page == .checkTerms { + delegate?.pushTermsViewController() + } else if page == .signOut { + delegate?.pushSignOutReasonViewController() + } + + return nil + case .goToNextSignOutPage: + delegate?.pushSignOutConfirmViewController() + return nil + case .popPage: + delegate?.popViewController() + return nil + case .signOut: + return Future { promise in + Task { @MainActor in + do { + _ = try await UserNetwork.shared.signOut() + KeyChain.delete(key: .accessToken) + KeyChain.delete(key: .refreshToken) + delegate?.goToLogInViewController() + } catch { + promise(.success(.signOutFailure)) + } + } + } + .eraseToAnyPublisher() + } + } + + func reduce(state: State, mutation: Mutation) -> State { + var newState = state + + switch mutation { + case .signOutFailure: + newState.isSignOutSuccess = .failure + } + + return newState + } +} diff --git a/echog/echog/Presentation/MyPage/MyPageStore.swift b/echog/echog/Presentation/MyPage/MyPageStore.swift new file mode 100644 index 0000000..4a3f5a5 --- /dev/null +++ b/echog/echog/Presentation/MyPage/MyPageStore.swift @@ -0,0 +1,35 @@ +// +// MyPageStore.swift +// echog +// +// Created by minsong kim on 2/20/25. +// + +import Combine +import Foundation + +final class MyPageStore: StoreProtocol { + typealias Reducer = MyPageReducer + + var cancellables = Set() + @Published var state: MyPageReducer.State + var reducer: MyPageReducer + + init(reducer: MyPageReducer) { + self.reducer = reducer + self.state = reducer.initialState + } + + func dispatch(_ intent: MyPageReducer.Intent) { + let mutationPublisher = reducer.mutate(action: intent) + + mutationPublisher? + .sink { [weak self] mutation in + guard let self else { return } + + let newState = self.reducer.reduce(state: self.state, mutation: mutation) + self.state = newState + } + .store(in: &cancellables) + } +} From 7068e64929334620a997d9a19773b0b24e513d00 Mon Sep 17 00:00:00 2001 From: mint3382 Date: Fri, 28 Feb 2025 14:30:56 +0900 Subject: [PATCH 08/12] =?UTF-8?q?=E2=9C=A8(feat)=20TermsCheckViewControlle?= =?UTF-8?q?r=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- echog/echog.xcodeproj/project.pbxproj | 4 + .../MyPage/TermsCheckViewController.swift | 111 ++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 echog/echog/Presentation/MyPage/TermsCheckViewController.swift diff --git a/echog/echog.xcodeproj/project.pbxproj b/echog/echog.xcodeproj/project.pbxproj index d167701..8bb1099 100644 --- a/echog/echog.xcodeproj/project.pbxproj +++ b/echog/echog.xcodeproj/project.pbxproj @@ -30,6 +30,7 @@ 92325FD52D6DC1FE00F5CCE9 /* SignOutReasonCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92325FD42D6DC1F900F5CCE9 /* SignOutReasonCell.swift */; }; 92325FD72D6DCDEB00F5CCE9 /* SignOutConfirmViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92325FD62D6DCDE100F5CCE9 /* SignOutConfirmViewController.swift */; }; 92325FD92D6DCE1300F5CCE9 /* SignOutReason.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92325FD82D6DCE0C00F5CCE9 /* SignOutReason.swift */; }; + 923260012D6EEA4C00F5CCE9 /* TermsCheckViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 923260002D6EEA3900F5CCE9 /* TermsCheckViewController.swift */; }; 92365B5F2D06B108001D4A71 /* Pretendard-SemiBold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 9204707E2C9A760300D547FB /* Pretendard-SemiBold.otf */; }; 92365B602D06B121001D4A71 /* Pretendard-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = 920470872C9A7A7300D547FB /* Pretendard-Regular.otf */; }; 92365B612D06B127001D4A71 /* Pretendard-Medium.otf in Resources */ = {isa = PBXBuildFile; fileRef = 9204707F2C9A760F00D547FB /* Pretendard-Medium.otf */; }; @@ -153,6 +154,7 @@ 92325FD42D6DC1F900F5CCE9 /* SignOutReasonCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignOutReasonCell.swift; sourceTree = ""; }; 92325FD62D6DCDE100F5CCE9 /* SignOutConfirmViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignOutConfirmViewController.swift; sourceTree = ""; }; 92325FD82D6DCE0C00F5CCE9 /* SignOutReason.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignOutReason.swift; sourceTree = ""; }; + 923260002D6EEA3900F5CCE9 /* TermsCheckViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TermsCheckViewController.swift; sourceTree = ""; }; 92365B572D05D96D001D4A71 /* InformationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InformationViewController.swift; sourceTree = ""; }; 92365B592D05DEC3001D4A71 /* TextFieldView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldView.swift; sourceTree = ""; }; 92365B5B2D06A066001D4A71 /* UIControl+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIControl+.swift"; sourceTree = ""; }; @@ -428,6 +430,7 @@ 92325FD22D6CB25500F5CCE9 /* SignOutReasonViewController.swift */, 92325FD62D6DCDE100F5CCE9 /* SignOutConfirmViewController.swift */, 92365BE02D1D7387001D4A71 /* MyVoteListViewController.swift */, + 923260002D6EEA3900F5CCE9 /* TermsCheckViewController.swift */, 92365BDB2D1D043A001D4A71 /* MyPageViewController.swift */, ); path = MyPage; @@ -715,6 +718,7 @@ 92325FD92D6DCE1300F5CCE9 /* SignOutReason.swift in Sources */, 92DFD3F62D3236C8008CFE95 /* UIView+.swift in Sources */, 92365BC22D1C16A4001D4A71 /* HeaderView.swift in Sources */, + 923260012D6EEA4C00F5CCE9 /* TermsCheckViewController.swift in Sources */, 92E697462D5DA8A80059D3AE /* VoteSelectLineView.swift in Sources */, 92E697352D5CDF180059D3AE /* VoteCell.swift in Sources */, 92DFD4C72D531D7C008CFE95 /* OnBoardingReducer.swift in Sources */, diff --git a/echog/echog/Presentation/MyPage/TermsCheckViewController.swift b/echog/echog/Presentation/MyPage/TermsCheckViewController.swift new file mode 100644 index 0000000..ba98306 --- /dev/null +++ b/echog/echog/Presentation/MyPage/TermsCheckViewController.swift @@ -0,0 +1,111 @@ +// +// TermsCheckViewController.swift +// echog +// +// Created by minsong kim on 2/26/25. +// + +import Combine +import UIKit +import WebKit + +class TermsCheckViewController: UIViewController { + var store: MyPageStore + private var cancellables = Set() + + private let titleLabel: UILabel = { + let label = UILabel() + label.font = .semiboldLargetitle17 + label.textColor = .black + label.text = "개인정보 처리방침" + + return label + }() + + private let backButton: UIButton = { + var configuration = UIButton.Configuration.plain() + configuration.image = UIImage(systemName: "arrow.backward") + configuration.baseForegroundColor = .slate800 + + let button = UIButton(configuration: configuration) + + return button + }() + + private let webView: WKWebView = { + let configuration = WKWebViewConfiguration() + let view = WKWebView(frame: .zero, configuration: configuration) + view.translatesAutoresizingMaskIntoConstraints = false + + return view + }() + + required init(store: MyPageStore) { + self.store = store + + super.init(nibName: nil, bundle: nil) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + + configureBar() + configureView() + loadWebView() + + bind() + } + + private func bind() { + backButton.publisher(for: .touchUpInside) + .sink { [weak self] in + self?.store.dispatch(.popPage) + } + .store(in: &cancellables) + } + + private func configureBar() { + view.addSubview(titleLabel) + view.addSubview(backButton) + + backButton.snp.makeConstraints { make in + make.top.equalTo(view.safeAreaLayoutGuide) + make.leading.equalToSuperview().inset(8) + } + + titleLabel.snp.makeConstraints { make in + make.leading.equalTo(backButton.snp.trailing).inset(8) + make.centerY.equalTo(backButton.snp.centerY) + } + } + + private func configureView() { + view.addSubview(webView) + + webView.snp.makeConstraints { make in + make.top.equalTo(titleLabel.snp.bottom).offset(8) + make.leading.trailing.bottom.equalToSuperview() + } + } + + private func loadWebView() { + //웹 링크 띄우기 + let link = "https://marchens.notion.site/echog-terms?pvs=4" + guard let url = URL(string: link) else { + return + } + let request = URLRequest(url: url) + + webView.load(request) + } +} + +//#Preview { +// let vc = TermsCheckViewController() +// +// return vc +//} From a61aa76c99937f65e455c1b7b2b5a4e577113b1d Mon Sep 17 00:00:00 2001 From: mint3382 Date: Fri, 28 Feb 2025 14:31:37 +0900 Subject: [PATCH 09/12] =?UTF-8?q?=F0=9F=9B=A0=EF=B8=8F(refactor)=20OnBoard?= =?UTF-8?q?ing=20=EC=88=9C=EC=84=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/Information/InformationViewController.swift | 2 +- echog/echog/Presentation/OnBoarding/OnBoardingReducer.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/echog/echog/Presentation/Information/InformationViewController.swift b/echog/echog/Presentation/Information/InformationViewController.swift index 6f9ee5f..6d36863 100644 --- a/echog/echog/Presentation/Information/InformationViewController.swift +++ b/echog/echog/Presentation/Information/InformationViewController.swift @@ -258,7 +258,7 @@ class InformationViewController: UIViewController, View, ToastProtocol, BottomSh nextButton.snp.makeConstraints { make in make.leading.trailing.equalToSuperview().inset(20) - make.bottom.equalTo(view.safeAreaLayoutGuide.snp.top).offset(-20) + make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom).offset(-20) make.height.equalTo(50) } } diff --git a/echog/echog/Presentation/OnBoarding/OnBoardingReducer.swift b/echog/echog/Presentation/OnBoarding/OnBoardingReducer.swift index 5a53f2b..11736cb 100644 --- a/echog/echog/Presentation/OnBoarding/OnBoardingReducer.swift +++ b/echog/echog/Presentation/OnBoarding/OnBoardingReducer.swift @@ -29,7 +29,7 @@ struct OnBoardingReducer: ReducerProtocol { weak var delegate: OnBoardingCoordinator? - let initialState: State = State(page: 0, image: UIImage(resource: .logo), title: "", isStartButton: false) + let initialState: State = State(page: 1, image: UIImage(resource: .diary), title: "나의 일기를 작성하고", isStartButton: false) func mutate(action: Intent) -> AnyPublisher? { switch action { From fefef777ef82baef17f93a63b099c62fe83c222d Mon Sep 17 00:00:00 2001 From: mint3382 Date: Fri, 28 Feb 2025 14:32:20 +0900 Subject: [PATCH 10/12] =?UTF-8?q?=F0=9F=9B=A0=EF=B8=8F(refactor)=20MyPage?= =?UTF-8?q?=20=ED=99=94=EB=A9=B4=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Cell/SignOutReasonCell.swift | 4 ++ .../MyPage/MyPageViewController.swift | 46 +++++++++---- .../MyPage/SignOutConfirmViewController.swift | 66 +++++++++++++++++-- .../MyPage/SignOutReasonViewController.swift | 40 ++++++++++- 4 files changed, 136 insertions(+), 20 deletions(-) diff --git a/echog/echog/Design System/Cell/SignOutReasonCell.swift b/echog/echog/Design System/Cell/SignOutReasonCell.swift index 471a70a..3e1db91 100644 --- a/echog/echog/Design System/Cell/SignOutReasonCell.swift +++ b/echog/echog/Design System/Cell/SignOutReasonCell.swift @@ -71,4 +71,8 @@ class SignOutReasonCell: UITableViewCell { configureTextView() } } + + func selectedCell() { + checkButton.isSelected.toggle() + } } diff --git a/echog/echog/Presentation/MyPage/MyPageViewController.swift b/echog/echog/Presentation/MyPage/MyPageViewController.swift index e942785..3d1a438 100644 --- a/echog/echog/Presentation/MyPage/MyPageViewController.swift +++ b/echog/echog/Presentation/MyPage/MyPageViewController.swift @@ -5,10 +5,14 @@ // Created by minsong kim on 12/26/24. // +import Combine import UIKit import SnapKit -class MyPageViewController: UIViewController { +class MyPageViewController: UIViewController, View { + var store: MyPageStore + private var cancellables = Set() + private let titleLabel: UILabel = { let label = UILabel() label.font = .semiboldHeadline24 @@ -34,6 +38,16 @@ class MyPageViewController: UIViewController { return table }() + required init(store: MyPageStore) { + self.store = store + + super.init(nibName: nil, bundle: nil) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .systemBackground @@ -76,22 +90,22 @@ class MyPageViewController: UIViewController { extension MyPageViewController: UITableViewDelegate, UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - 2 + 3 } - func numberOfSections(in tableView: UITableView) -> Int { - 2 - } +// func numberOfSections(in tableView: UITableView) -> Int { +// 2 +// } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = UITableViewCell(style: .default, reuseIdentifier: "MyPageListCell") var content = cell.defaultContentConfiguration() - if indexPath.section == 0 { - content.text = MyPageList.allCases[indexPath.item].title - } else { +// if indexPath.section == 0 { +// content.text = MyPageList.allCases[indexPath.item].title +// } else { content.text = MyPageSignOut.allCases[indexPath.item].title content.textProperties.color = MyPageSignOut.allCases[indexPath.item].color - } +// } content.textProperties.font = .mediumTitle15 cell.contentConfiguration = content @@ -113,10 +127,14 @@ extension MyPageViewController: UITableViewDelegate, UITableViewDataSource { func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 60 } + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + store.dispatch(.selectMyPage(indexPath)) + } } -//#Preview { -// let vc = MyPageViewController() -// -// return vc -//} +#Preview { + let vc = MyPageViewController(store: MyPageStore(reducer: MyPageReducer())) + + return vc +} diff --git a/echog/echog/Presentation/MyPage/SignOutConfirmViewController.swift b/echog/echog/Presentation/MyPage/SignOutConfirmViewController.swift index 3685e5b..955614d 100644 --- a/echog/echog/Presentation/MyPage/SignOutConfirmViewController.swift +++ b/echog/echog/Presentation/MyPage/SignOutConfirmViewController.swift @@ -5,10 +5,16 @@ // Created by minsong kim on 2/25/25. // +import Combine import UIKit import SnapKit -class SignOutConfirmViewController: UIViewController { +class SignOutConfirmViewController: UIViewController, ToastProtocol { + var window: UIWindow? = (UIApplication.shared.connectedScenes.first as? UIWindowScene)?.windows.first + + var store: MyPageStore + private var cancellables = Set() + private let titleLabel: UILabel = { let label = UILabel() label.font = .semiboldLargetitle17 @@ -94,6 +100,16 @@ class SignOutConfirmViewController: UIViewController { private let signOutButton = MainButton(title: "탈퇴하기") + required init(store: MyPageStore) { + self.store = store + + super.init(nibName: nil, bundle: nil) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .systemBackground @@ -102,6 +118,37 @@ class SignOutConfirmViewController: UIViewController { configureGuideLabel() configureConfirmLabel() configureButton() + + bind() + } + + private func setUpBind() { + store.$state + .receive(on: DispatchQueue.main) + .sink { [weak self] newState in + self?.render(newState) + } + .store(in: &cancellables) + } + + private func render(_ state: MyPageReducer.State) { + if state.isSignOutSuccess == .failure { + showToast(icon: .colorXmark, message: "탈퇴에 실패했어요.") + } + } + + private func bind() { + backButton.publisher(for: .touchUpInside) + .sink { [weak self] in + self?.store.dispatch(.popPage) + } + .store(in: &cancellables) + + signOutButton.publisher(for: .touchUpInside) + .sink { [weak self] in + self?.store.dispatch(.signOut) + } + .store(in: &cancellables) } private func configureBar() { @@ -147,6 +194,8 @@ class SignOutConfirmViewController: UIViewController { view.addSubview(confirmTextLabel) view.addSubview(signOutTextView) + signOutTextView.delegate = self + separatorSecondLine.snp.makeConstraints { make in make.leading.trailing.equalToSuperview() make.height.equalTo(0.5) @@ -182,8 +231,15 @@ class SignOutConfirmViewController: UIViewController { } } -#Preview { - let vc = SignOutConfirmViewController() - - return vc +extension SignOutConfirmViewController: UITextViewDelegate { + func textViewDidBeginEditing(_ textView: UITextView) { + textView.text = nil + textView.textColor = .slate800 + } } + +//#Preview { +// let vc = SignOutConfirmViewController(store: MyPageStore(reducer: MyPageReducer())) +// +// return vc +//} diff --git a/echog/echog/Presentation/MyPage/SignOutReasonViewController.swift b/echog/echog/Presentation/MyPage/SignOutReasonViewController.swift index 5b274ba..63014c3 100644 --- a/echog/echog/Presentation/MyPage/SignOutReasonViewController.swift +++ b/echog/echog/Presentation/MyPage/SignOutReasonViewController.swift @@ -10,6 +10,9 @@ import UIKit import SnapKit class SignOutReasonViewController: UIViewController { + var store: MyPageStore + private var cancellables = Set() + private let titleLabel: UILabel = { let label = UILabel() label.font = .semiboldLargetitle17 @@ -39,6 +42,16 @@ class SignOutReasonViewController: UIViewController { private let nextButton = MainButton(title: "다음") + required init(store: MyPageStore) { + self.store = store + + super.init(nibName: nil, bundle: nil) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .systemBackground @@ -46,6 +59,22 @@ class SignOutReasonViewController: UIViewController { configureBar() configureTableView() configureButton() + + bind() + } + + private func bind() { + backButton.publisher(for: .touchUpInside) + .sink { [weak self] in + self?.store.dispatch(.popPage) + } + .store(in: &cancellables) + + nextButton.publisher(for: .touchUpInside) + .sink { [weak self] in + self?.store.dispatch(.goToNextSignOutPage) + } + .store(in: &cancellables) } private func configureBar() { @@ -70,6 +99,7 @@ class SignOutReasonViewController: UIViewController { tableView.separatorStyle = .singleLine tableView.separatorInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) tableView.separatorColor = .slate100 + tableView.allowsMultipleSelection = false view.addSubview(tableView) @@ -129,6 +159,14 @@ extension SignOutReasonViewController: UITableViewDelegate, UITableViewDataSourc 56 } } + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + guard let cell = tableView.cellForRow(at: indexPath) as? SignOutReasonCell else { + return + } + + cell.selectedCell() + } } extension SignOutReasonViewController: UITextViewDelegate { @@ -139,7 +177,7 @@ extension SignOutReasonViewController: UITextViewDelegate { } #Preview { - let vc = SignOutReasonViewController() + let vc = SignOutReasonViewController(store: MyPageStore(reducer: MyPageReducer())) return vc } From bcce3b3a0dc4819f47697fb7b13d4b6ebc2fe7d7 Mon Sep 17 00:00:00 2001 From: mint3382 Date: Fri, 28 Feb 2025 14:51:30 +0900 Subject: [PATCH 11/12] =?UTF-8?q?=F0=9F=9B=A0=EF=B8=8F(refactor)=20MyPage?= =?UTF-8?q?=20=EB=8B=AB=EA=B8=B0=20=EB=B2=84=ED=8A=BC=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../echog/Presentation/LogIn/LogInViewController.swift | 2 +- echog/echog/Presentation/MyPage/MyPageReducer.swift | 4 ++++ .../Presentation/MyPage/MyPageViewController.swift | 10 ++++++++++ .../MyPage/SignOutReasonViewController.swift | 4 ++-- .../Presentation/MyPage/TermsCheckViewController.swift | 1 + 5 files changed, 18 insertions(+), 3 deletions(-) diff --git a/echog/echog/Presentation/LogIn/LogInViewController.swift b/echog/echog/Presentation/LogIn/LogInViewController.swift index ec96bf8..4f09340 100644 --- a/echog/echog/Presentation/LogIn/LogInViewController.swift +++ b/echog/echog/Presentation/LogIn/LogInViewController.swift @@ -238,7 +238,7 @@ extension LogInViewController { extension LogInViewController: UITextFieldDelegate { func textFieldShouldReturn(_ textField: UITextField) -> Bool { if textField == emailTextField.mainTextField { - emailTextField.mainTextField.becomeFirstResponder() + passwordTextField.mainTextField.becomeFirstResponder() } else { textField.resignFirstResponder() } diff --git a/echog/echog/Presentation/MyPage/MyPageReducer.swift b/echog/echog/Presentation/MyPage/MyPageReducer.swift index f7eeafa..88b574b 100644 --- a/echog/echog/Presentation/MyPage/MyPageReducer.swift +++ b/echog/echog/Presentation/MyPage/MyPageReducer.swift @@ -17,6 +17,7 @@ struct MyPageReducer: ReducerProtocol { case goToNextSignOutPage case popPage case signOut + case goBackDiaryHome } enum Mutation { @@ -67,6 +68,9 @@ struct MyPageReducer: ReducerProtocol { } } .eraseToAnyPublisher() + case .goBackDiaryHome: + delegate?.goToDiaryViewController() + return nil } } diff --git a/echog/echog/Presentation/MyPage/MyPageViewController.swift b/echog/echog/Presentation/MyPage/MyPageViewController.swift index 3d1a438..7a316c2 100644 --- a/echog/echog/Presentation/MyPage/MyPageViewController.swift +++ b/echog/echog/Presentation/MyPage/MyPageViewController.swift @@ -54,6 +54,16 @@ class MyPageViewController: UIViewController, View { configureBar() configureTableView() + + bind() + } + + private func bind() { + closeButton.publisher(for: .touchUpInside) + .sink { [weak self] in + self?.store.dispatch(.goBackDiaryHome) + } + .store(in: &cancellables) } private func configureBar() { diff --git a/echog/echog/Presentation/MyPage/SignOutReasonViewController.swift b/echog/echog/Presentation/MyPage/SignOutReasonViewController.swift index 63014c3..d436451 100644 --- a/echog/echog/Presentation/MyPage/SignOutReasonViewController.swift +++ b/echog/echog/Presentation/MyPage/SignOutReasonViewController.swift @@ -171,8 +171,8 @@ extension SignOutReasonViewController: UITableViewDelegate, UITableViewDataSourc extension SignOutReasonViewController: UITextViewDelegate { func textViewDidBeginEditing(_ textView: UITextView) { - textView.text = nil - textView.textColor = .slate800 + textView.text = nil + textView.textColor = .slate800 } } diff --git a/echog/echog/Presentation/MyPage/TermsCheckViewController.swift b/echog/echog/Presentation/MyPage/TermsCheckViewController.swift index ba98306..6f4c913 100644 --- a/echog/echog/Presentation/MyPage/TermsCheckViewController.swift +++ b/echog/echog/Presentation/MyPage/TermsCheckViewController.swift @@ -52,6 +52,7 @@ class TermsCheckViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() + view.backgroundColor = .systemBackground configureBar() configureView() From 2a2eb4fa5e23e0b22841dee18b89b08f64370736 Mon Sep 17 00:00:00 2001 From: mint3382 Date: Fri, 28 Feb 2025 14:52:03 +0900 Subject: [PATCH 12/12] =?UTF-8?q?=E2=9A=99=EF=B8=8F(chore)=20Eager=20Linki?= =?UTF-8?q?ng=20=3D=20YES?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- echog/echog.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/echog/echog.xcodeproj/project.pbxproj b/echog/echog.xcodeproj/project.pbxproj index 8bb1099..5f86828 100644 --- a/echog/echog.xcodeproj/project.pbxproj +++ b/echog/echog.xcodeproj/project.pbxproj @@ -956,6 +956,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = BMG3X5CM6G; + EAGER_LINKING = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = echog/Info.plist; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; @@ -984,6 +985,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = BMG3X5CM6G; + EAGER_LINKING = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = echog/Info.plist; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;