From cbd3bde14787be936fabf5f25839a40fd6b6392b Mon Sep 17 00:00:00 2001 From: blwxnhan Date: Mon, 17 Nov 2025 14:23:20 +0900 Subject: [PATCH 1/3] =?UTF-8?q?[Fix]=20=EC=B5=9C=EC=8B=A0=20=EC=BF=A0?= =?UTF-8?q?=ED=8F=B0=20=EB=8D=94=EB=B3=B4=EA=B8=B0=20=ED=99=94=EB=A9=B4=20?= =?UTF-8?q?=EC=BF=A0=ED=8F=B0=20DTO=20=EC=84=9C=EB=B2=84=EC=99=80=20?= =?UTF-8?q?=EB=8F=99=EC=9D=BC=ED=95=98=EA=B2=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MarketPlace/API/Endpoint/CouponEndpoint.swift | 5 +++-- MarketPlace/Model/CouponModel.swift | 1 + MarketPlace/Service/CouponService.swift | 4 +++- MarketPlace/Types/CouponType.swift | 4 ++-- .../View/Main/Components/NewEventView.swift | 4 ++-- .../View/Main/View/NewEventDetailView.swift | 14 ++++++++++---- MarketPlace/ViewModel/Main/NewEventViewModel.swift | 4 ++++ 7 files changed, 25 insertions(+), 11 deletions(-) diff --git a/MarketPlace/API/Endpoint/CouponEndpoint.swift b/MarketPlace/API/Endpoint/CouponEndpoint.swift index 1e58d87..d171c48 100644 --- a/MarketPlace/API/Endpoint/CouponEndpoint.swift +++ b/MarketPlace/API/Endpoint/CouponEndpoint.swift @@ -14,7 +14,7 @@ enum CouponEndpoint: Endpoint { case fetchTopLatestCoupon(pageSize: Int?) case fetchTopClosingCoupon(pageSize: Int?) case fetchPopularCoupon(lastIssuedCount: Int?, lastCouponId: Int?, pageSize: Int?) - case fetchLatestCoupon(lastCreatedAt: String?, lastCouponId: Int?, pageSize: Int?) + case fetchLatestCoupon(lastCreatedAt: String?, lastCouponId: Int?, couponType: String?, pageSize: Int?) case putSubmitReceipt(memberCouponId: Int, image: Data, bodyBoundary: String) var baseURL: URL { URLManager.shared.baseURL } @@ -81,12 +81,13 @@ enum CouponEndpoint: Endpoint { return items - case .fetchLatestCoupon(let lastCreatedAt, let lastCouponId, let pageSize): + case .fetchLatestCoupon(let lastCreatedAt, let lastCouponId, let couponType, let pageSize): var items: [URLQueryItem] = [] items.append(contentsOf: [ lastCreatedAt.map { URLQueryItem(name: "lastCreatedAt", value: String($0)) }, lastCouponId.map { URLQueryItem(name: "lastCouponId", value: String($0)) }, + URLQueryItem(name: "couponType", value: couponType), pageSize.map { URLQueryItem(name: "pageSize", value: String($0)) } ].compactMap { $0 }) diff --git a/MarketPlace/Model/CouponModel.swift b/MarketPlace/Model/CouponModel.swift index be90367..90910b9 100644 --- a/MarketPlace/Model/CouponModel.swift +++ b/MarketPlace/Model/CouponModel.swift @@ -19,6 +19,7 @@ struct CouponNewModel: Codable, Identifiable { let couponName: String let marketId: Int let marketName: String + let couponType: String let address: String let thumbnail: String let isAvailable: Bool diff --git a/MarketPlace/Service/CouponService.swift b/MarketPlace/Service/CouponService.swift index fb345be..02f5450 100644 --- a/MarketPlace/Service/CouponService.swift +++ b/MarketPlace/Service/CouponService.swift @@ -27,7 +27,7 @@ protocol CouponServiceProtocol { func fetchCouponPopular(lastIssuedCount: Int?, lastCouponId: Int?, pageSize: Int?) async -> NetworkResult> // MARK: - 최신 등록 쿠폰 더보기 조회 API - func fetchLatestCoupons(lastCreatedAt: String?, lastCouponId: Int?, pageSize: Int?) async -> NetworkResult> + func fetchLatestCoupons(lastCreatedAt: String?, lastCouponId: Int?, couponType: String?, pageSize: Int?) async -> NetworkResult> // MARK: - 영수증 쿠폰 제출하기 func putSubmitReceipt(memberCouponId: Int, image: Data, bodyBoundary: String) async -> NetworkResult> @@ -77,12 +77,14 @@ final class CouponService: CouponServiceProtocol { func fetchLatestCoupons( lastCreatedAt: String? = nil, lastCouponId: Int? = nil, + couponType: String? = nil, pageSize: Int? = nil ) async -> NetworkResult> { return await networkService.request( CouponEndpoint.fetchLatestCoupon( lastCreatedAt: lastCreatedAt, lastCouponId: lastCouponId, + couponType: couponType, pageSize: pageSize ) ) diff --git a/MarketPlace/Types/CouponType.swift b/MarketPlace/Types/CouponType.swift index 2692dfa..5fab45c 100644 --- a/MarketPlace/Types/CouponType.swift +++ b/MarketPlace/Types/CouponType.swift @@ -12,8 +12,8 @@ enum CouponType: String, CaseIterable { func toString() -> String { switch self { - case .giftableCoupon: return "" - case .refundableCoupon: return "" + case .giftableCoupon: return "GIFT" + case .refundableCoupon: return "PAYBACK" } } diff --git a/MarketPlace/View/Main/Components/NewEventView.swift b/MarketPlace/View/Main/Components/NewEventView.swift index 7e62eaa..7bce1f4 100644 --- a/MarketPlace/View/Main/Components/NewEventView.swift +++ b/MarketPlace/View/Main/Components/NewEventView.swift @@ -9,10 +9,10 @@ struct NewEventView: View { VStack { HStack { Text("\(currentMonth) 신규 | 멤버십 혜택") - .pretendardFont(size: 19, weight: .bold) + .pretendardFont(size: 19, weight: .semibold) .foregroundColor(.black) Spacer() - NavigationLink(destination: NewEventDetailView()) { + NavigationLink(destination: NewEventDetailView(currentMonth: self.currentMonth)) { Text("더보기 >") .pretendardFont(size: 14, weight: .medium) .foregroundColor(Color(red: 0.29, green: 0.29, blue: 0.29)) diff --git a/MarketPlace/View/Main/View/NewEventDetailView.swift b/MarketPlace/View/Main/View/NewEventDetailView.swift index 898cd72..41b9818 100644 --- a/MarketPlace/View/Main/View/NewEventDetailView.swift +++ b/MarketPlace/View/Main/View/NewEventDetailView.swift @@ -4,6 +4,7 @@ import SwiftUI struct NewEventDetailView: View { @Environment(\.presentationMode) var presentationMode @ObservedObject var viewModel = NewEventViewModel() + var currentMonth: String var body: some View { VStack(spacing: 0) { @@ -38,11 +39,16 @@ struct NewEventDetailView: View { }.onAppear { guard index == viewModel.newCoupons.count - 1, let lastId = viewModel.lastCouponId, - let lastCreated = viewModel.lastCreatedAt + let lastCreated = viewModel.lastCreatedAt, + let lastCouponType = viewModel.lastCouponType else { return } - + Task { - await viewModel.fetchLatestCoupons(lastCreatedAt: lastCreated, lastCouponId: lastId) + await viewModel.fetchLatestCoupons( + lastCreatedAt: lastCreated, + lastCouponId: lastId, + couponType: lastCouponType + ) } } } @@ -54,7 +60,7 @@ struct NewEventDetailView: View { await viewModel.fetchLatestCoupons() } } - .navigationTitle("1월 신규 | 멤버십 혜택") + .navigationTitle("\(currentMonth)월 신규 | 멤버십 혜택") .navigationBarTitleDisplayMode(.inline) .navigationBarBackButtonHidden(true) .toolbar { diff --git a/MarketPlace/ViewModel/Main/NewEventViewModel.swift b/MarketPlace/ViewModel/Main/NewEventViewModel.swift index 18bd6cb..c28317e 100644 --- a/MarketPlace/ViewModel/Main/NewEventViewModel.swift +++ b/MarketPlace/ViewModel/Main/NewEventViewModel.swift @@ -12,6 +12,7 @@ final class NewEventViewModel: ObservableObject { @Published var errorMessage: String? @Published var lastCouponId: Int? @Published var lastCreatedAt: String? + @Published var lastCouponType: String? var currentPage: Int = 1 var hasNextPage: Bool = true @@ -28,6 +29,7 @@ final class NewEventViewModel: ObservableObject { func fetchLatestCoupons( lastCreatedAt: String? = nil, lastCouponId: Int? = nil, + couponType: String? = nil, pageSize: Int? = nil ) async { guard !isLoading, hasNextPage else { return } @@ -37,6 +39,7 @@ final class NewEventViewModel: ObservableObject { let result = await couponService.fetchLatestCoupons( lastCreatedAt: lastCreatedAt, lastCouponId: lastCouponId, + couponType: couponType, pageSize: pageSize ) @@ -51,6 +54,7 @@ final class NewEventViewModel: ObservableObject { if let last = data.response.couponResDtos.last { self.lastCouponId = last.couponId self.lastCreatedAt = last.couponCreatedAt + self.lastCouponType = last.couponType } self.hasNextPage = data.response.hasNext From c099cbbdd423f9f2c5fa5b9b3fbbdd8d041f3192 Mon Sep 17 00:00:00 2001 From: blwxnhan Date: Mon, 17 Nov 2025 15:12:44 +0900 Subject: [PATCH 2/3] =?UTF-8?q?[Fix]=20=EC=BF=A0=ED=8F=B0=20Endpoint=20Que?= =?UTF-8?q?ry=20=EB=B0=98=ED=99=98=EA=B0=92=EC=9D=B4=20=EB=AA=A8=EB=91=90?= =?UTF-8?q?=20=EC=97=86=EC=9D=84=EB=95=8C=20nil=20=EB=B0=98=ED=99=98?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MarketPlace/API/Endpoint/CouponEndpoint.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/MarketPlace/API/Endpoint/CouponEndpoint.swift b/MarketPlace/API/Endpoint/CouponEndpoint.swift index d171c48..0e72911 100644 --- a/MarketPlace/API/Endpoint/CouponEndpoint.swift +++ b/MarketPlace/API/Endpoint/CouponEndpoint.swift @@ -79,7 +79,7 @@ enum CouponEndpoint: Endpoint { pageSize.map { URLQueryItem(name: "pageSize", value: String($0)) } ].compactMap { $0 }) - return items + return items.isEmpty ? nil : items case .fetchLatestCoupon(let lastCreatedAt, let lastCouponId, let couponType, let pageSize): var items: [URLQueryItem] = [] @@ -87,11 +87,11 @@ enum CouponEndpoint: Endpoint { items.append(contentsOf: [ lastCreatedAt.map { URLQueryItem(name: "lastCreatedAt", value: String($0)) }, lastCouponId.map { URLQueryItem(name: "lastCouponId", value: String($0)) }, - URLQueryItem(name: "couponType", value: couponType), + couponType.map { URLQueryItem(name: "couponType", value: $0) }, pageSize.map { URLQueryItem(name: "pageSize", value: String($0)) } ].compactMap { $0 }) - return items + return items.isEmpty ? nil : items case .fetchValidCoupon(let marketId, let couponId, let size), .fetchValidPaybackCoupon(let marketId, let couponId, let size): @@ -103,7 +103,7 @@ enum CouponEndpoint: Endpoint { size.map { URLQueryItem(name: "size", value: String($0)) } ].compactMap { $0 }) - return items + return items.isEmpty ? nil : items case .putSubmitReceipt(let memberCouponId, _, _): return [URLQueryItem(name: "memberCouponId", value: String(memberCouponId))] From d1add1749f956673bd9c239666308c26521e4cc8 Mon Sep 17 00:00:00 2001 From: blwxnhan Date: Mon, 17 Nov 2025 16:24:11 +0900 Subject: [PATCH 3/3] =?UTF-8?q?[Fix]=20=EC=9D=B8=EA=B8=B0=20=EC=BF=A0?= =?UTF-8?q?=ED=8F=B0=20=EB=8D=94=EB=B3=B4=EA=B8=B0=20=ED=99=94=EB=A9=B4=20?= =?UTF-8?q?=EC=BF=A0=ED=8F=B0=20DTO=20=EC=84=9C=EB=B2=84=EC=99=80=20?= =?UTF-8?q?=EB=8F=99=EC=9D=BC=ED=95=98=EA=B2=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MarketPlace.xcodeproj/project.pbxproj | 4 +- MarketPlace/API/Endpoint/CouponEndpoint.swift | 5 ++- MarketPlace/Model/CouponModel.swift | 2 + MarketPlace/Service/CouponService.swift | 4 +- .../View/Main/View/NewEventDetailView.swift | 2 +- .../View/Main/View/Top20DetailView.swift | 37 +++++++++++++++---- MarketPlace/View/Map/View/MapView.swift | 2 +- .../ViewModel/Main/Top20DetailViewModel.swift | 6 +++ 8 files changed, 48 insertions(+), 14 deletions(-) diff --git a/MarketPlace.xcodeproj/project.pbxproj b/MarketPlace.xcodeproj/project.pbxproj index cade305..33ae3a6 100644 --- a/MarketPlace.xcodeproj/project.pbxproj +++ b/MarketPlace.xcodeproj/project.pbxproj @@ -1377,7 +1377,7 @@ CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"MarketPlace/Preview Content\""; - DEVELOPMENT_TEAM = 7RR74CRWQW; + DEVELOPMENT_TEAM = F7GYZYWC6V; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = MarketPlace/Info.plist; @@ -1417,7 +1417,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"MarketPlace/Preview Content\""; - DEVELOPMENT_TEAM = 7RR74CRWQW; + DEVELOPMENT_TEAM = F7GYZYWC6V; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = MarketPlace/Info.plist; diff --git a/MarketPlace/API/Endpoint/CouponEndpoint.swift b/MarketPlace/API/Endpoint/CouponEndpoint.swift index 0e72911..337ccf1 100644 --- a/MarketPlace/API/Endpoint/CouponEndpoint.swift +++ b/MarketPlace/API/Endpoint/CouponEndpoint.swift @@ -13,7 +13,7 @@ enum CouponEndpoint: Endpoint { case fetchTopPoplarCoupon(pageSize: Int?) case fetchTopLatestCoupon(pageSize: Int?) case fetchTopClosingCoupon(pageSize: Int?) - case fetchPopularCoupon(lastIssuedCount: Int?, lastCouponId: Int?, pageSize: Int?) + case fetchPopularCoupon(lastIssuedCount: Int?, lastCouponId: Int?, couponType: String?, pageSize: Int?) case fetchLatestCoupon(lastCreatedAt: String?, lastCouponId: Int?, couponType: String?, pageSize: Int?) case putSubmitReceipt(memberCouponId: Int, image: Data, bodyBoundary: String) @@ -70,12 +70,13 @@ enum CouponEndpoint: Endpoint { .fetchTopClosingCoupon(let pageSize): return pageSize.map { [URLQueryItem(name: "pageSize", value: String($0))] } ?? nil - case .fetchPopularCoupon(let lastIssuedCount, let lastCouponId, let pageSize): + case .fetchPopularCoupon(let lastIssuedCount, let lastCouponId, let couponType, let pageSize): var items: [URLQueryItem] = [] items.append(contentsOf: [ lastIssuedCount.map { URLQueryItem(name: "lastIssuedCount", value: String($0)) }, lastCouponId.map { URLQueryItem(name: "lastCouponId", value: String($0)) }, + couponType.map { URLQueryItem(name: "couponType", value: $0) }, pageSize.map { URLQueryItem(name: "pageSize", value: String($0)) } ].compactMap { $0 }) diff --git a/MarketPlace/Model/CouponModel.swift b/MarketPlace/Model/CouponModel.swift index 90910b9..0c4cb06 100644 --- a/MarketPlace/Model/CouponModel.swift +++ b/MarketPlace/Model/CouponModel.swift @@ -10,6 +10,8 @@ struct CouponPopularModel: Codable, Identifiable { let isAvailable: Bool let isMemberIssued: Bool let issuedCount: Int + let couponType: String + let orderNo: Int var id: Int { couponId } } diff --git a/MarketPlace/Service/CouponService.swift b/MarketPlace/Service/CouponService.swift index 02f5450..9b39b64 100644 --- a/MarketPlace/Service/CouponService.swift +++ b/MarketPlace/Service/CouponService.swift @@ -24,7 +24,7 @@ protocol CouponServiceProtocol { func fetchCouponTopClosing(pageSize: Int?) async -> NetworkResult> // MARK: - 인기 쿠폰 더보기 조회 API - func fetchCouponPopular(lastIssuedCount: Int?, lastCouponId: Int?, pageSize: Int?) async -> NetworkResult> + func fetchCouponPopular(lastIssuedCount: Int?, lastCouponId: Int?, couponType: String?, pageSize: Int?) async -> NetworkResult> // MARK: - 최신 등록 쿠폰 더보기 조회 API func fetchLatestCoupons(lastCreatedAt: String?, lastCouponId: Int?, couponType: String?, pageSize: Int?) async -> NetworkResult> @@ -62,12 +62,14 @@ final class CouponService: CouponServiceProtocol { func fetchCouponPopular( lastIssuedCount: Int? = nil, lastCouponId: Int? = nil, + couponType: String? = nil, pageSize: Int? = nil ) async -> NetworkResult> { return await networkService.request( CouponEndpoint.fetchPopularCoupon( lastIssuedCount: lastIssuedCount, lastCouponId: lastCouponId, + couponType: couponType, pageSize: pageSize ) ) diff --git a/MarketPlace/View/Main/View/NewEventDetailView.swift b/MarketPlace/View/Main/View/NewEventDetailView.swift index 41b9818..a865db4 100644 --- a/MarketPlace/View/Main/View/NewEventDetailView.swift +++ b/MarketPlace/View/Main/View/NewEventDetailView.swift @@ -60,7 +60,7 @@ struct NewEventDetailView: View { await viewModel.fetchLatestCoupons() } } - .navigationTitle("\(currentMonth)월 신규 | 멤버십 혜택") + .navigationTitle("\(currentMonth) 신규 | 멤버십 혜택") .navigationBarTitleDisplayMode(.inline) .navigationBarBackButtonHidden(true) .toolbar { diff --git a/MarketPlace/View/Main/View/Top20DetailView.swift b/MarketPlace/View/Main/View/Top20DetailView.swift index ac02969..791f8d7 100644 --- a/MarketPlace/View/Main/View/Top20DetailView.swift +++ b/MarketPlace/View/Main/View/Top20DetailView.swift @@ -11,7 +11,7 @@ struct Top20DetailView: View { .background(Color.gray.opacity(0.5)) ScrollView { LazyVStack(spacing: 16) { - ForEach(viewModel.topCoupons) { coupon in + ForEach(Array(viewModel.topCoupons.enumerated()), id: \.offset) { index, coupon in NavigationLink(destination: MarketDetailView(marketId: coupon.marketId) ) { @@ -37,13 +37,36 @@ struct Top20DetailView: View { } } .onAppear { - if let lastCoupon = viewModel.topCoupons.last, - coupon.couponId == lastCoupon.couponId, - let lastId = viewModel.lastCouponId, - let lastIssued = viewModel.lastIssuedCount { - Task { - await viewModel.fetchCouponPopular(lastIssuedCount: lastIssued, lastCouponId: lastId) + guard index == viewModel.topCoupons.count - 1, + let lastCouponType = viewModel.couponType, + let lastId = viewModel.lastCouponId + else { return } + + switch lastCouponType { + case "PAYBACK": + if let lastOrderNo = viewModel.lastOrderNo { + Task { + await viewModel.fetchCouponPopular( + lastIssuedCount: lastOrderNo, + lastCouponId: lastId, + couponType: lastCouponType + ) + } } + + case "GIFT": + if let lastIssued = viewModel.lastIssuedCount { + Task { + await viewModel.fetchCouponPopular( + lastIssuedCount: lastIssued, + lastCouponId: lastId, + couponType: lastCouponType + ) + } + } + + default: print("") + } } } diff --git a/MarketPlace/View/Map/View/MapView.swift b/MarketPlace/View/Map/View/MapView.swift index b38c275..da7de92 100644 --- a/MarketPlace/View/Map/View/MapView.swift +++ b/MarketPlace/View/Map/View/MapView.swift @@ -33,7 +33,7 @@ struct MapView: View { await viewModel.fetchMarketsWithAddress( lastPageIndex: nil, category: Category(index: selectedCategory)?.toString() ?? nil, - pageSize: 20 + pageSize: 40 ) } }) diff --git a/MarketPlace/ViewModel/Main/Top20DetailViewModel.swift b/MarketPlace/ViewModel/Main/Top20DetailViewModel.swift index 98fd47a..af36de9 100644 --- a/MarketPlace/ViewModel/Main/Top20DetailViewModel.swift +++ b/MarketPlace/ViewModel/Main/Top20DetailViewModel.swift @@ -12,6 +12,8 @@ final class Top20DetailViewModel: ObservableObject { @Published var errorMessage: String? @Published var lastCouponId: Int? @Published var lastIssuedCount: Int? + @Published var lastOrderNo: Int? + @Published var couponType: String? var currentPage: Int = 1 var isLoading: Bool = false @@ -28,6 +30,7 @@ final class Top20DetailViewModel: ObservableObject { func fetchCouponPopular( lastIssuedCount: Int? = nil, lastCouponId: Int? = nil, + couponType: String? = nil, pageSize: Int? = nil ) async { guard !isLoading, hasNextPage else { return } @@ -37,6 +40,7 @@ final class Top20DetailViewModel: ObservableObject { let result = await couponService.fetchCouponPopular( lastIssuedCount: lastIssuedCount, lastCouponId: lastCouponId, + couponType: couponType, pageSize: pageSize ) @@ -51,6 +55,8 @@ final class Top20DetailViewModel: ObservableObject { if let last = data.response.couponResDtos.last { self.lastCouponId = last.couponId self.lastIssuedCount = last.issuedCount + self.couponType = last.couponType + self.lastOrderNo = last.orderNo } self.hasNextPage = data.response.hasNext