[input] refactor inputWithAutocomplete for team share

No need for separate inputWithAutocomplete' which just duplicates code
and is aimed specifically for node share.
parent c13a7aff
...@@ -8,12 +8,14 @@ import Data.Maybe (Maybe(..)) ...@@ -8,12 +8,14 @@ import Data.Maybe (Maybe(..))
import Data.Show.Generic (genericShow) import Data.Show.Generic (genericShow)
import Data.String (Pattern(..), contains, trim) import Data.String (Pattern(..), contains, trim)
import Data.Tuple.Nested ((/\)) import Data.Tuple.Nested ((/\))
import Effect.Aff (Aff) import Effect.Aff (Aff, launchAff_)
import Gargantext.Components.Bootstrap as B
import Gargantext.Components.Bootstrap.Types (Elevation(Level1))
import Gargantext.Components.Forest.Tree.Node.Action.Types (Action) import Gargantext.Components.Forest.Tree.Node.Action.Types (Action)
import Gargantext.Components.Forest.Tree.Node.Action.Types as Action import Gargantext.Components.Forest.Tree.Node.Action.Types as Action
import Gargantext.Components.Forest.Tree.Node.Tools as Tools import Gargantext.Components.Forest.Tree.Node.Tools as Tools
import Gargantext.Components.Forest.Tree.Node.Tools.SubTree (subTreeView, SubTreeParamsIn) import Gargantext.Components.Forest.Tree.Node.Tools.SubTree (subTreeView, SubTreeParamsIn)
import Gargantext.Components.InputWithAutocomplete (inputWithAutocomplete') import Gargantext.Components.InputWithAutocomplete (inputWithAutocomplete)
import Gargantext.Config.REST (AffRESTError, logRESTError) import Gargantext.Config.REST (AffRESTError, logRESTError)
import Gargantext.Hooks.Loader (useLoader) import Gargantext.Hooks.Loader (useLoader)
import Gargantext.Routes as GR import Gargantext.Routes as GR
...@@ -88,24 +90,30 @@ shareNodeInnerCpt :: R.Component ShareNodeInner ...@@ -88,24 +90,30 @@ shareNodeInnerCpt :: R.Component ShareNodeInner
shareNodeInnerCpt = here.component "shareNodeInner" cpt shareNodeInnerCpt = here.component "shareNodeInner" cpt
where where
cpt { dispatch, completions } _ = do cpt { dispatch, completions } _ = do
state <- T.useBox "" state' /\ state <- R2.useBox' ""
text' /\ text <- R2.useBox' "" text' /\ text <- R2.useBox' ""
pure $ Tools.panel pure $ Tools.panel
[ inputWithAutocomplete' { boxAction: shareAction [ inputWithAutocomplete { autocompleteSearch
, dispatch , classes: "share-users-completions d-flex align-items-center"
, state , onAutocompleteClick
, classes: "share-users-completions d-flex align-items-center" , onEnterPress: onEnterPress text
, autocompleteSearch , placeholder: "username or email"
, onAutocompleteClick , pattern: "^\\S+$" -- pattern doesn't allow space characters
, text , title: "Enter a username or an email address (space characters are not allowed)"
, pattern: "^\\S+$" -- pattern doesn't allow space characters , state }
, title: "Enter a username or an email address (space characters are not allowed)" [ B.iconButton { callback: submit state' text
, placeholder: "username or email"} , elevation: Level1
] (H.div {} [H.text text']) , name: "send"
, title: "Submit" } ]
] (H.div {} [ H.text text' ])
where where
autocompleteSearch input = pure $ nub $ filter (contains (Pattern input)) completions autocompleteSearch input = pure $ nub $ filter (contains (Pattern input)) completions
onAutocompleteClick _ = pure unit onAutocompleteClick _ = pure unit
onEnterPress text val = T.write_ ("Invited " <> val <> " to the team") text
submit val text _ = do
onEnterPress text val
launchAff_ $ dispatch (shareAction val)
------------------------------------------------------------------------ ------------------------------------------------------------------------
publishNode :: R2.Component SubTreeParamsIn publishNode :: R2.Component SubTreeParamsIn
publishNode = R.createElement publishNodeCpt publishNode = R.createElement publishNodeCpt
......
...@@ -69,7 +69,7 @@ nodeSearchControlCpt = here.component "nodeSearchControl" cpt ...@@ -69,7 +69,7 @@ nodeSearchControlCpt = here.component "nodeSearchControl" cpt
, pattern: ".*" , pattern: ".*"
, title: "" , title: ""
, placeholder: "find and select a term here..." , placeholder: "find and select a term here..."
} } []
, ,
B.button B.button
{ callback: \_ -> doSearch search' { callback: \_ -> doSearch search'
......
...@@ -37,8 +37,8 @@ type Props = ...@@ -37,8 +37,8 @@ type Props =
, state :: T.Box String , state :: T.Box String
) )
inputWithAutocomplete :: R2.Leaf Props inputWithAutocomplete :: R2.Component Props
inputWithAutocomplete = R2.leaf inputWithAutocompleteCpt inputWithAutocomplete = R2.component inputWithAutocompleteCpt
inputWithAutocompleteCpt :: R.Component Props inputWithAutocompleteCpt :: R.Component Props
inputWithAutocompleteCpt = here.component "inputWithAutocomplete" cpt inputWithAutocompleteCpt = here.component "inputWithAutocomplete" cpt
where where
...@@ -49,7 +49,7 @@ inputWithAutocompleteCpt = here.component "inputWithAutocomplete" cpt ...@@ -49,7 +49,7 @@ inputWithAutocompleteCpt = here.component "inputWithAutocomplete" cpt
, placeholder , placeholder
, pattern , pattern
, title , title
, state } _ = do , state } children = do
-- States -- States
state' <- T.useLive T.unequal state state' <- T.useLive T.unequal state
containerRef <- R.useRef null containerRef <- R.useRef null
...@@ -67,7 +67,7 @@ inputWithAutocompleteCpt = here.component "inputWithAutocomplete" cpt ...@@ -67,7 +67,7 @@ inputWithAutocompleteCpt = here.component "inputWithAutocomplete" cpt
{ className: "input-with-autocomplete " <> classes { className: "input-with-autocomplete " <> classes
, ref: containerRef , ref: containerRef
} }
[ ([
completionsCpt { completions, onAutocompleteClick, state } [] completionsCpt { completions, onAutocompleteClick, state } []
, H.input { type: "text" , H.input { type: "text"
, ref: inputRef , ref: inputRef
...@@ -83,7 +83,7 @@ inputWithAutocompleteCpt = here.component "inputWithAutocomplete" cpt ...@@ -83,7 +83,7 @@ inputWithAutocompleteCpt = here.component "inputWithAutocomplete" cpt
, blur: onBlur completions containerRef , blur: onBlur completions containerRef
} }
} }
] ] <> children)
-- Helpers -- Helpers
where where
...@@ -143,139 +143,6 @@ inputWithAutocompleteCpt = here.component "inputWithAutocomplete" cpt ...@@ -143,139 +143,6 @@ inputWithAutocompleteCpt = here.component "inputWithAutocomplete" cpt
else else
pure $ false pure $ false
type Props' =
(
autocompleteSearch :: String -> Effect Completions
, classes :: String
, onAutocompleteClick :: String -> Effect Unit
, dispatch :: Action -> Aff Unit
, boxAction :: String -> Action
, state :: T.Box String
, text :: T.Box String
, pattern :: String
, title :: String
, placeholder :: String
)
inputWithAutocomplete' :: R2.Leaf Props'
inputWithAutocomplete' = R2.leaf inputWithAutocompleteCpt'
inputWithAutocompleteCpt' :: R.Component Props'
inputWithAutocompleteCpt' = here.component "inputWithAutocomplete" cpt
where
cpt { autocompleteSearch
, classes
, onAutocompleteClick
, dispatch
, boxAction
, state
, text
, pattern
, title
, placeholder } _ = do
-- States
state' <- T.useLive T.unequal state
containerRef <- R.useRef null
inputRef <- R.useRef null
completions <- T.useBox []
R.useEffectOnce' $ do
cs <- autocompleteSearch state'
T.write_ cs completions
-- Render
pure $
H.div
{ className: "input-with-autocomplete " <> classes
, ref: containerRef
}
[
completionsCpt { completions, onAutocompleteClick, state } []
, H.input { type: "text"
, ref: inputRef
, className: "form-control"
, value: state'
, pattern: pattern
, title: title
, placeholder
, on: { focus: onFocus completions state'
, input: onInput completions
, change: onInput completions
, keyUp: onInputKeyUp inputRef
, blur: onBlur completions containerRef
}
}
, B.iconButton
{ callback: submit state'
, title: "Submit"
, name: "send"
, elevation: Level1
}
]
-- Helpers
where
-- (!) `onBlur` DOM.Event is triggered before any `onClick` DOM.Event
-- So when a completion is being clicked, the UX will be broken
--
-- ↳ As a solution we chose to check if the click is made from
-- the autocompletion list
onBlur :: forall event.
T.Box Completions
-> R.Ref (Nullable DOM.Element)
-> event
-> Effect Unit
onBlur completions containerRef event =
if isInnerEvent
then
pure $ (event .. "preventDefault")
else
T.write_ [] completions
where
mContains = do
a <- toMaybe $ R.readRef containerRef
b <- toMaybe (event .. "relatedTarget")
Just (contains a b)
isInnerEvent = maybe false identity mContains
onFocus :: forall event. T.Box Completions -> String -> event -> Effect Unit
onFocus completions st _ = do
cs <- autocompleteSearch st
T.write_ cs completions
onInput :: forall event. T.Box Completions -> event -> Effect Unit
onInput completions e = do
let val = R.unsafeEventValue e
T.write_ val state
cs <- autocompleteSearch val
T.write_ cs completions
onInputKeyUp :: R.Ref (Nullable DOM.Element) -> DE.KeyboardEvent -> Effect Boolean
onInputKeyUp inputRef e = do
if DE.key e == "Enter" then do
R2.preventDefault e
R2.stopPropagation e
let val = S.trim $ R.unsafeEventValue e
let mInput = toMaybe $ R.readRef inputRef
T.write_ val state
launchAff_ $ dispatch (boxAction val)
T.write_ ("Invited " <> val <> " to the team") text
case mInput of
Nothing -> pure false
Just input -> do
R2.blur input
pure false
else
pure $ false
submit val _ = do
T.write_ ("Invited " <> S.trim val <> " to the team") text
launchAff_ $ dispatch (boxAction val)
--------------------------------------------------------- ---------------------------------------------------------
type CompletionsProps = type CompletionsProps =
......
...@@ -151,7 +151,7 @@ component = here.component "main" cpt where ...@@ -151,7 +151,7 @@ component = here.component "main" cpt where
, title: "" , title: ""
, placeholder: "find and select a term here..." , placeholder: "find and select a term here..."
, state: searchState , state: searchState
} } []
] ]
] ]
......
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