Skip to content

Commit 4bc2af5

Browse files
committed
refresh
1 parent 5f85168 commit 4bc2af5

4 files changed

Lines changed: 177 additions & 130 deletions

File tree

LetsEatingTime_iOS/LetsEatingTime_iOSApp.swift

Lines changed: 58 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,27 @@
66
//
77

88
import SwiftUI
9+
import Alamofire
910

1011
@main
1112
struct LetsEatingTime_iOSApp: App {
1213

1314
@State private var isLoggedIn: Bool = false
1415
@State private var isTokenChecked: Bool = false
15-
16+
@State private var isFirstLaunch: Bool = true
17+
1618
var body: some Scene {
1719
WindowGroup {
18-
if isTokenChecked {
20+
if isFirstLaunch {
21+
OnboardingView()
22+
.onAppear {
23+
checkFirstLaunch()
24+
}
25+
} else if isTokenChecked {
1926
if isLoggedIn {
2027
BottomNavigationView()
2128
} else {
22-
OnboardingView()
29+
LoginView()
2330
}
2431
} else {
2532
ProgressView()
@@ -30,36 +37,59 @@ struct LetsEatingTime_iOSApp: App {
3037
}
3138
}
3239

33-
func checkAccessToken() {
34-
if let token = TokenManager.shared.accessToken {
35-
if isTokenExpired(token) {
36-
TokenManager.shared.refreshAccessToken { success, _ in
37-
DispatchQueue.main.async {
38-
isLoggedIn = success
39-
isTokenChecked = true
40-
}
41-
}
42-
} else {
43-
isLoggedIn = true
44-
isTokenChecked = true
45-
}
40+
func checkFirstLaunch() {
41+
let hasLaunchedKey = "hasLaunchedBefore"
42+
if UserDefaults.standard.bool(forKey: hasLaunchedKey) {
43+
isFirstLaunch = false
4644
} else {
47-
isTokenChecked = true
45+
UserDefaults.standard.set(true, forKey: hasLaunchedKey)
46+
isFirstLaunch = true
4847
}
4948
}
50-
51-
func isTokenExpired(_ token: String) -> Bool {
52-
let parts = token.split(separator: ".")
53-
guard parts.count == 3 else { return true }
5449

55-
let payloadData = Data(base64Encoded: String(parts[1])
56-
.replacingOccurrences(of: "-", with: "+")
57-
.replacingOccurrences(of: "_", with: "/") + "==") ?? Data()
50+
func checkAccessToken() {
51+
guard let accessToken = UserDefaults.standard.string(forKey: "accessToken") else {
52+
DispatchQueue.main.async {
53+
isLoggedIn = false
54+
isTokenChecked = true
55+
}
56+
return
57+
}
5858

59-
guard let payload = try? JSONSerialization.jsonObject(with: payloadData) as? [String: Any],
60-
let exp = payload["exp"] as? TimeInterval else { return true }
59+
let headers: HTTPHeaders = [
60+
"Authorization": "Bearer \(accessToken)"
61+
]
6162

62-
let expirationDate = Date(timeIntervalSince1970: exp)
63-
return Date() > expirationDate
63+
AF.request("http://www.dgsw-team-alt.xyz/api/user/profile", headers: headers)
64+
.validate()
65+
.responseJSON { response in
66+
switch response.result {
67+
case .success(let value):
68+
if let json = value as? [String: Any],
69+
let data = json["data"] as? [String: Any],
70+
let user = data["user"] as? [String: Any],
71+
let _ = user["name"] as? String {
72+
DispatchQueue.main.async {
73+
isLoggedIn = true
74+
isTokenChecked = true
75+
}
76+
} else {
77+
DispatchQueue.main.async {
78+
isLoggedIn = false
79+
isTokenChecked = true
80+
}
81+
}
82+
case .failure(let error):
83+
if let responseCode = response.response?.statusCode, responseCode == 401 {
84+
print("Token expired: \(error.localizedDescription)")
85+
} else {
86+
print("Request failed: \(error.localizedDescription)")
87+
}
88+
DispatchQueue.main.async {
89+
isLoggedIn = false
90+
isTokenChecked = true
91+
}
92+
}
93+
}
6494
}
6595
}

LetsEatingTime_iOS/View/Login/LoginView.swift

Lines changed: 86 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -14,92 +14,106 @@ struct LoginView: View {
1414
@State private var stayLoggedIn: Bool = false
1515
@State private var loginError: String? = nil
1616
@State private var isLoading: Bool = false
17-
@State private var isLoggedIn: Bool = false
17+
@State private var navigateToMain: Bool = false
18+
19+
@Environment(\.dismiss) private var dismiss
1820

1921
var body: some View {
20-
VStack {
21-
Image("title")
22-
.resizable()
23-
.scaledToFit()
24-
.frame(maxWidth: UIScreen.main.bounds.width * 0.7)
25-
.clipped()
26-
27-
Spacer()
28-
.frame(height: 30)
29-
30-
TextField("아이디를 입력해주세요", text: $id)
31-
.padding()
32-
.background(Color(hex: "#F2F2F2"))
33-
.cornerRadius(10)
34-
.padding(.bottom, 10)
35-
36-
SecureField("비밀번호를 입력해주세요", text: $password)
37-
.padding()
38-
.background(Color(hex: "#F2F2F2"))
39-
.cornerRadius(10)
40-
41-
Spacer()
42-
.frame(height: 20)
43-
44-
Button(action: login) {
45-
Text("로그인")
46-
.fontWeight(.bold)
47-
.frame(maxWidth: .infinity)
22+
NavigationView {
23+
VStack {
24+
Image("title")
25+
.resizable()
26+
.scaledToFit()
27+
.frame(maxWidth: UIScreen.main.bounds.width * 0.7)
28+
.clipped()
29+
30+
Spacer()
31+
.frame(height: 30)
32+
33+
TextField("아이디를 입력해주세요", text: $id)
4834
.padding()
49-
.background(Color(hex: "#636363"))
50-
.foregroundColor(.white)
35+
.background(Color(hex: "#F2F2F2"))
5136
.cornerRadius(10)
52-
}
53-
.disabled(isLoading)
37+
.padding(.bottom, 10)
5438

55-
if let error = loginError {
56-
Text(error)
57-
.foregroundColor(Color(hex: "#FE3939"))
58-
.font(.caption)
59-
}
39+
SecureField("비밀번호를 입력해주세요", text: $password)
40+
.padding()
41+
.background(Color(hex: "#F2F2F2"))
42+
.cornerRadius(10)
6043

61-
HStack {
62-
Toggle(isOn: $stayLoggedIn) {
63-
Text("로그인 상태 유지")
64-
.font(.system(size: 14))
65-
.foregroundColor(.black)
66-
}
67-
.toggleStyle(CheckboxToggleStyle())
6844
Spacer()
69-
}
70-
.padding(.top, 3)
45+
.frame(height: 20)
46+
47+
Button(action: login) {
48+
Text("로그인")
49+
.fontWeight(.bold)
50+
.frame(maxWidth: .infinity)
51+
.padding()
52+
.background(Color(hex: "#636363"))
53+
.foregroundColor(.white)
54+
.cornerRadius(10)
55+
}
56+
.disabled(isLoading)
7157

72-
HStack(spacing: 8) {
73-
NavigationLink(destination: ChangeCheckView()) {
74-
Text("비밀번호 변경")
75-
.font(.system(size: 14))
76-
.foregroundColor(.black)
58+
if let error = loginError {
59+
Text(error)
60+
.foregroundColor(Color(hex: "#FE3939"))
61+
.font(.caption)
62+
}
63+
64+
HStack {
65+
Toggle(isOn: $stayLoggedIn) {
66+
Text("로그인 상태 유지")
67+
.font(.system(size: 14))
68+
.foregroundColor(.black)
69+
}
70+
.toggleStyle(CheckboxToggleStyle())
71+
Spacer()
7772
}
73+
.padding(.top, 3)
7874

79-
Text("|")
80-
.font(.system(size: 14))
81-
.foregroundColor(Color(hex: "#BFBFBF"))
75+
HStack(spacing: 8) {
76+
NavigationLink(destination: ChangeCheckView()) {
77+
Text("비밀번호 변경")
78+
.font(.system(size: 14))
79+
.foregroundColor(.black)
80+
}
8281

83-
NavigationLink(destination: RegisterIdView()) {
84-
Text("회원가입")
82+
Text("|")
8583
.font(.system(size: 14))
86-
.foregroundColor(.black)
84+
.foregroundColor(Color(hex: "#BFBFBF"))
85+
86+
NavigationLink(destination: RegisterIdView()) {
87+
Text("회원가입")
88+
.font(.system(size: 14))
89+
.foregroundColor(.black)
90+
}
8791
}
88-
}
89-
.padding(.top, 16)
92+
.padding(.top, 16)
9093

91-
Spacer()
92-
.frame(height: 30)
94+
Spacer()
95+
.frame(height: 30)
9396

94-
Image("eating_woman")
95-
.resizable()
96-
.scaledToFit()
97-
.clipped()
97+
Image("eating_woman")
98+
.resizable()
99+
.scaledToFit()
100+
.clipped()
101+
}
102+
.padding(.init(top: 16, leading: 32, bottom: 0, trailing: 32))
103+
.background(
104+
NavigationLink(
105+
destination: BottomNavigationView()
106+
.navigationBarBackButtonHidden(true)
107+
.onAppear {
108+
dismiss()
109+
},
110+
isActive: $navigateToMain
111+
) {
112+
EmptyView()
113+
}
114+
)
115+
.navigationBarBackButtonHidden()
98116
}
99-
.padding(.init(top: 16, leading: 32, bottom: 0, trailing: 32))
100-
.background(
101-
NavigationLink(destination: BottomNavigationView(), isActive: $isLoggedIn) { EmptyView() }
102-
)
103117
.navigationBarBackButtonHidden()
104118
}
105119

@@ -133,9 +147,9 @@ struct LoginView: View {
133147
print(accessToken)
134148
print("---")
135149
print(refreshToken)
136-
isLoggedIn = true
150+
navigateToMain = true
137151
}
138-
case .failure(let error):
152+
case .failure:
139153
loginError = "아이디와 비밀번호를 확인해주세요"
140154
}
141155
}

LetsEatingTime_iOS/View/Navigation/BottomNavigationView.swift

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -49,40 +49,43 @@ struct BottomNavigationView: View {
4949
}
5050

5151
var body: some View {
52-
if isLoggedOut {
53-
LoginView()
54-
} else {
55-
TabView(selection: $selectedTab) {
56-
StoreView()
57-
.tabItem {
58-
Image(systemName: "cart.fill")
59-
}
60-
.tag(0)
52+
NavigationView {
53+
if isLoggedOut {
54+
LoginView()
55+
} else {
56+
TabView(selection: $selectedTab) {
57+
StoreView()
58+
.tabItem {
59+
Image(systemName: "cart.fill")
60+
}
61+
.tag(0)
6162

62-
MainView()
63-
.tabItem {
64-
Image(systemName: "house.fill")
65-
}
66-
.tag(1)
63+
MainView()
64+
.tabItem {
65+
Image(systemName: "house.fill")
66+
}
67+
.tag(1)
6768

68-
ProfileView()
69-
.tabItem {
70-
Image(systemName: "person.crop.circle.fill")
71-
}
72-
.tag(2)
73-
}
74-
.navigationBarBackButtonHidden()
75-
.accentColor(Color(hex: "#FE6B4B"))
76-
.alert(isPresented: .constant(!isAccessTokenValid)) {
77-
Alert(
78-
title: Text("로그인 만료"),
79-
message: Text("로그인이 만료되었습니다. 다시 로그인해주세요."),
80-
dismissButton: .default(Text("확인")) {
81-
logout()
82-
}
83-
)
69+
ProfileView()
70+
.tabItem {
71+
Image(systemName: "person.crop.circle.fill")
72+
}
73+
.tag(2)
74+
}
75+
.navigationBarBackButtonHidden()
76+
.accentColor(Color(hex: "#FE6B4B"))
77+
.alert(isPresented: .constant(!isAccessTokenValid)) {
78+
Alert(
79+
title: Text("로그인 만료"),
80+
message: Text("로그인이 만료되었습니다. 다시 로그인해주세요."),
81+
dismissButton: .default(Text("확인")) {
82+
logout()
83+
}
84+
)
85+
}
8486
}
8587
}
88+
.navigationBarBackButtonHidden()
8689
}
8790

8891
private func logout() {

0 commit comments

Comments
 (0)