Skip to content

Instantly share code, notes, and snippets.

@danielt1263
Last active May 2, 2022 11:44
Show Gist options
  • Save danielt1263/bb1af5f2864b2ee788c129deb5f48be2 to your computer and use it in GitHub Desktop.
Save danielt1263/bb1af5f2864b2ee788c129deb5f48be2 to your computer and use it in GitHub Desktop.
struct MenuViewModelInput {
let fetchMenus: Observable<Void>
let clearSelections: Observable<Void>
let makeOrder: Observable<Void>
let increaseMenuCount: Observable<(menu: ViewMenu, inc: Int)>
}
struct MenuViewModelOutput {
let activated: Observable<Bool>
let errorMessage: Observable<Error>
let allMenus: Observable<[ViewMenu]>
let totalSelectedCountText: Observable<String>
let totalPriceText: Observable<String>
let showOrderPage: Observable<[ViewMenu]>
}
func menuViewModel(fetchMenus: Observable<[Thing]>) -> (MenuViewModelInput) -> MenuViewModelOutput {
{ input in
let errorSubject = PublishSubject<Error>()
enum Action {
case reset([ViewMenu])
case adjustCount(menu: ViewMenu, inc: Int)
}
let resetMenus = input.fetchMenus
.flatMap {
fetchMenus
.catch { error in
errorSubject.onNext(error)
return .empty()
}
}
.map { Action.reset($0.map { ViewMenu($0) }) }
let allMenus = Observable.merge(
resetMenus,
input.increaseMenuCount.map(Action.adjustCount(menu:inc:))
)
.scan(into: [ViewMenu]()) { state, action in
switch action {
case let .reset(viewMenus):
state = viewMenus
case .adjustCount(menu: let menu, inc: let inc):
guard let index = state.firstIndex(where: { $0.name == menu.name }) else { break }
state[index] = state[index].countUpdated(inc)
}
}
.share(replay: 1)
return MenuViewModelOutput(
activated: Observable.merge(
input.fetchMenus.map { true },
resetMenus.map { _ in false }
)
.startWith(false),
errorMessage: errorSubject.asObservable(),
allMenus: allMenus,
totalSelectedCountText: allMenus
.map { $0.map { $0.count }.reduce(0, +) }
.map { "\($0)" },
totalPriceText: allMenus
.map { $0.map { $0.price * $0.count }.reduce(0, +) }
.map { $0.currencyKR() },
showOrderPage: input.makeOrder
.withLatestFrom(allMenus)
.map { $0.filter { $0.count > 0 } }
.do(onNext: { items in
if items.count == 0 {
let err = NSError(domain: "No Orders", code: -1, userInfo: nil)
errorSubject.onNext(err)
}
})
.filter { $0.count > 0 }
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment