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 1e58d87..337ccf1 100644 --- a/MarketPlace/API/Endpoint/CouponEndpoint.swift +++ b/MarketPlace/API/Endpoint/CouponEndpoint.swift @@ -13,8 +13,8 @@ enum CouponEndpoint: Endpoint { case fetchTopPoplarCoupon(pageSize: Int?) 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 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) var baseURL: URL { URLManager.shared.baseURL } @@ -70,27 +70,29 @@ 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 }) - return items + return items.isEmpty ? nil : 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)) }, + 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): @@ -102,7 +104,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))] diff --git a/MarketPlace/Model/CouponModel.swift b/MarketPlace/Model/CouponModel.swift index be90367..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 } } @@ -19,6 +21,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..9b39b64 100644 --- a/MarketPlace/Service/CouponService.swift +++ b/MarketPlace/Service/CouponService.swift @@ -24,10 +24,10 @@ 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?, 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> @@ -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 ) ) @@ -77,12 +79,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..a865db4 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/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/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 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