Skip to content

Commit c958d1f

Browse files
authored
Merge branch 'main' into fix/PC-630-check-firebase
2 parents f08eb85 + 5217b4b commit c958d1f

File tree

23 files changed

+342
-7
lines changed

23 files changed

+342
-7
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ Derived/
6969
### xcconfig ###
7070
*.xcconfig
7171

72+
## key
73+
*.p8
7274

7375
### Tuist managed dependencies ###
7476
Tuist/.build

App/Sources/PieceApp.swift

+9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import DesignSystem
22
import PCFirebase
3+
import LocalStorage
34
import Router
45
import KakaoSDKCommon
56
import KakaoSDKAuth
@@ -26,6 +27,14 @@ struct PieceApp: App {
2627
return
2728
}
2829
KakaoSDK.initSDK(appKey: kakaoAppKey)
30+
31+
// 앱 첫 실행 테스트 시, 아래 주석 해제
32+
// PCUserDefaultsService.shared.resetFirstLaunch()
33+
if PCUserDefaultsService.shared.checkFirstLaunch() {
34+
PCUserDefaultsService.shared.initialize()
35+
PCUserDefaultsService.shared.setDidSeeOnboarding(false)
36+
PCKeychainManager.shared.deleteAll()
37+
}
2938
}
3039

3140
var body: some Scene {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//
2+
// AppleOathTokenResponseDTO.swift
3+
// DTO
4+
//
5+
// Created by eunseou on 2/17/25.
6+
//
7+
8+
import SwiftUI
9+
10+
public struct AppleOathTokenResponseDTO: Codable {
11+
public let access_token: String
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//
2+
// AppleOauthTokenRequestDTO.swift
3+
// DTO
4+
//
5+
// Created by eunseou on 2/17/25.
6+
//
7+
8+
import SwiftUI
9+
import Entities
10+
11+
public struct AppleRevokeOauthTokenRequestDTO: Encodable {
12+
public let client_id: String
13+
public let client_secret: String
14+
public let token: String
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//
2+
// WithdrawRequestDTO.swift
3+
// DTO
4+
//
5+
// Created by eunseou on 2/17/25.
6+
//
7+
8+
import SwiftUI
9+
import Entities
10+
11+
public struct WithdrawRequestDTO: Encodable {
12+
public let reason: String
13+
14+
public init(reason: String) {
15+
self.reason = reason
16+
}
17+
}

Data/LocalStorage/Sources/Keychain/PCKeychain.swift

+3
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,7 @@ public enum PCKeychain: String, CaseIterable {
1111
case accessToken
1212
case refreshToken
1313
case role
14+
15+
// apple auth
16+
case appleAuthCode
1417
}

Data/LocalStorage/Sources/UserDefaults/PCUserDefaultsService.swift

+25
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,16 @@ public final class PCUserDefaultsService {
2929
_ = PCUserDefaults.setObjectFor(key: .blockContactsLastUpdatedDate, object: newValue)
3030
}
3131
}
32+
33+
// 처음 앱을 실행하는지
34+
var isFirstLaunch: Bool {
35+
get {
36+
PCUserDefaults.objectFor(key: .isFirstLaunch) as? Bool ?? true
37+
}
38+
set {
39+
_ = PCUserDefaults.setObjectFor(key: .isFirstLaunch, object: newValue)
40+
}
41+
}
3242
}
3343

3444
public extension PCUserDefaultsService {
@@ -52,4 +62,19 @@ public extension PCUserDefaultsService {
5262
func setBlockContactsLastUpdatedDate(_ date: Date) {
5363
self.blockContactsLastUpdatedDate = date
5464
}
65+
66+
/// 첫 실행 여부 확인
67+
func checkFirstLaunch() -> Bool {
68+
if isFirstLaunch {
69+
isFirstLaunch = false
70+
return true
71+
}
72+
return false
73+
}
74+
75+
// 강제로 첫 실행 플래그를 리셋 (테스트용)
76+
func resetFirstLaunch() {
77+
isFirstLaunch = true
78+
didSeeOnboarding = false
79+
}
5580
}

Data/LocalStorage/Sources/UserDefaults/UserDefaultsKeys.swift

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//
77

88
public enum UserDefaultsKeys: String {
9+
case isFirstLaunch
910
case didSeeOnboarding
1011
case socialLoginType
1112
case blockContactsLastUpdatedDate // TODO: - 서버에서 준다고 해서 지우기

Data/PCNetwork/Sources/Endpoint/CommonEndpoint.swift

+7
Original file line numberDiff line numberDiff line change
@@ -7,31 +7,38 @@
77

88
import Alamofire
99
import DTO
10+
import LocalStorage
1011

1112
public enum CommonEndpoint: TargetType {
1213
case healthCheck
14+
case withdrawWithPiece(WithdrawRequestDTO)
1315

1416
public var method: Alamofire.HTTPMethod {
1517
switch self {
1618
case .healthCheck: .get
19+
case .withdrawWithPiece: .delete
1720
}
1821
}
1922

2023
public var path: String {
2124
switch self {
2225
case .healthCheck: "api/common/health"
26+
case .withdrawWithPiece: "api/users"
2327
}
2428
}
2529

2630
public var headers: [String : String] {
2731
switch self {
2832
case .healthCheck: [:]
33+
case .withdrawWithPiece: [NetworkHeader.contentType : NetworkHeader.applicationJson,
34+
NetworkHeader.authorization: NetworkHeader.bearer(PCKeychainManager.shared.read(.accessToken) ?? "")]
2935
}
3036
}
3137

3238
public var requestType: RequestType {
3339
switch self {
3440
case .healthCheck: .plain
41+
case let .withdrawWithPiece(body): .body(body)
3542
}
3643
}
3744
}

Data/PCNetwork/Sources/Endpoint/LoginEndpoint.swift

+8-5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public enum LoginEndpoint: TargetType {
1313
case loginWithOAuth(body: SocialLoginRequsetDTO)
1414
case sendSMSCode(body: SMSCodeRequestDTO)
1515
case verifySMSCode(body: VerifySMSCodeRequestDTO)
16+
case socialLoginTokenRefresh(body: SocialLoginTokenRefreshRequestDTO)
1617

1718
public var headers: [String : String] {
1819
switch self {
@@ -28,6 +29,8 @@ public enum LoginEndpoint: TargetType {
2829
NetworkHeader.contentType: NetworkHeader.applicationJson,
2930
NetworkHeader.authorization: NetworkHeader.bearer(PCKeychainManager.shared.read(.accessToken) ?? "")
3031
]
32+
case .socialLoginTokenRefresh(body: let body):
33+
[:]
3134
}
3235
}
3336

@@ -39,7 +42,7 @@ public enum LoginEndpoint: TargetType {
3942
.post
4043
case .verifySMSCode:
4144
.post
42-
// case .socialLoginTokenRefresh: .patch
45+
case .socialLoginTokenRefresh: .patch
4346
}
4447
}
4548

@@ -51,8 +54,8 @@ public enum LoginEndpoint: TargetType {
5154
"api/register/sms/auth/code"
5255
case .verifySMSCode:
5356
"api/register/sms/auth/code/verify"
54-
// case .socialLoginTokenRefresh:
55-
// "/api/login/token/refresh"
57+
case .socialLoginTokenRefresh:
58+
"/api/login/token/refresh"
5659
}
5760
}
5861

@@ -64,8 +67,8 @@ public enum LoginEndpoint: TargetType {
6467
.body(body)
6568
case .verifySMSCode(let body):
6669
.body(body)
67-
// case let .socialLoginTokenRefresh(body):
68-
// .body(body)
70+
case let .socialLoginTokenRefresh(body):
71+
.body(body)
6972
}
7073
}
7174
}

Data/PCNetwork/Sources/NetworkHeader.swift

+2
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,6 @@ enum NetworkHeader {
1717
static func bearer(_ token: String) -> String {
1818
return "Bearer \(token)"
1919
}
20+
static let formUrlEncoded = "x-www-form-urlencoded"
21+
static let application = "application"
2022
}

Data/PCNetwork/Sources/NetworkService.swift

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import DTO
99
import Foundation
1010
import Alamofire
11+
import LocalStorage
1112

