feat(gift): 선물함 목록 화면을 추가한다
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
import Foundation
|
||||
import Combine
|
||||
|
||||
final class GiftBoxListViewModel: ObservableObject {
|
||||
private let repository = GiftRepository()
|
||||
private let pageSize = 20
|
||||
private var subscription: AnyCancellable?
|
||||
private var page = 0
|
||||
private var isRequestInFlight = false
|
||||
|
||||
@Published private(set) var items = [GiftListItemResponse]()
|
||||
@Published private(set) var totalCount = 0
|
||||
@Published private(set) var hasNext = false
|
||||
@Published private(set) var hasLoaded = false
|
||||
@Published private(set) var isLoading = false
|
||||
@Published private(set) var isLoadingMore = false
|
||||
@Published private(set) var isRefreshing = false
|
||||
@Published private(set) var errorMessage = ""
|
||||
@Published var isShowPopup = false
|
||||
|
||||
func fetchInitialPage() {
|
||||
guard !hasLoaded else { return }
|
||||
fetch(page: 0)
|
||||
}
|
||||
|
||||
func fetchNextPage(currentItem: GiftListItemResponse) {
|
||||
guard hasLoaded, hasNext,
|
||||
currentItem.applicationNo == items.last?.applicationNo else { return }
|
||||
fetch(page: page + 1)
|
||||
}
|
||||
|
||||
@MainActor
|
||||
func refresh() async {
|
||||
await withCheckedContinuation { continuation in
|
||||
fetch(page: 0, isRefresh: true) {
|
||||
continuation.resume()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func fetch(page requestedPage: Int, isRefresh: Bool = false, completion: (() -> Void)? = nil) {
|
||||
guard !isRequestInFlight else {
|
||||
completion?()
|
||||
return
|
||||
}
|
||||
|
||||
isRequestInFlight = true
|
||||
isLoading = requestedPage == 0 && !isRefresh
|
||||
isLoadingMore = requestedPage > 0
|
||||
isRefreshing = isRefresh
|
||||
errorMessage = ""
|
||||
isShowPopup = false
|
||||
|
||||
subscription = repository.getGifts(page: requestedPage, size: pageSize)
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] result in
|
||||
defer { completion?() }
|
||||
guard let self else { return }
|
||||
|
||||
if case .failure(let error) = result {
|
||||
self.showError(data: error.response?.data)
|
||||
}
|
||||
self.isLoading = false
|
||||
self.isLoadingMore = false
|
||||
self.isRefreshing = false
|
||||
self.isRequestInFlight = false
|
||||
} receiveValue: { [weak self] response in
|
||||
guard let self else { return }
|
||||
|
||||
do {
|
||||
let decoded = try JSONDecoder().decode(ApiResponse<GiftListResponse>.self, from: response.data)
|
||||
guard decoded.success, let data = decoded.data else {
|
||||
self.showError(data: response.data)
|
||||
return
|
||||
}
|
||||
|
||||
if requestedPage == 0 {
|
||||
self.items = data.items
|
||||
} else {
|
||||
self.items.append(contentsOf: data.items)
|
||||
}
|
||||
self.page = data.page
|
||||
self.totalCount = data.totalCount
|
||||
self.hasNext = data.hasNext
|
||||
self.hasLoaded = true
|
||||
} catch {
|
||||
self.showError(data: response.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func showError(data: Data?) {
|
||||
struct ErrorResponse: Decodable {
|
||||
let message: String?
|
||||
}
|
||||
|
||||
let decoded = data.flatMap { try? JSONDecoder().decode(ErrorResponse.self, from: $0) }
|
||||
let message = decoded?.message?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
||||
errorMessage = message.isEmpty ? I18n.Common.commonError : message
|
||||
isShowPopup = true
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user