feat(event): ID 기반 이벤트 상세 API를 연동한다

This commit is contained in:
Yu Sung
2026-10-29 12:03:02 +09:00
parent d664448f38
commit 468a766242
15 changed files with 549 additions and 44 deletions
@@ -11,6 +11,7 @@ import Moya
enum EventApi {
case getEvents
case getEventPopup
case getEventDetail(id: Int)
}
extension EventApi: TargetType {
@@ -25,24 +26,30 @@ extension EventApi: TargetType {
case .getEventPopup:
return "/event/popup"
case .getEventDetail(let id):
return "/api/v2/events/\(id)"
}
}
var method: Moya.Method {
switch self {
case .getEvents, .getEventPopup:
case .getEvents, .getEventPopup, .getEventDetail:
return .get
}
}
var task: Task {
switch self {
case .getEvents, .getEventPopup:
case .getEvents, .getEventPopup, .getEventDetail:
return .requestPlain
}
}
var headers: [String : String]? {
if case .getEventDetail = self, UserDefaults.string(forKey: .token).isEmpty {
return nil
}
return ["Authorization": "Bearer \(UserDefaults.string(forKey: UserDefaultsKey.token))"]
}
}
@@ -9,38 +9,50 @@ import SwiftUI
import Kingfisher
struct EventDetailView: View {
let event: EventItem
@Environment(\.dismiss) private var dismiss
@StateObject private var viewModel: EventDetailViewModel
init(eventId: Int) {
_viewModel = StateObject(wrappedValue: EventDetailViewModel(eventId: eventId))
}
var body: some View {
BaseView {
BaseView(isLoading: $viewModel.isLoading) {
GeometryReader { proxy in
VStack(spacing: 0) {
DetailNavigationBar(title: I18n.Settings.Event.detailTitle)
DetailNavigationBar(title: I18n.Settings.Event.detailTitle, backAction: {
viewModel.cancel()
dismiss()
})
ScrollView(.vertical, showsIndicators: false) {
KFImage(URL(string: event.detailImageUrl!))
.cancelOnDisappear(true)
.resizable()
.scaledToFit()
if case .loaded(let event) = viewModel.state,
let detailImageUrl = event.detailImageUrl {
KFImage(URL(string: detailImageUrl))
.cancelOnDisappear(true)
.resizable()
.scaledToFit()
}
}
Spacer()
if let link = event.link, link.count > 0, let url = URL(string: link), UIApplication.shared.canOpenURL(url) {
Text(I18n.Settings.Event.participateButton)
.appFont(size: 18.3, weight: .bold)
.foregroundColor(.white)
.padding(.vertical, 16)
.frame(width: screenSize().width - 26.7)
.background(Color(hex: "3e737c"))
.cornerRadius(10)
.padding(13.3)
.background(Color(hex: "222222"))
.cornerRadius(16.7, corners: [.topLeft, .topRight])
.onTapGesture {
UIApplication.shared.open(url)
}
if let url = viewModel.participationURL, UIApplication.shared.canOpenURL(url) {
Button {
UIApplication.shared.open(url)
} label: {
Text(I18n.Settings.Event.participateButton)
.appFont(size: 18.3, weight: .bold)
.foregroundColor(.white)
.padding(.vertical, 16)
.frame(width: screenSize().width - 26.7)
.background(Color(hex: "3e737c"))
.cornerRadius(10)
.padding(13.3)
.background(Color(hex: "222222"))
.cornerRadius(16.7, corners: [.topLeft, .topRight])
}
.buttonStyle(.plain)
}
if proxy.safeAreaInsets.bottom > 0 {
@@ -52,19 +64,23 @@ struct EventDetailView: View {
.edgesIgnoringSafeArea(.bottom)
}
}
.sodaToast(isPresented: $viewModel.isShowPopup, message: viewModel.errorMessage, autohideIn: 2)
.onAppear {
viewModel.load()
}
.onDisappear {
viewModel.cancel()
}
.onReceive(viewModel.$state) { state in
if state == .unavailable, viewModel.takeUnavailableDismissal() {
dismiss()
}
}
}
}
struct EventDetailView_Previews: PreviewProvider {
static var previews: some View {
EventDetailView(
event: EventItem(
id: 1,
thumbnailImageUrl: "",
detailImageUrl: "",
popupImageUrl: "",
link: "http://m.naver.com"
)
)
EventDetailView(eventId: 0)
}
}
@@ -38,7 +38,7 @@ struct EventListView: View {
.contentShape(Rectangle())
.onTapGesture {
if let _ = event.detailImageUrl {
AppState.shared.setAppStep(step: .eventDetail(event: event))
AppState.shared.setAppStep(step: .eventDetail(eventId: event.id))
} else if let link = event.link, link.trimmingCharacters(in: .whitespaces).count > 0, let url = URL(string: link), UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url)
}
@@ -20,5 +20,8 @@ final class EventRepository {
func getEventPopup() -> AnyPublisher<Response, MoyaError> {
return api.requestPublisher(.getEventPopup)
}
}
func getEventDetail(id: Int) -> AnyPublisher<Response, MoyaError> {
return api.requestPublisher(.getEventDetail(id: id))
}
}