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
43 changes: 10 additions & 33 deletions SampoomManagement/App/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import SwiftUI

enum Tabs {
case dashboard, delivery, cart, orders, parts
case dashboard, outbound, cart, orders, parts
}

struct ContentView: View {
Expand Down Expand Up @@ -52,50 +52,26 @@ struct ContentView: View {
}
}

// Delivery 탭 (임시)
Tab(value: .delivery) {
// Outbound 탭
Tab(value: .outbound) {
NavigationStack {
VStack(spacing: 20) {
Spacer()
Text(StringResources.Tabs.delivery)
.font(.largeTitle)
.fontWeight(.bold)
Text(StringResources.Placeholders.inventoryDescription)
.font(.body)
.foregroundColor(.secondary)
.multilineTextAlignment(.center)
.padding(.horizontal, 32)
Spacer()
}
.navigationTitle(StringResources.Tabs.delivery)
OutboundListView(viewModel: dependencies.makeOutboundListViewModel())
}
} label: {
Label {
Text(StringResources.Tabs.delivery)
Text(StringResources.Tabs.outbound)
.font(.gmarketSubheadline)
} icon: {
Image("delivery")
Image("outbound")
.renderingMode(.template)
.foregroundStyle(Color.text)
}
}

// Cart 탭 (임시)
// Cart 탭
Tab(value: .cart) {
NavigationStack {
VStack(spacing: 20) {
Spacer()
Text(StringResources.Tabs.cart)
.font(.largeTitle)
.fontWeight(.bold)
Text(StringResources.Placeholders.inventoryDescription)
.font(.body)
.foregroundColor(.secondary)
.multilineTextAlignment(.center)
.padding(.horizontal, 32)
Spacer()
}
.navigationTitle(StringResources.Tabs.cart)
CartListView(viewModel: dependencies.makeCartListViewModel())
}
} label: {
Label {
Expand Down Expand Up @@ -150,7 +126,8 @@ struct ContentView: View {
viewModel: PartListViewModel(
getPartUseCase: dependencies.getPartUseCase,
groupId: groupId
)
),
dependencies: dependencies
)
}
}
Expand Down
61 changes: 61 additions & 0 deletions SampoomManagement/Core/DI/AppDependencies.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,25 @@ class AppDependencies {
let getGroupUseCase: GetGroupUseCase
let getPartUseCase: GetPartUseCase

// MARK: - Outbound
let outboundAPI: OutboundAPI
let outboundRepository: OutboundRepository
let getOutboundUseCase: GetOutboundUseCase
let addOutboundUseCase: AddOutboundUseCase
let deleteOutboundUseCase: DeleteOutboundUseCase
let deleteAllOutboundUseCase: DeleteAllOutboundUseCase
let processOutboundUseCase: ProcessOutboundUseCase
let updateOutboundQuantityUseCase: UpdateOutboundQuantityUseCase

// MARK: - Cart
let cartAPI: CartAPI
let cartRepository: CartRepository
let getCartUseCase: GetCartUseCase
let addCartUseCase: AddCartUseCase
let deleteCartUseCase: DeleteCartUseCase
let deleteAllCartUseCase: DeleteAllCartUseCase
let updateCartQuantityUseCase: UpdateCartQuantityUseCase

init() {
// Core
networkManager = NetworkManager()
Expand All @@ -47,6 +66,25 @@ class AppDependencies {
getCategoryUseCase = GetCategoryUseCase(repository: partRepository)
getGroupUseCase = GetGroupUseCase(repository: partRepository)
getPartUseCase = GetPartUseCase(repository: partRepository)

// Outbound
outboundAPI = OutboundAPI(networkManager: networkManager)
outboundRepository = OutboundRepositoryImpl(api: outboundAPI)
getOutboundUseCase = GetOutboundUseCase(repository: outboundRepository)
addOutboundUseCase = AddOutboundUseCase(repository: outboundRepository)
deleteOutboundUseCase = DeleteOutboundUseCase(repository: outboundRepository)
deleteAllOutboundUseCase = DeleteAllOutboundUseCase(repository: outboundRepository)
processOutboundUseCase = ProcessOutboundUseCase(repository: outboundRepository)
updateOutboundQuantityUseCase = UpdateOutboundQuantityUseCase(repository: outboundRepository)

// Cart
cartAPI = CartAPI(networkManager: networkManager)
cartRepository = CartRepositoryImpl(api: cartAPI)
getCartUseCase = GetCartUseCase(repository: cartRepository)
addCartUseCase = AddCartUseCase(repository: cartRepository)
deleteCartUseCase = DeleteCartUseCase(repository: cartRepository)
deleteAllCartUseCase = DeleteAllCartUseCase(repository: cartRepository)
updateCartQuantityUseCase = UpdateCartQuantityUseCase(repository: cartRepository)
}

// MARK: - ViewModel Factories
Expand All @@ -71,5 +109,28 @@ class AppDependencies {
getPartUseCase: getPartUseCase, groupId: groupId
)
}

func makePartDetailViewModel() -> PartDetailViewModel {
return PartDetailViewModel(addOutboundUseCase: addOutboundUseCase, addCartUseCase: addCartUseCase)
}

func makeOutboundListViewModel() -> OutboundListViewModel {
return OutboundListViewModel(
getOutboundUseCase: getOutboundUseCase,
processOutboundUseCase: processOutboundUseCase,
updateOutboundQuantityUseCase: updateOutboundQuantityUseCase,
deleteOutboundUseCase: deleteOutboundUseCase,
deleteAllOutboundUseCase: deleteAllOutboundUseCase
)
}

func makeCartListViewModel() -> CartListViewModel {
return CartListViewModel(
getCartUseCase: getCartUseCase,
updateCartQuantityUseCase: updateCartQuantityUseCase,
deleteCartUseCase: deleteCartUseCase,
deleteAllCartUseCase: deleteAllCartUseCase
)
}
}

