feat(home): 추천 배너 섹션을 연결한다

This commit is contained in:
Yu Sung
2026-06-29 15:39:23 +09:00
parent c441fb0b02
commit 0e31c69be8
10 changed files with 454 additions and 41 deletions

View File

@@ -0,0 +1,83 @@
import SwiftUI
struct MainHomeBannerSection: View {
let items: [RecommendationBannerResponse]
let onTapBanner: (RecommendationBannerResponse) -> Void
init(
items: [RecommendationBannerResponse],
onTapBanner: @escaping (RecommendationBannerResponse) -> Void = { _ in }
) {
self.items = items
self.onTapBanner = onTapBanner
}
var body: some View {
if !items.isEmpty {
BannerCarousel(items: carouselItems) { item in
guard let banner = banner(for: item) else { return }
onTapBanner(banner)
}
}
}
private var carouselItems: [BannerCarouselItem] {
items.enumerated().map { index, item in
BannerCarouselItem(
id: fallbackId(for: item, index: index),
imageUrl: item.imageUrl
)
}
}
private func banner(for carouselItem: BannerCarouselItem) -> RecommendationBannerResponse? {
items.enumerated().first { index, item in
fallbackId(for: item, index: index) == carouselItem.id
}?.element
}
private func fallbackId(for item: RecommendationBannerResponse, index: Int) -> String {
if let eventItem = item.eventItem {
return "banner-\(index)-event-\(eventItem.id)"
}
if let creatorId = item.creatorId {
return "banner-\(index)-creator-\(creatorId)"
}
if let seriesId = item.seriesId {
return "banner-\(index)-series-\(seriesId)"
}
if let link = item.link, !link.isEmpty {
return "banner-\(index)-link-\(link)"
}
return "banner-\(index)-image-\(item.imageUrl)"
}
}
struct MainHomeBannerSection_Previews: PreviewProvider {
static var previews: some View {
MainHomeBannerSection(
items: [
RecommendationBannerResponse(
imageUrl: "https://picsum.photos/500/500",
eventItem: nil,
creatorId: nil,
seriesId: nil,
link: nil
),
RecommendationBannerResponse(
imageUrl: "https://picsum.photos/500/500",
eventItem: nil,
creatorId: 1,
seriesId: nil,
link: nil
)
]
)
.background(Color.black)
.previewLayout(.sizeThatFits)
}
}

View File

@@ -55,7 +55,7 @@ private struct MainHomeLiveItemView: View {
}
struct MainHomeLiveSection_Previews: PreviewProvider {
private static let previewImageUrl = "https://placehold.co/500"
private static let previewImageUrl = "https://picsum.photos/500/500"
static var previews: some View {
Group {

View File

@@ -6,6 +6,7 @@ struct MainHomeRecommendationView: View {
let onTapContent: (Int) -> Void
let onTapCharacter: (Int) -> Void
let onTapCommunity: (Int) -> Void
let onTapBanner: (RecommendationBannerResponse) -> Void
@StateObject private var viewModel = MainHomeRecommendationViewModel()
@@ -24,6 +25,11 @@ struct MainHomeRecommendationView: View {
items: viewModel.recommendations?.lives ?? [],
onTapLive: onTapLive
)
MainHomeBannerSection(
items: viewModel.recommendations?.banners ?? [],
onTapBanner: onTapBanner
)
}
.padding(.vertical, SodaSpacing.s20)
}
@@ -49,7 +55,8 @@ struct MainHomeRecommendationView_Previews: PreviewProvider {
onTapCreator: { _ in },
onTapContent: { _ in },
onTapCharacter: { _ in },
onTapCommunity: { _ in }
onTapCommunity: { _ in },
onTapBanner: { _ in }
)
}
}

View File

@@ -19,14 +19,11 @@ struct HomeLiveItem: Decodable, Hashable {
}
struct RecommendationBannerResponse: Decodable, Hashable {
let bannerId: Int?
let type: String?
let title: String?
let imageUrl: String?
let link: String?
let eventId: Int?
let imageUrl: String
let eventItem: EventItem?
let creatorId: Int?
let seriesId: Int?
let link: String?
}
struct HomeActiveCreatorItem: Decodable, Hashable {