diff --git a/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj b/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj index 7f32d704..ecd3af5e 100644 --- a/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj +++ b/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj @@ -21,8 +21,7 @@ A3C2CACE29E313CC00EC525B /* SettingVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3C2CACD29E313CC00EC525B /* SettingVC.swift */; }; A3C2CAD329E4F77C00EC525B /* TermsOfServiceVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3C2CAD229E4F77C00EC525B /* TermsOfServiceVC.swift */; }; A3C2CAD529E4F85400EC525B /* PersonalInfoVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3C2CAD429E4F85400EC525B /* PersonalInfoVC.swift */; }; - A3C2CAD729E53B2900EC525B /* LogoutVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3C2CAD629E53B2900EC525B /* LogoutVC.swift */; }; - A3C2CADB29E9A12400EC525B /* DeleteAccountVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3C2CADA29E9A12400EC525B /* DeleteAccountVC.swift */; }; + A3C2CAD729E53B2900EC525B /* RNAlertVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3C2CAD629E53B2900EC525B /* RNAlertVC.swift */; }; A3D1A77929CF03D200DD54EC /* AuthRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3D1A77829CF03D200DD54EC /* AuthRouter.swift */; }; A3D1A77E29CF09B600DD54EC /* SignInResponseDto.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3D1A77D29CF09B600DD54EC /* SignInResponseDto.swift */; }; A3D1A78029CF142E00DD54EC /* UserManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3D1A77F29CF142E00DD54EC /* UserManager.swift */; }; @@ -145,6 +144,7 @@ CEEC6B492961C5E200D00E1E /* SplashVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEEC6B482961C5E200D00E1E /* SplashVC.swift */; }; CEEC6B4B2961D89700D00E1E /* CustomNavigationBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEEC6B4A2961D89700D00E1E /* CustomNavigationBar.swift */; }; CEF3CD9A296DB305002723A1 /* CourseDetailResponseDto.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEF3CD99296DB305002723A1 /* CourseDetailResponseDto.swift */; }; + CEFA9A2F29FC263700F2D0CF /* UserDeleteResponseDto.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEFA9A2E29FC263700F2D0CF /* UserDeleteResponseDto.swift */; }; DA20D847296697A600F1581F /* MyCourseSelectVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA20D846296697A600F1581F /* MyCourseSelectVC.swift */; }; DA20D849296697B400F1581F /* CourseUploadVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA20D848296697B400F1581F /* CourseUploadVC.swift */; }; DA20D84E2966A9B300F1581F /* CourseSearchVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA20D84D2966A9B300F1581F /* CourseSearchVC.swift */; }; @@ -171,8 +171,7 @@ A3C2CACD29E313CC00EC525B /* SettingVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingVC.swift; sourceTree = ""; }; A3C2CAD229E4F77C00EC525B /* TermsOfServiceVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TermsOfServiceVC.swift; sourceTree = ""; }; A3C2CAD429E4F85400EC525B /* PersonalInfoVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersonalInfoVC.swift; sourceTree = ""; }; - A3C2CAD629E53B2900EC525B /* LogoutVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogoutVC.swift; sourceTree = ""; }; - A3C2CADA29E9A12400EC525B /* DeleteAccountVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeleteAccountVC.swift; sourceTree = ""; }; + A3C2CAD629E53B2900EC525B /* RNAlertVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNAlertVC.swift; sourceTree = ""; }; A3D1A77829CF03D200DD54EC /* AuthRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRouter.swift; sourceTree = ""; }; A3D1A77D29CF09B600DD54EC /* SignInResponseDto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInResponseDto.swift; sourceTree = ""; }; A3D1A77F29CF142E00DD54EC /* UserManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserManager.swift; sourceTree = ""; }; @@ -186,7 +185,6 @@ CE0C23782966D6AF00B45063 /* ViewPager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewPager.swift; sourceTree = ""; }; CE0D9FD229648DA300CEB5CD /* CustomAlertVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomAlertVC.swift; sourceTree = ""; }; CE10063929680C5700FD31FB /* .gitkeep */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitkeep; sourceTree = ""; }; - CE10063D29680C8100FD31FB /* .gitkeep */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitkeep; sourceTree = ""; }; CE10064D29680D2500FD31FB /* .gitkeep */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitkeep; sourceTree = ""; }; CE10064F29680D3300FD31FB /* .gitkeep */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitkeep; sourceTree = ""; }; CE10065029680D3800FD31FB /* .gitkeep */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitkeep; sourceTree = ""; }; @@ -308,6 +306,7 @@ CEEC6B482961C5E200D00E1E /* SplashVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashVC.swift; sourceTree = ""; }; CEEC6B4A2961D89700D00E1E /* CustomNavigationBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomNavigationBar.swift; sourceTree = ""; }; CEF3CD99296DB305002723A1 /* CourseDetailResponseDto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseDetailResponseDto.swift; sourceTree = ""; }; + CEFA9A2E29FC263700F2D0CF /* UserDeleteResponseDto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDeleteResponseDto.swift; sourceTree = ""; }; DA20D846296697A600F1581F /* MyCourseSelectVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyCourseSelectVC.swift; sourceTree = ""; }; DA20D848296697B400F1581F /* CourseUploadVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseUploadVC.swift; sourceTree = ""; }; DA20D84D2966A9B300F1581F /* CourseSearchVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseSearchVC.swift; sourceTree = ""; }; @@ -391,8 +390,6 @@ A3C2CACD29E313CC00EC525B /* SettingVC.swift */, A3C2CAD229E4F77C00EC525B /* TermsOfServiceVC.swift */, A3C2CAD429E4F85400EC525B /* PersonalInfoVC.swift */, - A3C2CAD629E53B2900EC525B /* LogoutVC.swift */, - A3C2CADA29E9A12400EC525B /* DeleteAccountVC.swift */, ); path = SettingVC; sourceTree = ""; @@ -452,10 +449,10 @@ CE10063429680C0800FD31FB /* MyPageDto */ = { isa = PBXGroup; children = ( - CE10063D29680C8100FD31FB /* .gitkeep */, A3F67AE1296D33AC001598A2 /* MyPageDto.swift */, A3F67AE9296E4936001598A2 /* ActivityRecordInfoDto.swift */, A3305A96296EF58C000B1A10 /* GoalRewardInfoDto.swift */, + CEFA9A2E29FC263700F2D0CF /* UserDeleteResponseDto.swift */, ); path = MyPageDto; sourceTree = ""; @@ -1032,6 +1029,7 @@ CE9291262965D0ED0010959C /* StatsInfoView.swift */, CE6B63D729673450003F900F /* ListEmptyView.swift */, CEB0BCBB29D123350048CCD5 /* GuideView.swift */, + A3C2CAD629E53B2900EC525B /* RNAlertVC.swift */, ); path = UIComponents; sourceTree = ""; @@ -1361,7 +1359,7 @@ CE40BB1C2967E4910030ABCA /* RunningWaitingVC.swift in Sources */, CE6B63D6296731F9003F900F /* ScrapCourseListView.swift in Sources */, CE6655F8295D90CF00C64E12 /* adjusted+.swift in Sources */, - A3C2CAD729E53B2900EC525B /* LogoutVC.swift in Sources */, + A3C2CAD729E53B2900EC525B /* RNAlertVC.swift in Sources */, DAD5A3E2296D4C6500C8166B /* PickedMapListResponseDto.swift in Sources */, CE4545CB295D7AF4003201E1 /* SceneDelegate.swift in Sources */, A3F67AE2296D33AC001598A2 /* MyPageDto.swift in Sources */, @@ -1375,6 +1373,7 @@ DAD5A3D8296C6D9600C8166B /* AdImageCollectionViewCell.swift in Sources */, CE18E890296C76C100FEB569 /* RNLocationModel.swift in Sources */, CE6655DC295D873500C64E12 /* UIButton+.swift in Sources */, + CEFA9A2F29FC263700F2D0CF /* UserDeleteResponseDto.swift in Sources */, CE21C02C299E601000F62AF5 /* ScrapRouter.swift in Sources */, A3D1A78029CF142E00DD54EC /* UserManager.swift in Sources */, A3D1A77929CF03D200DD54EC /* AuthRouter.swift in Sources */, @@ -1392,7 +1391,6 @@ CEEC6B3A2961C4F300D00E1E /* CourseDrawingHomeVC.swift in Sources */, CEB0BCBC29D123350048CCD5 /* GuideView.swift in Sources */, CEC2A6902962B06C00160BF7 /* convertLocationObject.swift in Sources */, - A3C2CADB29E9A12400EC525B /* DeleteAccountVC.swift in Sources */, CEC2A6852961F92C00160BF7 /* CustomButton.swift in Sources */, CE6B63D3296725E6003F900F /* CourseListCVC.swift in Sources */, CEF3CD9A296DB305002723A1 /* CourseDetailResponseDto.swift in Sources */, diff --git a/Runnect-iOS/Runnect-iOS/Global/Literal/ImageLiterals.swift b/Runnect-iOS/Runnect-iOS/Global/Literal/ImageLiterals.swift index 849f47c8..c625596e 100644 --- a/Runnect-iOS/Runnect-iOS/Global/Literal/ImageLiterals.swift +++ b/Runnect-iOS/Runnect-iOS/Global/Literal/ImageLiterals.swift @@ -31,7 +31,7 @@ enum ImageLiterals { static var icMapStart: UIImage { .load(named: "ic_map_start") } static var icMypageFill: UIImage { .load(named: "ic_mypage_fill") } static var icMypage: UIImage { .load(named: "ic_mypage") } - static var icPlus: UIImage { .load(named: "ic_plus") } + static var icPlusButton: UIImage { .load(named: "ic_plus_button") } static var icSearch: UIImage { .load(named: "ic_search") } static var icStar: UIImage { .load(named: "ic_star") } static var icStar2: UIImage { .load(named: "ic_star2") } @@ -43,6 +43,7 @@ enum ImageLiterals { static var icLocationOverlay: UIImage { .load(named: "ic_location_overlay") } static var icLogoCircle: UIImage { .load(named: "ic_logo_circle") } static var icMore: UIImage { .load(named: "ic_more") } + static var icPlus: UIImage { .load(named: "ic_plus") } // img static var imgBackground: UIImage { .load(named: "img_background") } diff --git a/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_plus.imageset/Contents.json b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_plus.imageset/Contents.json index 044ff80f..9c8472d0 100644 --- a/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_plus.imageset/Contents.json +++ b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_plus.imageset/Contents.json @@ -1,17 +1,17 @@ { "images" : [ { - "filename" : "plus.png", + "filename" : "Group 9553.png", "idiom" : "universal", "scale" : "1x" }, { - "filename" : "plus@2x.png", + "filename" : "Group 9553@2x.png", "idiom" : "universal", "scale" : "2x" }, { - "filename" : "plus@3x.png", + "filename" : "Group 9553@3x.png", "idiom" : "universal", "scale" : "3x" } @@ -19,8 +19,5 @@ "info" : { "author" : "xcode", "version" : 1 - }, - "properties" : { - "template-rendering-intent" : "original" } } diff --git a/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_plus.imageset/Group 9553.png b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_plus.imageset/Group 9553.png new file mode 100644 index 00000000..29e97a23 Binary files /dev/null and b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_plus.imageset/Group 9553.png differ diff --git a/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_plus.imageset/Group 9553@2x.png b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_plus.imageset/Group 9553@2x.png new file mode 100644 index 00000000..fecd014d Binary files /dev/null and b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_plus.imageset/Group 9553@2x.png differ diff --git a/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_plus.imageset/Group 9553@3x.png b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_plus.imageset/Group 9553@3x.png new file mode 100644 index 00000000..fffad8b5 Binary files /dev/null and b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_plus.imageset/Group 9553@3x.png differ diff --git a/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_plus_button.imageset/Contents.json b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_plus_button.imageset/Contents.json new file mode 100644 index 00000000..044ff80f --- /dev/null +++ b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_plus_button.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "filename" : "plus.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "plus@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "plus@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "original" + } +} diff --git a/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_plus.imageset/plus.png b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_plus_button.imageset/plus.png similarity index 100% rename from Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_plus.imageset/plus.png rename to Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_plus_button.imageset/plus.png diff --git a/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_plus.imageset/plus@2x.png b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_plus_button.imageset/plus@2x.png similarity index 100% rename from Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_plus.imageset/plus@2x.png rename to Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_plus_button.imageset/plus@2x.png diff --git a/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_plus.imageset/plus@3x.png b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_plus_button.imageset/plus@3x.png similarity index 100% rename from Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_plus.imageset/plus@3x.png rename to Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_plus_button.imageset/plus@3x.png diff --git a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/SettingVC/LogoutVC.swift b/Runnect-iOS/Runnect-iOS/Global/UIComponents/RNAlertVC.swift similarity index 77% rename from Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/SettingVC/LogoutVC.swift rename to Runnect-iOS/Runnect-iOS/Global/UIComponents/RNAlertVC.swift index d3644fc2..fe610b6e 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/SettingVC/LogoutVC.swift +++ b/Runnect-iOS/Runnect-iOS/Global/UIComponents/RNAlertVC.swift @@ -10,18 +10,19 @@ import UIKit import SnapKit import Then -final class LogoutVC: UIViewController { +final class RNAlertVC: UIViewController { // MARK: - Properties + var rightButtonTapAction: (() -> Void)? + // MARK: - UI Components private let containerView = UIView().then { $0.layer.cornerRadius = 15 } - private let logoutQuestionLabel = UILabel().then { - $0.text = "로그아웃 하시겠어요?" + private let descriptionLabel = UILabel().then { $0.font = .b4 $0.textColor = .g2 } @@ -42,6 +43,15 @@ final class LogoutVC: UIViewController { $0.layer.cornerRadius = 10 } + init(description: String) { + super.init(nibName: nil, bundle: nil) + self.descriptionLabel.text = description + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + // MARK: - View Life Cycle override func viewDidLoad() { @@ -54,7 +64,7 @@ final class LogoutVC: UIViewController { // MARK: - Methods -extension LogoutVC { +extension RNAlertVC { override func touchesBegan(_ touches: Set, with event: UIEvent?) { super.touchesBegan(touches, with: event) if let touch = touches.first, touch.view == self.view { @@ -64,20 +74,25 @@ extension LogoutVC { private func setAddTarget() { self.noButton.addTarget(self, action: #selector(touchUpNoButton), for: .touchUpInside) + self.yesButton.addTarget(self, action: #selector(touchYesButton), for: .touchUpInside) } } // MARK: - @objc Function -extension LogoutVC { - @objc func touchUpNoButton() { +extension RNAlertVC { + @objc private func touchUpNoButton() { dismiss(animated: false) } + + @objc private func touchYesButton() { + self.rightButtonTapAction?() + } } // MARK: - Layout Helpers -extension LogoutVC { +extension RNAlertVC { private func setUI() { view.backgroundColor = .black.withAlphaComponent(0.8) containerView.backgroundColor = .w1 @@ -93,9 +108,9 @@ extension LogoutVC { make.height.equalTo(126) } - containerView.addSubviews(logoutQuestionLabel, yesButton, noButton) + containerView.addSubviews(descriptionLabel, yesButton, noButton) - logoutQuestionLabel.snp.makeConstraints { make in + descriptionLabel.snp.makeConstraints { make in make.centerX.equalToSuperview() make.top.equalToSuperview().offset(26) } diff --git a/Runnect-iOS/Runnect-iOS/Global/Utils/RNUtils/UserManager.swift b/Runnect-iOS/Runnect-iOS/Global/Utils/RNUtils/UserManager.swift index 861e77d3..604ce2c2 100644 --- a/Runnect-iOS/Runnect-iOS/Global/Utils/RNUtils/UserManager.swift +++ b/Runnect-iOS/Runnect-iOS/Global/Utils/RNUtils/UserManager.swift @@ -90,4 +90,14 @@ final class UserManager { } } } + + func logout() { + self.resetTokens() + } + + private func resetTokens() { + self.accessToken = nil + self.refreshToken = nil + self.isKakao = nil + } } diff --git a/Runnect-iOS/Runnect-iOS/Network/Dto/MyPageDto/.gitkeep b/Runnect-iOS/Runnect-iOS/Network/Dto/MyPageDto/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/Runnect-iOS/Runnect-iOS/Network/Dto/MyPageDto/UserDeleteResponseDto.swift b/Runnect-iOS/Runnect-iOS/Network/Dto/MyPageDto/UserDeleteResponseDto.swift new file mode 100644 index 00000000..54b30f12 --- /dev/null +++ b/Runnect-iOS/Runnect-iOS/Network/Dto/MyPageDto/UserDeleteResponseDto.swift @@ -0,0 +1,12 @@ +// +// UserDeleteResponseDto.swift +// Runnect-iOS +// +// Created by sejin on 2023/04/29. +// + +import Foundation + +struct UserDeleteResponseDto: Codable { + let deletedUserId: Int +} diff --git a/Runnect-iOS/Runnect-iOS/Network/Router/UserRouter.swift b/Runnect-iOS/Runnect-iOS/Network/Router/UserRouter.swift index b3bcce38..cd391b6c 100644 --- a/Runnect-iOS/Runnect-iOS/Network/Router/UserRouter.swift +++ b/Runnect-iOS/Runnect-iOS/Network/Router/UserRouter.swift @@ -12,6 +12,7 @@ import Moya enum UserRouter { case getMyPageInfo case updateUserNickname(nickname: String) + case deleteUser(appleToken: String?) } extension UserRouter: TargetType { @@ -25,7 +26,7 @@ extension UserRouter: TargetType { var path: String { switch self { - case .getMyPageInfo, .updateUserNickname: + case .getMyPageInfo, .updateUserNickname, .deleteUser: return "/user" } } @@ -36,12 +37,14 @@ extension UserRouter: TargetType { return .get case .updateUserNickname: return .patch + case .deleteUser: + return .delete } } var task: Moya.Task { switch self { - case .getMyPageInfo: + case .getMyPageInfo, .deleteUser: return .requestPlain case .updateUserNickname(let nickname): return .requestParameters(parameters: ["nickname": nickname], encoding: JSONEncoding.default) @@ -49,7 +52,16 @@ extension UserRouter: TargetType { } var headers: [String: String]? { - return Config.defaultHeader + switch self { + case .deleteUser(let appleToken): + if let appleToken = appleToken { + return ["Content-Type": "application/json", "appleAccessToken": appleToken] + } else { + return Config.defaultHeader + } + default: + return Config.defaultHeader + } } var validationType: ValidationType { diff --git a/Runnect-iOS/Runnect-iOS/Network/Service/AuthInterceptor.swift b/Runnect-iOS/Runnect-iOS/Network/Service/AuthInterceptor.swift index 32017703..8470cc98 100644 --- a/Runnect-iOS/Runnect-iOS/Network/Service/AuthInterceptor.swift +++ b/Runnect-iOS/Runnect-iOS/Network/Service/AuthInterceptor.swift @@ -35,7 +35,8 @@ final class AuthInterceptor: RequestInterceptor { func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) { print("retry 진입") - guard let response = request.task?.response as? HTTPURLResponse, response.statusCode == 401 + guard let response = request.task?.response as? HTTPURLResponse, response.statusCode == 401, let pathComponents = request.request?.url?.pathComponents, + !pathComponents.contains("getNewToken") else { completion(.doNotRetryWithError(error)) return diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseDiscoveryVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseDiscoveryVC.swift index e5e1eda2..f4856ab5 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseDiscoveryVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseDiscoveryVC.swift @@ -28,8 +28,11 @@ final class CourseDiscoveryVC: UIViewController { $0.setImage(ImageLiterals.icSearch, for: .normal) $0.tintColor = .g1 } - private let uploadButton = CustomButton(title: "업로드하기").then { + private let uploadButton = CustomButton(title: "업로드").then { $0.layer.cornerRadius = 20 + $0.setImage(ImageLiterals.icPlus, for: .normal) + $0.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 10) + $0.titleEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 0) } // MARK: - collectionview @@ -49,6 +52,7 @@ final class CourseDiscoveryVC: UIViewController { override func viewDidLoad () { super.viewDidLoad() + setUI() register() setNavigationBar() setDelegate() @@ -105,6 +109,11 @@ extension CourseDiscoveryVC { // MARK: - UI & Layout extension CourseDiscoveryVC { + private func setUI() { + view.backgroundColor = .w1 + mapCollectionView.backgroundColor = .w1 + } + private func setNavigationBar() { view.addSubview(navibar) view.addSubview(searchButton) @@ -120,8 +129,6 @@ extension CourseDiscoveryVC { } private func layout() { - view.backgroundColor = .w1 - mapCollectionView.backgroundColor = .w1 view.addSubviews(uploadButton, mapCollectionView) view.bringSubviewToFront(uploadButton) @@ -134,7 +141,7 @@ extension CourseDiscoveryVC { make.trailing.equalTo(self.view.safeAreaLayoutGuide).inset(16) make.bottom.equalTo(self.view.safeAreaLayoutGuide).inset(20) make.height.equalTo(40) - make.width.equalTo(136) + make.width.equalTo(92) } } } diff --git a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/SettingVC/DeleteAccountVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/SettingVC/DeleteAccountVC.swift deleted file mode 100644 index 4fd4d503..00000000 --- a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/SettingVC/DeleteAccountVC.swift +++ /dev/null @@ -1,119 +0,0 @@ -// -// DeleteAccountVC.swift -// Runnect-iOS -// -// Created by 몽이 누나 on 2023/04/14. -// - -import UIKit - -import SnapKit -import Then - -final class DeleteAccountVC: UIViewController { - - // MARK: - Properties - - // MARK: - UI Components - - private let containerView = UIView().then { - $0.layer.cornerRadius = 15 - } - - private let logoutQuestionLabel = UILabel().then { - $0.text = "정말로 탈퇴하시겠어요?" - $0.font = .b4 - $0.textColor = .g2 - } - - private lazy var yesButton = UIButton(type: .custom).then { - $0.setTitle("네", for: .normal) - $0.titleLabel?.font = .h5 - $0.setTitleColor(.w1, for: .normal) - $0.layer.backgroundColor = UIColor.m1.cgColor - $0.layer.cornerRadius = 10 - } - - private lazy var noButton = UIButton(type: .custom).then { - $0.setTitle("아니오", for: .normal) - $0.titleLabel?.font = .h5 - $0.setTitleColor(.m1, for: .normal) - $0.layer.backgroundColor = UIColor.m3.cgColor - $0.layer.cornerRadius = 10 - } - - // MARK: - View Life Cycle - - override func viewDidLoad() { - super.viewDidLoad() - setUI() - setLayout() - setAddTarget() - } -} - -// MARK: - Methods - -extension DeleteAccountVC { - override func touchesBegan(_ touches: Set, with event: UIEvent?) { - super.touchesBegan(touches, with: event) - if let touch = touches.first, touch.view == self.view { - dismiss(animated: false) - } - } - - private func setAddTarget() { - self.noButton.addTarget(self, action: #selector(touchUpNoButton), for: .touchUpInside) - } -} - -// MARK: - @objc Function - -extension DeleteAccountVC { - @objc func touchUpNoButton() { - dismiss(animated: false) - } -} - -// MARK: - Layout Helpers - -extension DeleteAccountVC { - private func setUI() { - view.backgroundColor = .black.withAlphaComponent(0.8) - containerView.backgroundColor = .w1 - } - - private func setLayout() { - view.addSubviews(containerView) - - containerView.snp.makeConstraints { make in - make.centerX.equalToSuperview() - make.centerY.equalToSuperview() - make.leading.trailing.equalToSuperview().inset(30) - make.height.equalTo(126) - } - - containerView.addSubviews(logoutQuestionLabel, yesButton, noButton) - - logoutQuestionLabel.snp.makeConstraints { make in - make.centerX.equalToSuperview() - make.top.equalToSuperview().offset(26) - } - - noButton.snp.makeConstraints { make in - make.leading.equalToSuperview().offset(16) - make.trailing.equalTo(containerView.snp.centerX).offset(-4) - make.height.equalTo(44) - make.width.equalTo(145) - make.bottom.equalToSuperview().inset(16) - } - - yesButton.snp.makeConstraints { make in - make.trailing.equalToSuperview().inset(16) - make.leading.equalTo(containerView.snp.centerX).offset(4) - make.height.equalTo(44) - make.width.equalTo(145) - make.bottom.equalToSuperview().inset(16) - } - } -} diff --git a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/SettingVC/PersonalInfoVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/SettingVC/PersonalInfoVC.swift index 8d305225..85066225 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/SettingVC/PersonalInfoVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/SettingVC/PersonalInfoVC.swift @@ -6,12 +6,17 @@ // import UIKit +import AuthenticationServices import SnapKit import Then final class PersonalInfoVC: UIViewController { + // MARK: - Properties + + private let userProvider = Providers.userProvider + // MARK: - UI Components private lazy var navibar = CustomNavigationBar(self, type: .titleWithLeftButton).setTitle("계정 정보") @@ -97,16 +102,55 @@ extension PersonalInfoVC { } private func pushToLogoutVC() { - let logoutVC = LogoutVC() + let logoutVC = RNAlertVC(description: "로그아웃 하시겠어요?") + logoutVC.rightButtonTapAction = { [weak self] in + self?.logout() + } logoutVC.modalPresentationStyle = .overFullScreen self.present(logoutVC, animated: false) } private func pushToDeleteAccountVC() { - let deleteAccountVC = DeleteAccountVC() + let deleteAccountVC = RNAlertVC(description: "정말로 탈퇴하시겠어요?") + deleteAccountVC.rightButtonTapAction = { [weak self] in + // 애플 유저가 탈퇴할 경우 애플로부터 토큰을 한번 더 받아서 보내주기 + if let isKakao = UserManager.shared.isKakao, !isKakao { + // 애플 토큰 받기 + self?.requestAppleToken() + } else { + // 카카오 유저 탈퇴 + self?.deleteUser(appleToken: nil) + } + } deleteAccountVC.modalPresentationStyle = .overFullScreen self.present(deleteAccountVC, animated: false) } + + private func logout() { + UserManager.shared.logout() + self.showSplashVC() + } + + private func deleteUserDidComplete() { + self.logout() + } + + private func showSplashVC() { + let splashVC = SplashVC() + let navigationController = UINavigationController(rootViewController: splashVC) + guard let window = self.view.window else { return } + ViewControllerUtils.setRootViewController(window: window, viewController: navigationController, withAnimation: true) + } + + private func requestAppleToken() { + let appleIDProvider = ASAuthorizationAppleIDProvider() + let request = appleIDProvider.createRequest() + + let authorizationController = ASAuthorizationController(authorizationRequests: [request]) + authorizationController.delegate = self + authorizationController.presentationContextProvider = self + authorizationController.performRequests() + } } // MARK: - Layout Helpers @@ -207,3 +251,67 @@ extension PersonalInfoVC { } } } + +// MARK: - Network + +extension PersonalInfoVC { + private func deleteUser(appleToken: String?) { + LoadingIndicator.showLoading() + self.userProvider.request(.deleteUser(appleToken: appleToken)) { [weak self] result in + LoadingIndicator.hideLoading() + guard let self = self else { return } + switch result { + case .success(let response): + let status = response.statusCode + if 200..<300 ~= status { + do { + let responseDto = try response.map(BaseResponse.self) + guard let data = responseDto.data else { return } + print("삭제된 유저 아이디: \(data.deletedUserId)") + self.deleteUserDidComplete() + } catch { + print(error.localizedDescription) + } + } + if status >= 400 { + print("400 error") + self.showNetworkFailureToast() + } + case .failure(let error): + print(error) + self.showNetworkFailureToast() + } + } + } +} + +extension PersonalInfoVC: ASAuthorizationControllerPresentationContextProviding, ASAuthorizationControllerDelegate { + func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor { + return self.view.window! + } + + /// Apple ID 연동 성공 시 + func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) { + switch authorization.credential { + /// Apple ID + case let appleIDCredential as ASAuthorizationAppleIDCredential: + + /// 계정 정보 가져오기 + let userIdentifier = appleIDCredential.user + let idToken = appleIDCredential.identityToken! + guard let tokenStr = String(data: idToken, encoding: .utf8) else { return } + + print("User ID : \(userIdentifier)") + print("token : \(String(describing: tokenStr))") + + self.deleteUser(appleToken: tokenStr) + default: + break + } + } + + /// Apple ID 연동 실패 시 + func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) { + print("Apple Login error") + } +}