package com.weEat.view import com.raquo.laminar.api.L._ import io.laminext.syntax.core._ import com.raquo.waypoint._ import play.api.libs.json.{JsValue,Json} import com.weEat.controllers.{FoodController,USDAController} import com.weEat.modules._ import com.weEat.shared.models.USDANodeNoId import gov.usda.nal.fdc.models._ import gov.usda.nal.fdc.models.DataType._ import org.scalajs.dom.Event import scala.concurrent.Future import scala.util.Success object UsdaImporter extends View[Option[String]] { import com.weEat.Main.headers implicit val ctx = com.weEat.shared.ctx val navName = Some("Usda Import") val tag = "importer" override val permissions = Set("admin") case class ViewPage(val q: Option[String] = None) extends P { val title = "USDA Import" + q.map((q) => s" - $q").getOrElse("") def jsonValue = Json.toJson(q) } def parseJson(jsVal: JsValue) = ViewPage(jsVal.asOpt[String]) def route = Route.onlyQuery( encode = (page: ViewPage) => page.q, decode = (q: Option[String]) => ViewPage(q = q), pattern = (root / tag / endOfSegments) ? param[String]("q").? ) def defaultPage = ViewPage() import com.raquo.airstream.custom.CustomSource._ def lazyFutureSignal[T](fut: => Future[T]) = Signal.fromCustomSource( Success(fut), (_: SetCurrentValue[Future[T]], _: GetCurrentValue[Future[T]], _, _) => (), (_) => () ).flatMap { (fut) => Signal.fromFuture(fut) } def lazyFutureSignal[T](fut: => Future[T], default: => T) = Signal.fromCustomSource( Success(fut), (_: SetCurrentValue[Future[T]], _: GetCurrentValue[Future[T]], _, _) => (), (_) => () ).flatMap { (fut) => Signal.fromFuture(fut) } private val SEARCH_PAGE_SIZE = 40.asInstanceOf[Short] def content(queryPage: Signal[ViewPage]) = { val searchBar: SearchBar[Seq[Signal[Option[Seq[SearchResultFood]]]]] = SearchBar((term) => USDAController.getFoodsSearch(term, Seq( // Branded, Foundation, SRLegacy ).map(_.toString), pageSize = Some(SEARCH_PAGE_SIZE))().map { case SearchResult(criteria, n, cur, tot, baseList) => Val(Some(baseList)) +: (cur + 1 to tot).map({ (c) => lazyFutureSignal( USDAController.postFoodsSearch()( criteria.copy(pageNumber = Some(c)) ).map(_.foods), Nil ) }) }, inSignal = queryPage.map(_.q).withDefault("") ) val searchResults = searchBar.result val pageSizeSel = Select(Val((10 to SEARCH_PAGE_SIZE by 10))) val numPages = pageSizeSel.value.combineWithFn(searchResults) { case (_, None) => 0 case (size, Some(results)) => results.length * SEARCH_PAGE_SIZE / size } val pageSel = PageSelect(numPages) val currentSearchPageNum = pageSel.page.combineWithFn(pageSizeSel.value) { case (pageNum, pageSize) => pageNum * pageSize / SEARCH_PAGE_SIZE } val currentSearchPageOffset = pageSel.page.combineWithFn(pageSizeSel.value) { case (pageNum, pageSize) => pageNum % (SEARCH_PAGE_SIZE / pageSize) } val currentSearchPage = searchResults.combineWithFn(currentSearchPageNum) { case (Some(Nil), _) => Val(Nil) case (None, _) => Val(Nil) // [2023-09-26]@tflucke TODO: implement loading UI instead of default case (Some(res), pageNum) => res(pageNum).withDefault(Nil) }.flatMap(identity) // TODO: Prefetch next page div( h2("USDA Importer"), div(cls := "form-group", label(forId := "search", "Search: "), searchBar.render ), searchBar.searchTerm --> { (str: Option[String]) => val oldQ = View.router.currentPageSignal.now().asInstanceOf[ViewPage].q if (oldQ != str) View.router.pushState(ViewPage(q = str)) }, PaginatedTable[SearchResultFood](Seq( ("", 1, { (x) => button(cls := "btn btn-light", onClick --> {(e: Event) => val editor = USDAEditor(USDANodeNoId.fromSearchResult(x), true) Overlay.confirm(editor.render) { () => import com.weEat.Main.headers FoodController.add()(editor.getUSDANode()) } }, "Add" )}), ("ID", 1, { (x) => span(x.fdcId.toString)}), ("Name", 3, { (x) => span(x.description)}), ("Desc", 4, { (x) => span(x.additionalDescriptions)}), ("Brand", 3, { (x) => span(x.brandOwner)}) ), currentSearchPage, currentSearchPageOffset, pageSizeSel.value ).render, (pageSel.render).amendThis( (elm) => cls := s"${elm.ref.className} col-3 float-left" ), (pageSizeSel.render).amendThis( (elm) => cls := s"${elm.ref.className} col-1 float-right" ) ) } }