5 changes: 4 additions & 1 deletion SampoomManagement/Core/Network/APIResponse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,8 @@ struct APIResponse<T: Codable>: Codable {
let status: Int
let success: Bool
let message: String
let data: T
let data: T?
}

struct EmptyResponse: Codable {
}
6 changes: 6 additions & 0 deletions SampoomManagement/Core/Network/NetworkError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ enum NetworkError: Error, LocalizedError {
case invalidURL
case noData
case serverError(Int)
case invalidParameters

var errorDescription: String? {
switch self {
Expand All @@ -26,6 +27,8 @@ enum NetworkError: Error, LocalizedError {
return "데이터가 없습니다"
case .serverError(let code):
return "서버 오류: \(code)"
case .invalidParameters:
return "잘못된 매개변수입니다"
}
}
}
Expand All @@ -34,6 +37,7 @@ enum AuthError: Error, LocalizedError {
case tokenSaveFailed(Error)
case invalidCredentials
case networkError(Error)
case invalidResponse

var errorDescription: String? {
switch self {
Expand All @@ -43,6 +47,8 @@ enum AuthError: Error, LocalizedError {
return "잘못된 인증 정보입니다"
case .networkError(let error):
return "네트워크 오류: \(error.localizedDescription)"
case .invalidResponse:
return "잘못된 응답입니다"
}
}
}
53 changes: 30 additions & 23 deletions SampoomManagement/Core/Network/NetworkManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,33 +19,40 @@ class NetworkManager {
endpoint: String,
method: HTTPMethod = .get,
parameters: Parameters? = nil,
responseType: T.Type,
completion: @escaping (Result<APIResponse<T>, NetworkError>) -> Void
) {
responseType: T.Type
) async throws -> APIResponse<T> {
let url = baseURL + endpoint

return try await withTaskCancellationHandler(operation: {
try await withCheckedThrowingContinuation { continuation in
let dataRequest = AF.request(
url,
method: method,
parameters: parameters,
encoding: JSONEncoding.default
)

AF.request(
url,
method: method,
parameters: parameters,
encoding: JSONEncoding.default
)
.responseData { response in
switch response.result {
case .success(let data):
Task { @MainActor in
do {
let apiResponse = try JSONDecoder().decode(APIResponse<T>.self, from: data)
completion(.success(apiResponse))
} catch {
completion(.failure(.decodingError(error)))
dataRequest.responseData { response in
switch response.result {
case .success(let data):
do {
print("NetworkManager - Raw response data: \(String(data: data, encoding: .utf8) ?? "Unable to decode")")
let decoder = JSONDecoder()
let apiResponse = try decoder.decode(APIResponse<T>.self, from: data)
print("NetworkManager - Decoded response: \(apiResponse)")
continuation.resume(returning: apiResponse)
} catch {
print("NetworkManager - Decoding error: \(error)")
continuation.resume(throwing: NetworkError.decodingError(error))
}
case .failure(let error):
print("NetworkManager - Network error: \(error)")
continuation.resume(throwing: NetworkError.networkError(error))
}
}
case .failure(let error):
Task { @MainActor in
completion(.failure(.networkError(error)))
}
}
}
}, onCancel: {
// Task cancellation handled by Alamofire automatically
})
}
}
54 changes: 53 additions & 1 deletion SampoomManagement/Core/Resources/StringResources.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ struct StringResources {
// MARK: - Tabs
struct Tabs {
static let dashboard = "대시보드"
static let delivery = "출고목록"
static let outbound = "출고목록"
static let cart = "장바구니"
static let orders = "주문관리"
static let parts = "부품조회"
Expand Down Expand Up @@ -71,6 +71,58 @@ struct StringResources {
static let done = "완료"
}

// MARK: - Outbound
struct Outbound {
static let title = "출고"
static let emptyAll = "출고목록 비우기"
static let processOrder = "부품 출고처리"
static let orderSuccess = "출고 주문 성공"
static let updateQuantityError = "수량 업데이트 에러"
static let deleteError = "삭제 에러"
static let confirmProcessTitle = "출고 확인"
static let confirmProcessMessage = "선택하신 부품들을 출고 처리하시겠습니까?"
static let confirmEmptyTitle = "전체 삭제"
static let confirmEmptyMessage = "출고 목록을 모두 삭제하시겠습니까?"
static let deleteItemHint = "이 항목을 출고 목록에서 삭제합니다"
}

// MARK: - Cart
struct Cart {
static let title = "장바구니"
static let emptyAll = "장바구니 비우기"
static let processOrder = "부품 주문"
static let orderSuccess = "주문 성공!"
static let updateQuantityError = "수량 업데이트 에러"
static let deleteError = "삭제 에러"
static let confirmProcessTitle = "주문 확인"
static let confirmProcessMessage = "선택하신 부품을 주문하시겠습니까?"
static let confirmEmptyTitle = "장바구니 비우기"
static let confirmEmptyMessage = "장바구니를 비우시겠습니까?"
static let emptyMessage = "장바구니가 비어있습니다"
static let deleteItemHint = "이 항목을 장바구니에서 삭제합니다"
}

// MARK: - PartDetail
struct PartDetail {
static let title = "부품 상세"
static let currentQuantity = "현재 수량"
static let quantity = "수량"
static let addToOutbound = "출고 추가"
static let addToCart = "장바구니 추가"
static let outboundSuccess = "출고 성공!"
static let cartSuccess = "장바구니 추가 성공!"
static let errorOccurred = "에러 발생"
static let confirmOutboundTitle = "출고 확인"
static let confirmOutboundMessage = "선택하신 부품을 출고 목록에 추가하시겠습니까?"
static let confirmCartTitle = "장바구니 확인"
static let confirmCartMessage = "선택하신 부품을 장바구니에 추가하시겠습니까?"
}

// MARK: - Part
struct Part {
static let quantity = "수량"
}

// MARK: - Auth
struct Auth {
// Login
Expand Down
9 changes: 0 additions & 9 deletions SampoomManagement/Core/UI/Components/AppHeader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,3 @@ struct AppHeader: View {
}
}

#Preview {
VStack {
AppHeader(title: "인벤토리")
AppHeader(title: "상세보기", showBackButton: true) {
print("Back pressed")
}
Spacer()
}
}
Loading