-
Notifications
You must be signed in to change notification settings - Fork 1
Feat/#34 travel tool #35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
0a79159
7f36d7e
cc88efe
0edff57
4a1b92c
bd9dc92
221355d
2558cb8
1be36e0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
| <plist version="1.0"> | ||
| <dict> | ||
| <!-- μ¬μ©μ νλ μΆμ μ¬λΆ --> | ||
| <key>NSPrivacyTracking</key> | ||
| <false/> | ||
|
|
||
| <!-- μΆμ μ μ¬μ©λλ λλ©μΈ (μΆμ μμΌλ―λ‘ λΉ λ°°μ΄) --> | ||
| <key>NSPrivacyTrackingDomains</key> | ||
| <array/> | ||
|
|
||
| <!-- μμ§νλ λ°μ΄ν° μ ν (μ§μ μμ§ μμΌλ―λ‘ λΉ λ°°μ΄) --> | ||
| <key>NSPrivacyCollectedDataTypes</key> | ||
| <array/> | ||
|
|
||
| <!-- Required Reason API μ¬μ© λͺ©μ μ μΈ --> | ||
| <key>NSPrivacyAccessedAPITypes</key> | ||
| <array> | ||
| <!-- UserDefaults: uuid, nickname λ± μ± μν κ΄λ¦¬μ©μΌλ‘λ§ μ¬μ© --> | ||
| <dict> | ||
| <key>NSPrivacyAccessedAPIType</key> | ||
| <string>NSPrivacyAccessedAPICategoryUserDefaults</string> | ||
| <key>NSPrivacyAccessedAPITypeReasons</key> | ||
| <array> | ||
| <string>CA92.1</string> | ||
| </array> | ||
| </dict> | ||
| </array> | ||
| </dict> | ||
| </plist> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| // | ||
| // WeatherServiceFactory.swift | ||
| // Data | ||
| // | ||
| // Created by kimnahun on 2026-02-21. | ||
| // Copyright Β© 2026 NDGL-iOS. All rights reserved. | ||
| // | ||
|
|
||
| import Foundation | ||
| import Networks | ||
| import Moya | ||
|
|
||
| public func makeWeatherService() -> WeatherServiceProtocol { | ||
| let provider = MoyaProvider<WeatherAPI>() | ||
| return WeatherService(provider: provider) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| // | ||
| // WeatherRepository.swift | ||
| // Data | ||
| // | ||
| // Created by kimnahun on 2026-02-21. | ||
| // Copyright Β© 2026 NDGL-iOS. All rights reserved. | ||
| // | ||
|
|
||
| import Foundation | ||
| import Domain | ||
| import Networks | ||
|
|
||
| public final class WeatherRepository: WeatherRepositoryInterface { | ||
| private let service: WeatherServiceProtocol | ||
|
|
||
| public init(service: WeatherServiceProtocol) { | ||
| self.service = service | ||
| } | ||
|
|
||
| public func fetchForecast( | ||
| latitude: Double, | ||
| longitude: Double, | ||
| days: Int | ||
| ) async throws -> [DailyWeatherInfo] { | ||
| do { | ||
| let response = try await service.getForecast( | ||
| latitude: latitude, | ||
| longitude: longitude, | ||
| days: days | ||
| ) | ||
| return response.forecastDays.compactMap { $0.toDomain() } | ||
| } catch { | ||
| throw error.toNDGLError() | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| // | ||
| // WeatherTransform.swift | ||
| // Data | ||
| // | ||
| // Created by kimnahun on 2026-02-21. | ||
| // Copyright Β© 2026 NDGL-iOS. All rights reserved. | ||
| // | ||
|
|
||
| import Foundation | ||
| import Domain | ||
| import Networks | ||
|
|
||
| extension ForecastDayResponse { | ||
| func toDomain() -> DailyWeatherInfo? { | ||
| var components = DateComponents() | ||
| components.year = displayDate.year | ||
| components.month = displayDate.month | ||
| components.day = displayDate.day | ||
|
|
||
| guard let date = Calendar.current.date(from: components) else { return nil } | ||
|
|
||
| return DailyWeatherInfo( | ||
| date: date, | ||
| maxTemperature: maxTemperature?.degrees ?? 0, | ||
| minTemperature: minTemperature?.degrees ?? 0, | ||
|
Comment on lines
+24
to
+25
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. μ¨λ nil μ
π‘οΈ Double.nan λλ λ³λ sentinel μ¬μ© μ μλλ©μΈ λͺ¨λΈ( π€ Prompt for AI Agents |
||
| weatherType: daytimeForecast?.weatherCondition.type ?? "CLOUDY" | ||
| ) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| // | ||
| // WeatherRepositoryInterface.swift | ||
| // Domain | ||
| // | ||
| // Created by kimnahun on 2026-02-21. | ||
| // Copyright Β© 2026 NDGL-iOS. All rights reserved. | ||
| // | ||
|
|
||
| import Foundation | ||
|
|
||
| public protocol WeatherRepositoryInterface { | ||
| func fetchForecast( | ||
| latitude: Double, | ||
| longitude: Double, | ||
| days: Int | ||
| ) async throws -> [DailyWeatherInfo] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| // | ||
| // WeatherInfo.swift | ||
| // Domain | ||
| // | ||
| // Created by kimnahun on 2026-02-21. | ||
| // Copyright Β© 2026 NDGL-iOS. All rights reserved. | ||
| // | ||
|
|
||
| import Foundation | ||
|
|
||
| public struct DailyWeatherInfo { | ||
| public let date: Date | ||
| public let maxTemperature: Double | ||
| public let minTemperature: Double | ||
| public let weatherType: String | ||
|
|
||
| public init( | ||
| date: Date, | ||
| maxTemperature: Double, | ||
| minTemperature: Double, | ||
| weatherType: String | ||
| ) { | ||
| self.date = date | ||
| self.maxTemperature = maxTemperature | ||
| self.minTemperature = minTemperature | ||
| self.weatherType = weatherType | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,7 +15,7 @@ import RxSwift | |
|
|
||
| public protocol FollowDetailListener: AnyObject { | ||
| func detachFollowDetail() | ||
| func followDetailDidAddTrip(title: String, startDate: Date, endDate: Date) | ||
| func followDetailDidViewTrip() | ||
| } | ||
|
|
||
| // MARK: - FollowDetailPresentable | ||
|
|
@@ -28,6 +28,7 @@ protocol FollowDetailPresentable: Presentable { | |
| func updateTravelDetail(_ detail: TravelDetail) | ||
| func updatePlaces(_ places: [TravelPlace]) | ||
| func showPlaceDetail(_ place: TravelPlace) | ||
| func showTripCreatedModal(onLater: @escaping () -> Void, onViewTrip: @escaping () -> Void) | ||
| } | ||
|
|
||
| // MARK: - FollowDetailPresentableListener | ||
|
|
@@ -192,16 +193,24 @@ extension FollowDetailInteractor: TripCalendarListener { | |
| await MainActor.run { | ||
| presenter.showLoading() | ||
| } | ||
|
|
||
| do { | ||
| let response = try await followDetailUsecase.createUserTravel(request: request) | ||
|
|
||
| await MainActor.run { | ||
|
|
||
| await MainActor.run { [weak self] in | ||
| guard let self else { return } | ||
| presenter.hideLoading() | ||
| router?.detachTripCalendar() | ||
|
|
||
| let tripTitle = "\(travelDetail?.city ?? "μλ‘μ΄") μ¬ν" | ||
| listener?.followDetailDidAddTrip(title: tripTitle, startDate: startDate, endDate: endDate) | ||
|
|
||
| presenter.showTripCreatedModal( | ||
| onLater: { [weak self] in | ||
| self?.router?.detachTripCalendar() | ||
| self?.listener?.detachFollowDetail() | ||
| }, | ||
| onViewTrip: { [weak self] in | ||
| self?.router?.detachTripCalendar() | ||
| self?.listener?.followDetailDidViewTrip() | ||
| } | ||
| ) | ||
|
Comment on lines
+200
to
+213
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π§© Analysis chainπ Script executed: find . -type f -name "*NDGLModal*" -o -name "*FollowDetailInteractor*" | head -20Repository: YAPP-Github/27th-App-Team-1-iOS Length of output: 218 π Script executed: cat -n Projects/Features/FollowFeature/Sources/FollowDetailInteractor.swift | sed -n '195,230p'Repository: YAPP-Github/27th-App-Team-1-iOS Length of output: 1676 π Script executed: cat -n Projects/Modules/DSKit/Sources/Component/NDGLModalViewController.swiftRepository: YAPP-Github/27th-App-Team-1-iOS Length of output: 8140 π Script executed: cat -n Projects/Features/FollowFeature/Sources/FollowDetailInteractor.swift | sed -n '226,240p'Repository: YAPP-Github/27th-App-Team-1-iOS Length of output: 658
κ²°κ³Όμ μΌλ‘:
ν΄κ²°λ°©μ:
λν λΌμΈ 214μ π€ Prompt for AI Agents |
||
| print("μ¬ν μμ± μ±κ³΅ - userTravelId: \(response.userTravelId)") | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. λλ²κ·Έ
π€ Prompt for AI Agents |
||
| } | ||
| } catch { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π§© Analysis chain
π Script executed:
Repository: YAPP-Github/27th-App-Team-1-iOS
Length of output: 1449
π Script executed:
Repository: YAPP-Github/27th-App-Team-1-iOS
Length of output: 649
π Script executed:
Repository: YAPP-Github/27th-App-Team-1-iOS
Length of output: 3939
π Script executed:
Repository: YAPP-Github/27th-App-Team-1-iOS
Length of output: 1063
π Script executed:
Repository: YAPP-Github/27th-App-Team-1-iOS
Length of output: 1935
π Script executed:
rg -n "displayDate" Projects/Data/Sources/Transform/WeatherTransform.swiftRepository: YAPP-Github/27th-App-Team-1-iOS
Length of output: 212
π Script executed:
rg -n "ForecastDayResponse" Projects/Modules/Networks/Sources/DTO/Weather/ -A 15Repository: YAPP-Github/27th-App-Team-1-iOS
Length of output: 1956
π Script executed:
rg -n "timezone\|TimeZone\|GMT" Projects/Data/Sources/Transform/ Projects/Modules/Networks/Sources/DTO/Repository: YAPP-Github/27th-App-Team-1-iOS
Length of output: 57
μ묡μ νμμ‘΄ μ²λ¦¬λ‘ μΈν μ μ§λ³΄μ μν
WeatherTransformμCalendar.current.date(from: components)μUserTravelTransformμDateFormatter(timezone λ―Έμ§μ )λ λͺ¨λ κΈ°κΈ°μ λ‘컬 νμμ‘΄μ μ¬μ©ν©λλ€. λ°λΌμ μλ μ§μ ν UTC vs λ‘컬 νμμ‘΄ λΆμΌμΉλ λ°μνμ§ μμ΅λλ€.λ€λ§ λ μ¬κ°ν λ¬Έμ λ νμμ‘΄μ λͺ μμ μΌλ‘ μ§μ νμ§ μμ μ묡μ μ²λ¦¬μ λλ€:
DateFormatterμ timezone μμ± λ―Έμ€μ β κΈ°κΈ° μ€μ μ μμ‘΄Calendar.currentβ κΈ°κΈ° λ‘컬 νμμ‘΄μ μμ‘΄μ μ§λ³΄μ μ κ°λ°μκ° UTC, μλ² νμμ‘΄ λ±μ κ°μ ν μ μμΌλ©°, κΈ°κΈ° μ€μ λ³κ²½ μ μμ μΈ λμ κ°λ₯μ±μ΄ μμ΅λλ€.
formatter.timeZone = TimeZone(abbreviation: "UTC")λλcomponents.timeZone = TimeZone(secondsFromGMT: 0)μΌλ‘ νμμ‘΄μ λͺ μμ μΌλ‘ μ§μ νμ¬ μλλ₯Ό λͺ νν νμΈμ.π€ Prompt for AI Agents