Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
de6e351
[REFAC] 막대그래프 크기 수정
Yoo-Hyuna Nov 8, 2025
04b8a70
[REFAC] 부족 재고 페이지 상단 탭 수정
Yoo-Hyuna Nov 8, 2025
c5cfa15
[REFAC] 상단바 뒤로가기 버튼 수정
Yoo-Hyuna Nov 8, 2025
630ac48
[REFAC] 수량조절 공통 컴포넌트화 및 장바구니 ui 수정
Yoo-Hyuna Nov 8, 2025
bf0123e
[REFAC] 수량조절 공통 컴포넌트화 및 장바구니 ui 수정
Yoo-Hyuna Nov 8, 2025
4198d58
[REFAC] 재고 필터링 UI 수정
Yoo-Hyuna Nov 8, 2025
f484565
[REFAC] 재고탭 플로팅 버튼 수정
Yoo-Hyuna Nov 9, 2025
3a62b31
[FEAT] 화면 터치 시 키보드 자동 숨김 기능 추가
Yoo-Hyuna Nov 9, 2025
f8c2c67
[STYLE] 결제 페이지 안드로이드와 일관성 유지
Yoo-Hyuna Nov 9, 2025
2017216
[STYLE] 영수증 페이지 안드로이드와 일관성 유지
Yoo-Hyuna Nov 9, 2025
6abb58d
[REFAC] 주문 내역 상세: 요청사항이 있는 경우만 요청사항 영역을 보여주도록 수정
Yoo-Hyuna Nov 9, 2025
d8cf1f4
[REFAC] 주문 내역 상세: 입고처리 버튼 기능 연결 및 재주문하기 버튼 삭제
Yoo-Hyuna Nov 9, 2025
3fc46e3
[REFAC] 영수증 폭 수정
Yoo-Hyuna Nov 9, 2025
d47b069
[FEAT] 토스트 메세지 추가
Yoo-Hyuna Nov 9, 2025
44a664b
[REFAC] 예치금 페이지 안드로이드와 일관성 유지
Yoo-Hyuna Nov 9, 2025
c972bcc
[REFAC] 주문상세 안드로이드와 일관성 유지
Yoo-Hyuna Nov 9, 2025
44ee0d2
[REFAC] 안드로이드와 디자인 일관성 유지
Yoo-Hyuna Nov 10, 2025
c20c01f
[REFAC] 안드로이드와 디자인 통일, 앱로고 및 스플래시 화면 추가
Yoo-Hyuna Nov 10, 2025
36862d5
[CHORE] 주석 추가 및 코드 정리
Yoo-Hyuna Nov 12, 2025
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
Binary file modified StockMate/.DS_Store
Binary file not shown.
4 changes: 4 additions & 0 deletions StockMate/StockMate.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 35TSG7VB2B;
Expand All @@ -290,6 +291,7 @@
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.hyuna.StockMate;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
Expand All @@ -301,6 +303,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 35TSG7VB2B;
Expand All @@ -320,6 +323,7 @@
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.hyuna.StockMate;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
Expand Down
18 changes: 16 additions & 2 deletions StockMate/StockMate/app/StockMateApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,25 @@ import SwiftUI
@main
struct StockMateApp: App {
@StateObject private var authViewModel = AuthViewModel()
@State private var isLoading = true // 인트로 상태

var body: some Scene {
WindowGroup {
AppNavHost()
.environmentObject(authViewModel)

Group {
if isLoading {
IntroView() // 로고만 보여주는 화면
} else {
AppNavHost()
.environmentObject(authViewModel)
}
}
.onAppear {
Task {
try await Task.sleep(nanoseconds: 1_500_000_000) // 1.5초
isLoading = false
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class KakaoZipCodeVC: UIViewController {
// MARK: - Properties
var webView: WKWebView?
let indicator = UIActivityIndicatorView(style: .medium)
var onAddressSelected: ((String) -> Void)? // SwiftUI로 결과 전달용 콜백
var onAddressSelected: ((String) -> Void)? // SwiftUI로 결과 전달용 콜백

override func viewDidLoad() {
super.viewDidLoad()
Expand Down Expand Up @@ -64,7 +64,7 @@ extension KakaoZipCodeVC: WKScriptMessageHandler {
didReceive message: WKScriptMessage) {
guard let data = message.body as? [String: Any] else { return }
let address = data["roadAddress"] as? String ?? ""
onAddressSelected?(address) // SwiftUI로 전달
onAddressSelected?(address) // SwiftUI로 전달
dismiss(animated: true)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,23 @@
import SwiftUI
import WebKit

// SwiftUI에서 UIKit 기반의 Kakao 우편번호 검색 화면을 사용하기 위한 래퍼 뷰
// UIViewControllerRepresentable을 통해 KakaoZipCodeVC를 SwiftUI에 통합
struct KakaoZipCodeView: UIViewControllerRepresentable {
// 선택된 주소 값을 SwiftUI와 바인딩
@Binding var address: String

// KakaoZipCodeVC 생성 및 초기 설정
func makeUIViewController(context: Context) -> KakaoZipCodeVC {
let vc = KakaoZipCodeVC()

// 주소가 선택되었을 때 SwiftUI 바인딩 변수로 전달
vc.onAddressSelected = { selectedAddress in
address = selectedAddress
}
return vc
}


// UIViewController 상태 갱신 (현재는 별도 갱신 로직 없음)
func updateUIViewController(_ uiViewController: KakaoZipCodeVC, context: Context) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
// Created by Admin on 11/5/25.
//


import UIKit

// 기본 테스트용 ViewController
// 버튼을 눌러 Kakao 우편번호 검색 화면(KakaoZipCodeVC)을 표시함
class ViewController: UIViewController {

// MARK: - UI Components
Expand Down
6 changes: 3 additions & 3 deletions StockMate/StockMate/app/core/common/Validators.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ func isValidEmail(_ email: String) -> Bool {
func isValidPassword(_ pw: String) -> Bool {
guard pw.count >= 8 else { return false }
return pw.range(of: "[A-Za-z]", options: .regularExpression) != nil &&
pw.range(of: "[0-9]", options: .regularExpression) != nil
pw.range(of: "[0-9]", options: .regularExpression) != nil
}

func isValidBizNo(_ no: String) -> Bool {
let pattern = #"^\d{3}-\d{2}-\d{5}$"#
return no.range(of: pattern, options: .regularExpression) != nil
let regex = "^\\d{3}-\\d{2}-\\d{5}$"
return NSPredicate(format: "SELF MATCHES %@", regex).evaluate(with: no)
}
45 changes: 30 additions & 15 deletions StockMate/StockMate/app/core/components/AlertModal.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,42 +5,50 @@
// Created by Admin on 11/4/25.
//


import SwiftUI


// 공용 알림 모달 뷰
// 아이콘, 제목, 메시지, 버튼 구성에 따라 다양한 형태로 표시 가능
struct AlertModal: View {
var icon: Image? = nil // ✅ 아이콘 없을 수도 있음
var icon: Image? = nil
var title: String
var message: String? = nil

// 주요 버튼 텍스트 및 동작
var primaryButtonTitle: String
var primaryAction: () -> Void

// 보조 버튼 텍스트 및 동작 (선택)
var secondaryButtonTitle: String? = nil
var secondaryAction: (() -> Void)? = nil

var buttonLayout: ButtonLayout = .vertical // ✅ horizontal / vertical
// 버튼 배치 방향 설정 (세로 / 가로)
var buttonLayout: ButtonLayout = .vertical

// 버튼 레이아웃 타입 정의
enum ButtonLayout {
case vertical
case horizontal
}

var body: some View {
VStack(spacing: 15) {
// 아이콘이 있을 경우 표시
if let icon = icon {
icon
.resizable()
.scaledToFit()
.frame(width: 120, height: 120)
.padding(.top, 6)
}

// 제목 텍스트
Text(title)
.font(.system(size: 18, weight: .bold))
.multilineTextAlignment(.center)
.padding(.top, 10)

// 메시지 텍스트가 있을 경우 표시
if let message = message {
Text(message)
.font(.system(size: 14, weight: .regular))
Expand All @@ -49,23 +57,34 @@ struct AlertModal: View {
.padding(.bottom, 6)
}

// 버튼 레이아웃에 따라 분기
if buttonLayout == .vertical {
// 세로 방향 버튼 배치
VStack(spacing: 10) {
if let secondary = secondaryButtonTitle, let secondaryAction = secondaryAction {
Button(secondary, action: secondaryAction)
.buttonStyle(CustomButtonStyle(type: .outlined(.Primary)))
.buttonStyle(
CustomButtonStyle(type: .outlined(.Primary))
)
}
Button(primaryButtonTitle, action: primaryAction)
.buttonStyle(CustomButtonStyle(type: .filled(Color.Primary)))
.buttonStyle(
CustomButtonStyle(type: .filled(Color.Primary))
)
}
} else {
// 가로 방향 버튼 배치
HStack(spacing: 10) {
if let secondary = secondaryButtonTitle, let secondaryAction = secondaryAction {
Button(secondary, action: secondaryAction)
.buttonStyle(CustomButtonStyle(type: .outlined(.Primary)))
.buttonStyle(
CustomButtonStyle(type: .outlined(.Primary))
)
}
Button(primaryButtonTitle, action: primaryAction)
.buttonStyle(CustomButtonStyle(type: .filled(Color.Primary)))
.buttonStyle(
CustomButtonStyle(type: .filled(Color.Primary))
)
}
}
}
Expand All @@ -82,7 +101,7 @@ import SwiftUI
#Preview {
ScrollView{
VStack(spacing: 40) {
// ✅ 1. 체크 아이콘 + 버튼 1개
// 체크 아이콘 + 버튼 1개
AlertModal(
icon: Image("SuccessIllust"),
title: "등록 완료!",
Expand All @@ -98,9 +117,7 @@ import SwiftUI
primaryAction: {}
)



// ✅ 2. 아이콘 없이 버튼 2개 (가로)
// 아이콘 없이 버튼 2개 (가로 배치)
AlertModal(
title: "주문 취소",
message: "주문을 취소하시겠습니까?",
Expand All @@ -120,8 +137,7 @@ import SwiftUI
buttonLayout: .horizontal
)


// ✅ 3. 주문완료
// 주문 완료 알림 (세로 버튼 배치)
AlertModal(
icon: Image("SuccessIllust"),
title: "주문완료!",
Expand All @@ -136,5 +152,4 @@ import SwiftUI
.padding()
.background(Color.gray.opacity(0.1))
}

}
44 changes: 23 additions & 21 deletions StockMate/StockMate/app/core/components/BarChartView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ struct BarChartView: View {
@Binding var selectedMonth: String?

var body: some View {
// 최신월이 오른쪽에 오도록 역순 정렬
// 최신월이 오른쪽에 오도록 역순 정렬
let reversedValues = Array(values.reversed())
let reversedLabels = Array(labels.reversed())
let reversedAmounts = Array(amounts.reversed())

// "07" → "7월" 형식 변환
// "07" → "7월" 형식 변환
let displayLabels = reversedLabels.map { label in
if let monthInt = Int(label) {
return "\(monthInt)월"
Expand All @@ -28,60 +28,62 @@ struct BarChartView: View {
}
}

// 기본 선택: 최신월
// 기본 선택: 최신월
let defaultMonth = displayLabels.last ?? ""
let activeMonth = selectedMonth ?? defaultMonth

VStack(alignment: .leading, spacing: 14) {
// 막대 그래프
VStack(alignment: .leading, spacing: 12) {
// 막대 그래프
GeometryReader { geometry in
let chartHeight = geometry.size.height * 0.85 // 상하 여백 고려
let chartHeight = geometry.size.height * 0.88 // 상하 여백 고려
let totalWidth = geometry.size.width
let barCount = CGFloat(reversedValues.count)
let barWidth: CGFloat = 28
let barWidth: CGFloat = 35
let spacing = max((totalWidth - (barWidth * barCount)) / (barCount + 1), 6)

HStack(alignment: .bottom, spacing: spacing) {
ForEach(reversedValues.indices, id: \.self) { i in
VStack {
RoundedRectangle(cornerRadius: 8)
RoundedRectangle(cornerRadius: 10)
.fill(activeMonth == displayLabels[i] ? Color.Primary : Color.LightBlue04)
// ✅ 막대 높이를 geometry 기준으로 조정
.frame(width: barWidth, height: chartHeight * reversedValues[i])
.frame(width: barWidth, height: max(chartHeight * reversedValues[i], 8)) // 최소 높이 보장
.onTapGesture {
selectedMonth = (selectedMonth == displayLabels[i]) ? nil : displayLabels[i]
}

Text(displayLabels[i])
.font(.caption2)
.foregroundColor(.black)
.padding(.top, 4)
.font(.system(size: 13, weight: activeMonth == displayLabels[i] ? .semibold : .light)) // 선택된 막대는 글씨 bold
.padding(.top, 3)
}
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottom)
}
.frame(height: 140) // 전체 그래프 영역 높이 확장
.padding(.vertical, 8)
.frame(height: 163) // 전체 그래프 영역 높이 확장
.padding(.bottom, 7)

Divider()
Rectangle()
.fill(Color.textGray2)
.frame(height: 0.8) // Divider보다 살짝 두껍게
.padding(.horizontal, 4)

// ✅ 하단 "n월 지출금액 ooo원" 표시

// 하단 "n월 지출금액 ooo원" 표시
if let index = displayLabels.firstIndex(of: activeMonth) {
HStack {
Text("\(displayLabels[index]) 지출 현황")
.font(.system(size: 17, weight: .medium))
.font(.system(size: 15, weight: .regular))
Spacer()
Text("\(reversedAmounts[index].formatted())원")
.font(.system(size: 18, weight: .bold))
.font(.system(size: 17, weight: .bold))
.foregroundColor(Color.Primary)
}
.padding(.top, 6)
.padding(.horizontal,4)
.padding(.vertical, 2)
}
}
.frame(maxWidth: .infinity)
// 초기 로드 시 최신월 자동 선택
// 초기 로드 시 최신월 자동 선택
.onAppear {
if selectedMonth == nil {
selectedMonth = defaultMonth
Expand Down
Loading