Skip to content
33 changes: 31 additions & 2 deletions Projects/App/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,20 @@
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundleDisplayName</key>
<string>$(APP_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleURLSchemes</key>
<array>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
</array>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
Expand All @@ -27,6 +35,8 @@
</array>
</dict>
</array>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleVersion</key>
<string>100</string>
<key>LSApplicationQueriesSchemes</key>
Expand Down Expand Up @@ -69,5 +79,24 @@
</array>
<key>UIUserInterfaceStyle</key>
<string>Light</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleURLSchemes</key>
<array>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
</array>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>com.googleusercontent.apps.753472005020-3ferbo60566boe71vebq2vd2g4gc0g9h</string>
</array>
</dict>
</array>
</dict>
</plist>
3 changes: 2 additions & 1 deletion Projects/App/Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ let project = Project.make(
.Shared.designSystem,
.Shared.utils
],
settings: .appSettings(teamID: Environment.teamID)
settings: .appSettings(teamID: Environment.teamID),
entitlements: .file(path: .relativeToRoot("Projects/App/App.entitlements"))
)
],
resourceSynthesizers: [
Expand Down
13 changes: 3 additions & 10 deletions Projects/App/Sources/Tabbar/TabBarView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ public struct TabBarView: View {

@State private var selectedTab: Tab = .home
@EnvironmentObject var appCoordinator: AppCoordinator
@State private var calendarTargetDate: Date?

public init() {}

Expand All @@ -66,7 +65,7 @@ public struct TabBarView: View {
.tag(Tab.home)

// 캘린더 탭
CalendarCoordinatorView(initialDate: calendarTargetDate)
CalendarCoordinatorView()
.tabItem {
(selectedTab == .calendar ? Tab.calendar.iconOn : Tab.calendar.iconOff)
Text(Tab.calendar.title)
Expand All @@ -82,14 +81,8 @@ public struct TabBarView: View {
.tag(Tab.profile)
}
.accentColor(DS.Colors.Neutral.gray900)
.onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("SwitchToCalendarTab"))) { notification in
selectedTab = .calendar
if let userInfo = notification.userInfo,
let selectedDate = userInfo["selectedDate"] as? Date {
calendarTargetDate = selectedDate
} else {
calendarTargetDate = nil
}
.onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("SwitchToCalendarTab"))) { _ in
selectedTab = .calendar
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,21 @@ import SwiftUI

public struct CalendarCoordinatorView: View {
@StateObject private var coordinator = CalendarCoordinator()

private let initialDate: Date?
@State private var targetDate: Date?

public init(initialDate: Date? = nil) {
self.initialDate = initialDate
self._targetDate = State(initialValue: initialDate)
print("📅 CalendarCoordinatorView 초기화 - initialDate: \(initialDate?.description ?? "nil")")
}

public init() {
self._targetDate = State(initialValue: nil)
print("📅 CalendarCoordinatorView 초기화 - initialDate: nil")
}

public var body: some View {
NavigationStack(path: $coordinator.path) {
coordinator.view(.main(initialDate: initialDate))
coordinator.view(.main(initialDate: targetDate))
.navigationDestination(for: CalendarRouter.Screen.self) { screen in
coordinator.view(screen)
.environmentObject(coordinator)
Expand All @@ -45,5 +49,13 @@ public struct CalendarCoordinatorView: View {
}
}
.environmentObject(coordinator)
.onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("SwitchToCalendarTab"))) { notification in
if let userInfo = notification.userInfo,
let selectedDate = userInfo["selectedDate"] as? Date {
targetDate = selectedDate
} else {
targetDate = nil
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ public struct CalendarView: View {
}
store.send(.viewDidAppear)
}
.onChange(of: initialDate) { oldValue, newValue in
// initialDate가 변경될 때마다 날짜 선택 처리
if let newDate = newValue {
store.send(.dateSelected(newDate))
}
}
.onReceive(store.effect) { effect in
handleEffect(effect)
}
Expand Down
25 changes: 23 additions & 2 deletions Projects/Home/HomeData/Sources/DTOs/SandwichHolidayDTO.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,28 @@ public struct SandwichHolidayResponseDTO: Codable {
}

public struct SandwichHolidayDataDTO: Codable {
public let responses: [SandwichHolidayItemDTO]

public init(responses: [SandwichHolidayItemDTO]) {
self.responses = responses
}

public func toDomain() -> [SandwichHoliday] {
return responses.compactMap { $0.toDomain() }
}
}

public struct SandwichHolidayItemDTO: Codable {
public let startDate: String
public let endDate: String
public let useAnnualLeave: Int
public let totalVacationDays: Int

public init(startDate: String, endDate: String) {
public init(startDate: String, endDate: String, useAnnualLeave: Int, totalVacationDays: Int) {
self.startDate = startDate
self.endDate = endDate
self.useAnnualLeave = useAnnualLeave
self.totalVacationDays = totalVacationDays
}

public func toDomain() -> SandwichHoliday? {
Expand All @@ -39,6 +55,11 @@ public struct SandwichHolidayDataDTO: Codable {
return nil
}

return SandwichHoliday(startDate: startDate, endDate: endDate)
return SandwichHoliday(
startDate: startDate,
endDate: endDate,
useAnnualLeave: useAnnualLeave,
totalVacationDays: totalVacationDays
)
}
}
107 changes: 107 additions & 0 deletions Projects/Home/HomeData/Sources/DTOs/VacationRecommendDTO.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
//
// VacationRecommendDTO.swift
// HomeData
//
// Created by 김나희 on 7/18/25.
// Copyright © 2025 com.noweekend. All rights reserved.
//

import Foundation

// MARK: - 휴가 추천 요청 DTO
public struct VacationRecommendRequestDTO: Codable {
public let days: Int
public let travelStyle: String
public let activityType: String
public let restPreference: String
public let leisurePreference: String

public init(
days: Int,
travelStyle: String,
activityType: String,
restPreference: String,
leisurePreference: String
) {
self.days = days
self.travelStyle = travelStyle
self.activityType = activityType
self.restPreference = restPreference
self.leisurePreference = leisurePreference
}
}

// MARK: - 휴가 추천 생성 응답 DTO
public struct VacationRecommendCreateResponseDTO: Codable {
public let result: String
public let data: String
public let error: String?

public init(result: String, data: String, error: String?) {
self.result = result
self.data = data
self.error = error
}
}

// MARK: - 휴가 추천 조회 응답 DTO
public struct VacationRecommendResponseDTO: Codable {
public let result: String
public let data: VacationRecommendDataDTO?
public let error: String?

public init(result: String, data: VacationRecommendDataDTO?, error: String?) {
self.result = result
self.data = data
self.error = error
}
}

public struct VacationRecommendDataDTO: Codable {
public let title: String
public let content: String
public let iconStyle: String

public init(title: String, content: String, iconStyle: String) {
self.title = title
self.content = content
self.iconStyle = iconStyle
}
}

// MARK: - DTO to Domain 변환
import HomeDomain

extension VacationRecommendRequestDTO {
public func toDomain() -> VacationRecommendRequest {
return VacationRecommendRequest(
days: days,
travelStyle: travelStyle,
activityType: activityType,
restPreference: restPreference,
leisurePreference: leisurePreference
)
}
}

extension VacationRecommendRequest {
public func toDTO() -> VacationRecommendRequestDTO {
return VacationRecommendRequestDTO(
days: days,
travelStyle: travelStyle,
activityType: activityType,
restPreference: restPreference,
leisurePreference: leisurePreference
)
}
}

extension VacationRecommendDataDTO {
public func toDomain() -> VacationRecommend {
return VacationRecommend(
title: title,
content: content,
iconStyle: iconStyle
)
}
}
41 changes: 38 additions & 3 deletions Projects/Home/HomeData/Sources/HomeRepositoryImpl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,11 @@ public final class HomeRepositoryImpl: HomeRepositoryProtocol {
throw NetworkError.serverError(response.error ?? "샌드위치 휴일 조회 실패")
}

guard let data = response.data,
let sandwichHoliday = data.toDomain() else {
guard let data = response.data else {
return []
}

return [sandwichHoliday]
return data.toDomain()
}

public func getHolidays() async throws -> [Holiday] {
Expand All @@ -81,4 +80,40 @@ public final class HomeRepositoryImpl: HomeRepositoryProtocol {

return response.data?.holidays.compactMap { $0.toDomain() } ?? []
}

public func createVacationRecommend(_ request: VacationRecommendRequest) async throws -> String {
let dto = request.toDTO()
let parameters: [String: Any] = [
"days": dto.days,
"travelStyle": dto.travelStyle,
"activityType": dto.activityType,
"restPreference": dto.restPreference,
"leisurePreference": dto.leisurePreference
]

let response: VacationRecommendCreateResponseDTO = try await networkService.post(
endpoint: HomeEndpoint.createVacationRecommend.path,
parameters: parameters
)

guard response.result == "SUCCESS" else {
throw NetworkError.serverError(response.error ?? "휴가 추천 생성 실패")
}

return response.data
}

public func getVacationRecommend() async throws -> VacationRecommend? {
let response: VacationRecommendResponseDTO = try await networkService.get(
endpoint: HomeEndpoint.getVacationRecommend.path,
parameters: nil
)

guard response.result == "SUCCESS" else {
// 아직 완성되지 않은 경우 nil 반환
return nil
}

return response.data?.toDomain()
}
}
8 changes: 8 additions & 0 deletions Projects/Home/HomeData/Sources/Services/HomeEndpoint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ enum HomeEndpoint {
case getWeatherRecommendations
case getSandwichHoliday
case getHolidays
/// 휴가 추천 생성 (POST)
case createVacationRecommend
/// 휴가 추천 조회 (GET)
case getVacationRecommend


var path: String {
Expand All @@ -28,6 +32,10 @@ enum HomeEndpoint {
return "/recommend/sandwich"
case .getHolidays:
return "/holiday/remaining"
case .createVacationRecommend:
return "/recommend/vacation"
case .getVacationRecommend:
return "/recommend/vacation"
}
}
}
Loading
Loading