[input] refactor inputWithAutocomplete for team share

No need for separate inputWithAutocomplete' which just duplicates code
and is aimed specifically for node share.
parent c13a7aff
Pipeline #5464 failed with stage
in 0 seconds
......@@ -8,12 +8,14 @@ import Data.Maybe (Maybe(..))
import Data.Show.Generic (genericShow)
import Data.String (Pattern(..), contains, trim)
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 as Action
import Gargantext.Components.Forest.Tree.Node.Tools as Tools
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.Hooks.Loader (useLoader)
import Gargantext.Routes as GR
......@@ -88,24 +90,30 @@ shareNodeInnerCpt :: R.Component ShareNodeInner
shareNodeInnerCpt = here.component "shareNodeInner" cpt
where
cpt { dispatch, completions } _ = do
state <- T.useBox ""
state' /\ state <- R2.useBox' ""
text' /\ text <- R2.useBox' ""
pure $ Tools.panel
[ inputWithAutocomplete' { boxAction: shareAction
, dispatch
, state
, classes: "share-users-completions d-flex align-items-center"
, autocompleteSearch
, onAutocompleteClick
, text
, pattern: "^\\S+$" -- pattern doesn't allow space characters
, title: "Enter a username or an email address (space characters are not allowed)"
, placeholder: "username or email"}
] (H.div {} [H.text text'])
[ inputWithAutocomplete { autocompleteSearch
, classes: "share-users-completions d-flex align-items-center"
, onAutocompleteClick
, onEnterPress: onEnterPress text
, placeholder: "username or email"
, pattern: "^\\S+$" -- pattern doesn't allow space characters
, title: "Enter a username or an email address (space characters are not allowed)"
, state }
[ B.iconButton { callback: submit state' text
, elevation: Level1
, name: "send"
, title: "Submit" } ]
] (H.div {} [ H.text text' ])
where
autocompleteSearch input = pure $ nub $ filter (contains (Pattern input)) completions
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 = R.createElement publishNodeCpt
......
......@@ -69,7 +69,7 @@ nodeSearchControlCpt = here.component "nodeSearchControl" cpt
, pattern: ".*"
, title: ""
, placeholder: "find and select a term here..."
}
} []
,
B.button
{ callback: \_ -> doSearch search'
......
......@@ -37,8 +37,8 @@ type Props =
, state :: T.Box String
)
inputWithAutocomplete :: R2.Leaf Props
inputWithAutocomplete = R2.leaf inputWithAutocompleteCpt
inputWithAutocomplete :: R2.Component Props
inputWithAutocomplete = R2.component inputWithAutocompleteCpt
inputWithAutocompleteCpt :: R.Component Props
inputWithAutocompleteCpt = here.component "inputWithAutocomplete" cpt
where
......@@ -49,7 +49,7 @@ inputWithAutocompleteCpt = here.component "inputWithAutocomplete" cpt
, placeholder
, pattern
, title
, state } _ = do
, state } children = do
-- States
state' <- T.useLive T.unequal state
containerRef <- R.useRef null
......@@ -67,7 +67,7 @@ inputWithAutocompleteCpt = here.component "inputWithAutocomplete" cpt
{ className: "input-with-autocomplete " <> classes
, ref: containerRef
}
[
([
completionsCpt { completions, onAutocompleteClick, state } []
, H.input { type: "text"
, ref: inputRef
......@@ -83,7 +83,7 @@ inputWithAutocompleteCpt = here.component "inputWithAutocomplete" cpt
, blur: onBlur completions containerRef
}
}
]
] <> children)
-- Helpers
where
......@@ -143,139 +143,6 @@ inputWithAutocompleteCpt = here.component "inputWithAutocomplete" cpt
else
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 =
......
......@@ -151,7 +151,7 @@ component = here.component "main" cpt where
, title: ""
, placeholder: "find and select a term here..."
, 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