From 1ed766afb5ff760d29df92fdf5778efb8f24bece Mon Sep 17 00:00:00 2001 From: seozero Date: Fri, 20 Mar 2026 16:56:02 +0100 Subject: [PATCH 1/9] =?UTF-8?q?[chore/#466]=20component=20=ED=8F=B4?= =?UTF-8?q?=EB=8D=94=EB=A7=81=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{ => AIRecommendPrompt}/Component/AIRecommendBar.swift | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Solply/Solply/Presentation/AIRecommend/{ => AIRecommendPrompt}/Component/AIRecommendBar.swift (100%) diff --git a/Solply/Solply/Presentation/AIRecommend/Component/AIRecommendBar.swift b/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/Component/AIRecommendBar.swift similarity index 100% rename from Solply/Solply/Presentation/AIRecommend/Component/AIRecommendBar.swift rename to Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/Component/AIRecommendBar.swift From 679dea94944bbd69ee9582af7c2dfa475c39b416 Mon Sep 17 00:00:00 2001 From: seozero Date: Fri, 20 Mar 2026 17:07:22 +0100 Subject: [PATCH 2/9] =?UTF-8?q?[feat/#466]=20TownSelectBottomSheet=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Component/TownSelectBottomSheet.swift | 118 ++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/Component/TownSelectBottomSheet.swift diff --git a/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/Component/TownSelectBottomSheet.swift b/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/Component/TownSelectBottomSheet.swift new file mode 100644 index 00000000..e91e2a9c --- /dev/null +++ b/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/Component/TownSelectBottomSheet.swift @@ -0,0 +1,118 @@ +// +// TownSelectBottomSheet.swift +// Solply +// +// Created by seozero on 3/19/26. +// + +import SwiftUI + +struct TownSelectBottomSheet: View { + + // MARK: - Properties + + @Environment(\.dismiss) private var dismiss + @StateObject private var store = AIRecommendPromptStore() + + // MARK: - Body + + var body: some View { + VStack(alignment: .center, spacing: 0) { + header + + divider + + ZStack(alignment: .bottom) { + VStack(alignment: .center, spacing: 0) { + HStack(alignment: .top, spacing: 0) { + townListView + + Divider() + + subTownListView + } + } + + SolplyMainButton( + title: "완료", + isEnabled: true + ) { + + } + .padding(.horizontal, 20.adjustedWidth) + .padding(.bottom, 38.adjustedHeight) + } + } + .onAppear { + store.dispatch(.fetchTowns) + } + } +} + +// MARK: - Subviews + +extension TownSelectBottomSheet { + private var header: some View { + HStack(alignment: .center, spacing: 0) { + Text("동네") + .applySolplyFont(.title_18_sb) + .foregroundStyle(.coreBlack) + + Spacer() + + Button { + dismiss() + } label: { + Image(.xIconSm) + .resizable() + .frame(width: 24.adjusted, height: 24.adjusted) + .foregroundStyle(.gray800) + } + .buttonStyle(.plain) + } + .padding(.horizontal, 16.adjustedWidth) + .padding(.top, 24.adjustedHeight) + .padding(.bottom, 20.adjustedHeight) + } + + private var divider: some View { + Rectangle() + .frame(height: 1.adjustedHeight) + .foregroundStyle(.gray300) + } + + private var townListView: some View { + VStack(spacing: 0) { + ForEach(store.state.townList, id: \.self) { town in + JGDTopTownRow( + title: town.townName, + isSelected: store.state.selectedTown?.id == town.id + ) { + store.dispatch(.selectTown(town)) + } + } + + Spacer() + } + .frame(maxHeight: .infinity) + .background(.gray100) + } + + private var subTownListView: some View { + let subTowns = store.state.selectedTown?.subTowns ?? [] + + return VStack(spacing: 0) { + ForEach(subTowns, id: \.self) { subTown in + JGDSubTownRow( + title: subTown.townName, + isSelected: store.state.selectedSubTown?.id == subTown.id + ) { + store.dispatch(.selectSubTown(subTown)) + } + } + + Spacer() + } + .frame(width: 247.adjustedWidth) + } +} From 4ccb9c691fa5dc1de5191133a795ec8dae233667 Mon Sep 17 00:00:00 2001 From: seozero Date: Fri, 20 Mar 2026 17:08:07 +0100 Subject: [PATCH 3/9] =?UTF-8?q?[feat/#466]=20TownSelectBottomSheet=20?= =?UTF-8?q?=EB=B6=80=EB=AA=A8=20=EB=B7=B0=EC=97=90=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/AIRecommendPromptView.swift | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/View/AIRecommendPromptView.swift b/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/View/AIRecommendPromptView.swift index 238910bf..0ac74611 100644 --- a/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/View/AIRecommendPromptView.swift +++ b/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/View/AIRecommendPromptView.swift @@ -33,6 +33,16 @@ struct AIRecommendPromptView: View { appCoordinator.goBack() }) .customModal() + .sheet( + isPresented: Binding( + get: { store.state.isTownSelectBottomSheetPresented }, + set: { store.dispatch(.showTownSelectBottomSheet(isSheetPresented: $0)) } + ) + ) { + TownSelectBottomSheet() + .presentationDetents([.height(654.adjustedHeight)]) + .presentationCornerRadius(20) + } } } @@ -62,7 +72,7 @@ extension AIRecommendPromptView { private var townSelect: some View { Button { - // TODO: - 동네 선택 바텀시트 연결 + store.dispatch(.showTownSelectBottomSheet(isSheetPresented: true)) } label: { HStack(alignment: .center, spacing: 4.adjustedWidth) { Image(.townIcon) From 4f4a1322a0b80ff45a7caba726d1411d17c340b5 Mon Sep 17 00:00:00 2001 From: seozero Date: Fri, 20 Mar 2026 17:09:37 +0100 Subject: [PATCH 4/9] =?UTF-8?q?[feat/#466]=20=EB=8F=99=EB=84=A4=20?= =?UTF-8?q?=EC=84=A0=ED=83=9D=20=EB=B0=94=ED=85=80=20=EC=8B=9C=ED=8A=B8=20?= =?UTF-8?q?api=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Effect/AIRecommendEffect.swift | 34 +++++++++++ .../Intent/AIRecommendPromptAction.swift | 16 +++++ .../Intent/AIRecommendPromptStore.swift | 10 +++ .../State/AIRecommendPromptReducer.swift | 61 +++++++++++++++++++ .../State/AIRecommendPromptState.swift | 15 +++++ 5 files changed, 136 insertions(+) create mode 100644 Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/Effect/AIRecommendEffect.swift diff --git a/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/Effect/AIRecommendEffect.swift b/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/Effect/AIRecommendEffect.swift new file mode 100644 index 00000000..01fef6cc --- /dev/null +++ b/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/Effect/AIRecommendEffect.swift @@ -0,0 +1,34 @@ +// +// AIRecommendEffect.swift +// Solply +// +// Created by seozero on 3/20/26. +// + +import Foundation + +struct AIRecommendEffect { + private let townService: TownAPI + + init(townService: TownAPI) { + self.townService = townService + } + + func fetchTowns() async -> AIRecommendPromptAction { + do { + let response = try await townService.fetchTownList() + + guard let data = response.data else { + return .fetchTownsFailure(error: .responseError) + } + + let towns = data.toEntity() + + return .fetchTownsSuccess(townList: towns) + } catch let error as NetworkError { + return .fetchTownsFailure(error: error) + } catch { + return .fetchTownsFailure(error: .unknownError) + } + } +} diff --git a/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/Intent/AIRecommendPromptAction.swift b/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/Intent/AIRecommendPromptAction.swift index 82ee44a4..2e5d9e41 100644 --- a/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/Intent/AIRecommendPromptAction.swift +++ b/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/Intent/AIRecommendPromptAction.swift @@ -11,4 +11,20 @@ enum AIRecommendPromptAction { case selectTab(selectedCategory: SolplyContentType) case toggleWritingGuide case updatePromptText(String) + case showTownSelectBottomSheet(isSheetPresented: Bool) + + // MARK: - TownSelectBottomSheet + + case fetchTowns + case fetchTownsSuccess(townList: [Town]) + case fetchTownsFailure(error: NetworkError) + + case setInitialTownId(townId: Int) + + case selectTown(Town) + case selectSubTown(SubTown) + + case saveSelection + case saveSelectionSuccess + case saveSelectionFailure(error: NetworkError) } diff --git a/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/Intent/AIRecommendPromptStore.swift b/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/Intent/AIRecommendPromptStore.swift index 88928101..b68b563a 100644 --- a/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/Intent/AIRecommendPromptStore.swift +++ b/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/Intent/AIRecommendPromptStore.swift @@ -11,10 +11,20 @@ import Foundation final class AIRecommendPromptStore: ObservableObject { @Published private(set) var state = AIRecommendPromptState() + private let effect = AIRecommendEffect( + townService: TownService() + ) + func dispatch(_ action: AIRecommendPromptAction) { AIRecommendPromptReducer.reduce(state: &state, action: action) switch action { + case .fetchTowns: + Task { + let result = await effect.fetchTowns() + dispatch(result) + } + default: break } diff --git a/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/State/AIRecommendPromptReducer.swift b/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/State/AIRecommendPromptReducer.swift index a46a172a..a54c6f55 100644 --- a/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/State/AIRecommendPromptReducer.swift +++ b/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/State/AIRecommendPromptReducer.swift @@ -21,6 +21,67 @@ enum AIRecommendPromptReducer { case .updatePromptText(let text): state.isRecommendButtonEnabled = text.count >= 5 + + case .showTownSelectBottomSheet(let isSheetPresented): + state.isTownSelectBottomSheetPresented = isSheetPresented + + // api + + case .fetchTowns: + state.isTownLoading = true + + case .fetchTownsSuccess(let townList): + state.townList = townList + + let subTowns = townList.flatMap { $0.subTowns } + state.selectedSubTown = subTowns.first { $0.id == state.initialTownId } + state.currentSelectedSubTown = state.selectedSubTown + + if let selectedSubTown = state.selectedSubTown { + state.selectedTown = townList.first { $0.subTowns.contains(selectedSubTown) } + } else { + if let firstTown = townList.first { + state.selectedTown = firstTown + state.selectedSubTown = firstTown.subTowns.first + state.currentSelectedSubTown = state.selectedSubTown + } else { + state.selectedTown = nil + state.selectedSubTown = nil + state.currentSelectedSubTown = nil + } + } + + state.isTownLoading = false + + case .fetchTownsFailure(let error): + print(error) + + case .setInitialTownId(let townId): + state.initialTownId = townId + + case .selectTown(let town): + state.selectedTown = town + + let subTowns = town.subTowns + + if let current = state.currentSelectedSubTown, subTowns.contains(current) { + state.selectedSubTown = current + } else { + state.selectedSubTown = subTowns.first + } + + case .selectSubTown(let subTown): + state.selectedSubTown = subTown + state.currentSelectedSubTown = subTown + + + // TODO: - API에 따라 달라질듯 + case .saveSelection: + break + case .saveSelectionSuccess: + break + case .saveSelectionFailure(let error): + break } } } diff --git a/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/State/AIRecommendPromptState.swift b/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/State/AIRecommendPromptState.swift index e43efc32..735425dd 100644 --- a/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/State/AIRecommendPromptState.swift +++ b/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/State/AIRecommendPromptState.swift @@ -11,4 +11,19 @@ struct AIRecommendPromptState { var selectedCategory: SolplyContentType = .place var isWritingGuidePresented: Bool = false var isRecommendButtonEnabled: Bool = false + var isTownSelectBottomSheetPresented: Bool = false + + // MARK: - TownSelectBottomSheet + + var isTownLoading: Bool = false + var isCompleteButtonLoading: Bool = false + + var initialTownId: Int = 0 + var currentSelectedSubTown: SubTown? = nil + + var townList: [Town] = [] + var selectedTown: Town? = nil + var selectedSubTown: SubTown? = nil + + } From 78277a8d6f7a6704a84c86f71ee42fb731ed454a Mon Sep 17 00:00:00 2001 From: seozero Date: Fri, 20 Mar 2026 17:30:13 +0100 Subject: [PATCH 5/9] =?UTF-8?q?[chore/#466]=20JGDRow=20=EA=B3=B5=ED=86=B5?= =?UTF-8?q?=20=EC=BB=B4=ED=8F=AC=EB=A1=9C=20=ED=8F=B4=EB=8D=94=EB=A7=81=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{Presentation/JGD => Global}/Component/JGDSubTownRow.swift | 0 .../{Presentation/JGD => Global}/Component/JGDTopTownRow.swift | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename Solply/Solply/{Presentation/JGD => Global}/Component/JGDSubTownRow.swift (100%) rename Solply/Solply/{Presentation/JGD => Global}/Component/JGDTopTownRow.swift (100%) diff --git a/Solply/Solply/Presentation/JGD/Component/JGDSubTownRow.swift b/Solply/Solply/Global/Component/JGDSubTownRow.swift similarity index 100% rename from Solply/Solply/Presentation/JGD/Component/JGDSubTownRow.swift rename to Solply/Solply/Global/Component/JGDSubTownRow.swift diff --git a/Solply/Solply/Presentation/JGD/Component/JGDTopTownRow.swift b/Solply/Solply/Global/Component/JGDTopTownRow.swift similarity index 100% rename from Solply/Solply/Presentation/JGD/Component/JGDTopTownRow.swift rename to Solply/Solply/Global/Component/JGDTopTownRow.swift From 2b113f561462df323ccc1b02ee378f3aa833f714 Mon Sep 17 00:00:00 2001 From: seozero Date: Sat, 21 Mar 2026 11:42:38 +0100 Subject: [PATCH 6/9] =?UTF-8?q?[feat/#466]=20TownSelectBottomSheet=20?= =?UTF-8?q?=EC=8A=A4=EC=BC=88=EB=A0=88=ED=86=A4=20=EB=B7=B0=20=EC=97=B0?= =?UTF-8?q?=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Component/TownSelectBottomSheet.swift | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/Component/TownSelectBottomSheet.swift b/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/Component/TownSelectBottomSheet.swift index e91e2a9c..8e32a0a4 100644 --- a/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/Component/TownSelectBottomSheet.swift +++ b/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/Component/TownSelectBottomSheet.swift @@ -17,31 +17,33 @@ struct TownSelectBottomSheet: View { // MARK: - Body var body: some View { - VStack(alignment: .center, spacing: 0) { - header - - divider - - ZStack(alignment: .bottom) { - VStack(alignment: .center, spacing: 0) { - HStack(alignment: .top, spacing: 0) { - townListView - - Divider() - - subTownListView - } + ZStack(alignment: .bottom) { + VStack(alignment: .center, spacing: 0) { + header + + if !store.state.isTownLoading { + divider } - SolplyMainButton( - title: "완료", - isEnabled: true - ) { + HStack(alignment: .top, spacing: 0) { + townListView + Divider() + + subTownListView } - .padding(.horizontal, 20.adjustedWidth) - .padding(.bottom, 38.adjustedHeight) + .customLoading(.JGDLoading, isLoading: store.state.isTownLoading) + } + .ignoresSafeArea(edges: .bottom) + + SolplyMainButton( + title: "완료", + isEnabled: true + ) { + } + .padding(.horizontal, 20.adjustedWidth) + .padding(.bottom, 38.adjustedHeight) } .onAppear { store.dispatch(.fetchTowns) @@ -77,7 +79,7 @@ extension TownSelectBottomSheet { private var divider: some View { Rectangle() - .frame(height: 1.adjustedHeight) + .frame(height: 1) .foregroundStyle(.gray300) } From bf8774684e63d8f27a9f4023753220230e442db4 Mon Sep 17 00:00:00 2001 From: seozero Date: Thu, 26 Mar 2026 16:17:37 +0100 Subject: [PATCH 7/9] =?UTF-8?q?[refactor/#466]=20BottomSheet=EC=9D=98=20st?= =?UTF-8?q?ore=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit store 직접 참조를 삭제하고 프로퍼티로 전달 --- .../Component/TownSelectBottomSheet.swift | 56 +++++++++++++++---- .../State/AIRecommendPromptReducer.swift | 2 +- .../View/AIRecommendPromptView.swift | 11 +++- 3 files changed, 56 insertions(+), 13 deletions(-) diff --git a/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/Component/TownSelectBottomSheet.swift b/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/Component/TownSelectBottomSheet.swift index 8e32a0a4..3c78fb61 100644 --- a/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/Component/TownSelectBottomSheet.swift +++ b/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/Component/TownSelectBottomSheet.swift @@ -12,7 +12,34 @@ struct TownSelectBottomSheet: View { // MARK: - Properties @Environment(\.dismiss) private var dismiss - @StateObject private var store = AIRecommendPromptStore() + + @State private var selectedTown: Town? + @State private var selectedSubTown: SubTown? + + private let isTownLoading: Bool + private let townList: [Town] + + private let initialTown: Town? + private let initialSubTown: SubTown? + + private let onAppear: (() -> Void)? + private let onComplete: ((Town?, SubTown?) -> Void)? + + init( + isTownLoading: Bool, + townList: [Town], + initialTown: Town? = nil, + initialSubTown: SubTown? = nil, + onAppear: (() -> Void)? = nil, + onComplete: ((Town?, SubTown?) -> Void)? = nil + ) { + self.isTownLoading = isTownLoading + self.townList = townList + self.initialTown = initialTown + self.initialSubTown = initialSubTown + self.onAppear = onAppear + self.onComplete = onComplete + } // MARK: - Body @@ -21,7 +48,7 @@ struct TownSelectBottomSheet: View { VStack(alignment: .center, spacing: 0) { header - if !store.state.isTownLoading { + if !isTownLoading { divider } @@ -32,7 +59,7 @@ struct TownSelectBottomSheet: View { subTownListView } - .customLoading(.JGDLoading, isLoading: store.state.isTownLoading) + .customLoading(.JGDLoading, isLoading: isTownLoading) } .ignoresSafeArea(edges: .bottom) @@ -40,13 +67,19 @@ struct TownSelectBottomSheet: View { title: "완료", isEnabled: true ) { - + onComplete?(selectedTown, selectedSubTown) } .padding(.horizontal, 20.adjustedWidth) .padding(.bottom, 38.adjustedHeight) } .onAppear { - store.dispatch(.fetchTowns) + onAppear?() + } + .onChange(of: townList) { + if selectedTown == nil { + selectedTown = initialTown + selectedSubTown = initialSubTown + } } } } @@ -85,12 +118,13 @@ extension TownSelectBottomSheet { private var townListView: some View { VStack(spacing: 0) { - ForEach(store.state.townList, id: \.self) { town in + ForEach(townList, id: \.self) { town in JGDTopTownRow( title: town.townName, - isSelected: store.state.selectedTown?.id == town.id + isSelected: selectedTown?.id == town.id ) { - store.dispatch(.selectTown(town)) + selectedTown = town + selectedSubTown = nil } } @@ -101,15 +135,15 @@ extension TownSelectBottomSheet { } private var subTownListView: some View { - let subTowns = store.state.selectedTown?.subTowns ?? [] + let subTowns = selectedTown?.subTowns ?? [] return VStack(spacing: 0) { ForEach(subTowns, id: \.self) { subTown in JGDSubTownRow( title: subTown.townName, - isSelected: store.state.selectedSubTown?.id == subTown.id + isSelected: selectedSubTown?.id == subTown.id ) { - store.dispatch(.selectSubTown(subTown)) + selectedSubTown = subTown } } diff --git a/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/State/AIRecommendPromptReducer.swift b/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/State/AIRecommendPromptReducer.swift index a54c6f55..7dc485cf 100644 --- a/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/State/AIRecommendPromptReducer.swift +++ b/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/State/AIRecommendPromptReducer.swift @@ -81,7 +81,7 @@ enum AIRecommendPromptReducer { case .saveSelectionSuccess: break case .saveSelectionFailure(let error): - break + print(error) } } } diff --git a/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/View/AIRecommendPromptView.swift b/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/View/AIRecommendPromptView.swift index 0ac74611..0f2953ad 100644 --- a/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/View/AIRecommendPromptView.swift +++ b/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/View/AIRecommendPromptView.swift @@ -39,7 +39,16 @@ struct AIRecommendPromptView: View { set: { store.dispatch(.showTownSelectBottomSheet(isSheetPresented: $0)) } ) ) { - TownSelectBottomSheet() + TownSelectBottomSheet( + isTownLoading: store.state.isTownLoading, + townList: store.state.townList, + initialTown: store.state.selectedTown, + initialSubTown: store.state.selectedSubTown, + onAppear: { store.dispatch(.fetchTowns) }, + onComplete: { town, subTown in + // TODO: 완료 버튼 기능 구현 후 연결 + } + ) .presentationDetents([.height(654.adjustedHeight)]) .presentationCornerRadius(20) } From 05ac3e8bd9c372f951ecad89d838ff42f4628114 Mon Sep 17 00:00:00 2001 From: seozero Date: Thu, 26 Mar 2026 16:21:53 +0100 Subject: [PATCH 8/9] =?UTF-8?q?[chore/#466]=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Solply/Solply.xcodeproj/project.pbxproj | 17 ---------------- .../xcshareddata/swiftpm/Package.resolved | 20 +------------------ 2 files changed, 1 insertion(+), 36 deletions(-) diff --git a/Solply/Solply.xcodeproj/project.pbxproj b/Solply/Solply.xcodeproj/project.pbxproj index 6cb4e600..0ef7e2cf 100644 --- a/Solply/Solply.xcodeproj/project.pbxproj +++ b/Solply/Solply.xcodeproj/project.pbxproj @@ -8,7 +8,6 @@ /* Begin PBXBuildFile section */ 985476632E255FA5005164CF /* Lottie in Frameworks */ = {isa = PBXBuildFile; productRef = 985476622E255FA5005164CF /* Lottie */; }; - E34011482E151709008944E7 /* NMapsMap in Frameworks */ = {isa = PBXBuildFile; productRef = E34011472E151709008944E7 /* NMapsMap */; }; E3430A9F2E2643C900EA1CE5 /* KakaoSDKAuth in Frameworks */ = {isa = PBXBuildFile; productRef = E3430A9E2E2643C900EA1CE5 /* KakaoSDKAuth */; }; E3430AA12E2643C900EA1CE5 /* KakaoSDKCommon in Frameworks */ = {isa = PBXBuildFile; productRef = E3430AA02E2643C900EA1CE5 /* KakaoSDKCommon */; }; E3430AA32E2643C900EA1CE5 /* KakaoSDKUser in Frameworks */ = {isa = PBXBuildFile; productRef = E3430AA22E2643C900EA1CE5 /* KakaoSDKUser */; }; @@ -49,7 +48,6 @@ files = ( E3475AE72F1F958200D530DB /* AmplitudeSwift in Frameworks */, E36882862E0DD935008A7288 /* Moya in Frameworks */, - E34011482E151709008944E7 /* NMapsMap in Frameworks */, E36882832E0DD8AF008A7288 /* Kingfisher in Frameworks */, E3430AA32E2643C900EA1CE5 /* KakaoSDKUser in Frameworks */, 985476632E255FA5005164CF /* Lottie in Frameworks */, @@ -99,7 +97,6 @@ packageProductDependencies = ( E36882822E0DD8AF008A7288 /* Kingfisher */, E36882852E0DD935008A7288 /* Moya */, - E34011472E151709008944E7 /* NMapsMap */, 985476622E255FA5005164CF /* Lottie */, E3430A9E2E2643C900EA1CE5 /* KakaoSDKAuth */, E3430AA02E2643C900EA1CE5 /* KakaoSDKCommon */, @@ -137,7 +134,6 @@ packageReferences = ( E36882812E0DD8AF008A7288 /* XCRemoteSwiftPackageReference "Kingfisher" */, E36882842E0DD935008A7288 /* XCRemoteSwiftPackageReference "Moya" */, - E34011462E151709008944E7 /* XCRemoteSwiftPackageReference "SPM-NMapsMap" */, 985476612E255FA5005164CF /* XCRemoteSwiftPackageReference "lottie-ios" */, E3430A9D2E2643C900EA1CE5 /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */, E3475AE52F1F958200D530DB /* XCRemoteSwiftPackageReference "Amplitude-Swift" */, @@ -416,14 +412,6 @@ minimumVersion = 4.5.2; }; }; - E34011462E151709008944E7 /* XCRemoteSwiftPackageReference "SPM-NMapsMap" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/navermaps/SPM-NMapsMap"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 3.22.0; - }; - }; E3430A9D2E2643C900EA1CE5 /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/kakao/kakao-ios-sdk"; @@ -464,11 +452,6 @@ package = 985476612E255FA5005164CF /* XCRemoteSwiftPackageReference "lottie-ios" */; productName = Lottie; }; - E34011472E151709008944E7 /* NMapsMap */ = { - isa = XCSwiftPackageProductDependency; - package = E34011462E151709008944E7 /* XCRemoteSwiftPackageReference "SPM-NMapsMap" */; - productName = NMapsMap; - }; E3430A9E2E2643C900EA1CE5 /* KakaoSDKAuth */ = { isa = XCSwiftPackageProductDependency; package = E3430A9D2E2643C900EA1CE5 /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */; diff --git a/Solply/Solply.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Solply/Solply.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index fc7b09fa..518e63f2 100644 --- a/Solply/Solply.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Solply/Solply.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "55b551d101d1df63f953c78b36c5ab5ddd14380b691245491bbbd97061e98728", + "originHash" : "8e1158d37f3a2648a75252d030dbe6d1f09429ab07c22f76d4b2389c60fca86b", "pins" : [ { "identity" : "alamofire", @@ -90,24 +90,6 @@ "revision" : "5dd1907d64f0d36f158f61a466bab75067224893", "version" : "6.9.0" } - }, - { - "identity" : "spm-nmapsgeometry", - "kind" : "remoteSourceControl", - "location" : "https://github.com/navermaps/SPM-NMapsGeometry.git", - "state" : { - "revision" : "436d5e2e684f557faf5ef5862fd6633a42d7af11", - "version" : "1.0.2" - } - }, - { - "identity" : "spm-nmapsmap", - "kind" : "remoteSourceControl", - "location" : "https://github.com/navermaps/SPM-NMapsMap", - "state" : { - "revision" : "13a6d280a57c4ebab8320e2d5bf3ce89adacf95e", - "version" : "3.22.0" - } } ], "version" : 3 From 12466a36ec780bd4648173dd0038881ad133ec5c Mon Sep 17 00:00:00 2001 From: seozero Date: Thu, 26 Mar 2026 16:25:19 +0100 Subject: [PATCH 9/9] =?UTF-8?q?[chore/#466]=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AIRecommendPrompt/Component/TownSelectBottomSheet.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/Component/TownSelectBottomSheet.swift b/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/Component/TownSelectBottomSheet.swift index 3c78fb61..66641ea3 100644 --- a/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/Component/TownSelectBottomSheet.swift +++ b/Solply/Solply/Presentation/AIRecommend/AIRecommendPrompt/Component/TownSelectBottomSheet.swift @@ -100,6 +100,7 @@ extension TownSelectBottomSheet { } label: { Image(.xIconSm) .resizable() + .aspectRatio(contentMode: .fit) .frame(width: 24.adjusted, height: 24.adjusted) .foregroundStyle(.gray800) } @@ -117,7 +118,7 @@ extension TownSelectBottomSheet { } private var townListView: some View { - VStack(spacing: 0) { + VStack(alignment: .center, spacing: 0) { ForEach(townList, id: \.self) { town in JGDTopTownRow( title: town.townName, @@ -137,7 +138,7 @@ extension TownSelectBottomSheet { private var subTownListView: some View { let subTowns = selectedTown?.subTowns ?? [] - return VStack(spacing: 0) { + return VStack(alignment: .center, spacing: 0) { ForEach(subTowns, id: \.self) { subTown in JGDSubTownRow( title: subTown.townName,