forked from AcaMate/AcaMate_iOS
[✨] 학원 선택 페이지 작성 및 기존 코드 로직 분리 작업
This commit is contained in:
parent
ca49db680c
commit
71b2c3389f
Binary file not shown.
|
@ -7,9 +7,12 @@
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
// MARK: - ACAMATE
|
// MARK: - ACAMATE
|
||||||
// APPSTORE_URL : https://apps.apple.com/us/app/%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%A9%94%EC%9D%B4%ED%8A%B8/id6739448113
|
// APPSTORE_URL : https://apps.apple.com/us/app/%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%A9%94%EC%9D%B4%ED%8A%B8/id6739448113
|
||||||
|
/// 주의사항
|
||||||
|
/// plist 에서 http 설정 걸려있는거 지워야 함
|
||||||
#if LOCAL
|
#if LOCAL
|
||||||
//public let API_URL: String = "http://0.0.0.0:5144"
|
public let API_URL: String = "http://10.149.217.64:5144"
|
||||||
public let API_URL: String = "https://localhost:7086"
|
//public let API_URL: String = "http://localhost:5144"
|
||||||
|
//public let API_URL: String = "https://localhost:7086"
|
||||||
public let WS_URL: String = "ws://localhost:5144"
|
public let WS_URL: String = "ws://localhost:5144"
|
||||||
|
|
||||||
/// 회사 맥에서 사용할 경우의 URL
|
/// 회사 맥에서 사용할 경우의 URL
|
||||||
|
|
|
@ -1,117 +1,117 @@
|
||||||
|
////
|
||||||
|
//// AccountLoginView.swift
|
||||||
|
//// AcaMate
|
||||||
|
////
|
||||||
|
//// Created by Sean Kim on 12/14/24.
|
||||||
|
////
|
||||||
//
|
//
|
||||||
// AccountLoginView.swift
|
//import SwiftUI
|
||||||
// AcaMate
|
|
||||||
//
|
//
|
||||||
// Created by Sean Kim on 12/14/24.
|
//struct AccountLoginView: View {
|
||||||
//
|
// @ObservedObject var loginVM.: LoginViewModel
|
||||||
|
// @Binding var userId: String
|
||||||
import SwiftUI
|
// @Binding var password: String
|
||||||
|
// @Binding var isSecure: Bool
|
||||||
struct AccountLoginView: View {
|
// @Binding var isSave: Bool
|
||||||
@ObservedObject var viewModel: LoginViewModel
|
// var body: some View {
|
||||||
@Binding var userId: String
|
// VStack(spacing: 0) {
|
||||||
@Binding var password: String
|
// ZStack(alignment: .leading) {
|
||||||
@Binding var isSecure: Bool
|
// if userId.isEmpty {
|
||||||
@Binding var isSave: Bool
|
// Text("아이디를 입력하세요.")
|
||||||
var body: some View {
|
// .font(.nps(font: .regular, size: 16))
|
||||||
VStack(spacing: 0) {
|
// .foregroundStyle(Color(.Text.border))
|
||||||
ZStack(alignment: .leading) {
|
// .padding(EdgeInsets(top: 12, leading: 24, bottom: 12, trailing: 24))
|
||||||
if userId.isEmpty {
|
// }
|
||||||
Text("아이디를 입력하세요.")
|
// CustomTextField(placeholder: "", text: $userId)
|
||||||
.font(.nps(font: .regular, size: 16))
|
// .frame(maxWidth: .infinity,maxHeight: 24)
|
||||||
.foregroundStyle(Color(.Text.border))
|
// .padding(EdgeInsets(top: 12, leading: 24, bottom: 12, trailing: 24))
|
||||||
.padding(EdgeInsets(top: 12, leading: 24, bottom: 12, trailing: 24))
|
// }
|
||||||
}
|
// .background {
|
||||||
CustomTextField(placeholder: "", text: $userId)
|
// RoundedRectangle(cornerRadius: 24)
|
||||||
.frame(maxWidth: .infinity,maxHeight: 24)
|
// .foregroundStyle(.white)
|
||||||
.padding(EdgeInsets(top: 12, leading: 24, bottom: 12, trailing: 24))
|
// }
|
||||||
}
|
// .padding(EdgeInsets(top: 0, leading: 12, bottom: 8, trailing: 12))
|
||||||
.background {
|
//
|
||||||
RoundedRectangle(cornerRadius: 24)
|
// ZStack(alignment: .leading) {
|
||||||
.foregroundStyle(.white)
|
// if password.isEmpty {
|
||||||
}
|
// Text("비밀번호를 입력하세요.")
|
||||||
.padding(EdgeInsets(top: 0, leading: 12, bottom: 8, trailing: 12))
|
// .font(.nps(font: .regular, size: 16))
|
||||||
|
// .foregroundStyle(Color(.Text.border))
|
||||||
ZStack(alignment: .leading) {
|
// .padding(EdgeInsets(top: 12, leading: 24, bottom: 12, trailing: 24))
|
||||||
if password.isEmpty {
|
// }
|
||||||
Text("비밀번호를 입력하세요.")
|
// CustomTextField(placeholder: "", text: $password, isSecure: $isSecure)
|
||||||
.font(.nps(font: .regular, size: 16))
|
// .frame(maxWidth: .infinity,maxHeight: 24)
|
||||||
.foregroundStyle(Color(.Text.border))
|
// .padding(EdgeInsets(top: 12, leading: 24, bottom: 12, trailing: 24))
|
||||||
.padding(EdgeInsets(top: 12, leading: 24, bottom: 12, trailing: 24))
|
//
|
||||||
}
|
// HStack {
|
||||||
CustomTextField(placeholder: "", text: $password, isSecure: $isSecure)
|
// Spacer()
|
||||||
.frame(maxWidth: .infinity,maxHeight: 24)
|
// Button {
|
||||||
.padding(EdgeInsets(top: 12, leading: 24, bottom: 12, trailing: 24))
|
// isSecure.toggle()
|
||||||
|
// } label: {
|
||||||
HStack {
|
// if password.isEmpty {
|
||||||
Spacer()
|
// Rectangle()
|
||||||
Button {
|
// .frame(width: 16, height: 2)
|
||||||
isSecure.toggle()
|
// .foregroundStyle(Color(.Text.border))
|
||||||
} label: {
|
// .padding(.trailing,24)
|
||||||
if password.isEmpty {
|
// }
|
||||||
Rectangle()
|
// else {
|
||||||
.frame(width: 16, height: 2)
|
// if isSecure {
|
||||||
.foregroundStyle(Color(.Text.border))
|
// Image(systemName: "eye")
|
||||||
.padding(.trailing,24)
|
// .frame(width: 16, height: 16)
|
||||||
}
|
// .foregroundStyle(Color(.Text.detail))
|
||||||
else {
|
// .padding(.trailing,24)
|
||||||
if isSecure {
|
// }
|
||||||
Image(systemName: "eye")
|
// else {
|
||||||
.frame(width: 16, height: 16)
|
// Image(systemName: "eye.slash")
|
||||||
.foregroundStyle(Color(.Text.detail))
|
// .frame(width: 16, height: 16)
|
||||||
.padding(.trailing,24)
|
// .foregroundStyle(Color(.Text.detail))
|
||||||
}
|
// .padding(.trailing,24)
|
||||||
else {
|
//
|
||||||
Image(systemName: "eye.slash")
|
// }
|
||||||
.frame(width: 16, height: 16)
|
// }
|
||||||
.foregroundStyle(Color(.Text.detail))
|
// }
|
||||||
.padding(.trailing,24)
|
// }
|
||||||
|
// }
|
||||||
}
|
// .background {
|
||||||
}
|
// RoundedRectangle(cornerRadius: 24)
|
||||||
}
|
// .foregroundStyle(.white)
|
||||||
}
|
// }
|
||||||
}
|
// .padding(EdgeInsets(top: 0, leading: 12, bottom: 8, trailing: 12))
|
||||||
.background {
|
//
|
||||||
RoundedRectangle(cornerRadius: 24)
|
// Button {
|
||||||
.foregroundStyle(.white)
|
// isSave.toggle()
|
||||||
}
|
// } label: {
|
||||||
.padding(EdgeInsets(top: 0, leading: 12, bottom: 8, trailing: 12))
|
// HStack(alignment: .center, spacing: 4) {
|
||||||
|
// Spacer(minLength: 1)
|
||||||
Button {
|
// if isSave {
|
||||||
isSave.toggle()
|
// Image(systemName: "checkmark.square")
|
||||||
} label: {
|
// .foregroundStyle(Color(.Second.normal))
|
||||||
HStack(alignment: .center, spacing: 4) {
|
// .frame(width: 24, height: 24)
|
||||||
Spacer(minLength: 1)
|
// } else {
|
||||||
if isSave {
|
// Image(systemName: "square")
|
||||||
Image(systemName: "checkmark.square")
|
// .foregroundStyle(Color(.Second.normal))
|
||||||
.foregroundStyle(Color(.Second.normal))
|
// .frame(width: 24, height: 24)
|
||||||
.frame(width: 24, height: 24)
|
// }
|
||||||
} else {
|
//
|
||||||
Image(systemName: "square")
|
// Text("로그인 정보 저장")
|
||||||
.foregroundStyle(Color(.Second.normal))
|
// .font(.nps(font: .regular, size: 16))
|
||||||
.frame(width: 24, height: 24)
|
// .foregroundStyle(Color(.Text.detail))
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
Text("로그인 정보 저장")
|
// .padding(EdgeInsets(top: 0, leading: 0, bottom: 24, trailing: 12))
|
||||||
.font(.nps(font: .regular, size: 16))
|
//
|
||||||
.foregroundStyle(Color(.Text.detail))
|
// Button {
|
||||||
}
|
// loginVM..loginAction.send(true)
|
||||||
}
|
// } label: {
|
||||||
.padding(EdgeInsets(top: 0, leading: 0, bottom: 24, trailing: 12))
|
// Text("로그인")
|
||||||
|
// .font(.nps(font: .bold, size: 24))
|
||||||
Button {
|
// .foregroundStyle(Color(.Text.white))
|
||||||
viewModel.loginAction.send(true)
|
// .padding(EdgeInsets(top: 8, leading: 48, bottom: 8, trailing: 48))
|
||||||
} label: {
|
// .background{
|
||||||
Text("로그인")
|
// RoundedRectangle(cornerRadius: 12)
|
||||||
.font(.nps(font: .bold, size: 24))
|
// .foregroundStyle(Color(.Second.normal))
|
||||||
.foregroundStyle(Color(.Text.white))
|
// }
|
||||||
.padding(EdgeInsets(top: 8, leading: 48, bottom: 8, trailing: 48))
|
// }
|
||||||
.background{
|
// }
|
||||||
RoundedRectangle(cornerRadius: 12)
|
// }
|
||||||
.foregroundStyle(Color(.Second.normal))
|
//}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -11,16 +11,6 @@ import Combine
|
||||||
struct LoginView: View {
|
struct LoginView: View {
|
||||||
@EnvironmentObject var appVM: AppViewModel
|
@EnvironmentObject var appVM: AppViewModel
|
||||||
@StateObject private var loginVM = LoginViewModel()
|
@StateObject private var loginVM = LoginViewModel()
|
||||||
@State var cancellables: Set<AnyCancellable> = []
|
|
||||||
// @Binding var naviState : NaviState
|
|
||||||
|
|
||||||
@State var selectIdLogin: Bool = false
|
|
||||||
|
|
||||||
@State var userId: String = ""
|
|
||||||
@State var password: String = ""
|
|
||||||
@State var isSecure: Bool = true
|
|
||||||
@State var isSave: Bool = false
|
|
||||||
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
|
@ -28,22 +18,22 @@ struct LoginView: View {
|
||||||
Image(.Logo.appIcon)
|
Image(.Logo.appIcon)
|
||||||
.resizable()
|
.resizable()
|
||||||
.frame(width: 200, height: 200)
|
.frame(width: 200, height: 200)
|
||||||
// .padding(.top, 80)
|
// .padding(.top, 80)
|
||||||
.padding(.bottom, 84)
|
.padding(.bottom, 84)
|
||||||
|
|
||||||
/// 앱 아이콘 이미지
|
/// 앱 아이콘 이미지
|
||||||
VStack(spacing: 16) {
|
VStack(spacing: 16) {
|
||||||
Button {
|
Button {
|
||||||
// MARK: - TODO, 카카오 계정 로그인 구현
|
// MARK: - TODO, 카카오 계정 로그인 구현
|
||||||
appVM.isLoading.toggle()
|
loginVM.toggleLoading = true
|
||||||
loginAction(type: .Kakao)
|
loginVM.loginAction(type: .Kakao)
|
||||||
|
|
||||||
} label: {
|
} label: {
|
||||||
makeButton(image: Image(.Logo.kakaoIcon),color: Color(.Other.yellow), "카카오 계정으로 시작하기")
|
makeButton(image: Image(.Logo.kakaoIcon),color: Color(.Other.yellow), "카카오 계정으로 시작하기")
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
// MARK: - TODO, 애플 계정 로그인 구현
|
// MARK: - TODO, 애플 계정 로그인 구현
|
||||||
// appVM.naviState.set(act: .MOVE, path: .Main)
|
|
||||||
appVM.naviState.set(act: .ADD, path: .SelectAcademy(bids: ["AA0000", "AA0001"]))
|
appVM.naviState.set(act: .ADD, path: .SelectAcademy(bids: ["AA0000", "AA0001"]))
|
||||||
|
|
||||||
} label: {
|
} label: {
|
||||||
|
@ -53,66 +43,18 @@ struct LoginView: View {
|
||||||
.padding([.leading,.trailing], 28)
|
.padding([.leading,.trailing], 28)
|
||||||
|
|
||||||
Spacer(minLength: 1)
|
Spacer(minLength: 1)
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
VStack(spacing: 16) {
|
|
||||||
|
|
||||||
Button {
|
|
||||||
// MARK: TO-DO
|
|
||||||
// 카카오 로그인 연동
|
|
||||||
naviState.set(act: .MOVE, path: .Main)
|
|
||||||
} label: {
|
|
||||||
HStack(spacing: 24) {
|
|
||||||
Image("Kakao_Icon")
|
|
||||||
.resizable()
|
|
||||||
.frame(width: 32, height: 32)
|
|
||||||
Text("카카오 계정으로 시작하기")
|
|
||||||
.font(.nps(font: .regular, size: 16))
|
|
||||||
.foregroundStyle(Color(.Text.black))
|
|
||||||
}
|
|
||||||
.frame(maxWidth: .infinity)
|
|
||||||
.padding(12)
|
|
||||||
.background {
|
|
||||||
RoundedRectangle(cornerRadius: 12)
|
|
||||||
.foregroundStyle(Color(.Other.yellow))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.frame(maxWidth: .infinity)
|
|
||||||
/// KAKAO 로그인 버튼
|
|
||||||
|
|
||||||
Button {
|
|
||||||
// MARK: TO-DO
|
|
||||||
// 애플 로그인 연동
|
|
||||||
} label: {
|
|
||||||
HStack(spacing: 24) {
|
|
||||||
Image(systemName: "apple.logo")
|
|
||||||
.resizable()
|
|
||||||
.accentColor(Color(.Text.white))
|
|
||||||
.frame(width: 32, height: 32)
|
|
||||||
|
|
||||||
Text("애플 계정으로 시작하기")
|
|
||||||
.font(.nps(font: .regular, size: 16))
|
|
||||||
.foregroundStyle(Color(.Text.white))
|
|
||||||
}
|
|
||||||
.frame(maxWidth: .infinity)
|
|
||||||
.padding(12)
|
|
||||||
.background {
|
|
||||||
RoundedRectangle(cornerRadius: 12)
|
|
||||||
.foregroundStyle(Color(.Text.black))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.frame(maxWidth: .infinity)
|
|
||||||
/// APPLE 로그인 버튼
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
}
|
|
||||||
.onAppear {
|
|
||||||
subscribeLoginAction()
|
|
||||||
}
|
}
|
||||||
.frame(maxWidth: .infinity,maxHeight: .infinity)
|
.frame(maxWidth: .infinity,maxHeight: .infinity)
|
||||||
.fullDrawView(.Normal.normal)
|
.fullDrawView(.Normal.normal)
|
||||||
|
.onChange(of: loginVM.navigateToAcademy, { _, _ in
|
||||||
|
appVM.naviState.set(act: .ADD, path: .SelectAcademy(bids: loginVM.bidArray))
|
||||||
|
})
|
||||||
|
|
||||||
|
.onChange(of: loginVM.toggleLoading) { _, new in
|
||||||
|
appVM.isLoading = new
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeButton(image: Image, color: Color? = nil, _ body: String) -> some View {
|
func makeButton(image: Image, color: Color? = nil, _ body: String) -> some View {
|
||||||
|
@ -134,58 +76,4 @@ struct LoginView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func subscribeLoginAction() {
|
|
||||||
loginVM.loginAction
|
|
||||||
.sink { isTapped in
|
|
||||||
if isTapped {
|
|
||||||
if userId.isEmpty || password.isEmpty {
|
|
||||||
appVM.alertData = SetAlertData().setErrorLogin()
|
|
||||||
appVM.showAlert.toggle()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
}
|
|
||||||
printLog("로그인")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.store(in: &cancellables)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func loginAction(type: SNSLoginType) {
|
|
||||||
LoginController().login(type)
|
|
||||||
.flatMap{ snsId in
|
|
||||||
loadAPIData(url: "\(API_URL)",
|
|
||||||
path: "/api/v1/in/user/login",
|
|
||||||
parameters: [
|
|
||||||
"sns_id": "\(snsId.snsId)",
|
|
||||||
"acctype": "\(type == .Apple ? "ST00": "ST01")"
|
|
||||||
],
|
|
||||||
decodingType: APIResponse<User_Academy>.self)
|
|
||||||
|
|
||||||
}
|
|
||||||
.sink { completion in
|
|
||||||
switch completion {
|
|
||||||
case .failure(let error):
|
|
||||||
printLog("\(error)")
|
|
||||||
appVM.isLoading.toggle()
|
|
||||||
case .finished:
|
|
||||||
appVM.isLoading.toggle()
|
|
||||||
}
|
|
||||||
} receiveValue: { response in
|
|
||||||
guard let ua = response as? APIResponse<User_Academy> else {return}
|
|
||||||
if let bids = ua.data.toStringDict()["bid"] {
|
|
||||||
printLog(bids)
|
|
||||||
if let bidArray: [String] = jsonToSwift(bids) {
|
|
||||||
// 정상 적으로 학원 ID를 불러 온거니까 이제 여기서 할 걸 정해야 함
|
|
||||||
appVM.naviState.set(act: .ADD, path: .SelectAcademy(bids: bidArray))
|
|
||||||
} else {
|
|
||||||
printLog("JSON 변환 실패")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.store(in: &cancellables)
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,56 +6,131 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import Combine
|
|
||||||
|
|
||||||
|
|
||||||
struct SelectAcademyView: View {
|
struct SelectAcademyView: View {
|
||||||
@State var cancellables: Set<AnyCancellable> = []
|
@EnvironmentObject var appVM: AppViewModel
|
||||||
|
@StateObject var saVM = SelectAcademyViewModel()
|
||||||
|
|
||||||
|
@State private var scrollOffset: CGPoint = .zero
|
||||||
|
|
||||||
var bids: [String]
|
var bids: [String]
|
||||||
@State private var academyCode: String = ""
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
Spacer()
|
Spacer()
|
||||||
.frame(height: 100)
|
.frame(maxHeight: 100)
|
||||||
Image(.Logo.appIcon)
|
Image(.Logo.appIcon)
|
||||||
.resizable()
|
.resizable()
|
||||||
.frame(width: 200, height: 200)
|
.frame(width: 200, height: 200)
|
||||||
CustomTextField(placeholder: "학원 코드 입력", text: $academyCode)
|
|
||||||
.frame(maxWidth: .infinity,maxHeight: 48)
|
VStack(spacing: 4) {
|
||||||
.padding(EdgeInsets(top: 0, leading: 20, bottom: 0, trailing: 20))
|
HStack(spacing: 0){
|
||||||
.background {
|
Text("학원 코드")
|
||||||
RoundedRectangle(cornerRadius: 24)
|
.font(.nps(font: .bold, size: 16))
|
||||||
|
.foregroundStyle(Color(.Text.detail))
|
||||||
|
Spacer(minLength: 1)
|
||||||
|
}
|
||||||
|
//MARK: TO-DO
|
||||||
|
// 문제
|
||||||
|
// 1. txf 클릭시 겉 뷰가 작아지는 현상
|
||||||
|
// 2. 코드 입력시 버튼 나타나게 하기
|
||||||
|
CustomTextField(placeholder: "학원 코드 입력", text: $saVM.academyCode)
|
||||||
|
.frame(maxWidth: .infinity,maxHeight: 48)
|
||||||
|
.padding(EdgeInsets(top: 0, leading: 20, bottom: 0, trailing: 20))
|
||||||
|
.background {
|
||||||
|
RoundedRectangle(cornerRadius: 24)
|
||||||
|
.foregroundStyle(Color(.Normal.light))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(EdgeInsets(top: 12, leading: 24, bottom: 40, trailing: 24))
|
||||||
|
|
||||||
|
VStack(spacing: 4) {
|
||||||
|
HStack(spacing: 0){
|
||||||
|
Text("학원 목록")
|
||||||
|
.font(.nps(font: .bold, size: 16))
|
||||||
|
.foregroundStyle(Color(.Text.detail))
|
||||||
|
Spacer(minLength: 1)
|
||||||
|
}
|
||||||
|
.padding(EdgeInsets(top: 12, leading: 24, bottom: 0, trailing: 24))
|
||||||
|
OffsetObservableScrollView(showsIndicators: false, scrollOffset: $scrollOffset) { proxy in
|
||||||
|
VStack(spacing: 12) {
|
||||||
|
ForEach(Array(saVM.academyList.enumerated()), id: \.offset) { index, academy in
|
||||||
|
AcademyCell(numbering: index, academy: saVM.academyList[index],selectNum: $saVM.selectNum){
|
||||||
|
saVM.toggleSelection(for: index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(EdgeInsets(top: 0, leading: 24, bottom: 12, trailing: 24))
|
||||||
|
}
|
||||||
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(minLength: 1)
|
||||||
|
|
||||||
|
Button {
|
||||||
|
appVM.naviState.set(act: .MOVE, path: .Main)
|
||||||
|
} label: {
|
||||||
|
ZStack {
|
||||||
|
RoundedRectangle(cornerRadius: 12)
|
||||||
|
.fill(Color(.Second.normal))
|
||||||
|
Text("입장하기")
|
||||||
|
.font(.nps(size: 16))
|
||||||
.foregroundStyle(Color(.Normal.light))
|
.foregroundStyle(Color(.Normal.light))
|
||||||
}
|
}
|
||||||
// .padding([.leading, .trailing], 24)
|
.frame(height: 56)
|
||||||
.padding(EdgeInsets(top: 12, leading: 24, bottom: 12, trailing: 24))
|
}
|
||||||
|
.opacity(saVM.selectNum >= 0 ? 1 : 0)
|
||||||
|
.padding(EdgeInsets(top: 12, leading: 24, bottom: 12, trailing: 24))
|
||||||
|
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
loadAPIData(url: "\(API_URL)",
|
saVM.loadAcademy(bids: bids)
|
||||||
path: "/api/v1/in/member/academy",
|
|
||||||
method: .post,
|
|
||||||
parameters: ["bids": bids],
|
|
||||||
decodingType: APIResponse<[AcademyName]>.self)
|
|
||||||
.sink { completion in
|
|
||||||
|
|
||||||
switch completion {
|
|
||||||
case .failure(let error):
|
|
||||||
printLog("\(error)")
|
|
||||||
// appVM.isLoading.toggle()
|
|
||||||
case .finished:
|
|
||||||
break
|
|
||||||
// appVM.isLoading.toggle()
|
|
||||||
}
|
|
||||||
} receiveValue: { response in
|
|
||||||
guard let ua = response as? APIResponse<[AcademyName]> else {return}
|
|
||||||
printLog(ua)
|
|
||||||
}
|
|
||||||
.store(in: &cancellables)
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct AcademyCell: View {
|
||||||
|
let numbering: Int
|
||||||
|
let academy: AcademyName
|
||||||
|
@Binding var selectNum: Int
|
||||||
|
let action: VOID_TO_VOID
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
HStack(alignment: .center, spacing: 0) {
|
||||||
|
Image(.Logo.pageIcon)
|
||||||
|
.resizable()
|
||||||
|
.frame(width: 32, height: 32, alignment: .center)
|
||||||
|
.padding(12)
|
||||||
|
Spacer(minLength: 1)
|
||||||
|
|
||||||
|
Text("\(academy.name)")
|
||||||
|
.font(.nps(size: 18))
|
||||||
|
.foregroundStyle(Color(.Text.detail))
|
||||||
|
.multilineStyle(.center)
|
||||||
|
|
||||||
|
Spacer(minLength: 1)
|
||||||
|
|
||||||
|
Button{
|
||||||
|
// saVM.toggleSelection(for: numbering)
|
||||||
|
action()
|
||||||
|
} label: {
|
||||||
|
Circle()
|
||||||
|
.stroke(Color(.Text.detail), lineWidth: 4)
|
||||||
|
.fill (selectNum == numbering ? Color(.Point.normal) : Color(.Normal.normal))
|
||||||
|
.frame(width: 18, height: 18)
|
||||||
|
}
|
||||||
|
.frame(width: 32, height: 32)
|
||||||
|
.padding(12)
|
||||||
|
}
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
.background {
|
||||||
|
RoundedRectangle(cornerRadius: 12)
|
||||||
|
.stroke(Color(.Second.normal), lineWidth: 2)
|
||||||
|
}
|
||||||
|
.onTapGesture {
|
||||||
|
action()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,49 @@
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import Combine
|
import Combine
|
||||||
|
|
||||||
|
|
||||||
class LoginViewModel: ObservableObject {
|
class LoginViewModel: ObservableObject {
|
||||||
let loginAction = CurrentValueSubject<Bool, Never>(false)
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
@Published var toggleLoading: Bool = false
|
||||||
|
|
||||||
|
@Published var navigateToAcademy: Bool = false
|
||||||
|
@Published var bidArray: [String] = []
|
||||||
|
|
||||||
|
func loginAction(type: SNSLoginType) {
|
||||||
|
LoginController().login(type)
|
||||||
|
.flatMap{ snsId in
|
||||||
|
loadAPIData(url: "\(API_URL)",
|
||||||
|
path: "/api/v1/in/user/login",
|
||||||
|
parameters: [
|
||||||
|
"acctype": "\(type == .Apple ? "ST00": "ST01")",
|
||||||
|
"sns_id": "\(snsId.snsId)"
|
||||||
|
],
|
||||||
|
decodingType: APIResponse<User_Academy>.self)
|
||||||
|
|
||||||
|
}
|
||||||
|
.sink { [weak self] completion in
|
||||||
|
switch completion {
|
||||||
|
case .failure(let error):
|
||||||
|
printLog("\(error)")
|
||||||
|
self?.toggleLoading = false
|
||||||
|
case .finished:
|
||||||
|
self?.toggleLoading = false
|
||||||
|
}
|
||||||
|
} receiveValue: { [weak self] response in
|
||||||
|
guard let self = self else { return }
|
||||||
|
guard let ua = response as? APIResponse<User_Academy> else {return}
|
||||||
|
if let bids = ua.data.toStringDict()["bid"] {
|
||||||
|
printLog(bids)
|
||||||
|
if let bidArray: [String] = jsonToSwift(bids) {
|
||||||
|
// 정상 적으로 학원 ID를 불러 온거니까 이제 여기서 할 걸 정해야 함
|
||||||
|
printLog("GOOD")
|
||||||
|
self.navigateToAcademy = true
|
||||||
|
self.bidArray = bidArray
|
||||||
|
} else {
|
||||||
|
printLog("JSON 변환 실패")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
45
AcaMate/3. ViewModel/SelectAcademyViewModel.swift
Normal file
45
AcaMate/3. ViewModel/SelectAcademyViewModel.swift
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
//
|
||||||
|
// SelectAcademyViewModel.swift
|
||||||
|
// AcaMate
|
||||||
|
//
|
||||||
|
// Created by TAnine on 2/19/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
import Combine
|
||||||
|
|
||||||
|
class SelectAcademyViewModel: ObservableObject {
|
||||||
|
private var cancellables: Set<AnyCancellable> = []
|
||||||
|
|
||||||
|
@Published var academyCode: String = ""
|
||||||
|
@Published var academyList: [AcademyName] = []
|
||||||
|
@Published var selectNum: Int = -1
|
||||||
|
|
||||||
|
func loadAcademy(bids: [String]) {
|
||||||
|
loadAPIData(url: "\(API_URL)",
|
||||||
|
path: "/api/v1/in/member/academy",
|
||||||
|
method: .post,
|
||||||
|
parameters: ["bids": bids],
|
||||||
|
decodingType: APIResponse<[AcademyName]>.self)
|
||||||
|
.sink { completion in
|
||||||
|
switch completion {
|
||||||
|
case .failure(let error):
|
||||||
|
printLog("\(error)")
|
||||||
|
case .finished:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} receiveValue: { [weak self] response in
|
||||||
|
guard let self = self else {return}
|
||||||
|
guard let academyNames = response as? APIResponse<[AcademyName]> else {return}
|
||||||
|
self.academyList = academyNames.data
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
|
}
|
||||||
|
|
||||||
|
func toggleSelection(for index: Int){
|
||||||
|
if selectNum == index {
|
||||||
|
selectNum = -1
|
||||||
|
} else {
|
||||||
|
selectNum = index
|
||||||
|
}}
|
||||||
|
}
|
|
@ -11,7 +11,6 @@ import KakaoSDKCommon
|
||||||
import KakaoSDKAuth
|
import KakaoSDKAuth
|
||||||
import KakaoSDKUser
|
import KakaoSDKUser
|
||||||
|
|
||||||
import Alamofire
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
class LoginController {
|
class LoginController {
|
||||||
|
@ -29,7 +28,6 @@ class LoginController {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.eraseToAnyPublisher()
|
.eraseToAnyPublisher()
|
||||||
//
|
|
||||||
|
|
||||||
case .Apple:
|
case .Apple:
|
||||||
return Fail(error: NSError(domain: "Apple login not implemented", code: 1, userInfo: nil))
|
return Fail(error: NSError(domain: "Apple login not implemented", code: 1, userInfo: nil))
|
||||||
|
|
|
@ -16,12 +16,13 @@ public func loadAPIData<T: Decodable>(url: String, path: String,
|
||||||
parameters: [String: Any],
|
parameters: [String: Any],
|
||||||
headers: HTTPHeaders = [:],//["Accept": "application/json"],
|
headers: HTTPHeaders = [:],//["Accept": "application/json"],
|
||||||
decodingType: T.Type) -> Future<Any, Error> {
|
decodingType: T.Type) -> Future<Any, Error> {
|
||||||
|
let encoding: ParameterEncoding = (method == .get) ? URLEncoding.default : JSONEncoding.default
|
||||||
return Future { promise in
|
return Future { promise in
|
||||||
printLog(parameters)
|
printLog(parameters)
|
||||||
AF.request("\(url)\(path)",
|
AF.request("\(url)\(path)",
|
||||||
method: method,
|
method: method,
|
||||||
parameters: parameters,
|
parameters: parameters,
|
||||||
encoding: JSONEncoding.default,
|
encoding: encoding,
|
||||||
headers: headers
|
headers: headers
|
||||||
)
|
)
|
||||||
.validate(statusCode: 200 ..< 300)
|
.validate(statusCode: 200 ..< 300)
|
||||||
|
@ -38,3 +39,5 @@ public func loadAPIData<T: Decodable>(url: String, path: String,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,10 +8,6 @@
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
protocol MultilineStyle: View {
|
protocol MultilineStyle: View {
|
||||||
// func lineLimit(_ limit: Int?) -> Self
|
|
||||||
// func minimumScaleFactor(_ scale: CGFloat) -> Self
|
|
||||||
// func multilineTextAlignment(_ alignment: TextAlignment) -> Self
|
|
||||||
// func truncationMode(_ mode: Text.TruncationMode) -> Self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Text: MultilineStyle {
|
extension Text: MultilineStyle {
|
||||||
|
|
|
@ -21,6 +21,13 @@
|
||||||
<dict>
|
<dict>
|
||||||
<key>NSExceptionDomains</key>
|
<key>NSExceptionDomains</key>
|
||||||
<dict>
|
<dict>
|
||||||
|
<key>10.149.217.64</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSIncludesSubdomains</key>
|
||||||
|
<true/>
|
||||||
|
<key>NSExceptionAllowsInsecureHTTPLoads</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
<key>ipstein.myds.me</key>
|
<key>ipstein.myds.me</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>NSExceptionAllowsInsecureHTTPLoads</key>
|
<key>NSExceptionAllowsInsecureHTTPLoads</key>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user