1213
public class NetworkService {
1314
public static let shared = NetworkService()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//
2+
// WithdrawRepository.swift
3+
// Repository
4+
//
5+
// Created by eunseou on 2/17/25.
6+
//
7+
8+
import DTO
9+
import Entities
10+
import PCNetwork
11+
import RepositoryInterfaces
12+
13+
final class WithdrawRepository: WithdrawRepositoryInterface {
14+
private let networkService: NetworkService
15+
16+
init(networkService: NetworkService) {
17+
self.networkService = networkService
18+
}
19+
20+
public func deleteUserAccount(reason: String) async throws -> VoidModel {
21+
let body = WithdrawRequestDTO(reason: reason)
22+
let endpoint = CommonEndpoint.withdrawWithPiece(body)
23+
let response: VoidResponseDTO = try await networkService.request(endpoint: endpoint)
24+
return response.toDomain()
25+
}
26+
public func withdrawWithApple() async throws -> VoidModel {
27+
28+
// TODO: - 애플 전용 탈퇴 (미완)
29+
/// 추후 서버와 맞춰볼 필요있음.
30+
let body = WithdrawRequestDTO(reason: "")
31+
let endpoint = CommonEndpoint.withdrawWithPiece(body)
32+
let response: VoidResponseDTO = try await networkService.request(endpoint: endpoint)
33+
return response.toDomain()
34+
}
35+
}
36+
37+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//
2+
// WithdrawRepositoryInterface.swift
3+
// RepositoryInterfaces
4+
//
5+
// Created by eunseou on 2/17/25.
6+
//
7+
8+
import SwiftUI
9+
import Entities
10+
11+
public protocol WithdrawRepositoryInterface {
12+
func deleteUserAccount(reason: String) async throws -> VoidModel
13+
func withdrawWithApple() async throws -> VoidModel
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//
2+
// deleteUserAccountUseCase.swift
3+
// UseCases
4+
//
5+
// Created by eunseou on 2/17/25.
6+
//
7+
8+
import SwiftUI
9+
import Entities
10+
import RepositoryInterfaces
11+
12+
public protocol DeleteUserAccountUseCase {
13+
func execute(reason: String) async throws -> VoidModel
14+
}
15+
16+
final class DeleteUserAccountUseCaseImpl: DeleteUserAccountUseCase {
17+
private let repository: WithdrawRepositoryInterface
18+
19+
public init(repository: WithdrawRepositoryInterface) {
20+
self.repository = repository
21+
}
22+
23+
func execute(reason: String) async throws -> VoidModel {
24+
return try await repository.deleteUserAccount(reason: reason)
25+
}
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//
2+
// GetAppleOauthToken.swift
3+
// UseCases
4+
//
5+
// Created by eunseou on 2/17/25.
6+
//
7+
8+
import SwiftUI
9+
import Entities
10+
import RepositoryInterfaces
11+
12+
public protocol RevokeAppleOauthTokenUseCase {
13+
func execute() async throws -> VoidModel
14+
}
15+
16+
final class RevokeAppleOauthTokenUseCaseImpl: RevokeAppleOauthTokenUseCase {
17+
private let repository: WithdrawRepositoryInterface
18+
19+
public init(repository: WithdrawRepositoryInterface) {
20+
self.repository = repository
21+
}
22+
23+
func execute() async throws -> VoidModel {
24+
return try await repository.withdrawWithApple()
25+
}
26+
}

Presentation/DesignSystem/Project.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,6 @@ let project = Project.dynamicResourceFramework(
2828
infoPlist: .extendingDefault(with: infoPlist),
2929
dependencies: [
3030
.utility(target: .PCFoundationExtension),
31-
.externalDependency(dependency: .Lottie),
31+
.externalDependency(dependency: .Lottie)
3232
]
3333
)

Presentation/Feature/Login/Sources/Login/LoginViewModel.swift

+1
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ extension LoginViewModel: ASAuthorizationControllerDelegate, ASAuthorizationCont
164164

165165
print("🍎 identityToken : \(identityToken)")
166166
print("🍎 authorizationCode : \(authorizationCode)")
167+
PCKeychainManager.shared.save(.appleAuthCode, value: authorizationCode)
167168

168169
Task {
169170
do {

Presentation/Feature/Onboarding/Sources/OnboardingView.swift

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ struct OnboardingView: View {
3131
.onAppear {
3232
viewModel.handleAction(.onAppear)
3333
}
34+
.toolbar(.hidden)
3435
}
3536

3637
private var topBar: some View {

0 commit comments

Comments
 (0)