Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion SampoomManagement.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
/* Begin PBXBuildFile section */
533528342E8BD99400F38FD1 /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = 533528332E8BD99400F38FD1 /* Alamofire */; };
5387CA3A2E8F676E005A3936 /* Swinject in Frameworks */ = {isa = PBXBuildFile; productRef = 5387CA392E8F676E005A3936 /* Swinject */; };
53F27C452E9F9C8800D223ED /* Toast in Frameworks */ = {isa = PBXBuildFile; productRef = 53F27C442E9F9C8800D223ED /* Toast */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
Expand All @@ -19,7 +20,7 @@
533528372E8BDAB300F38FD1 /* Exceptions for "SampoomManagement" folder in "SampoomManagement" target */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
Resources/Info.plist,
Info.plist,
);
target = 53A7B4BE2E8A43AF00BC946E /* SampoomManagement */;
};
Expand All @@ -41,6 +42,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
53F27C452E9F9C8800D223ED /* Toast in Frameworks */,
533528342E8BD99400F38FD1 /* Alamofire in Frameworks */,
5387CA3A2E8F676E005A3936 /* Swinject in Frameworks */,
);
Expand Down Expand Up @@ -87,6 +89,7 @@
packageProductDependencies = (
533528332E8BD99400F38FD1 /* Alamofire */,
5387CA392E8F676E005A3936 /* Swinject */,
53F27C442E9F9C8800D223ED /* Toast */,
);
productName = SampoomManagement;
productReference = 53A7B4BF2E8A43AF00BC946E /* SampoomManagement.app */;
Expand Down Expand Up @@ -119,6 +122,7 @@
packageReferences = (
533528322E8BD99400F38FD1 /* XCRemoteSwiftPackageReference "Alamofire" */,
5387CA382E8F676E005A3936 /* XCRemoteSwiftPackageReference "Swinject" */,
53F27C432E9F9C8800D223ED /* XCRemoteSwiftPackageReference "toast-swift" */,
);
preferredProjectObjectVersion = 77;
productRefGroup = 53A7B4C02E8A43AF00BC946E /* Products */;
Expand Down Expand Up @@ -282,6 +286,7 @@
DEVELOPMENT_TEAM = B9PUAVBBKX;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = SampoomManagement/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "삼품관리";
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
Expand Down Expand Up @@ -316,6 +321,7 @@
DEVELOPMENT_TEAM = B9PUAVBBKX;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = SampoomManagement/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "삼품관리";
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
Expand Down Expand Up @@ -380,6 +386,14 @@
minimumVersion = 2.10.0;
};
};
53F27C432E9F9C8800D223ED /* XCRemoteSwiftPackageReference "toast-swift" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/BastiaanJansen/toast-swift";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 2.1.3;
};
};
/* End XCRemoteSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
Expand All @@ -393,6 +407,11 @@
package = 5387CA382E8F676E005A3936 /* XCRemoteSwiftPackageReference "Swinject" */;
productName = Swinject;
};
53F27C442E9F9C8800D223ED /* Toast */ = {
isa = XCSwiftPackageProductDependency;
package = 53F27C432E9F9C8800D223ED /* XCRemoteSwiftPackageReference "toast-swift" */;
productName = Toast;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 53A7B4B72E8A43AF00BC946E /* Project object */;
Expand Down
10 changes: 4 additions & 6 deletions SampoomManagement/App/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,13 @@ enum Tabs {
}

struct ContentView: View {
let dependencies: AppDependencies
@StateObject private var partViewModel: PartViewModel
@State private var selectedTab: Tabs = .dashboard

init() {
// DI Container에서 ViewModel 주입
guard let viewModel = DIContainer.shared.resolve(PartViewModel.self) else {
fatalError("PartViewModel을 DIContainer에서 찾을 수 없습니다.")
}
_partViewModel = StateObject(wrappedValue: viewModel)
init(dependencies: AppDependencies) {
self.dependencies = dependencies
_partViewModel = StateObject(wrappedValue: dependencies.makePartViewModel())
}

var body: some View {
Expand Down
76 changes: 76 additions & 0 deletions SampoomManagement/App/RootView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//
// RootView.swift
// SampoomManagement
//
// Created by 채상윤 on 10/15/25.
//

import SwiftUI

struct RootView: View {
let dependencies: AppDependencies

@StateObject private var loginViewModel: LoginViewModel
@StateObject private var signUpViewModel: SignUpViewModel
@State private var isAuthenticated: Bool = false
@State private var showSignUp: Bool = false

init(dependencies: AppDependencies) {
self.dependencies = dependencies
_loginViewModel = StateObject(wrappedValue: dependencies.makeLoginViewModel())
_signUpViewModel = StateObject(wrappedValue: dependencies.makeSignUpViewModel())
}

var body: some View {
Group {
if isAuthenticated {
// 로그인 되어있으면 메인 화면
ContentView(dependencies: dependencies)
} else {
// 로그인 안되어있으면 로그인/회원가입 화면
if showSignUp {
NavigationStack {
SignUpView(
viewModel: signUpViewModel,
onSuccess: {
// 회원가입 성공 시 자동 로그인 완료 → 메인 화면으로
isAuthenticated = true
}
)
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button(action: {
showSignUp = false
}) {
Image(systemName: "chevron.left")
.foregroundColor(Color(red: 0.5, green: 0.2, blue: 0.8))
}
}
}
}
} else {
LoginView(
viewModel: loginViewModel,
onSuccess: {
// 로그인 성공 시 메인 화면으로
isAuthenticated = true
},
onNavigateSignUp: {
// 회원가입 화면으로
showSignUp = true
}
)
}
}
}
.onAppear {
// 앱 시작 시 로그인 상태 확인
checkAuthenticationStatus()
}
}

private func checkAuthenticationStatus() {
isAuthenticated = dependencies.authPreferences.hasToken()
}
}
19 changes: 16 additions & 3 deletions SampoomManagement/App/SampoomManagementApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,28 @@ import SwiftUI

@main
struct SampoomManagementApp: App {
// SwiftUI Environment 기반 DI
private let dependencies = AppDependencies()

init() {
// DI Container 초기화
_ = DIContainer.shared
// 앱 전체 폰트 설정
setupGlobalFont()
}

var body: some Scene {
WindowGroup {
ContentView()
RootView(dependencies: dependencies)
}
}

// MARK: - Setup

private func setupGlobalFont() {
// UIKit 컴포넌트에 대한 기본 폰트 설정
if let font = UIFont.gmarketSans(size: 16, weight: .medium) {
UILabel.appearance().font = font
UITextField.appearance().font = font
UITextView.appearance().font = font
}
}
}
62 changes: 62 additions & 0 deletions SampoomManagement/Core/DI/AppDependencies.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//
// AppDependencies.swift
// SampoomManagement
//
// Created by 채상윤 on 10/15/25.
//

import Foundation
import SwiftUI

/// SwiftUI Environment 기반 의존성 관리
class AppDependencies {
// MARK: - Core
let networkManager: NetworkManager

// MARK: - Auth
let authPreferences: AuthPreferences
let authAPI: AuthAPI
let authRepository: AuthRepository
let loginUseCase: LoginUseCase
let signUpUseCase: SignUpUseCase

// MARK: - Part
let partAPI: PartAPI
let partRepository: PartRepository
let getPartUseCase: GetPartUseCase

init() {
// Core
networkManager = NetworkManager()

// Auth
authPreferences = AuthPreferences()
authAPI = AuthAPI(networkManager: networkManager)
authRepository = AuthRepositoryImpl(
api: authAPI,
preferences: authPreferences
)
loginUseCase = LoginUseCase(repository: authRepository)
signUpUseCase = SignUpUseCase(repository: authRepository)

// Part
partAPI = PartAPI(networkManager: networkManager)
partRepository = PartRepositoryImpl(api: partAPI)
getPartUseCase = GetPartUseCase(repository: partRepository)
}

// MARK: - ViewModel Factories

func makeLoginViewModel() -> LoginViewModel {
return LoginViewModel(loginUseCase: loginUseCase)
}

func makeSignUpViewModel() -> SignUpViewModel {
return SignUpViewModel(signUpUseCase: signUpUseCase)
}

func makePartViewModel() -> PartViewModel {
return PartViewModel(getPartUseCase: getPartUseCase)
}
}

20 changes: 0 additions & 20 deletions SampoomManagement/Core/DI/CoreDIModule.swift

This file was deleted.

32 changes: 0 additions & 32 deletions SampoomManagement/Core/DI/DIContainer.swift

This file was deleted.

17 changes: 17 additions & 0 deletions SampoomManagement/Core/Network/NetworkError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,20 @@ enum NetworkError: Error, LocalizedError {
}
}
}

enum AuthError: Error, LocalizedError {
case tokenSaveFailed(Error)
case invalidCredentials
case networkError(Error)

var errorDescription: String? {
switch self {
case .tokenSaveFailed(let error):
return "토큰 저장 실패: \(error.localizedDescription)"
case .invalidCredentials:
return "잘못된 인증 정보입니다"
case .networkError(let error):
return "네트워크 오류: \(error.localizedDescription)"
}
}
}
2 changes: 1 addition & 1 deletion SampoomManagement/Core/Network/NetworkManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Alamofire
class NetworkManager {
static let shared = NetworkManager()

private let baseURL = "http://localhost:8080/api/"
private let baseURL = "https://sampoom.store/api/"

init() {}

Expand Down
Loading