Commit 5f21c692 authored by James Laver's avatar James Laver

Refactor SearchField to work over a State Search, add G.Utils.Reactix.useLayoutEffect1'

parent 07196b05
module Gargantext.Components.Search.SearchField where
module Gargantext.Components.Search.SearchField
( Search, Props, searchField, searchFieldComponent )where
import Prelude hiding (div)
import Data.Map as Map
......@@ -21,11 +22,16 @@ import Reactix.SyntheticEvent as E
select = R.createElement "select"
type Search = { category :: String, term :: String }
defaultSearch :: Search
defaultSearch = { category: "PubMed", term: "" }
type Props =
-- list of categories to search, or parsers to use on uploads
( categories :: Array String
-- State hook for a search term, how we get data in and out
, term :: R.State String
-- State hook for a search, how we get data in and out
, search :: R.State (Maybe Search)
)
searchField :: Record Props -> R.Element
......@@ -38,24 +44,37 @@ searchFieldComponent :: R.Memo Props
searchFieldComponent = R.memo (R.hooksComponent "SearchField" cpt) hasChanged
where
cpt props _ = do
elemRef <- R.useRef $ null
let search = maybe defaultSearch identity (fst props.search)
cat <- R.useState $ \_ -> pure search.category
term <- R.useState $ \_ -> pure search.term
pure $
div { className: "search-field" }
[ select { className: "category" } (cat <$> props.categories)
, searchInput elemRef props.term
, submitButton elemRef props.term
[ categoryInput cat props.categories
, searchInput term
, submitButton cat term props.search
]
cat name = option { value: name } [text name]
hasChanged p p' = (p.categories /= p'.categories) || (fst p.term /= fst p.term)
hasChanged p p' = (p.categories /= p'.categories) || (fst p.search /= fst p.search)
searchInput :: R.Ref (Nullable DOM.Element) -> R.State String -> R.Element
searchInput ref (term /\ setTerm) =
categoryInput :: R.State String -> Array String -> R.Element
categoryInput (cat /\ setCat) cats =
select { className: "category", onChange } (item <$> cats)
where
onChange = mkEffectFn1 $ \e -> setCat (e .. "target" .. "value")
item name = option { value: name } [ text name ]
searchInput :: R.State String -> R.Element
searchInput (term /\ setTerm) =
input { defaultValue: term
, type: "text"
, ref: ref
, placeholder: placeholder }
, onChange
, placeholder }
where onChange = mkEffectFn1 $ \e -> setTerm $ e .. "target" .. "value"
submitButton :: R.Ref (Nullable DOM.Element) -> R.State String -> R.Element
submitButton ref (_ /\ setTerm) = button { onClick: click } [ text "Search" ]
submitButton :: R.State String -> R.State String -> R.State (Maybe Search) -> R.Element
submitButton (cat /\ _) (term /\ _) (_ /\ setSearch) = button { onClick: click } [ text "Search" ]
where
click = mkEffectFn1 $ \_ -> setTerm $ (R.readRef ref) .. "value"
click = mkEffectFn1 $ \_ -> do
case term of
"" -> setSearch Nothing
_ -> setSearch $ Just { category: cat, term: term }
......@@ -178,9 +178,9 @@ searchBar = simpleSpec defaultPerformAction render
[ divLogo
, div [ className "collapse navbar-collapse"
]
$ [ divDropdownLeft ]
<> [R'.scuff (SB.searchBar SB.defaultProps)] <>
[ divDropdownRight d s ]
$ [ divDropdownLeft ]
<> [ R'.scuff (SB.searchBar SB.defaultProps) ]
<> [ divDropdownRight d s ]
]
]
]
......
module Gargantext.Pages.Layout.Specs.SearchBar where
module Gargantext.Pages.Layout.Specs.SearchBar
( Props, defaultProps, searchBar, searchBarComponent
) where
import Prelude
import Data.Maybe (Maybe(..))
import Data.Traversable (traverse_)
import Data.Tuple (fst)
import Data.Tuple.Nested ( (/\) )
import Effect.Uncurried (EffectFn1, mkEffectFn1)
......@@ -10,12 +14,17 @@ import DOM.Simple.Console
import Gargantext.Utils.Reactix as R'
import Reactix.DOM.HTML as H
import Gargantext.Components.Modals.Modal (modalShow)
import Gargantext.Components.Search.SearchField (searchField)
import Gargantext.Components.Search.SearchField (Search, searchField)
type Props = ( open :: Boolean, categories :: Array String )
type Props =
( open :: Boolean
, categories :: Array String )
defaultCategories :: Array String
defaultCategories = ["PubMed", "HAL"]
defaultProps :: Record Props
defaultProps = { open: true, categories: ["PubMed", "HAL"] }
defaultProps = { open: true, categories: defaultCategories }
searchBar :: Record Props -> R.Element
searchBar p = R.createElement searchBarComponent p []
......@@ -25,25 +34,31 @@ searchBarComponent = R.hooksComponent "SearchBar" cpt
where
cpt props _ = do
open <- R.useState $ \_ -> pure $ props.open
term <- R.useState $ \_ -> pure ""
R.useLayoutEffect1 (fst term) $ \_ -> do
case (fst term) of
"" -> pure unit
term' -> do
log2 "Searching term: " term'
modalShow "addCorpus"
pure $ \_ -> pure unit
search <- R.useState $ \_ -> pure Nothing
onSearchChange search
pure $ H.div { className: "search-bar-container" }
[ toggleButton open, inner open term props ]
toggleButton :: R.State Boolean -> R.Element
toggleButton open =
H.button {onClick: onClickToggleExpanded open, className: "search-bar-toggle"}
[ H.i { className: "material-icons md-36", style: { marginTop: "-5px" } }
[ H.text "control_point" ] ]
inner :: R.State Boolean -> R.State String -> Record Props -> R.Element
inner (true /\ _) term props = H.div {className: "search-bar open"}
[ searchField { categories: props.categories, term: term } ]
inner (false /\ _) _ _ = H.div {className: "search-bar closed"} []
onClickToggleExpanded :: forall e. R.State Boolean -> EffectFn1 e Unit
onClickToggleExpanded open = mkEffectFn1 $ \_ -> R'.overState not open
[ toggleButton open
, searchFieldContainer open search props.categories ]
searchFieldContainer :: R.State Boolean -> R.State (Maybe Search) -> Array String -> R.Element
searchFieldContainer (true /\ _) search categories =
H.div { className: "search-bar open" } [ searchField { categories, search } ]
searchFieldContainer (false /\ _) _ _ = H.div {className: "search-bar closed"} []
onSearchChange :: R.State (Maybe Search) -> R.Hooks Unit
onSearchChange (search /\ setSearch) =
R'.useLayoutEffect1' search $ \_ -> traverse_ triggerSearch search
where
triggerSearch {term, category} = do
log4 "Searching term: " term " in cat:" category
modalShow "addCorpus"
toggleButton :: R.State Boolean -> R.Element
toggleButton open =
H.button { onClick: onToggleExpanded open, className: "search-bar-toggle" }
[ H.i { className: "material-icons md-36"
, style: { marginTop: "-5px", color: "#000" } }
[ H.text "control_point" ] ]
onToggleExpanded :: forall e. R.State Boolean -> EffectFn1 e Unit
onToggleExpanded open = mkEffectFn1 $ \_ -> R'.overState not open
......@@ -35,3 +35,8 @@ named = flip $ defineProperty "name"
overState :: forall t. (t -> t) -> R.State t -> Effect Unit
overState f (state /\ setState) = setState $ f state
useLayoutEffect1' :: forall a. a -> (Unit -> Effect Unit) -> R.Hooks Unit
useLayoutEffect1' a f = R.useLayoutEffect1 a $ \_ ->
do f unit
pure $ \_ -> pure unit
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment